Commit bfeaf32e by qinjianhui

feat: 发货单管理开发

parent cb427077
......@@ -11,6 +11,7 @@ declare module 'vue' {
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
......
......@@ -2,6 +2,7 @@ import { BasePaginationData, BaseRespData } from '@/types/api'
import axios from './axios'
import { LoginReq, LoginResp } from '@/types/api/auth'
import { UserEditForm, userData, userSearchForm } from '@/types/api/user'
import { NameSpaceList } from '@/types/api/deliveryNote'
export function loginApi(data: LoginReq) {
return axios.post<never, LoginResp>('/factory/login', data)
......@@ -62,10 +63,17 @@ export function getDetailsByIdApi(id: number) {
}
// 切换用户状态
export function changeUserStatusApi(status: number, id: number) {
return axios.get<never,BaseRespData<never>>('factory/factoryUser/enableDisable',{
params: {
status,
id
}
})
return axios.get<never, BaseRespData<never>>(
'factory/factoryUser/enableDisable',
{
params: {
status,
id,
},
},
)
}
export function getUserNameSpaceList() {
return axios.get<never, BaseRespData<NameSpaceList[]>>('dbDiyUser/getList')
}
......@@ -9,8 +9,13 @@ import {
ShipmentForm,
ShipmentOrderRes,
Tab,
InspectionData
InspectionData,
} from '@/types/api/order'
import {
DeliveryNoteData,
DeliveryNoteSearchForm,
ProductionOrder,
} from '@/types/api/deliveryNote'
export function getOrderList(
data: SearchForm,
......@@ -93,10 +98,10 @@ export function getQaOrderBySubOrderNumber(orderNumber: string) {
)
}
// 质检完成
export function qaFinishedApi(data:InspectionData[]) {
export function qaFinishedApi(data: InspectionData[]) {
return axios.post<never, BaseRespData<never>>(
'factory/customJomallOrder/inspection',
data
data,
)
}
......@@ -167,3 +172,48 @@ export function refreshProductInfo(data: number[]) {
data,
)
}
export function getDeliveryNoteList(
data: DeliveryNoteSearchForm,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<DeliveryNoteData>>(
'factory/customJomallShipment/list_page',
{
...data,
currentPage,
pageSize,
},
)
}
export function printDeliveryNote(data: string[]) {
return axios.post<never, BaseRespData<never>>(
'factory/customJomallShipment/printInvoiceStatistics',
{
startTime: data && data[0],
endTime: data && data[1],
},
)
}
export function getProductionOrderList(subOrderNumber: string) {
return axios.get<never, BaseRespData<ProductionOrder>>(
'customJomallOrderProduct/getBySubOrderNumber',
{
params: {
subOrderNumber,
},
},
)
}
export function getOrderByIdApi(id?: number) {
return axios.get<never, BaseRespData<OrderData>>(
'factory/customJomallOrder/getOrderById',
{
params: {
id,
},
},
)
}
......@@ -9,6 +9,7 @@ import OrderList from '@/views/order/index.vue'
import ProductionComplete from '@/views/production/complete.vue'
import { getToken} from '@/api/axios'
import UserPage from '@/views/UserPage.vue'
import DeliveryNotePage from '@/views/DeliveryNotePage.vue'
const router = createRouter({
history: createWebHistory(),
......@@ -33,6 +34,10 @@ const router = createRouter({
{
path: '/system/user',
component: UserPage
},
{
path: '/system/delivery-note',
component: DeliveryNotePage
}
],
},
......
......@@ -25,6 +25,11 @@ const menu: MenuItem[] = [
index: '/system/user',
id: 4,
label: '用户管理',
},
{
index: '/system/delivery-note',
id: 5,
label: '发货单管理',
}
]
},
......
export interface DeliveryNoteSearchForm {
subOrderNumber?: string
billNumber?: number
startTime?: string
endTime?: string
logisticsTracking?: string
lanshouName?: string
orderNumber?: string
namespace?: string
shippingWay?: number
}
export interface DeliveryNoteData {
id: number
billNumber?: string
shippingWay?: number
addressId?: number
carriageAmount?: number | string
carriageName?: string
logisticsTracking?: string
shippingStatus?: number
lanshouName?: string
lanshouPhone?: string
lanshouRegion?: string
lanshouAddress?: string
lanshouPost?: string
inspectionStatus?: boolean
facotoryNo?: number
updateTime?: string
createTime?: string
subOrderNumber?: string
detailList: DetailList[]
}
export interface DetailList {
id: number
shipmentId?: number
customOrderId?: number
customOrderNumber?: string
subOrderNumber?: string
baseSku?: string
variantSku?: string
variantImage?: string
shipmentNum?: number
passNum?: number
notPassNum?: number
inspectionStatus?: boolean
updateTime?: string
createTime?: string
productionNum?: number
notShipmentNum?: number
productName?: string
facotoryNo?: string | number
billNumber?: string | number
}
export interface NameSpaceList {
id: number
sku?: string
name?: string
password?: string
imgUrl?: string
chimaStatus?: number
status?: number
createDate?: string
updateDate?: string
}
export interface ProductionOrder {
id: number
erpId?: number
customOrderId?: number
subOrderNumber?: string
erpSubOrderNumber?: string
erpOrderId?: number
erpOrderItemId?: number
erpProductItemId?: number
shopNumber?: number
baseSku?: string
variantSku?: string
variantImage?: string
chimaId?: string
diyId?: string
endProductId?: string
num?: number
printType?: number
version?: number
shipmentNum?: number
price?: number
productName?: string
weight?: number
createTime?: string
updateTime?: string
notPassNum?: number
passNum?: number
}
<template>
<div class="delivery-note-page flex-column card h-100 overflow-hidden">
<div class="header-filter-form">
<ElForm :model="searchForm" inline>
<ElFormItem label="发货时间">
<el-date-picker
v-model="dateRange"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
style="width: 360px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</ElFormItem>
<ElFormItem label="生产单号">
<ElInput
v-model="searchForm.subOrderNumber"
clearable
placeholder="请输入生产单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="发货单号">
<ElInput
v-model="searchForm.billNumber"
clearable
placeholder="请输入发货单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="订单号">
<ElInput
v-model="searchForm.orderNumber"
placeholder="订单号"
clearable
style="width: 160px"
></ElInput>
</ElFormItem>
<ElFormItem label="收货人">
<ElInput
v-model="searchForm.lanshouName"
clearable
placeholder="请输入收货人"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="送货方式">
<ElSelect
v-model="searchForm.shippingWay"
clearable
placeholder="请选择送货方式"
style="width: 160px"
>
<ElOption label="快递" :value="2"></ElOption>
<ElOption label="送货上门" :value="1"></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="客户名称">
<ElSelect
v-model="searchForm.namespace"
clearable
placeholder="请选择客户名称"
style="width: 160px"
>
<ElOption
v-for="item in nameSpaceList"
:key="item.id"
:label="item.name"
:value="item.name"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="物流跟踪号" prop="logisticsTracking">
<ElInput
v-model="searchForm.logisticsTracking"
placeholder="请输入物流跟踪号"
clearable
style="width: 160px"
/>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search">查询</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="success" @click="onPrintDeliveryNote"
>打印发货单</ElButton
>
</ElFormItem>
</ElForm>
</div>
<div class="delivery-note-content flex-1 flex-column overflow-hidden">
<div class="delivery-note-list flex-1 overflow-hidden">
<ElTable
:data="tableData"
default-expand-all
style="width: 100%; height: 100%"
border
:cell-class-name="onCellClassName"
@selection-change="handleSelectionChange"
>
<ElTableColumn
type="selection"
width="50"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
type="index"
label="序号"
width="60"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="发货单号"
prop="billNumber"
header-align="center"
align="center"
width="180"
></ElTableColumn>
<ElTableColumn
label="发货单信息"
header-align="center"
prop="billNumberInfo"
min-width="300"
>
<template #default="scope">
<div class="send-order-column">
<div
v-for="od in scope.row.detailList"
:key="od.id"
class="send-order-product-item"
>
<div class="send-order-product-image">
<img :src="od.variantImage" :alt="od.productName" />
</div>
<div
v-for="(p, i) in productProps"
:key="i"
class="send-order-prop-list"
>
<div
v-for="(pi, index) in p"
:key="index"
class="send-order-prop-item"
>
<span> {{ pi.label }}{{ val(od, pi.key || '') }} </span>
<el-icon
v-if="pi.copyable"
class="icon"
@click="copy(val(od, pi.key || ''))"
><DocumentCopy
/></el-icon>
</div>
</div>
</div>
</div>
</template>
</ElTableColumn>
<ElTableColumn
label="物流信息"
header-align="center"
prop="logisticsInfo"
>
<template #default="{ row }">
<div class="send-order-logistics">
<div
v-for="pi in logisticsProps"
:key="pi.label"
class="send-order-prop-item"
>
<span v-if="val(row, pi.key)"
>{{ pi.label }}{{ val(row, pi.key) }}</span
>
<el-icon
v-if="pi.copyable && val(row, pi.key)"
class="icon"
@click="copy(val(row, pi.key || ''))"
><DocumentCopy
/></el-icon>
</div>
</div>
</template>
</ElTableColumn>
<ElTableColumn
label="操作"
header-align="center"
align="center"
prop="operation"
width="180"
>
<template #default="{ row }">
<div>
<ElButton type="text" @click="onViewOrder(row)"
>查看订单</ElButton
>
</div>
</template>
</ElTableColumn>
</ElTable>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</div>
</div>
<ElDialog
v-model="dialogVisible"
title="选择时间"
width="500px"
:close-on-click-modal="false"
>
<el-date-picker
v-model="dateRange"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<template #footer>
<div class="dialog-footer">
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="onConfirmDateRange">确定</ElButton>
</div>
</template>
</ElDialog>
<ElDrawer
v-model="orderDetailDialogVisible"
title="查看订单"
direction="rtl"
size="40%"
:close-on-click-modal="false"
>
<OrderDetail :order-detail-data="orderDetailData" />
</ElDrawer>
</template>
<script setup lang="ts">
import { DocumentCopy } from '@element-plus/icons-vue'
import {
DeliveryNoteSearchForm,
DeliveryNoteData,
NameSpaceList,
} from '@/types/api/deliveryNote'
import { OrderData } from '@/types/api/order'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import {
getDeliveryNoteList,
printDeliveryNote,
getOrderByIdApi,
} from '@/api/order'
import { getUserNameSpaceList } from '@/api/auth'
import { ref, onMounted } from 'vue'
import { val } from '@/utils'
import { showError } from '@/utils/ui'
import { filePath } from '@/api/axios'
import { type CellCls } from 'element-plus'
import OrderDetail from './order/OrderDetail.vue'
const [searchForm, resetSearchForm] = useValue<DeliveryNoteSearchForm>({})
const selection = ref<DeliveryNoteData[]>([])
const dateRange = ref<string[]>([])
const productProps = [
[
{ label: '商品名', key: 'productName' },
{ label: 'Base SKU', key: 'baseSku', copyable: true },
{ label: '变体SKU', key: 'variantSku', copyable: true },
],
[{ label: '生产单号', key: 'subOrderNumber', copyable: true }],
[
// { label: '生产数', key: 'productionNum' },
{ label: '发货数', key: 'shipmentNum' },
{ label: '质检(通过)', key: 'passNum' },
{ label: '质检(不通过)', key: 'notPassNum' },
],
]
const logisticsProps = [
{ label: '订单号', key: 'orderNumber', copyable: true },
{
label: '发货方式',
key: (d: DeliveryNoteData) =>
d.shippingWay && { 1: '送货上门', 2: '快递' }[d.shippingWay],
},
{
label: '物流跟踪号',
key: 'logisticsTracking',
copyable: true,
},
{ label: '创建时间', key: 'createTime' },
{ label: '收货人', key: 'lanshouName' },
{ label: '收货人电话', key: 'lanshouPhone' },
{ label: '邮编', key: 'lanshouPost' },
{
label: '收货地址',
key: (d: DeliveryNoteData) =>
`${d.lanshouRegion || ''}${d.lanshouAddress || ''}`,
},
]
const {
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
getDeliveryNoteList(
{
...searchForm.value,
startTime: dateRange.value && dateRange.value[0],
endTime: dateRange.value && dateRange.value[1],
},
page,
pageSize,
).then((res) => res.data),
})
const nameSpaceList = ref<NameSpaceList[]>([])
onMounted(() => {
getNameSpaceList()
})
const getNameSpaceList = async () => {
try {
const res = await getUserNameSpaceList()
nameSpaceList.value = res.data
} catch (e) {
showError(e)
}
}
const dialogVisible = ref(false)
const handleSelectionChange = (s: DeliveryNoteData[]) => {
selection.value = s
}
const onPrintDeliveryNote = () => {
dialogVisible.value = true
dateRange.value = []
}
const onConfirmDateRange = async () => {
if (dateRange.value.length === 0) {
return ElMessage({
message: '请选择时间',
type: 'warning',
offset: window.innerHeight / 2,
})
}
try {
const res = await printDeliveryNote(dateRange.value)
window.open(filePath + res.message)
dateRange.value = []
dialogVisible.value = false
search()
} catch (e) {
showError(e)
}
}
const onCellClassName: CellCls<DeliveryNoteData> = ({ column }) => {
if (
column.property === 'billNumberInfo' ||
column.property === 'logisticsInfo' ||
column.property === 'operation'
) {
return 'vertical-align-top'
} else {
return ''
}
}
// const onViewProductionOrder = async (item: DetailList) => {
// try {
// const res = await getProductionOrderList(item.subOrderNumber as string)
// } catch (e) {
// showError(e)
// }
// }
const orderDetailDialogVisible = ref(false)
const orderDetailData = ref<OrderData>({} as OrderData)
const onViewOrder = async (item: DeliveryNoteData) => {
try {
const res = await getOrderByIdApi(item.detailList[0]?.customOrderId)
orderDetailData.value = res.data
orderDetailDialogVisible.value = true
} catch (e) {
showError(e)
}
}
const copy = (text: string) => {
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
}
</script>
<style lang="scss" scoped>
.header-filter-form {
margin-bottom: 20px;
:deep(.el-form-item) {
margin-right: 14px;
margin-bottom: 10px;
}
}
$border: solid 1px #ddd;
.send-order-list {
display: grid;
grid-template-columns: 2fr 1fr;
border-left: $border;
border-top: $border;
}
.send-order-column {
padding: 10px 16px;
line-height: 1.5;
}
.send-order-header {
font-weight: bold;
text-align: center;
background-color: #f8f8f9;
}
.send-order-product-item {
display: flex;
justify-content: space-between;
gap: 20px;
&:not(:first-child) {
border-top: $border;
padding: 10px 0;
}
.send-order-prop-list {
flex: 1;
}
}
.send-order-product-image {
width: 100px;
}
.dialog-footer {
text-align: center;
}
.delivery-note-list {
:deep(.vertical-align-top) {
vertical-align: top;
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment