Commit dc9252f9 by zhuzhequan

Merge remote-tracking branch 'remotes/origin/wq' into zzq_bill_order

# Conflicts:
#	src/api/warehouse.ts
#	src/router/index.ts
#	src/router/menu.ts
parents 1379c57f 4a56b804
...@@ -57,6 +57,7 @@ declare module 'vue' { ...@@ -57,6 +57,7 @@ declare module 'vue' {
SplitDiv: typeof import('./src/components/splitDiv/splitDiv.vue')['default'] SplitDiv: typeof import('./src/components/splitDiv/splitDiv.vue')['default']
TableRightMenu: typeof import('./src/components/TableRightMenu.vue')['default'] TableRightMenu: typeof import('./src/components/TableRightMenu.vue')['default']
TableView: typeof import('./src/components/TableView.vue')['default'] TableView: typeof import('./src/components/TableView.vue')['default']
UploadExcel: typeof import('./src/components/UploadExcel.vue')['default']
UploadImage: typeof import('./src/components/UploadImage.vue')['default'] UploadImage: typeof import('./src/components/UploadImage.vue')['default']
WangEditor: typeof import('./src/components/WangEditor.vue')['default'] WangEditor: typeof import('./src/components/WangEditor.vue')['default']
} }
......
import { BasePaginationData, BaseRespData, RejectParams } from '@/types/api' import { BasePaginationData, BaseRespData, RejectParams } from '@/types/api'
import axios from './axios' import axios from './axios'
import {PaymentForm} from '@/types/api/index.ts' import { PaymentForm } from '@/types/api/index.ts'
import { import {
LogListData, LogListData,
OrderData, OrderData,
...@@ -16,9 +16,12 @@ import { ...@@ -16,9 +16,12 @@ import {
apiSubmitPodOrderForm, apiSubmitPodOrderForm,
DeliveryNoteData, DeliveryNoteData,
DeliveryNoteSearchForm, DeliveryNoteSearchForm,
DetailForm, LogListsData, DetailForm,
LogListsData,
ProductionOrder, ProductionOrder,
ShipmentOrderDetailData, updatePriceForm, ShipmentOrderDetailData,
updatePriceForm,
IUpdatePrice,
} from '@/types/api/deliveryNote' } from '@/types/api/deliveryNote'
import { import {
AccountStatementNote, AccountStatementNote,
...@@ -80,7 +83,16 @@ export function reCreateScriptUrlApi(id: number) { ...@@ -80,7 +83,16 @@ export function reCreateScriptUrlApi(id: number) {
}, },
) )
} }
export function apiGetCraftGroup(id?: number | string) {
return axios.get<never, BaseRespData<never>>(
'pod/podReconciliation/getCraftGroup',
{
params: {
id,
},
},
)
}
// 打印生产单 // 打印生产单
export function printOrder(ids: number[]) { export function printOrder(ids: number[]) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
...@@ -131,7 +143,27 @@ export function qaFinishedApi(data: InspectionData[]) { ...@@ -131,7 +143,27 @@ export function qaFinishedApi(data: InspectionData[]) {
data, data,
) )
} }
export function apiSetCraftData({
id,
craftTotalPrice,
recNumber,
craftPriceList,
}: {
id: number | undefined
craftTotalPrice: number | undefined
recNumber:string|undefined
craftPriceList: IUpdatePrice[]
}) {
return axios.post<never, BaseRespData<never>>(
'pod/podReconciliation/setCraftData',
{
id,
recNumber,
craftTotalPrice,
craftPriceList,
},
)
}
// 发货保存 // 发货保存
export function saveOrder( export function saveOrder(
sumbitSendOutList: ShipmentOrderRes[], sumbitSendOutList: ShipmentOrderRes[],
...@@ -366,11 +398,14 @@ export function exportExcelApi(ids: string) { ...@@ -366,11 +398,14 @@ export function exportExcelApi(ids: string) {
}) })
} }
export function exportPodExcelApi(ids: string) { export function exportPodExcelApi(ids: string) {
return axios.get<never, BaseRespData<never>>('pod/podReconciliation/exportExcel', { return axios.get<never, BaseRespData<never>>(
params: { 'pod/podReconciliation/exportExcel',
ids, {
params: {
ids,
},
}, },
}) )
} }
export function getShipmentDetailsById(data: DetailForm) { export function getShipmentDetailsById(data: DetailForm) {
return axios.post<never, BasePaginationData<BillOrderDetailData>>( return axios.post<never, BasePaginationData<BillOrderDetailData>>(
...@@ -382,12 +417,14 @@ export function apiupdateByPodExcel(formData: never) { ...@@ -382,12 +417,14 @@ export function apiupdateByPodExcel(formData: never) {
return axios.post('pod/podReconciliation/updateByExcel', formData, { return axios.post('pod/podReconciliation/updateByExcel', formData, {
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
}, },
}) })
} }
export function apiRejectedPodReconciliation(params?: RejectParams) { export function apiRejectedPodReconciliation(params?: RejectParams) {
return axios.post<never, BaseRespData<never>>('pod/podReconciliation/rejectedLocal', params) return axios.post<never, BaseRespData<never>>(
'pod/podReconciliation/rejectedLocal',
params,
)
} }
export function getPodShipmentDetailsById(data: DetailForm) { export function getPodShipmentDetailsById(data: DetailForm) {
return axios.post<never, BasePaginationData<BillOrderDetailData>>( return axios.post<never, BasePaginationData<BillOrderDetailData>>(
...@@ -396,27 +433,45 @@ export function getPodShipmentDetailsById(data: DetailForm) { ...@@ -396,27 +433,45 @@ export function getPodShipmentDetailsById(data: DetailForm) {
) )
} }
export function apiLogList(id?: number) { export function apiLogList(id?: number) {
return axios.get<never,BaseRespData<LogListsData[]>>('pod/podReconciliation/getLog', { params:{id} }) return axios.get<never, BaseRespData<LogListsData[]>>(
'pod/podReconciliation/getLog',
{ params: { id } },
)
} }
export function apiItemLogList(id?: number) { export function apiItemLogList(id?: number) {
return axios.get<never,BaseRespData<LogListsData[]>>('pod/podReconciliation/getItemLog', { params:{id} }) return axios.get<never, BaseRespData<LogListsData[]>>(
'pod/podReconciliation/getItemLog',
{ params: { id } },
)
} }
export function apiSubmitPodOrder(params: apiSubmitPodOrderForm) { export function apiSubmitPodOrder(params: apiSubmitPodOrderForm) {
return axios.get<never, BaseRespData<ShipmentOrderDetailData>>('pod/podReconciliation/create', { params }) return axios.get<never, BaseRespData<ShipmentOrderDetailData>>(
'pod/podReconciliation/create',
{ params },
)
} }
export function apiPodBillSubmit(ids: number[]) { export function apiPodBillSubmit(ids: number[]) {
return axios.post<never, BaseRespData<ShipmentOrderDetailData>>('pod/podReconciliation/submission', {ids}) return axios.post<never, BaseRespData<ShipmentOrderDetailData>>(
'pod/podReconciliation/submission',
{ ids },
)
} }
export function apiPodUpdatePrice(data:updatePriceForm) { export function apiPodUpdatePrice(data: updatePriceForm) {
return axios.get<never, BaseRespData<never>>('pod/podReconciliation/updatePrice', { params:data }) return axios.get<never, BaseRespData<never>>(
'pod/podReconciliation/updatePrice',
{ params: data },
)
} }
export function updateRecPrice(data:updatePriceForm) { export function updateRecPrice(data: updatePriceForm) {
return axios.get<never, BaseRespData<never>>('pod/podReconciliation/updateRecPrice', { params:data }) return axios.get<never, BaseRespData<never>>(
'pod/podReconciliation/updateRecPrice',
{ params: data },
)
} }
export function getLogListApi(id?: number) { export function getLogListApi(id?: number) {
...@@ -426,9 +481,12 @@ export function getLogListApi(id?: number) { ...@@ -426,9 +481,12 @@ export function getLogListApi(id?: number) {
} }
export function getPodLogListApi(id?: number) { export function getPodLogListApi(id?: number) {
return axios.get<never, BaseRespData<LogList[]>>('pod/podReconciliation/getLog', { return axios.get<never, BaseRespData<LogList[]>>(
params: { id }, 'pod/podReconciliation/getLog',
}) {
params: { id },
},
)
} }
export function auditOrderApi(url: string, data: string) { export function auditOrderApi(url: string, data: string) {
return axios.get(url, { return axios.get(url, {
...@@ -453,11 +511,34 @@ export function confirmOrderApi(data: ConfirmOrderForm) { ...@@ -453,11 +511,34 @@ export function confirmOrderApi(data: ConfirmOrderForm) {
} }
export function confirmPodOrderApi(data: ConfirmOrderForm) { export function confirmPodOrderApi(data: ConfirmOrderForm) {
return axios.post<never, BaseRespData<never>>('pod/podReconciliation/confirm', data) return axios.post<never, BaseRespData<never>>(
'pod/podReconciliation/confirm',
data,
)
} }
export function apiRejectionOfReview({
export function apiBillPodPayment(data:PaymentForm) { ids,
return axios.get<never, BaseRespData<never>>('pod/podReconciliation/payment', { params:data }) description,
recNumbers,
}: {
ids: string
recNumbers: string
description: string
}) {
return axios.post<never, BaseRespData<never>>(
'pod/podReconciliation/rejectionOfReview',
{
ids,
description,
recNumbers,
},
)
}
export function apiBillPodPayment(data: PaymentForm) {
return axios.post<never, BaseRespData<never>>(
'pod/podReconciliation/payment',
data,
)
} }
export function rejectOrderApi({ export function rejectOrderApi({
ids, ids,
...@@ -474,4 +555,3 @@ export function rejectOrderApi({ ...@@ -474,4 +555,3 @@ export function rejectOrderApi({
pass, pass,
}) })
} }
import { BasePaginationData, BaseRespData } from '@/types/api'
import {
ProductList,
PodUsOrderListData,
SearchForm,
Tab,
LogListData,
} from '@/types/api/podUsOrder'
import axios from './axios'
export function getOrderTabData() {
return axios.get<never, BaseRespData<Tab[]>>(
'/factory/podJomallOrderUs/findStateGroupList',
)
}
export function getOrderList(
params: SearchForm,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<PodUsOrderListData[]>>(
'/factory/podJomallOrderUs/list_page',
{
...params,
currentPage,
pageSize,
},
)
}
export function getCardOrderList(
params: SearchForm,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<ProductList[]>>(
'/factory/podJomallOrderProductUs/list_page',
{
...params,
currentPage,
pageSize,
},
)
}
export function confirmOrderApi(data: number[]) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderUs/confirmOrders',
data,
)
}
export function updateExceptionOrderApi(data: number[]) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderUs/updateExceptionOrders',
{
orderIds: data,
},
)
}
export function changeExceptionOrderApi(ids: number[], value: string) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderUs/exceptionOrders',
{
orderIds: ids,
exceptionReason: value,
},
)
}
export function cancelOrderApi(ids: number[], value: string) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderUs/cancelOrders',
{
orderIds: ids,
cancelReason: value,
},
)
}
export function getOperationLogApi(id: number) {
return axios.get<never, BaseRespData<LogListData[]>>(
`factory/podJomallOrderUsLog/getPodJomallOrderUsLog?id=${id}`,
)
}
export function getSubOrderBySubOrderNumber(factorySubOrderNumber: string) {
return axios.get<never, BaseRespData<ProductList>>(
'factory/podJomallOrderProductUs/getProductUsByFactorySubOrderNumber',
{
params: {
factorySubOrderNumber,
},
},
)
}
export function downloadMaterialApi(id: Array<number>) {
return axios.post<never, BaseRespData<Array<string>>>(
'factory/podJomallOrderProductUs/downloadDesignImages',
id,
)
}
export function productionQueryApi(id: number, podJomallOrderUsId: number) {
return axios.post<never, BasePaginationData<never>>(
'factory/podJomallOrderProductUs/completeDelivery',
{
id,
podJomallOrderUsId,
},
)
}
export function printProductionOrderApi(orderIds: number[]) {
return axios.post<never, BaseRespData<string>>(
'factory/podJomallOrderUs/printProducePdf',
orderIds,
)
}
import axios from '@/api/axios.ts' import axios from '@/api/axios.ts'
import { BasePaginationData, BaseRespData } from '@/types/api' import { BasePaginationData, BaseRespData } from '@/types/api'
export interface factoryWarehouseInfo{ import {
pageSize:number warehouseSearchForm,
currentPage:number InterWarehousePage,
total?:number InterWarehouseTree,
InterskuList,
InterWarehouseList,
ILocation,
InRecordEditForm
} from '@/types/api/warehouse'
export interface factoryWarehouseInfo {
pageSize: number
currentPage: number
total?: number
warehouseId?: string; warehouseId?: string;
locationName?: string; locationName?: string;
remark?: string; remark?: string;
...@@ -67,26 +76,26 @@ export interface positionFormInfo{ ...@@ -67,26 +76,26 @@ export interface positionFormInfo{
status: number status: number
} }
interface WarehouseWarningData { interface WarehouseWarningData {
id: number; id: number
factoryId: number; factoryId: number
warehouseId: number; warehouseId: number
warehouseName: string; warehouseName: string
warehouseLocationId: number; warehouseLocationId: number
locationName: string; locationName: string
warehouseSku: string; warehouseSku: string
skuName: string; skuName: string
unit: string; unit: string
occupyInventory: number; occupyInventory: number
freezeInventory: number; freezeInventory: number
inventory: number; inventory: number
upperLimit: number; upperLimit: number
floorLimit: number; floorLimit: number
productNumber: string; productNumber: string
itemSort: number; itemSort: number
dataVersion: number; dataVersion: number
status: number; status: number
createTime: string; createTime: string
updateTime: string; updateTime: string
} }
export function getFactoryLocation(data: factoryWarehouseInfo) { export function getFactoryLocation(data: factoryWarehouseInfo) {
return axios.post<never, BasePaginationData<positionInfo>>( return axios.post<never, BasePaginationData<positionInfo>>(
...@@ -108,10 +117,10 @@ export function getWarehouseInventoryInfo(data: WarehouseInventory) { ...@@ -108,10 +117,10 @@ export function getWarehouseInventoryInfo(data: WarehouseInventory) {
data, data,
) )
} }
export function createWarehouseApi(data:warehouseInfo) { export function createWarehouseApi(data: warehouseInfo) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
'/factoryWarehouseInfo/add', '/factoryWarehouseInfo/add',
data data,
) )
} }
...@@ -128,16 +137,16 @@ export function warehouseInfoGetAll() { ...@@ -128,16 +137,16 @@ export function warehouseInfoGetAll() {
) )
} }
export function createWarehouseInventoryApi(data:WarehouseWarningData) { export function createWarehouseInventoryApi(data: WarehouseWarningData) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
'/factoryWarehouseInventory/add', '/factoryWarehouseInventory/add',
data data,
) )
} }
export function updateWarehouseApi(data:positionInfo | UpdateDefaulted) { export function updateWarehouseApi(data: positionInfo | UpdateDefaulted) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
'/factoryWarehouseInfo/update', '/factoryWarehouseInfo/update',
data data,
) )
} }
...@@ -153,33 +162,98 @@ export function updatePositionStatusApi(data: UpdateStatus) { ...@@ -153,33 +162,98 @@ export function updatePositionStatusApi(data: UpdateStatus) {
{ params:data }, { params:data },
) )
} }
export function updateWarehouseInventoryApi(data:WarehouseWarningData) { export function updateWarehouseInventoryApi(data: WarehouseWarningData) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
'/factoryWarehouseInventory/update', '/factoryWarehouseInventory/update',
data data,
) )
} }
export function deleteWarehouseApi(ids:string) { export function deleteWarehouseApi(ids: string) {
return axios.get<never, BaseRespData<never>>('/factoryWarehouseInfo/delete', {
params: { ids },
})
}
export function deleteLocationApi(ids:string) {
return axios.get<never, BaseRespData<never>>( return axios.get<never, BaseRespData<never>>(
'/factoryWarehouseInfo/delete', '/factoryWarehouseLocation/delete',
{ {
params:{ids} params:{ids}
}, },
) )
} }
export function deleteLocationApi(ids:string) { export function deleteWarehouseInventory(ids: string) {
return axios.get<never, BaseRespData<never>>( return axios.get<never, BaseRespData<never>>(
'/factoryWarehouseLocation/delete', '/factoryWarehouseInventory/delete',
{ {
params:{ids} params: { ids },
},
)
}
// 入库单
export function warehouseInRecordListPage(
data: warehouseSearchForm,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<InterWarehousePage>>(
'/factory/warehouseInRecord/list_page',
{
...data,
currentPage,
pageSize,
}, },
) )
} }
export function deleteWarehouseInventory(ids:string) { export function addInRecordApi(form: InRecordEditForm) {
return axios.post<never, BaseRespData<never>>('factory/warehouseInRecord/add', {
...form,
})
}
export function updateInRecordApi(form: InRecordEditForm) {
return axios.post<never, BaseRespData<never>>('factory/warehouseInRecord/update', {
...form,
})
}
export function getWarehouseInRecordDetail(id: number) {
return axios.get<never, BaseRespData<never>>( return axios.get<never, BaseRespData<never>>(
'/factoryWarehouseInventory/delete', 'factory/warehouseInRecord/get',
{ {
params:{ids} params: {
id,
},
},
)
}
export function getBySku(warehouseId: number, sku: string | null) {
return axios.get<never, BaseRespData<InterskuList[]>>(
'customProductItem/getBySku',
{
params: {
warehouseId,
sku,
},
},
)
}
export function getByWareHouseIdAndCode(wareHouseId: number, code: string | null) {
return axios.get<never, BaseRespData<ILocation[]>>(
'factoryWarehouseLocation/getByWareHouseIdAndCode',
{
params: {
wareHouseId,
code,
},
}, },
) )
} }
export function getWarehouseStatusTree() {
return axios.get<never, BaseRespData<InterWarehouseTree[]>>(
'factory/warehouseInRecord/status_tree',
)
}
export function getWarehouseListApi() {
return axios.get<never, BaseRespData<InterWarehouseList[]>>(
'factoryWarehouseInfo/getAll',
)
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
v-if="selectionable" v-if="selectionable"
type="selection" type="selection"
width="50" width="50"
fixed="left"
header-align="center" header-align="center"
align="center" align="center"
></ElTableColumn> ></ElTableColumn>
...@@ -20,7 +21,8 @@ ...@@ -20,7 +21,8 @@
v-if="serialNumberable" v-if="serialNumberable"
label="序号" label="序号"
type="index" type="index"
width="50" width="60"
fixed="left"
header-align="center" header-align="center"
align="center" align="center"
></ElTableColumn> ></ElTableColumn>
......
<template>
<div v-loading="loading" class="enhanced-upload">
<div class="import-content">
<div>
<div class="upload-area" @click="triggerFileInput">
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
<div class="el-upload__text">
将文件拖到此处,或<span style="color: #409eff">点击上传</span>
</div>
</div>
<input
ref="fileInputRef"
type="file"
accept=".xls,.xlsx"
style="display: none"
@change="onFileChange"
/>
<div class="custom-tip">
<span>请上传Excel文件(.xls 或 .xlsx)</span>
</div>
</div>
<div v-if="fileList.length > 0">
<div
v-for="(item, idx) in fileList"
:key="idx"
class="custom-file-item"
>
<el-icon class="file-icon"><Document /></el-icon>
<div class="file-info">
<div
class="file-name"
:title="`点击下载 ${item.path} 文件`"
@click="downloadFile(item.path)"
>
{{ item?.filename || SetFileName(item.path) }}
</div>
</div>
<el-icon class="delete-icon" @click="removeFile(idx)"
><Close
/></el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, defineProps, defineEmits, computed } from 'vue'
import { UploadFilled, Document, Close } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { uploadFileApi } from '@/api/common'
interface FileItem {
path: string
filename?: string
}
const props = defineProps<{
modelValue: string
}>()
const emit = defineEmits(['update:modelValue'])
const fileList = ref<FileItem[]>([])
const fileInputRef = ref<HTMLInputElement | null>(null)
const loading = ref(false)
const value = computed({
get() {
return props.modelValue
},
set(val: string) {
emit('update:modelValue', val)
},
})
watch(
value,
() => {
let file: FileItem[] = []
if (!Array.isArray(value)) {
if (value.value) {
file.push({ path: value.value })
} else {
file = []
}
}
fileList.value = file
},
{ immediate: true },
)
const triggerFileInput = () => {
if (loading.value) return
fileInputRef.value?.click()
}
const downloadFile = (path: string) => {
window.open(path)
}
const SetFileName = (path: string) => {
if (!path) return ''
const i = path.lastIndexOf('/')
if (i === -1) return path
return path.substring(i + 1)
}
const onFileChange = async (e: Event) => {
const files = (e.target as HTMLInputElement).files
if (!files) return
const file = files[0]
// 校验类型
const isValidType = [
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
].includes(file.type)
if (!isValidType) {
ElMessage.error('文件类型错误,请上传Excel文件')
return
}
// 校验大小
const isSizeValid = file.size / 1024 / 1024 < 50
if (!isSizeValid) {
ElMessage.error('文件大小不能超过50MB')
return
}
await fileUpload(file)
// 清空input
if (fileInputRef.value) fileInputRef.value.value = ''
}
const fileUpload = async (file: File) => {
const formData = new FormData()
const filename = file.name
formData.append('file', file)
formData.append('businessType', 'product')
loading.value = true
try {
const res = await uploadFileApi(formData)
fileList.value = [{ path: res.message ?? '', filename }]
value.value = res.message
ElMessage.success('导入成功')
} catch (e) {
ElMessage.error('上传失败')
} finally {
loading.value = false
}
}
const removeFile = (idx: number) => {
fileList.value.splice(idx, 1)
value.value = ''
}
</script>
<style scoped lang="scss">
.enhanced-upload {
.import-content {
padding: 20px 0;
}
.custom-file-item {
display: flex;
align-items: center;
padding: 12px;
border: 1px solid #e8e8e8;
border-radius: 4px;
margin-top: 8px;
background: #fff;
.file-icon {
font-size: 24px;
color: #52c41a;
margin-right: 12px;
}
.file-info {
flex-grow: 1;
.file-name {
color: #333;
margin-bottom: 4px;
}
.file-name:hover {
text-decoration: underline;
color: blue;
}
}
.delete-icon {
color: #f56c6c;
font-size: 20px;
cursor: pointer;
margin-left: 10px;
&:hover {
color: #ff0000;
}
}
}
.upload-area {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px dashed #d9d9d9;
border-radius: 6px;
padding: 40px 20px;
// background: #fafafa;
background: var(--el-fill-color-blank);
cursor: pointer;
&:hover {
border-color: var(--el-color-primary);
}
.el-icon--upload {
font-size: 70px;
color: #a8abb2;
margin-bottom: 12px;
}
.el-upload__text {
color: #666;
}
}
.custom-tip {
display: flex;
align-items: center;
color: #666;
margin-top: 12px;
i {
margin-right: 6px;
}
}
}
</style>
...@@ -86,11 +86,11 @@ const onChange = async (e: Event) => { ...@@ -86,11 +86,11 @@ const onChange = async (e: Event) => {
const files = (e.target as HTMLInputElement).files const files = (e.target as HTMLInputElement).files
if (!files) return if (!files) return
const file = files[0] const file = files[0]
const isLtTenM = file.size / 1024 / 1024 < 200; const isLtTenM = file.size / 1024 / 1024 < 200
if (!isLtTenM) { if (!isLtTenM) {
ElMessage.error("上传文件大小不能超过 200MB!"); ElMessage.error('上传文件大小不能超过 200MB!')
return isLtTenM; return isLtTenM
} }
if (props.imageMode) { if (props.imageMode) {
imageUpload(file) imageUpload(file)
} else { } else {
......
...@@ -21,9 +21,13 @@ import PodBillOrder from '@/views/podBillOrder/index.vue' ...@@ -21,9 +21,13 @@ import PodBillOrder from '@/views/podBillOrder/index.vue'
import TypeseetingManagement from '@/views/typesetting/TypesettingManagement.vue' import TypeseetingManagement from '@/views/typesetting/TypesettingManagement.vue'
import PodOrderList from '@/views/order/pod/index.vue' import PodOrderList from '@/views/order/pod/index.vue'
import PodDeliveryNoteList from '@/views/order/pod/deliveryOrderList.vue' import PodDeliveryNoteList from '@/views/order/pod/deliveryOrderList.vue'
import PodUsOrderList from '@/views/order/podUs/index.vue'
import WarehouseManage from '@/views/warehouse/manage.vue' import WarehouseManage from '@/views/warehouse/manage.vue'
import WarehouseWarning from '@/views/warehouse/warning.vue' import WarehouseWarning from '@/views/warehouse/warning.vue'
import WarehousePosition from '@/views/warehouse/position.vue' import WarehousePosition from '@/views/warehouse/position.vue'
import receiptDoc from '@/views/warehouse/receiptDoc.vue'
import issueDoc from '@/views/warehouse/issueDoc.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),
routes: [ routes: [
...@@ -38,7 +42,8 @@ const router = createRouter({ ...@@ -38,7 +42,8 @@ const router = createRouter({
title: '概览', title: '概览',
}, },
component: Dashboard, component: Dashboard,
},{ },
{
path: '/product', path: '/product',
meta: { meta: {
title: '商品', title: '商品',
...@@ -60,6 +65,13 @@ const router = createRouter({ ...@@ -60,6 +65,13 @@ const router = createRouter({
component: PodOrderList, component: PodOrderList,
}, },
{ {
path: '/pod-us-order/list',
meta: {
title: 'POD订单(US)',
},
component: PodUsOrderList,
},
{
path: '/pod-delivery-note/list', path: '/pod-delivery-note/list',
meta: { meta: {
title: 'POD发货单', title: 'POD发货单',
...@@ -93,7 +105,8 @@ const router = createRouter({ ...@@ -93,7 +105,8 @@ const router = createRouter({
title: '定制对账单', title: '定制对账单',
}, },
component: AccountStatementNote, component: AccountStatementNote,
},{ },
{
path: '/account/pod-bill-order', path: '/account/pod-bill-order',
meta: { meta: {
title: 'POD对账单', title: 'POD对账单',
...@@ -106,13 +119,29 @@ const router = createRouter({ ...@@ -106,13 +119,29 @@ const router = createRouter({
title: '打版管理', title: '打版管理',
}, },
component: TypeseetingManagement, component: TypeseetingManagement,
},{ },
{
path: '/warehouse/manage', path: '/warehouse/manage',
meta: { meta: {
title: '仓库管理', title: '仓库管理',
}, },
component: WarehouseManage, component: WarehouseManage,
},{ },
{
path: '/warehouse/receipt-doc',
meta: {
title: '入库单',
},
component: receiptDoc,
},
{
path: '/warehouse/issue-doc',
meta: {
title: '出库单',
},
component: issueDoc,
},
{
path: '/warehouse/warning', path: '/warehouse/warning',
meta: { meta: {
title: '仓库预警', title: '仓库预警',
......
...@@ -6,48 +6,48 @@ export interface MenuItem { ...@@ -6,48 +6,48 @@ export interface MenuItem {
} }
const menu: MenuItem[] = [ const menu: MenuItem[] = [
{ {
index: '/dashboard', index: '/dashboard',
id: 1, id: 1,
label: '概览', label: '概览',
}, },
{ {
index: '/product', index: '/product',
id: 11, id: 11,
label: '商品', label: '商品',
}, },
{ {
index: '13', index: '13',
id: 13, id: 13,
label: '库存', label: '库存',
children: [ children: [
{ {
index: '/warehouse/manage', index: '/warehouse/manage',
id: 121, id: 121,
label: '仓库管理', label: '仓库管理',
}, },
{ {
index: '/warehouse/position', index: '/warehouse/position',
id: 122, id: 122,
label: '库位管理', label: '库位管理',
}, },
{ {
index: '/pod-order/list', index: '/warehouse/receipt-doc',
id: 123, id: 123,
label: '入库单', label: '入库单',
}, },
{ {
index: '/pod-order/list', index: '/warehouse/issue-doc',
id: 124, id: 124,
label: '出库单', label: '出库单',
}, },
{ {
index: '/warehouse/warning', index: '/warehouse/warning',
id: 125, id: 125,
label: '仓库预警', label: '仓库预警',
}, },
], ],
}, },
{ {
index: '1', index: '1',
id: 2, id: 2,
...@@ -63,6 +63,11 @@ const menu: MenuItem[] = [ ...@@ -63,6 +63,11 @@ const menu: MenuItem[] = [
id: 7, id: 7,
label: 'POD订单', label: 'POD订单',
}, },
{
index: '/pod-us-order/list',
id: 8,
label: 'POD订单(US)',
},
], ],
}, },
...@@ -130,6 +135,6 @@ const menu: MenuItem[] = [ ...@@ -130,6 +135,6 @@ const menu: MenuItem[] = [
// } // }
// ] // ]
// }, // },
] ]
export default menu export default menu
...@@ -114,3 +114,6 @@ img { ...@@ -114,3 +114,6 @@ img {
.mt-10 { .mt-10 {
margin-top: 10px; margin-top: 10px;
} }
.mb-10 {
margin-bottom: 10px;
}
...@@ -29,6 +29,7 @@ export interface AccountStatementNote { ...@@ -29,6 +29,7 @@ export interface AccountStatementNote {
pass_num?: number pass_num?: number
factory_code?: string factory_code?: string
total_amount?: string | number total_amount?: string | number
actual_amount?: string | number
num?: number num?: number
end_time?: string end_time?: string
rec_number?: string rec_number?: string
...@@ -43,6 +44,9 @@ export interface AccountStatementNote { ...@@ -43,6 +44,9 @@ export interface AccountStatementNote {
id?: number id?: number
erp_total_amount?: number erp_total_amount?: number
dataVersion: '' dataVersion: ''
water_list?: {
url: string | undefined
}[]
} }
export interface BillOrderDetailData { export interface BillOrderDetailData {
create_time?: string create_time?: string
...@@ -69,11 +73,11 @@ export interface LogList { ...@@ -69,11 +73,11 @@ export interface LogList {
create_time?: string create_time?: string
info_id?: number info_id?: number
id: string id: string
diy_id: number; diy_id: number
employee_account?: string; employee_account?: string
employee_name?: string; employee_name?: string
employee_id?: string; employee_id?: string
description?: string; description?: string
} }
export interface ItemList { export interface ItemList {
...@@ -95,5 +99,5 @@ export interface ItemList { ...@@ -95,5 +99,5 @@ export interface ItemList {
export interface ConfirmOrderForm { export interface ConfirmOrderForm {
pass?: number | null pass?: number | null
description?: string description?: string
ids?:string ids?: string
} }
...@@ -12,6 +12,11 @@ export interface DeliveryNoteSearchForm { ...@@ -12,6 +12,11 @@ export interface DeliveryNoteSearchForm {
status?: number | null status?: number | null
} }
export interface IUpdatePrice {
process: string
base_price: string | number
add_price: string | number
}
export interface DeliveryNoteData { export interface DeliveryNoteData {
id: number id: number
billNumber?: string billNumber?: string
...@@ -183,21 +188,32 @@ export interface DbFactory { ...@@ -183,21 +188,32 @@ export interface DbFactory {
status?: number status?: number
} }
export interface LogListsData { export interface LogListsData {
id: number; id: number
diy_id: number; diy_id: number
employee_account?: string; employee_account?: string
employee_name?: string; employee_name?: string
employee_id?: string; employee_id?: string
description?: string; description?: string
create_time?: string; create_time?: string
}
export interface LogListData {
id?: string | number | null
infoId?: number
employeeId?: number
employeeAccount?: string
description?: string
createTime?: string
} }
export interface DetailForm { export interface DetailForm {
billNumber?: string billNumber?: string
orderNumber?:string orderNumber?: string
shipmentNumber?:string baseSku?: string
dateRange?:string[] shipmentNumber?: string
endTime?:string process?: string
startTime?:string supplierItemNo?: string
dateRange?: string[]
endTime?: string
startTime?: string
subOrderNumber?: string subOrderNumber?: string
rows?: number rows?: number
page?: number page?: number
...@@ -205,15 +221,15 @@ export interface DetailForm { ...@@ -205,15 +221,15 @@ export interface DetailForm {
infoId?: number infoId?: number
} }
export interface BillForm { export interface BillForm {
timeRange: [string, string] | []; timeRange: [string, string] | []
} }
export interface apiSubmitPodOrderForm { export interface apiSubmitPodOrderForm {
startDate?: string; startDate?: string
endDate?: string; endDate?: string
} }
export interface updatePriceForm { export interface updatePriceForm {
ids?: string; ids?: string
infoId?: number; infoId?: number
price?: string; price?: string
} }
export interface BaseRespData<D> { export interface BaseRespData<D> {
code: number code: number
message?: string message?: string
...@@ -14,7 +13,7 @@ export interface PaginationData<D> { ...@@ -14,7 +13,7 @@ export interface PaginationData<D> {
current: number current: number
records: D[] records: D[]
} }
export interface Statistics<D> { export interface Statistics<D> {
sumNotPassNum: number sumNotPassNum: number
sumPassNum: number sumPassNum: number
sumShipmentNum: number sumShipmentNum: number
...@@ -30,20 +29,21 @@ export interface Statistics<D> { ...@@ -30,20 +29,21 @@ export interface Statistics<D> {
export type BasePaginationData<D> = BaseRespData<PaginationData<D>> export type BasePaginationData<D> = BaseRespData<PaginationData<D>>
export type StatisticsData<D> = BaseRespData<Statistics<D>> export type StatisticsData<D> = BaseRespData<Statistics<D>>
export interface baseRes { export interface baseRes {
code:number code: number
msg:string msg: string
} }
export interface PaymentForm{ export interface PaymentForm {
waterList: string waterList: string
id?:number | string id?: number | string
actualAmount?:number | string actualAmount?: number | string
payableAmount?:number | string payableAmount?: number | string
recNumber?: number | string
} }
export interface RejectParams{ export interface RejectParams {
id:number id: number
description?:string description?: string
ids?:string ids?: string
pass?:number pass?: number
} }
export interface Tab {
status?: string
statusName?: string
quantity?: number
}
export interface SearchForm {
timeType: number | null
shopNumber: string
userMark: string
logisticsTracking: string
baseSku: string
factoryOrderNumber: string
sku: string
factorySubOrderNumber: string
status: string
}
export interface PodUsOrderListData {
id: number
thirdOrderNumber?: string
factoryOrderNumber?: string
shopNumber?: string
factoryOnlineId?: number | null
factoryNo?: number | null
factoryCode?: string | null
status?: string
weight?: number | null
totalProductAmount?: number | null
productAmount?: number
carriageAmount?: number | null
totalAmount?: number | null
productNum?: number | null
trackStatus?: string | null
receiverName?: string
receiverPhone?: string
receiverCountry?: string
receiverProvince?: string
receiverCity?: string
receiverDistrict?: string
receiverAddress1?: string
receiverAddress2?: string
receiverPostCode?: string
paymentType?: string
paymentTime?: string
startStockingTime?: string
finishTime?: string
shipmentType?: string
expressSheet?: string
trackingNumber?: string
processNumber?: string
createTime?: string
updateTime?: string
remark?: string | null
userMark?: string
version?: number
productList?: ProductList[]
orderNumber?: string
}
export interface ProductList {
id: number
podJomallOrderUsId: number
thirdSubOrderNumber?: string
factorySubOrderNumber?: string
factoryCode?: string
productName?: string
baseSku?: string
variantSku?: string
productPrice?: number
templatePrice?: number
variantImage?: string
craftPrice?: number
imageAry?: string
designImages?: string
categoryId?: number
categoryName?: string
num?: number
passNum?: number
notPassNum?: number
payAmount?: number
weight?: number | null
diyId?: string
endProductId?: string
customizedQuantity?: number
tagIds?: string
isProduction?: boolean
createTime?: string
updateTime?: string
remark?: string | null
version?: number
subOrderNumber?: string
}
export interface cardImages {
title: string
url: string
sort: number
id?: number
}
export interface LogListData {
id: number
bizId: number
userId: number
employeeName: string
description: string
deleteContent: string
createTime: string
}
export interface PodOrderRes extends ProductList {
expectDeliveryTime?: string | null
thirdOrderNumber?: string | null
startStockingTime?: string | null
factoryOrderNumber?: string | null
userMark?: string | null
craftName?: string | null
craftId?: string | null
shopNumber?: string | null
color?: string | null
size?: string | null
note?: Array<{ prop: string | number; value: string | number }>
imgList: cardImages[]
}
export interface warehouseSearchForm {
status?: string
batchNumber?: string
createTimeEnd?: string
createTimeStart?: string
orderNumber?: string
sku?: string
warehouseId?: number
}
// 主表列表ts,看新增时是不是一样
export interface InterWarehousePage {
id: number
factoryId?: number
factoryCode?: string
warehouseId?: number
warehouseName?: string
inNo?: string
shipmentNumber?: string
skuAmount?: string
total?: number
totalPrice?: number
billStatus?: string
remark?: string
productList?: InterProductList[]
}
export interface InterWarehouseDetail {
id?: string
inId?: string
productNo?: string
warehouseSku?: string
skuImage?: string
skuName?: string
buyStored?: string
totalPrice?: number
rejectsAmount?: string
rejectsReason?: string
remark?: string
factoryId?: number
createTime?: string
updateTime?: string
}
export interface InterWarehouseTree {
id: number
code: string
name: string
countQuantity: string | null
children: null
leaf: boolean
}
export interface InterProductList {
createTime?: string
factoryId?: number
id?: number
inId?: number
productNo?: string | null //货号
buyStored?: number | null //入库数量
rejectsAmount?: number
rejectsReason?: string
remark?: string
skuImage?: string
skuName?: string
costPrice?: number | null
totalPrice?: number | null
updateTime?: string
warehouseSku?: string
locationId?: number | null
locationCode?: string | null
}
export interface InterskuList {
id?: number
productId?: number
sku?: string
skuName?: string
image?: string
factoryPrice?: number
productNo?: string | null //货号
locationId?: number | null
locationCode?: string | null
}
export interface InterWarehouseList {
id: number
name: string
code?: string
sort?: number
defaulted?: number
factoryId?: number
factoryCode?: string
remarks?: string | null
}
export interface ILocation {
id?: number
locationId?: number | null
locationCode?: string | null
}
export interface InRecordEditForm {
id: number
factoryId?: number
factoryCode?: string
warehouseId?: number
warehouseName?: string
inNo?: string
shipmentNumber?: string
skuAmount?: string
total?: number
totalPrice?: number
billStatus?: string
remark?: string
productList?: InterProductList[]
}
...@@ -57,7 +57,11 @@ export default function usePageList<T>(options: UsePageListOptions<T>) { ...@@ -57,7 +57,11 @@ export default function usePageList<T>(options: UsePageListOptions<T>) {
loadData() loadData()
} }
const refresh = () => { const refresh = (reset?: boolean) => {
if (reset) {
data.value = []
total.value = 0
}
currentPage.value = 1 currentPage.value = 1
loadData() loadData()
} }
......
...@@ -466,7 +466,7 @@ const changeStatus = async () => { ...@@ -466,7 +466,7 @@ const changeStatus = async () => {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}).then(() => { }).then(() => {
setData(TrackingNumber.value) setData(detail.value.factorySubOrderNumber || '')
}) })
} }
const setData = async (orderNumber: string) => { const setData = async (orderNumber: string) => {
......
...@@ -1084,7 +1084,7 @@ import { ...@@ -1084,7 +1084,7 @@ import {
OrderData, OrderData,
ShipmentForm, ShipmentForm,
} from '@/types/api/order' } from '@/types/api/order'
import fastProduction from '../fastProduction.vue' import fastProduction from './fastProduction.vue'
// import CardWrapper from '@/components/CardPods.vue' // import CardWrapper from '@/components/CardPods.vue'
import { useValue } from '@/utils/hooks/useValue' import { useValue } from '@/utils/hooks/useValue'
import { import {
......
<template>
<el-dialog
v-model="dialogVisible"
title="快捷生产"
top="140px"
:fullscreen="true"
:close-on-click-modal="false"
@opened="onOpened"
@close="emit('close')"
>
<div class="detail-div">
<div class="detail-content">
<div class="left">
<div class="left-images">
<el-carousel
v-if="detail?.imgList.length > 0"
style="height: 100%"
:autoplay="false"
indicator-position="none"
>
<el-carousel-item
v-for="(item, index) in detail?.imgList"
:key="index"
style="height: 100%"
>
<div class="left-image">
<b v-show="item?.title && item?.url">
{{ item?.title }}
<span
v-if="item?.id"
style="
text-decoration: underline;
cursor: pointer;
color: blue;
"
>
(DID:{{ item?.id }}
</span>
</b>
<img :src="item.url" alt="" />
</div>
</el-carousel-item>
</el-carousel>
</div>
</div>
<div class="right">
<div class="input">
<el-input
ref="trackingNumberRef"
v-model="TrackingNumber"
:placeholder="placeholderText"
style="width: 660px; margin-right: 10px"
clearable
@keydown.enter="trackCodeInput()"
></el-input>
<el-button type="primary" @click="trackCodeInput()">
查询
</el-button>
</div>
<div class="div-text">
<div class="div-content">
<div :title="String(detail?.userMark)" class="div-item">
<span style="font-size: 18px">客户</span>
<p style="color: red; font-size: 30px">
{{ detail?.userMark }}
</p>
</div>
<div
:title="String(detail?.factoryOrderNumber)"
class="div-item"
style="margin-top: 14px"
>
<span style="font-size: 18px">订单号</span>
<p style="color: red; font-size: 22px">
{{ detail?.factoryOrderNumber }}
</p>
</div>
</div>
</div>
<div class="div-text">
<b>生产单信息</b>
<div class="div-content">
<div :title="detail?.factorySubOrderNumber" class="div-item">
<span>生产单号</span>
<p>
{{ detail?.factorySubOrderNumber }}
</p>
</div>
<div :title="detail?.thirdSubOrderNumber || ''" class="div-item">
<span>第三方生产单号</span>
<p>
{{ detail?.thirdSubOrderNumber }}
</p>
</div>
<div :title="String(detail?.craftName)" class="div-item">
<span>生产工艺</span>
<p>
{{ detail?.craftName }}
</p>
</div>
<div :title="detail?.baseSku" class="div-item">
<span>基版</span>
<p>{{ detail?.baseSku }}</p>
</div>
<div :title="detail?.variantSku" class="div-item">
<span>变体SKU</span>
<p>{{ detail?.variantSku }}</p>
</div>
<div :title="String(detail?.num)" class="div-item">
<span>数量</span>
<p>{{ detail?.num }}</p>
</div>
<div :title="String(detail?.size)" class="div-item">
<span>尺寸</span>
<p>{{ detail?.size }}</p>
</div>
<div :title="detail?.shopNumber ?? ''" class="div-item">
<span>店铺单号</span>
<p>{{ detail?.shopNumber ?? '' }}</p>
</div>
<div :title="detail?.createTime" class="div-item">
<span>创建时间</span>
<p>{{ detail?.createTime }}</p>
</div>
</div>
</div>
<div class="btn">
<div class="btn-sure">
<el-button
style="width: 100%; height: 100%; font-size: 18px"
size="large"
type="success"
@click="changeStatus"
>
生产完成
</el-button>
<div class="check">
<el-checkbox v-model="isAutoSure"> 自动完成上一单 </el-checkbox>
</div>
</div>
<div class="btn-down">
<div class="check">
<el-checkbox v-model="isDownloadImage" size="large">
扫码下载素材
</el-checkbox>
</div>
<el-button
style="width: 100%; height: 100%; font-size: 18px"
type="primary"
@click="handleDownload"
>
下载素材
</el-button>
</div>
</div>
<div
class="div-text"
style="
flex: 1;
flex-shrink: 0;
display: flex;
flex-direction: column;
"
>
<div v-if="detail?.note" style="height: 100%" class="div-content">
<b style="position: absolute; top: -12px">客户留言信息</b>
<div
v-for="(item, index) in detail?.note"
:key="index"
class="div-item"
>
<span>{{ item.prop }}:</span>
<p>
{{ item.value }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup lang="tsx">
import {
productionQueryApi,
getSubOrderBySubOrderNumber,
downloadMaterialApi,
} from '@/api/podUsOrder'
import { cardImages, PodOrderRes } from '@/types/api/podUsOrder'
import { showConfirm } from '@/utils/ui'
import { filePath } from '@/api/axios'
import { ref, watch, defineProps, defineEmits } from 'vue'
interface HistoryDataItem {
orderNumber: string
finished: boolean
}
const trackingNumberRef = ref()
const historyData = ref<HistoryDataItem[]>([])
const placeholderText = ref('')
const sendNum = ref(0)
const isDownloadImage = ref(false)
const isAutoSure = ref(false)
const detail = ref<PodOrderRes>({
id: -1,
podJomallOrderUsId: -1,
imgList: [] as cardImages[],
})
const dialogVisible = ref(false)
// 通过import动态导入音频文件
const audios = {
weight_warning: new URL('@/assets/audio/weight_warning.mp3', import.meta.url)
.href,
weight_success: new URL('@/assets/audio/weight_success.mp3', import.meta.url)
.href,
weight_repeat: new URL('@/assets/audio/weight_repeat.mp3', import.meta.url)
.href,
weight_search_error: new URL(
'@/assets/audio/weight_search_error.mp3',
import.meta.url,
).href,
weight_search_success: new URL(
'@/assets/audio/weight_search_success.mp3',
import.meta.url,
).href,
}
const TrackingNumber = ref('')
const props = defineProps({
title: {
default: '',
type: String,
},
type: {
default: 0,
type: Number,
},
detailVisible: {
default: false,
type: Boolean,
},
})
const emit = defineEmits(['update:detailVisible', 'close', 'onSuccess'])
watch(
() => props.detailVisible,
(newVal: boolean) => {
dialogVisible.value = newVal
detail.value = { id: -1, podJomallOrderUsId: -1, imgList: [] }
if (newVal) {
const history = localStorage.getItem('historyUsData')
historyData.value = history ? JSON.parse(history) : []
const len = historyData.value
if (len.length > 0) {
confirmQuery(len, 0)
}
placeholderText.value =
'扫描枪输入生产单号,录入下一单本单自动生产完成,最后一单扫两次完成生产'
trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = ''
isAutoSure.value = false
sendNum.value = 0
}
},
)
const confirmQuery = (len: HistoryDataItem[], i: number) => {
const el = len[i]
showConfirm(`生产单号 ${el.orderNumber} 未生产完成,取消则不提醒?`, {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
TrackingNumber.value = el.orderNumber
await trackCodeInput()
await setData(el.orderNumber)
ElMessage.success('生产完成')
if (len[i + 1]) {
confirmQuery(len, i + 1)
}
})
.catch(() => {
const index = historyData.value.findIndex(
(item: HistoryDataItem) => item.orderNumber === el.orderNumber,
)
if (index >= 0) {
historyData.value.splice(index, 1)
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
if (len[i + 1]) {
confirmQuery(len, i + 1)
}
trackingNumberRef.value && trackingNumberRef.value.focus()
})
}
const changeStatus = async () => {
if (!detail.value || Object.keys(detail.value).length <= 1) {
return ElMessage.warning('请扫码生产单号')
}
showConfirm('确定生产完成?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
setData(detail.value.factorySubOrderNumber || '')
})
}
const setData = async (orderNumber: string) => {
if (!detail.value || detail.value?.id === -1) return
try {
const id = detail.value.id
const podJomallOrderUsId = detail.value.podJomallOrderUsId
await productionQueryApi(id, podJomallOrderUsId)
if (orderNumber) {
const index = historyData.value.findIndex(
(el: HistoryDataItem) => el.orderNumber === orderNumber,
)
if (index >= 0) {
// 扫单完成删除
historyData.value.splice(index, 1)
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
}
emit('onSuccess')
playAudio('weight_success')
detail.value = {
id: -1,
podJomallOrderUsId: -1,
imgList: [] as cardImages[],
}
TrackingNumber.value = ''
isAutoSure.value = false
isDownloadImage.value = false
trackingNumberRef.value && trackingNumberRef.value.focus()
} catch (e) {
console.error(e)
detail.value = {
id: -1,
podJomallOrderUsId: -1,
imgList: [] as cardImages[],
}
trackingNumberRef.value && trackingNumberRef.value.focus()
playAudio('weight_search_error')
}
}
const handleDownload = () => {
if (
!detail.value ||
Object.keys(detail.value).length <= 1 ||
detail.value.id == -1
) {
return ElMessage.warning('请扫码生产单号')
}
download()
}
const download = async () => {
if (detail.value && detail.value?.id != -1) {
try {
const id = detail.value.id
if (id !== undefined) {
try {
const res = await downloadMaterialApi([id])
if (res.code !== 200) return
window.open(filePath + res.message)
} catch (e) {
console.error(e)
}
}
} catch (e) {
// showError(e)
console.error(e)
}
}
}
type AudioKey = keyof typeof audios // 创建一个类型,确保 key 只能是 audios 对象的键之一
const playAudio = (key: AudioKey, message?: string) => {
let text = ''
switch (key) {
case 'weight_search_success':
text = ''
break
case 'weight_search_error':
text = '请录入生产单号'
break
case 'weight_success':
text = ''
break
case 'weight_repeat':
text = '称重复录入'
break
default:
text = '请录入跟踪号或重量'
break
}
if (message || text) ElMessage.warning(message || text)
const audio = new Audio()
if (audios[key]) {
audio.src = audios[key] // 获取对应 key 的音频路径
audio.play().catch((err) => console.error('Audio play failed:', err)) // 捕获音频播放失败的错误
} else {
console.error(`No audio found for key: ${key}`)
}
}
const trackCodeInput = async () => {
if (!TrackingNumber.value) {
// ElMessage.warning('请扫描生产单号')
playAudio('weight_search_error')
trackingNumberRef.value && trackingNumberRef.value.focus()
return
}
const item = historyData.value.find(
(el: HistoryDataItem) => el.orderNumber === TrackingNumber.value,
)
if (!item) {
// 记录扫单
historyData.value.push({
orderNumber: TrackingNumber.value,
finished: false,
})
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
const orderNumber = TrackingNumber.value
if (isAutoSure.value) {
await setData(
historyData.value[historyData.value.length - 1].orderNumber || '',
)
}
try {
const res = await getSubOrderBySubOrderNumber(orderNumber)
if (!res.data) {
return ElMessage.error('生产单不存在')
}
const d = JSON.parse(JSON.stringify(res.data))
if (d.note) {
d.note = JSON.parse(d.note)
} else {
d.note = []
}
if (d.imageAry) {
d.imgList = JSON.parse(d.imageAry)
} else {
d.imgList = []
}
detail.value = d
if (isDownloadImage.value) {
download()
}
playAudio('weight_search_success')
trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = ''
} catch (e) {
console.error(e)
trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = ''
}
}
const onOpened = () => {
trackingNumberRef.value && trackingNumberRef.value.focus()
}
</script>
<style lang="scss" scoped>
.sure-btn {
position: absolute;
right: 62px;
top: 14px;
}
.detail-div {
display: flex;
height: 100%;
flex-direction: column;
justify-content: space-between;
.detail-images {
.scroll-list {
background: #ececec;
display: flex;
height: 100px;
width: 100%;
padding: 5px;
.scroll-content {
margin-left: 10px;
overflow-x: auto;
overflow-y: hidden;
flex: 1;
display: flex;
flex-wrap: nowrap;
flex-shrink: 0;
.scroll-item {
height: 100%;
min-width: 100px;
background: white;
margin-right: 5px;
}
}
.img-title {
display: flex;
flex-direction: column;
justify-content: center;
background: white;
padding: 10px;
b {
text-align: center;
color: black;
font-weight: bold;
font-size: 16px;
margin-bottom: 15px;
}
.id {
display: flex;
align-items: center;
padding: 3px 5px;
background: #ececec;
justify-content: center;
img {
width: 15px;
margin-right: 8px;
}
}
}
}
}
.detail-content {
display: flex;
width: 100%;
}
.right {
width: 730px;
height: 100%;
display: flex;
flex-direction: column;
.btn {
margin: 20px 0;
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
width: 100%;
.btn-sure,
.btn-down {
width: 49%;
position: relative;
.check {
position: absolute;
width: 144px;
height: 100%;
background: transparent;
display: flex;
align-items: center;
justify-content: center;
right: 0;
top: 1px;
}
}
}
.div-text {
.div-content {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-start;
padding: 15px 10px;
box-sizing: border-box;
.div-item {
width: 50%;
margin-bottom: 10px;
display: flex;
align-items: center;
p {
font-weight: 400;
color: black;
}
span {
display: inline-block;
text-align: right;
width: 120px;
}
span::after {
content: ':';
margin: 0 3px;
}
}
}
b {
position: relative;
background: white;
top: 9px;
left: 13px;
padding: 0 10px;
font-size: 18px;
color: black;
z-index: 3;
}
.div-content {
position: relative;
border: 1px solid #ececec;
}
}
.input {
display: flex;
align-items: center;
margin: 30px 0;
}
}
.left {
flex: 1;
flex-shrink: 0;
margin-right: 20px;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
.left-image {
display: flex;
height: 100%;
flex-direction: column;
justify-content: center;
img {
height: auto;
width: 100%;
max-height: 90%;
}
b {
color: black;
font-size: 18px;
margin-bottom: 15px;
}
}
.left-images {
display: flex;
width: 95%;
height: 100%;
flex-direction: column;
b {
color: black;
text-align: center;
margin-bottom: 15px;
}
}
}
}
.left-images {
:deep(.el-carousel__container) {
height: 100%;
}
:deep(.el-dialog__title) {
font-weight: bold;
font-size: 37px;
color: black;
position: relative;
left: 47%;
top: 13px;
}
}
.btn {
position: relative;
:deep(.el-button) {
span {
position: relative;
left: -30px;
}
}
.check {
:deep(.el-checkbox__inner) {
background-color: transparent !important;
border-color: white !important;
width: 12px;
height: 12px;
}
:deep(.el-checkbox__inner::after) {
left: 3px;
}
:deep(.el-checkbox__label) {
padding-left: 5px;
font-size: 12px;
color: white !important;
}
}
}
.warning {
font-size: 18px;
font-weight: bold;
color: #ff9900;
margin-left: 10px;
cursor: pointer;
}
</style>
<template>
<div class="card flex-column h-100 overflow-hidden">
<div class="header-filter-form">
<ElForm :model="searchForm" size="default" inline>
<ElFormItem label="客户">
<el-select
v-model="searchForm.userMark"
clearable
filterable
style="width: 180px"
placeholder="客户"
>
<el-option
v-for="item in userMarkList"
:key="item"
:value="item"
:label="item"
></el-option>
</el-select>
</ElFormItem>
<ElFormItem label="SKU">
<ElInput
v-model.trim="searchForm.sku"
placeholder=" SKU"
clearable
style="width: 180px"
></ElInput>
</ElFormItem>
<ElFormItem label="Base SKU">
<ElInput
v-model.trim="searchForm.baseSku"
placeholder=" Base SKU"
clearable
style="width: 180px"
></ElInput>
</ElFormItem>
<ElFormItem label="物流跟踪号">
<ElInput
v-model.trim="searchForm.logisticsTracking"
placeholder="物流跟踪号"
clearable
style="width: 180px"
></ElInput>
</ElFormItem>
<ElFormItem label="生产单号">
<ElInput
v-model="searchForm.factorySubOrderNumber"
placeholder="生产单号"
clearable
style="width: 180px"
/>
</ElFormItem>
<ElFormItem label="订单号">
<ElInput
v-model="searchForm.factoryOrderNumber"
placeholder="订单号"
clearable
style="width: 180px"
/>
</ElFormItem>
<ElFormItem label="店铺单号">
<ElInput
v-model="searchForm.shopNumber"
placeholder="店铺单号"
clearable
style="width: 180px"
/>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search">查询</ElButton>
</ElFormItem>
</ElForm>
</div>
<div class="header-filter-tab">
<div class="tabs">
<div
v-for="item in tabsNav"
:key="item.status"
class="tabs-node"
:class="item.status === status ? 'tabs-node_active' : ''"
@click="changeTab(item)"
>
<span class="tabs-node_label">{{ item.statusName }}</span>
<span class="tabs-node_count">{{ `(${item.quantity})` }}</span>
</div>
</div>
</div>
<div class="order-content flex-1 flex-column overflow-hidden mt-10">
<div class="operation-box mb-10">
<span v-if="status === 'TO_BE_CONFIRMED'" class="item">
<ElButton type="success" @click="confirmOrder"> 确认 </ElButton>
</span>
<span v-if="status === 'EXCEPTION'" class="item">
<ElButton type="success" @click="updateOrder"> 更新 </ElButton>
</span>
<span v-if="status === 'IN_PRODUCTION'" class="item">
<ElButton type="primary" @click="printProductionOrder"> 打印生产单 </ElButton>
</span>
<span v-if="status === 'TO_BE_CONFIRMED'" class="item">
<ElButton type="warning" @click="changeExceptionOrder">
转为异常单
</ElButton>
</span>
<span v-if="status === 'TO_BE_CONFIRMED' || status === 'EXCEPTION'" class="item">
<ElButton type="danger" @click="cancelOrder">取消</ElButton>
</span>
<span v-if="status !== 'IN_PRODUCTION'" class="item">
<ElButton type="success" @click="handleUpdateRemark">
添加内部标签
</ElButton>
</span>
<span v-if="status === 'IN_PRODUCTION'" class="item">
<ElButton type="warning" @click="onFastProduction">
快捷生产
</ElButton>
</span>
<span class="item">
<ElButton type="primary" @click="downloadMaterial">下载素材</ElButton>
</span>
</div>
<div
v-if="status !== 'IN_PRODUCTION'"
v-loading="loading"
element-loading-text="加载中..."
class="table-wrapper flex-1 flex-column overflow-hidden"
>
<TableView
:columns="tableColumns"
:stripe="true"
:serial-numberable="true"
:selectionable="true"
:paginated-data="tableData"
:cell-style="onCellStyle"
@selection-change="handleSelectionChange"
>
<template #goods="{ row }">
<div class="goods-info-box">
<div class="goods-list">
<div
v-for="item in row.productList"
:key="item"
class="goods-item"
>
<div class="goods-item-img">
<img :src="item.variantImage" alt="商品图片" />
</div>
<div class="goods-item-info">
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">商品名称:</span>
<span class="goods-item-info-item-value">
{{ item.productName }}
</span>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">Base SKU:</span>
<span class="goods-item-info-item-value">
{{ item.baseSku }}
</span>
<el-icon class="icon" @click="copy(item.baseSku || '')"
><DocumentCopy
/></el-icon>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">变体SKU:</span>
<span class="goods-item-info-item-value">
{{ item.variantSku }}
</span>
<el-icon class="icon" @click="copy(item.variantSku || '')"
><DocumentCopy
/></el-icon>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">备注:</span>
<span class="goods-item-info-item-value">
{{ item.remark }}
</span>
<el-icon
class="icon"
style="color: #e6a23c"
@click="handleUpdateRemark(item)"
><EditPen
/></el-icon>
</div>
</div>
<div class="goods-item-info">
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">生产单号:</span>
<span class="goods-item-info-item-value">
{{ item.factorySubOrderNumber }}
</span>
<el-icon
class="icon"
@click="copy(item.factorySubOrderNumber || '')"
><DocumentCopy
/></el-icon>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label"
>第三方生产单号:</span
>
<span class="goods-item-info-item-value">
{{ item.thirdSubOrderNumber }}
</span>
<el-icon
class="icon"
@click="copy(item.thirdSubOrderNumber || '')"
><DocumentCopy
/></el-icon>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">工厂:</span>
<span class="goods-item-info-item-value">
{{ item.factoryCode }}
</span>
</div>
</div>
<div class="goods-item-info">
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">单价:</span>
<span class="goods-item-info-item-value">
{{ item.productPrice }}()
</span>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">模板金额:</span>
<span class="goods-item-info-item-value">
{{ item.templatePrice }}()
</span>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">付款金额:</span>
<span class="goods-item-info-item-value">
{{ item.payAmount }}()
</span>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label">数量:</span>
<span class="goods-item-info-item-value">
{{ item.num }}
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<template #orderDetail="{ row }">
<div class="order-detail-box">
<div class="order-detail-item">
<span class="order-detail-item-label">订单号:</span>
<span class="order-detail-item-value">
{{ row.factoryOrderNumber }}
</span>
<el-icon
class="icon"
@click="copy(row.factoryOrderNumber || '')"
><DocumentCopy
/></el-icon>
</div>
<div class="order-detail-item">
<span class="order-detail-item-label">第三方订单号:</span>
<span class="order-detail-item-value">
{{ row.thirdOrderNumber }}
</span>
<el-icon class="icon" @click="copy(row.thirdOrderNumber || '')"
><DocumentCopy
/></el-icon>
</div>
<div class="order-detail-item">
<span class="order-detail-item-label">店铺单号:</span>
<span class="order-detail-item-value">
{{ row.shopNumber }}
</span>
<el-icon class="icon" @click="copy(row.shopNumber || '')"
><DocumentCopy
/></el-icon>
</div>
<div class="order-detail-item">
<span class="order-detail-item-label">收货人:</span>
<span class="order-detail-item-value">
{{ row.receiverName }}
</span>
</div>
<div class="order-detail-item">
<span class="order-detail-item-label">收货人电话:</span>
<span class="order-detail-item-value">
{{ row.receiverPhone }}
</span>
</div>
<div class="order-detail-item">
<span class="order-detail-item-label">收货人邮编:</span>
<span class="order-detail-item-value">
{{ row.receiverPostCode }}
</span>
</div>
<div class="order-detail-item">
<span class="order-detail-item-label">收货地址:</span>
<span class="order-detail-item-value">
{{ row.receiverCountry }}{{ row.receiverProvince
}}{{ row.receiverCity }}{{ row.receiverDistrict }}
</span>
</div>
</div>
</template>
<template #price="{ row }">
<div class="order-price-box">
<div class="order-price-item">
<span class="order-price-item-label">总价:</span>
<span class="order-price-item-value">
{{ row.totalAmount }}()
</span>
</div>
</div>
</template>
<template #time="{ row }">
<div class="order-time-box">
<div class="order-time-item">
<span class="order-time-item-label">创建时间:</span>
<span class="order-time-item-value">
{{ row.createTime }}
</span>
</div>
<div class="order-time-item">
<span class="order-time-item-label">更新时间:</span>
<span class="order-time-item-value">
{{ row.updateTime }}
</span>
</div>
<div class="order-time-item">
<span class="order-time-item-label">支付时间:</span>
<span class="order-time-item-value">
{{ row.paymentTime }}
</span>
</div>
</div>
</template>
<template #innerLabel="{ row }">
<div v-if="row.internalMemoList" class="inner-label-box">
<div
v-for="(item, index) in row.internalMemoList"
:key="index"
class="inner-label-item"
>
<span class="inner-label-item-value">
{{
`${item.operatorTime} ${item.operatorEmployeeName}: ${item.content}`
}}
</span>
</div>
</div>
</template>
<template #operate="{ row }">
<div class="operate-box">
<span class="operate-item">
<ElButton
link
type="primary"
@click="operationLog(row.id, null)"
>
操作日志
</ElButton>
</span>
</div>
</template>
</TableView>
</div>
<div
v-else
v-loading="loading"
element-loading-text="加载中..."
class="card-wrapper flex-1 flex-column overflow-hidden"
>
<div v-if="tableData.length > 0" class="card-list">
<div
v-for="cardItem in tableData as ProductList[]"
:key="cardItem.id"
class="card-list-item"
@click="cardClick(cardItem)"
@mouseleave="handleChangeImages(null, cardItem)"
>
<CommonCard
:card-item="cardItem"
:active="isSelectStatused(cardItem)"
:show-sku="false"
:show-product-info="false"
:image-field="'variantImage'"
@contextmenu.prevent="(v: MouseEvent) => rightClick(v)"
>
<template #bottom_left>
<span
v-if="cardItem?.factorySubOrderNumber"
title="生产单号"
class="factory-sub-order-number"
@click.stop="
copy(String(cardItem?.factorySubOrderNumber || ''))
"
>
{{ cardItem?.factorySubOrderNumber }}
</span>
</template>
<template #operations>
<Icon
name="caozuorizhi"
@click="(e: MouseEvent) => operationLog(cardItem.podJomallOrderUsId, e)"
>
<template #title>
<title>操作日志</title>
</template>
</Icon>
<Icon name="chakanxiangqing">
<template #title>
<title>查看详情</title>
</template>
</Icon>
</template>
<template #images>
<div class="flex-between">
<div v-if="cardItem.imageAry" class="images-position">
<div
v-for="(item, index) in JSON.parse(
cardItem.imageAry || '',
)"
:key="index"
:title="item.title"
class="item-image"
@mousemove="handleChangeImages(item, cardItem)"
>
<img :src="item?.url" height="28" />
</div>
</div>
</div>
</template>
<template #info>
<div class="grid-container">
<div class="grid-item" title="商品名称">
<span class="grid-item-value"
>{{ cardItem?.productName }}
</span>
</div>
<div class="grid-item" title="未生产数量">
<span class="grid-item-label">数量:</span>
<span class="grid-item-value">
{{ cardItem?.notPassNum }}
</span>
</div>
<div class="grid-item">
<span title="Base SKU" class="grid-item-value">
{{ cardItem?.baseSku }}
</span>
</div>
<div class="grid-item">
<span
:title="`第三方生产单号:${cardItem?.thirdSubOrderNumber}`"
class="grid-item-value"
@click.stop="
copy(String(cardItem?.thirdSubOrderNumber || ''))
"
>
{{ cardItem?.thirdSubOrderNumber }}
</span>
</div>
<div class="grid-item">
<span title="Variant SKU" class="grid-item-value">
{{ cardItem?.variantSku }}
</span>
</div>
</div>
</template>
</CommonCard>
</div>
</div>
<div v-else class="empty">暂无数据</div>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
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>
<right-menu ref="rightMenuRef" @change="rightChange" />
<el-dialog
v-model="logVisible"
title="操作日志"
width="1000px"
:close-on-click-modal="false"
>
<LogList :log-list="logList" />
</el-dialog>
<FastProduction
v-model:detailVisible="detailVisible"
:current-status="status"
@on-success="handleSuccess"
@close="fastClose"
></FastProduction>
</template>
<script setup lang="ts">
import { getUserMarkList } from '@/api/common'
import {
getCardOrderList,
getOrderList,
getOrderTabData,
confirmOrderApi,
changeExceptionOrderApi,
cancelOrderApi,
getOperationLogApi,
downloadMaterialApi,
updateExceptionOrderApi,
printProductionOrderApi,
} from '@/api/podUsOrder'
import TableView from '@/components/TableView.vue'
import {
LogListData,
PodUsOrderListData,
ProductList,
SearchForm,
Tab,
cardImages,
} from '@/types/api/podUsOrder'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import { showConfirm } from '@/utils/ui'
import { DocumentCopy, EditPen } from '@element-plus/icons-vue'
import { Column } from 'element-plus'
import { computed, onMounted, ref } from 'vue'
import FastProduction from './FastProduction.vue'
import { filePath } from '@/api/axios'
const tabsNav = ref<Tab[]>()
const status = ref('TO_BE_CONFIRMED')
const [searchForm] = useValue<SearchForm>({
timeType: null,
shopNumber: '',
userMark: '',
logisticsTracking: '',
baseSku: '',
factoryOrderNumber: '',
sku: '',
factorySubOrderNumber: '',
status: '',
})
const userMarkList = ref<string[]>([])
const selection = ref<PodUsOrderListData[]>([])
const tableColumns = computed(() => [
{
label: '商品',
prop: 'goods',
slot: 'goods',
minWidth: 800,
},
{
label: '订单详情',
prop: 'orderDetail',
slot: 'orderDetail',
width: 300,
},
{
label: '单价',
slot: 'price',
width: 160,
prop: 'price',
align: 'center',
},
{
label: '时间',
slot: 'time',
width: 300,
prop: 'time',
align: 'center',
},
{
label: '内部便签',
slot: 'innerLabel',
width: 300,
prop: 'innerLabel',
},
{
label: '操作',
slot: 'operate',
width: 180,
align: 'center',
fixed: 'right',
prop: 'operate',
},
])
const rightMenuRef = ref()
const rightClick = (e: MouseEvent) => {
rightMenuRef.value.setPosition({
x: e.clientX,
y: e.clientY,
cardItem: e.clientY,
el: e,
})
}
const handleSelectionChange = (val: PodUsOrderListData[]) => {
selection.value = val
}
const changeTab = (item: Tab) => {
status.value = item.status || ''
selection.value = []
cardSelection.value = []
search(true)
}
const onCellStyle = ({ column }: { column: Column }) => {
if (
column.property === 'orderDetail' ||
column.property === 'price' ||
column.property === 'time' ||
column.property === 'innerLabel' ||
column.property === 'goods' ||
column.property === 'operate'
) {
return { verticalAlign: 'top' }
}
}
const loadTabData = async () => {
try {
const res = await getOrderTabData()
tabsNav.value = res.data
} catch (error) {
// showError(error)
}
}
const getUserMark = async () => {
try {
const res = await getUserMarkList()
userMarkList.value = res.data
} catch (error) {
//showError(error)
}
}
const {
loading,
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) => {
if (status.value !== 'IN_PRODUCTION') {
return getOrderList(
{
...searchForm.value,
status: status.value,
},
page,
pageSize,
).then((res) => res.data) as never
} else {
return getCardOrderList(
{
...searchForm.value,
status: status.value,
},
page,
pageSize,
).then((res) => res.data) as never
}
},
})
const copy = (text: string) => {
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
}
const handleUpdateRemark = (item: PodUsOrderListData) => {
console.log(item)
}
const confirmOrder = async () => {
if (selection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
try {
await showConfirm('确定确认吗?', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
} catch {
return
}
const ids = selection.value.map((item) => item.id)
try {
const res = await confirmOrderApi(ids)
if (res.code !== 200) return
ElMessage.success('操作成功')
search()
loadTabData()
} catch (e) {
console.error(e)
}
}
const updateOrder = async () => {
if (selection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
try {
await showConfirm('确定更新吗?', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
} catch {
return
}
const ids = selection.value.map((item) => item.id)
try {
const res = await updateExceptionOrderApi(ids)
if (res.code !== 200) return
ElMessage.success('操作成功')
search()
loadTabData()
} catch (e) {
console.error(e)
}
}
const printProductionOrder = async () => {
if (cardSelection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
const orderIds = cardSelection.value.map((item) => item.id)
try {
const res = await printProductionOrderApi(orderIds)
if (res.code !== 200) return
ElMessage.success('操作成功')
window.open(filePath + res.message)
search()
loadTabData()
} catch (e) {
console.error(e)
}
}
const changeExceptionOrder = async () => {
if (selection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
const orderIds = selection.value.map((item) => item.id)
ElMessageBox.prompt('请填写异常原因', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputPattern: /^.{1,2000}$/,
inputErrorMessage: '请输入异常原因',
}).then(async ({ value }) => {
try {
const res = await changeExceptionOrderApi(orderIds, value)
if (res.code !== 200) return
ElMessage.success('操作成功')
search()
loadTabData()
} catch (e) {
console.error(e)
}
})
}
const cancelOrder = async () => {
if (selection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
const orderIds = selection.value.map((item) => item.id)
ElMessageBox.prompt('请填写取消原因', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputPattern: /^.{1,2000}$/,
inputErrorMessage: '请输入取消原因',
}).then(async ({ value }) => {
try {
const res = await cancelOrderApi(orderIds, value)
if (res.code !== 200) return
ElMessage.success('操作成功')
search()
loadTabData()
} catch (e) {
console.error(e)
}
})
}
const cardSelection = ref<ProductList[]>([])
const cardClick = (data: ProductList) => {
const status = isSelectStatused(data)
if (status) {
cardSelection.value = cardSelection.value.filter(
(item: ProductList) => item.id !== data.id,
)
} else {
cardSelection.value.push(data as ProductList)
}
}
const isSelectStatused = (data: ProductList) => {
const index = cardSelection.value.findIndex(
(item: ProductList) => item.id === data.id,
)
return index !== -1
}
const rightChange = async (code: string) => {
if (code === 'check_all') {
cardSelection.value = JSON.parse(JSON.stringify(tableData.value))
} else if (code === 'clear_check') {
cardSelection.value = []
} else if (code === 'copy_code') {
const str = cardSelection.value
.map((item) => item.factorySubOrderNumber)
.join()
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
}
}
const currentImage = ref('')
const handleChangeImages = (item: cardImages | null, cardItem: ProductList) => {
currentImage.value = item?.url || ''
cardItem.variantImage =
item?.url || JSON.parse(cardItem.imageAry || '')[0].url
}
const detailVisible = ref(false)
const onFastProduction = () => {
detailVisible.value = true
}
// 下载稿件
const downloadMaterial = async () => {
let selectedIds = []
if (status.value === 'IN_PRODUCTION') {
selectedIds = cardSelection.value.map(
(item: ProductList) => item.podJomallOrderUsId,
)
} else {
selectedIds = selection.value.map((item: PodUsOrderListData) => item.id)
}
if (selectedIds.length === 0) {
return ElMessage({
message: '请选择订单',
type: 'warning',
offset: window.innerHeight / 2,
})
}
try {
const res = await downloadMaterialApi(selectedIds)
if (res.code !== 200) return
window.open(filePath + res.message)
} catch (e) {
// showError(e)
console.error(e)
}
}
const logList = ref<LogListData[]>([])
const logVisible = ref(false)
const operationLog = async (id: number, e: MouseEvent | null) => {
e && e.stopPropagation()
try {
const res = await getOperationLogApi(id)
if (res.code !== 200) return
logList.value = res.data
logVisible.value = true
} catch (e) {
console.error(e)
}
}
const handleSuccess = () => {
loadTabData()
search()
}
const fastClose = () => {
loadTabData()
detailVisible.value = false
}
onMounted(() => {
loadTabData()
getUserMark()
})
</script>
<style lang="scss" scoped>
.header-filter-form {
:deep(.el-form-item) {
margin-right: 14px;
margin-bottom: 10px;
}
}
.tabs {
display: flex;
align-items: center;
gap: 10px;
border-bottom: 1px solid #f0f0f0;
height: 42px;
.tabs-node {
padding: 10px;
font-size: 14px;
color: #000;
cursor: pointer;
height: 40px;
}
.tabs-node:hover {
color: #409eff;
}
.tabs-node.tabs-node_active {
color: #409eff;
border-bottom: 2px solid #409eff;
font-weight: 600;
}
}
.goods-item {
display: grid;
grid-template-columns: 100px 1fr minmax(180px, 1fr) 140px;
gap: 20px;
.goods-item-img {
width: 100px;
height: 100px;
img {
width: 100%;
}
}
&:not(:last-child) {
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px solid #eee;
}
}
.goods-item-info-item {
display: flex;
align-items: center;
gap: 6px;
.goods-item-info-item-value {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.order-detail-item {
display: flex;
align-items: center;
gap: 6px;
.order-detail-item-value {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.card-list {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: max-content;
gap: 10px;
height: 100%;
overflow-y: auto;
}
.empty {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #999;
}
.card-list-item {
cursor: pointer;
}
.images-position {
display: flex;
gap: 5px;
.item-image {
cursor: pointer;
border: 1px solid #eee;
}
}
.grid-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
font-size: 12px;
margin-top: 10px;
}
.factory-sub-order-number {
font-size: 12px;
}
</style>
...@@ -23,20 +23,20 @@ ...@@ -23,20 +23,20 @@
</ElTree> </ElTree>
</div> </div>
<div class="right"> <div class="right">
<pending-reconciliation v-if="nodeId===0"></pending-reconciliation> <!-- <pending-reconciliation></pending-reconciliation> -->
<div v-else class="delivery-note-page flex-column card h-100 overflow-hidden"> <div class="delivery-note-page flex-column card h-100 overflow-hidden">
<splitDiv size="50"> <splitDiv size="50">
<template #top> <template #top>
<div class="header-filter-form"> <div class="header-filter-form">
<ElForm :model="searchForm" inline> <ElForm :model="searchForm" inline>
<ElFormItem label="账期"> <ElFormItem label="账期(发货时间)">
<div style="display: flex"> <div style="display: flex">
<el-date-picker <el-date-picker
v-model="dateRange" v-model="dateRange"
:default-time="[ :default-time="[
new Date(0, 0, 0, 0, 0, 0), new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59), new Date(0, 0, 0, 23, 59, 59),
]" ]"
type="datetimerange" type="datetimerange"
start-placeholder="开始时间" start-placeholder="开始时间"
end-placeholder="结束时间" end-placeholder="结束时间"
...@@ -82,16 +82,15 @@ ...@@ -82,16 +82,15 @@
</ElForm> </ElForm>
</div> </div>
<div class="btn-list"> <div class="btn-list">
<!-- <el-button
<el-button
v-if="nodeId === 10" v-if="nodeId === 10"
type="primary" type="primary"
@click="confirmOrder" @click="confirmOrder()"
> >
确认对账单 确认
</el-button> </el-button> -->
<el-button <el-button
v-if="nodeId === 10" v-if="nodeId === 15"
type="warning" type="warning"
@click="rejectOrder" @click="rejectOrder"
> >
...@@ -146,7 +145,7 @@ ...@@ -146,7 +145,7 @@
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="账期" label="账期(发货时间)"
header-align="center" header-align="center"
align="center" align="center"
min-width="340" min-width="340"
...@@ -156,23 +155,23 @@ ...@@ -156,23 +155,23 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="工厂总价格(¥)" label="总发货(件)"
header-align="center" header-align="center"
prop="product_total_amount" prop="num"
width="130" width="100"
align="center" align="center"
show-overflow-tooltip show-overflow-tooltip
> >
</el-table-column> </el-table-column>
<!-- <el-table-column <el-table-column
label="ERP总价格" label="成本总价(¥)"
header-align="center" header-align="center"
prop="erp_total_amount" prop="product_total_amount"
width="120" width="130"
align="center" align="center"
show-overflow-tooltip show-overflow-tooltip
> >
</el-table-column> --> </el-table-column>
<el-table-column <el-table-column
label="工艺总价(¥)" label="工艺总价(¥)"
header-align="center" header-align="center"
...@@ -219,7 +218,10 @@ ...@@ -219,7 +218,10 @@
style="display: flex; gap: 2px; align-items: center" style="display: flex; gap: 2px; align-items: center"
> >
<div <div
v-for="item in row.water_list.split(',')" v-for="item in (typeof row.water_list === 'string'
? row.water_list
: ''
).split(',')"
:key="item" :key="item"
style="width: 30px" style="width: 30px"
> >
...@@ -228,75 +230,6 @@ ...@@ -228,75 +230,6 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column
label="客户"
prop="name"
width="90"
header-align="center"
align="center"
show-overflow-tooltip
/> -->
<!-- <el-table-column
label="状态"
prop="status"
width="90"
header-align="center"
align="center"
show-overflow-tooltip
>
<template #default="scope">
{{ getTabsList(scope.row.status) }}
</template>
</el-table-column> -->
<!-- <el-table-column
label="ERP状态"
prop="erp_status"
width="90"
header-align="center"
align="center"
show-overflow-tooltip
>
<template #default="scope">
{{ getTabsList(scope.row.erp_status) }}
</template>
</el-table-column> -->
<el-table-column
label="总发货(件)"
header-align="center"
prop="num"
width="100"
align="center"
show-overflow-tooltip
>
</el-table-column>
<!-- <el-table-column
label="质检通过(件)"
header-align="center"
prop="pass_num"
width="120"
align="center"
show-overflow-tooltip
>
</el-table-column>
<el-table-column
label="质检不通过(件)"
header-align="center"
prop="not_pass_num"
width="130"
align="center"
show-overflow-tooltip
>
</el-table-column> -->
<!-- <el-table-column
label="物流运费"
header-align="center"
prop="factory_total_amount"
width="120"
align="center"
show-overflow-tooltip
>
</el-table-column> -->
<el-table-column <el-table-column
label="创建时间" label="创建时间"
prop="create_time" prop="create_time"
...@@ -305,22 +238,6 @@ ...@@ -305,22 +238,6 @@
align="center" align="center"
show-overflow-tooltip show-overflow-tooltip
/> />
<!-- <el-table-column
label="开始时间"
prop="start_time"
width="180"
header-align="center"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="结束时间"
prop="end_time"
width="180"
header-align="center"
align="center"
show-overflow-tooltip
/> -->
<el-table-column <el-table-column
label="操作" label="操作"
width="100" width="100"
...@@ -331,15 +248,23 @@ ...@@ -331,15 +248,23 @@
<template #default="{ row }"> <template #default="{ row }">
<div> <div>
<el-button <el-button
v-if="row.status===20" v-if="row.status === 10"
type="success" type="success"
link size="small"
@click="onPayment(row)" @click="confirmOrder(row)"
>付款
</el-button
> >
确认
</el-button>
</div>
<div>
<el-button
v-if="row.status === 20"
type="success"
size="small"
@click="onPayment(row)"
>付款
</el-button>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
</ElTable> </ElTable>
...@@ -361,13 +286,13 @@ ...@@ -361,13 +286,13 @@
<el-tabs v-model="tabsValue" @tab-click="tabsClick"> <el-tabs v-model="tabsValue" @tab-click="tabsClick">
<el-tab-pane name="0" label="对账单详情"> <el-tab-pane name="0" label="对账单详情">
<el-form :model="detailForm" inline> <el-form :model="detailForm" inline>
<el-form-item label="发货时间"> <!-- <el-form-item label="发货时间">
<el-date-picker <el-date-picker
v-model="detailForm.dateRange" v-model="detailForm.dateRange"
:default-time="[ :default-time="[
new Date(0, 0, 0, 0, 0, 0), new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59), new Date(0, 0, 0, 23, 59, 59),
]" ]"
type="datetimerange" type="datetimerange"
start-placeholder="开始时间" start-placeholder="开始时间"
end-placeholder="结束时间" end-placeholder="结束时间"
...@@ -377,6 +302,30 @@ ...@@ -377,6 +302,30 @@
format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
/> />
</el-form-item> -->
<el-form-item label="底胚">
<el-input
v-model="detailForm.baseSku"
placeholder="请输入底胚"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item label="工艺简称">
<el-input
v-model="detailForm.process"
placeholder="请输入工艺简称"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item label="供应商货号">
<el-input
v-model="detailForm.supplierItemNo"
placeholder="请输入供应商货号"
clearable
style="width: 130px"
/>
</el-form-item> </el-form-item>
<el-form-item label="发货单号"> <el-form-item label="发货单号">
<el-input <el-input
...@@ -403,34 +352,36 @@ ...@@ -403,34 +352,36 @@
style="width: 130px" style="width: 130px"
/> />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="searchDetail" <el-button type="primary" @click="searchDetail"
>查询 >查询
</el-button </el-button>
>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button <el-button
v-if="nodeId===1" v-if="[0, 1].some((id) => id === Number(nodeId))"
type="primary" type="primary"
@click="priceModification(1)" @click="priceModification(1)"
>修改工厂价格 >修改成本价格
</el-button </el-button>
>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button v-if="nodeId===1" type="warning" @click="priceModification(3)" <el-button
>修改工艺价格 v-if="[0, 1].some((id) => id === Number(nodeId))"
</el-button type="warning"
> @click="modifyProcessPrices"
>修改工艺价格
</el-button>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button v-if="nodeId===1" type="primary" @click="priceModification(4)" <el-button
>修改物流价格 v-if="[0, 1].some((id) => id === Number(nodeId))"
</el-button type="primary"
> @click="priceModification(4)"
>修改物流价格
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="table-wrap"> <div class="table-wrap">
<ElTable <ElTable
...@@ -438,10 +389,11 @@ ...@@ -438,10 +389,11 @@
:data="detailList" :data="detailList"
height="100%" height="100%"
border border
@selection-change="handleDetailSelectionChange"> @selection-change="handleDetailSelectionChange"
>
<el-table-column <el-table-column
type="selection" type="selection"
width="70" width="50"
header-align="center" header-align="center"
align="center" align="center"
/> />
...@@ -453,19 +405,43 @@ ...@@ -453,19 +405,43 @@
type="index" type="index"
/> />
<el-table-column <el-table-column
label="发货单号" label="生产单号"
prop="shipment_number" prop="factory_sub_order_number"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="160"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="店铺单号"
prop="shop_number"
header-align="center"
align="center"
min-width="160"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="客户"
prop="user_mark"
header-align="center"
align="center"
min-width="80"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="订单号" label="订单号"
prop="factory_order_number" prop="factory_order_number"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="130"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="底胚"
prop="base_sku"
header-align="center"
align="center"
min-width="150"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
...@@ -473,44 +449,52 @@ ...@@ -473,44 +449,52 @@
prop="shipment_num" prop="shipment_num"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="100"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="工厂价格(¥)" label="成本单价(¥)"
prop="cost_price" prop="cost_price"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="120"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="工艺价格(¥)" label="工艺简称"
prop="craft_price" prop="process"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="90"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="物流价格(¥)" label="设计面数"
prop="carriage_amount" prop="face_count"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="90"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="生产单号" label="工艺单价(¥)"
prop="factory_sub_order_number" prop="craft_price"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="120"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="店铺单号" label="物流价格(¥)"
prop="shop_number" prop="carriage_amount"
header-align="center"
align="center"
min-width="120"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="发货单号"
prop="shipment_number"
header-align="center" header-align="center"
align="center" align="center"
min-width="160" min-width="160"
...@@ -541,38 +525,6 @@ ...@@ -541,38 +525,6 @@
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
label="客户"
prop="user_mark"
header-align="center"
align="center"
min-width="160"
show-overflow-tooltip
></el-table-column>
<!-- <el-table-column
label="ERP订单号"
prop="erp_order_number"
header-align="center"
align="center"
min-width="160"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="erp子单号"
prop="erp_sub_order_number"
header-align="center"
align="center"
min-width="160"
show-overflow-tooltip
></el-table-column> -->
<el-table-column
label="baseSKU"
prop="base_sku"
header-align="center"
align="center"
min-width="160"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="变体SKU" label="变体SKU"
prop="variant_sku" prop="variant_sku"
header-align="center" header-align="center"
...@@ -641,8 +593,7 @@ ...@@ -641,8 +593,7 @@
<template #default="{ row }"> <template #default="{ row }">
{{ row.shipping_way == 1 ? '送货上门' : '快递' }} {{ row.shipping_way == 1 ? '送货上门' : '快递' }}
</template> </template>
</el-table-column </el-table-column>
>
<el-table-column <el-table-column
label="运费(¥)" label="运费(¥)"
prop="carriage_amount" prop="carriage_amount"
...@@ -715,52 +666,14 @@ ...@@ -715,52 +666,14 @@
min-width="180" min-width="180"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <!-- <el-table-column
label="更新时间" label="更新时间"
prop="update_time" prop="update_time"
header-align="center" header-align="center"
align="center" align="center"
min-width="180" min-width="180"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column> -->
<el-table-column
show-overflow-tooltip
align="center"
fixed="right"
header-align="center"
label="操作"
width="120">
<template #default="{row}">
<el-button type="primary" link @click="showLog(row)">操作日志</el-button>
</template>
</el-table-column>
<!-- <ElTableColumn
show-overflow-tooltip
align="center"
header-align="center"
label="操作"
width="120"
>
<template #default="scope">
<div class="flex items-center justify-center gap-2">
<img
v-if="type === 'draft'"
@click="handleDetail(scope.row, 'edit')"
src="../../../assets/images/edit1.png"
width="24"
title="编辑"
style="cursor: pointer"
/>
<img
src="../../../assets/images/view.png"
title="查看详情"
width="24"
style="cursor: pointer"
@click="handleDetail(scope.row, 'view')"
/>
</div>
</template>
</ElTableColumn> -->
</ElTable> </ElTable>
</div> </div>
...@@ -791,14 +704,14 @@ ...@@ -791,14 +704,14 @@
style="display: flex" style="display: flex"
> >
<span style="display: inline-block"> <span style="display: inline-block">
{{ item.create_time }} {{ item.createTime }}
</span> </span>
<span style="margin: 0 5px 0 20px">{{ <span style="margin: 0 5px 0 20px">{{
item.employee_account item.employeeAccount
}}</span> }}</span>
<span style="display: inline-block">{{ <span style="display: inline-block">{{
item.description item.description
}}</span> }}</span>
</li> </li>
</ul> </ul>
</el-tab-pane> </el-tab-pane>
...@@ -808,19 +721,6 @@ ...@@ -808,19 +721,6 @@
</div> </div>
</div> </div>
</div> </div>
<el-dialog v-model="logDialogVisible" title="操作日志" width="30%">
<ul style="color: #333; font-size: 12px; height: 100%; overflow: auto">
<li v-for="(item, index) in logList" :key="index" style="display: flex">
<span style="display: inline-block; width: 23%">
{{ item.create_time }}
</span>
<div style="display: inline-block; width: 80%">
<span style="word-break: normal"> {{ item.employee_name }}:</span>
<span v-html="item.description"></span>
</div>
</li>
</ul>
</el-dialog>
<!-- 付款 --> <!-- 付款 -->
<el-dialog <el-dialog
v-model="paymentDialogVisible" v-model="paymentDialogVisible"
...@@ -841,14 +741,15 @@ ...@@ -841,14 +741,15 @@
label="实付金额" label="实付金额"
prop="actualAmount" prop="actualAmount"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '请输入实付金额', message: '请输入实付金额',
},{ },
type: 'number', {
message: '实付金额需要为数字', type: 'number',
}, message: '实付金额需要为数字',
]" },
]"
> >
<el-input <el-input
v-model.number="paymentForm.actualAmount" v-model.number="paymentForm.actualAmount"
...@@ -860,12 +761,12 @@ ...@@ -860,12 +761,12 @@
label="水单" label="水单"
prop="waterList" prop="waterList"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '请上传水单', message: '请上传水单',
trigger: 'blur', trigger: 'blur',
}, },
]" ]"
> >
<div v-loading="uploadLoading" class="avatar-uploader-icon"> <div v-loading="uploadLoading" class="avatar-uploader-icon">
<div class="img-list"> <div class="img-list">
...@@ -881,18 +782,13 @@ ...@@ -881,18 +782,13 @@
class="close-bill" class="close-bill"
@click="paymentForm.waterList.splice(index, 1)" @click="paymentForm.waterList.splice(index, 1)"
> >
<CircleClose <CircleClose />
/>
</el-icon> </el-icon>
</div> </div>
</template> </template>
<div class="img-item"> <div class="img-item">
<el-icon <el-icon style="width: 100%; height: 100%" @click="toUpload">
style="width: 100%; height: 100%" <Plus />
@click="toUpload"
>
<Plus
/>
</el-icon> </el-icon>
</div> </div>
</div> </div>
...@@ -904,70 +800,133 @@ ...@@ -904,70 +800,133 @@
<el-button type="primary" @click="handlePayment">确定</el-button> <el-button type="primary" @click="handlePayment">确定</el-button>
</template> </template>
</el-dialog> </el-dialog>
<ElDrawer
v-model="shipmentOrderDetailDrawerVisible"
title="发货单详情"
size="50%"
>
<shipmentOrderDetailInfo :detail="shipmentOrderDetail" />
</ElDrawer>
<ElDialog <ElDialog
v-model="confirmOrderVisible" v-model="confirmOrderVisible"
title="确认对账单" title="确认对账单"
width="500px" width="70%"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<el-row>
<el-col :span="6"> 对账单号:{{ currentRow?.rec_number }} </el-col>
<el-col :span="12">
账期(发货时间) {{ currentRow?.start_time }} -
{{ currentRow?.end_time }}
</el-col>
<el-col :span="6">
成本总价() {{ currentRow?.product_total_amount }}
</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">
工艺总价(){{ currentRow?.craft_total_amount }}
</el-col>
<el-col :span="6">
物流总价() {{ currentRow?.carriage_total_amount }}
</el-col>
<el-col :span="6"> 应付金额(){{ currentRow?.total_amount }} </el-col>
<el-col :span="6"> 实付金额(){{ currentRow?.actual_amount }} </el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6" v-if="currentRow?.water_list">
水单:
<span
v-for="item in (typeof currentRow?.water_list === 'string'
? currentRow.water_list
: ''
).split(',')"
:key="item"
style="width: 30px"
>
<ImageView :src="item" />
</span>
</el-col>
<el-col :span="6"> 总发货() {{ currentRow?.num }} </el-col>
<el-col :span="6"> 创建时间: {{ currentRow?.create_time }} </el-col>
</el-row>
<div></div>
<ElForm ref="auditFormRef" :model="auditForm" label-width="80px"> <ElForm ref="auditFormRef" :model="auditForm" label-width="80px">
<ElFormItem <ElFormItem
label="意见" label="驳回原因"
prop="pass"
:rules="[{ required: true, message: '请选择' }]"
>
<ElRadioGroup v-model="auditForm.pass">
<ElRadio :label="1">通过</ElRadio>
<ElRadio :label="0">不通过</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
label="审核意见"
prop="description" prop="description"
:rules=" :rules="[{ required: true, message: '请输入驳回原因' }]"
auditForm.pass === 0
? [{ required: true, message: '请输入审核意见' }]
: []
"
> >
<ElInput v-model="auditForm.description" type="textarea" /> <ElInput v-model="auditForm.description" type="textarea" />
</ElFormItem> </ElFormItem>
</ElForm> </ElForm>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="confirmOrderVisible = false">取消</el-button> <!-- <el-button @click="confirmOrderVisible = false">取消</el-button> -->
<el-button type="primary" @click="submitConfirmOrder">确认</el-button> <el-button type="success" @click="submitConfirmOrder(1)"
>确认</el-button
>
<el-button type="danger" @click="submitConfirmOrder(2)">驳回</el-button>
</span> </span>
</template> </template>
</ElDialog> </ElDialog>
<el-dialog
v-model="processPriceDialogVisible"
title="修改工艺价格"
width="50%"
:close-on-click-modal="false"
>
<el-table :data="craftPriceList" border style="width: 100%" height="330px">
<el-table-column
prop="process"
label="工艺简称"
width="260"
align="center"
/>
<el-table-column prop="base_price" label="基础价格(¥)" align="center">
<template #default="scope">
<el-input
v-model="scope.row.base_price"
placeholder="请输入基础价格"
clearable
oninput="value=value.replace(/[^\-?\d.]/g,'')"
style="width: 100%"
/>
</template>
</el-table-column>
<el-table-column prop="add_price" label="加价(¥)" align="center">
<template #default="scope">
<el-input
v-model="scope.row.add_price"
placeholder="请输入加价"
clearable
oninput="value=value.replace(/[^\-?\d.]/g,'')"
style="width: 100%"
/>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="processPriceDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitPodPrice">确定</el-button>
</template>
</el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ElMessage, ElRadioGroup, ElTable, ElTree, TableColumnCtx } from 'element-plus' import { ElMessage, ElTable, ElTree, TableColumnCtx } from 'element-plus'
import splitDiv from '@/components/splitDiv/splitDiv.vue' import splitDiv from '@/components/splitDiv/splitDiv.vue'
import { CircleClose, Plus } from '@element-plus/icons-vue' import { CircleClose, Plus } from '@element-plus/icons-vue'
import pendingReconciliation from './pendingReconciliation.vue' // import pendingReconciliation from './pendingReconciliation.vue'
import usePageList from '@/utils/hooks/usePageList' import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue' import { useValue } from '@/utils/hooks/useValue'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { import {
apiBillPodPayment, apiBillPodPayment,
apiItemLogList,
auditOrderApi, auditOrderApi,
confirmPodOrderApi, confirmPodOrderApi,
apiRejectionOfReview,
exportPodExcelApi, exportPodExcelApi,
getPodLogListApi, getPodLogListApi,
getPodShipmentDetailsById, getPodShipmentDetailsById,
podReconciliation, podReconciliation,
podReconciliationList, podReconciliationList,
updateRecPrice, updateRecPrice,
apiGetCraftGroup,
apiSetCraftData,
} from '@/api/order' } from '@/api/order'
import { nextTick, onMounted, ref, watch } from 'vue' import { nextTick, onMounted, ref, watch } from 'vue'
...@@ -977,13 +936,11 @@ import { ...@@ -977,13 +936,11 @@ import {
AccountStatementNoteSearchForm, AccountStatementNoteSearchForm,
CountStatus, CountStatus,
ItemList, ItemList,
LogList, } from '@/types/api/billOrder'
} from '@/types/api/billOrder.ts' import { DetailForm, LogListData, IUpdatePrice } from '@/types/api/deliveryNote'
import { DetailForm, LogListsData, ShipmentOrderDetailData } from '@/types/api/deliveryNote'
import shipmentOrderDetailInfo from '@/components/ShipmentOrderDetail.vue'
import ImageView from '@/components/ImageView.vue' import ImageView from '@/components/ImageView.vue'
import { showConfirm } from '@/utils/ui' // import { showConfirm } from '@/utils/ui'
import { uploadImageApi } from '@/api/common.ts' import { uploadImageApi } from '@/api/common'
// import { getUserMarkList } from '@/api/auth.ts' // import { getUserMarkList } from '@/api/auth.ts'
interface Tree { interface Tree {
...@@ -1007,15 +964,13 @@ interface PaymentForm { ...@@ -1007,15 +964,13 @@ interface PaymentForm {
payableAmount?: number | string payableAmount?: number | string
} }
const logList = ref<(LogList | LogListsData)[]>([]) const logList = ref<LogListData[]>([])
const logDialogVisible = ref<boolean>(false)
// const nameSpaceList = ref<string[]>([]) // const nameSpaceList = ref<string[]>([])
const treeData = ref<CountStatus[]>() const treeData = ref<CountStatus[]>()
const [searchForm, resetSearchForm] = useValue<AccountStatementNoteSearchForm>( const [searchForm, resetSearchForm] = useValue<AccountStatementNoteSearchForm>(
{}, {},
) )
const paymentFormRef = ref() const paymentFormRef = ref()
const uploadLoading = ref(false) const uploadLoading = ref(false)
const dateRange = ref<string[]>([]) const dateRange = ref<string[]>([])
...@@ -1032,10 +987,14 @@ const paymentForm = ref<PaymentForm>({ ...@@ -1032,10 +987,14 @@ const paymentForm = ref<PaymentForm>({
id: '', id: '',
actualAmount: '', actualAmount: '',
payableAmount: '', payableAmount: '',
}) })
const nodeId = ref<number | string>(0) const getSelectionsProperty = (property: keyof AccountStatementNote) => {
return selections.value
.map((el: AccountStatementNote) => el[property])
.join(',')
}
const nodeId = ref<number | string>(0)
const treeRef = ref<InstanceType<typeof ElTree>>() const treeRef = ref<InstanceType<typeof ElTree>>()
const { const {
currentPage, currentPage,
...@@ -1056,15 +1015,19 @@ const { ...@@ -1056,15 +1015,19 @@ const {
}, },
page, page,
pageSize, pageSize,
).then((res) => res.data) as never, ).then((res) => res.data),
}) })
watch(()=>tableData.value,()=>{ watch(
(tableData.value as AccountStatementNote[]).forEach((item)=>{ () => tableData.value,
item.total_amount = computedPrice(item) () => {
}) ;(tableData.value as AccountStatementNote[]).forEach((item) => {
},{immediate:true,deep:true}) item.total_amount = computedPrice(item)
})
},
{ immediate: true, deep: true },
)
const reset = () => { const reset = () => {
dateRange.value =[] dateRange.value = []
resetSearchForm() resetSearchForm()
} }
const priceModification = (type: 1 | 3 | 4) => { const priceModification = (type: 1 | 3 | 4) => {
...@@ -1072,12 +1035,11 @@ const priceModification = (type: 1 | 3 | 4) => { ...@@ -1072,12 +1035,11 @@ const priceModification = (type: 1 | 3 | 4) => {
ElMessage.warning('至少选择一条对账单') ElMessage.warning('至少选择一条对账单')
return return
} }
const pricePrompts: Record<1 | 3 | 4, { title: string; param: string }> = const pricePrompts: Record<1 | 3 | 4, { title: string; param: string }> = {
{ 1: { title: '修改工厂价格', param: 'costPrice' },
1: { title: '修改工厂价格', param: 'costPrice' }, 3: { title: '修改工艺价格', param: 'craftPrice' },
3: { title: '修改工艺价格', param: 'craftPrice' }, 4: { title: '修改物流价格', param: 'carriageAmount' },
4: { title: '修改物流价格', param: 'carriageAmount' }, }
}
const promptConfig = pricePrompts[type] const promptConfig = pricePrompts[type]
if (!promptConfig) { if (!promptConfig) {
ElMessage.error('无效的操作类型') ElMessage.error('无效的操作类型')
...@@ -1088,14 +1050,14 @@ const priceModification = (type: 1 | 3 | 4) => { ...@@ -1088,14 +1050,14 @@ const priceModification = (type: 1 | 3 | 4) => {
cancelButtonText: '取消', cancelButtonText: '取消',
inputPattern: /\d+/, inputPattern: /\d+/,
inputErrorMessage: '请输入数字', inputErrorMessage: '请输入数字',
}).then(async ({ value }) => { }).then(async ({ value }: { value: string }) => {
const price = parseFloat(value) const price = parseFloat(value)
if (isNaN(price) || price < 0) { if (isNaN(price) || price < 0) {
ElMessage.error('价格必须为大于等于0的数字') ElMessage.error('价格必须为大于等于0的数字')
return return
} }
await updateRecPrice({ await updateRecPrice({
ids: detailSelections.value.map(item => item.id).join(), ids: detailSelections.value.map((item: ItemList) => item.id).join(),
...{ [promptConfig.param]: price }, ...{ [promptConfig.param]: price },
infoId: currentRow.value?.id, infoId: currentRow.value?.id,
}) })
...@@ -1116,33 +1078,29 @@ const onPayment = async (item: AccountStatementNote) => { ...@@ -1116,33 +1078,29 @@ const onPayment = async (item: AccountStatementNote) => {
paymentFormRef.value && paymentFormRef.value.clearValidate() paymentFormRef.value && paymentFormRef.value.clearValidate()
paymentDialogVisible.value = true paymentDialogVisible.value = true
} }
const handlePayment = async () => { const handlePayment = async () => {
try { try {
await paymentFormRef.value?.validate() await paymentFormRef.value?.validate()
} catch { } catch {
return return
} }
if(Number(paymentForm.value.actualAmount)<=0){ if (Number(paymentForm.value.actualAmount) <= 0) {
return ElMessage.warning('实付金额需大于等于0') return ElMessage.warning('实付金额需大于等于0')
} }
await apiBillPodPayment({ await apiBillPodPayment({
...paymentForm.value, ...paymentForm.value,
waterList: paymentForm.value.waterList waterList: paymentForm.value.waterList
.map((item) => item.url) .map((item: { url: string | undefined }) => item.url)
.join(','), .join(','),
id: currentRow.value?.id, id: currentRow.value?.id,
recNumber: currentRow.value?.rec_number,
}) })
ElMessage.success('付款成功') ElMessage.success('付款成功')
paymentDialogVisible.value = false paymentDialogVisible.value = false
search() search()
await getTreeNum()
} }
const showLog = async (row: ItemList) => {
const res = await apiItemLogList(row.id)
logList.value = res.data || []
logDialogVisible.value = true
}
const handleWaterBill = async (e: Event) => { const handleWaterBill = async (e: Event) => {
const files = (e.target as HTMLInputElement).files || [] const files = (e.target as HTMLInputElement).files || []
const request = [] const request = []
...@@ -1157,7 +1115,6 @@ const handleWaterBill = async (e: Event) => { ...@@ -1157,7 +1115,6 @@ const handleWaterBill = async (e: Event) => {
try { try {
const res = await Promise.all(request) const res = await Promise.all(request)
for (const item of res) { for (const item of res) {
console.log(item)
const { filePath, code } = item const { filePath, code } = item
if (code === 500) { if (code === 500) {
ElMessageBox.alert('上传失败', '系统提示', { type: 'error' }) ElMessageBox.alert('上传失败', '系统提示', { type: 'error' })
...@@ -1216,7 +1173,44 @@ const tabsClick = async () => { ...@@ -1216,7 +1173,44 @@ const tabsClick = async () => {
const computedPrice = (row: AccountStatementNote) => { const computedPrice = (row: AccountStatementNote) => {
return new BigNumber(row.product_total_amount || 0) return new BigNumber(row.product_total_amount || 0)
.plus(new BigNumber(row.carriage_total_amount || 0)) .plus(new BigNumber(row.carriage_total_amount || 0))
.plus(new BigNumber(row.craft_total_amount || 0)).toString() .plus(new BigNumber(row.craft_total_amount || 0))
.toString()
}
const craftPriceList = ref<IUpdatePrice[]>([])
const processPriceDialogVisible = ref(false)
const modifyProcessPrices = async () => {
const res = await apiGetCraftGroup(currentRow.value?.id)
const result = (res.data as string[]).map((item) => ({
process: item,
base_price: '',
add_price: '',
}))
craftPriceList.value = result || []
processPriceDialogVisible.value = true
}
const submitPodPrice = async () => {
const filteredList = craftPriceList.value.filter(
(item: IUpdatePrice) => item.base_price && item.add_price,
)
if (filteredList.length > 0) {
try {
const res = await apiSetCraftData({
id: currentRow.value?.id,
craftTotalPrice:currentRow.value?.craft_total_amount,
recNumber: currentRow.value?.rec_number,
craftPriceList: filteredList,
})
if (res.code !== 200) return
ElMessage.success('修改成功')
processPriceDialogVisible.value = false
search()
await getTreeNum()
} catch (error) {
console.error(error)
}
} else {
ElMessage.error('至少提交一条数据')
}
} }
const toUpload = () => { const toUpload = () => {
const input = document.createElement('input') const input = document.createElement('input')
...@@ -1224,7 +1218,7 @@ const toUpload = () => { ...@@ -1224,7 +1218,7 @@ const toUpload = () => {
input.type = 'file' input.type = 'file'
input.multiple = true input.multiple = true
input?.click() input?.click()
input.onchange = function(e:Event) { input.onchange = function (e: Event) {
handleWaterBill(e) handleWaterBill(e)
} }
} }
...@@ -1252,10 +1246,10 @@ const getSummaries = (param: SummaryMethodProps) => { ...@@ -1252,10 +1246,10 @@ const getSummaries = (param: SummaryMethodProps) => {
} }
sums[index] = values sums[index] = values
.reduce((prev: BigNumber, curr: number) => { .reduce((prev: BigNumber, curr: number) => {
const value = new BigNumber(curr); const value = new BigNumber(curr)
return prev.plus(value); // 直接处理 BigNumber 类型 return prev.plus(value) // 直接处理 BigNumber 类型
}, new BigNumber(0)) }, new BigNumber(0))
.toString(); .toString()
}, },
) )
...@@ -1263,7 +1257,6 @@ const getSummaries = (param: SummaryMethodProps) => { ...@@ -1263,7 +1257,6 @@ const getSummaries = (param: SummaryMethodProps) => {
} }
const confirmOrderVisible = ref<boolean>(false) const confirmOrderVisible = ref<boolean>(false)
const auditForm = ref({ const auditForm = ref({
pass: 1,
description: '', description: '',
}) })
const auditFormRef = ref() const auditFormRef = ref()
...@@ -1288,7 +1281,9 @@ const auditOrder = (key: string) => { ...@@ -1288,7 +1281,9 @@ const auditOrder = (key: string) => {
confirmButtonText: '确定', confirmButtonText: '确定',
type: 'warning', type: 'warning',
}).then(async () => { }).then(async () => {
const ids = selections.value.map((el) => el.id).join(',') const ids = selections.value
.map((el: AccountStatementNote) => el.id)
.join(',')
await auditOrderApi(url, ids) await auditOrderApi(url, ids)
ElMessage.success('操作成功') ElMessage.success('操作成功')
search() search()
...@@ -1307,10 +1302,15 @@ const rejectOrder = () => { ...@@ -1307,10 +1302,15 @@ const rejectOrder = () => {
customClass: 'reject', customClass: 'reject',
inputErrorMessage: '请输入驳回原因', inputErrorMessage: '请输入驳回原因',
inputPlaceholder: '驳回原因', inputPlaceholder: '驳回原因',
}).then(async ({ value }) => { }).then(async ({ value }: { value: string }) => {
const ids = selections.value.map((el) => el.id).join(',') const ids = getSelectionsProperty('id')
const recNumbers = getSelectionsProperty('rec_number')
try { try {
await confirmPodOrderApi({ ids: ids, description: value, pass: 0 }) await apiRejectionOfReview({
ids: ids,
description: value,
recNumbers: recNumbers,
})
ElMessage.success('操作成功') ElMessage.success('操作成功')
search() search()
await getTreeNum() await getTreeNum()
...@@ -1319,55 +1319,40 @@ const rejectOrder = () => { ...@@ -1319,55 +1319,40 @@ const rejectOrder = () => {
} }
}) })
} }
const confirmOrder = async () => { const confirmOrder = async (item: AccountStatementNote) => {
if (selections.value.length === 0) { currentRow.value = item
return ElMessage.warning('请选择要操作的数据') confirmOrderVisible.value = true
}
try {
await showConfirm('是否确认对账单?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
} catch {
return
}
const ids = selections.value.map((el) => el.id).join(',')
try {
await confirmPodOrderApi({
ids,
})
confirmOrderVisible.value = false
ElMessage.success('操作成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
// confirmOrderVisible.value = true
// auditForm.value = {
// pass: 1,
// description: '',
// }
// await nextTick()
// auditFormRef.value!.clearValidate()
} }
const submitConfirmOrder = async () => { interface ConfirmOrderPayload {
try { ids: string
await auditFormRef.value?.validate() description?: string
} catch { pass?: number
return }
const submitConfirmOrder = async (type: number) => {
// const ids = selections.value
// .map((el: AccountStatementNote) => el.id)
// .join(',')
let apiPayload: ConfirmOrderPayload = { ids: `${currentRow.value?.id}` }
if (type === 1) {
// 确认操作
await confirmPodOrderApi(apiPayload)
} else {
// 驳回操作
try {
await auditFormRef.value?.validate()
} catch {
return // 验证失败,终止操作
}
apiPayload = {
...apiPayload,
description: auditForm.value.description,
pass: 0,
}
await confirmPodOrderApi(apiPayload)
} }
const ids = selections.value.map((el) => el.id).join(',')
await confirmPodOrderApi({
...auditForm.value,
pass: auditForm.value.pass === 0 ? 0 : undefined,
description:
auditForm.value.description === ''
? undefined
: auditForm.value.description,
ids,
})
confirmOrderVisible.value = false confirmOrderVisible.value = false
ElMessage.success('操作成功') ElMessage.success('操作成功')
search() search()
...@@ -1392,13 +1377,10 @@ watch( ...@@ -1392,13 +1377,10 @@ watch(
) )
const nodeClick = (data: Tree) => { const nodeClick = (data: Tree) => {
nodeId.value = data.code ?? '' nodeId.value = data.code ?? ''
if (data.code !== 0) { // if (data.code !== 0) {
search() search()
} // }
} }
const shipmentOrderDetailDrawerVisible = ref(false)
const shipmentOrderDetail = ref({} as ShipmentOrderDetailData)
const detailForm = ref({} as DetailForm) const detailForm = ref({} as DetailForm)
const detailPager = ref({ const detailPager = ref({
page: 1, page: 1,
...@@ -1409,15 +1391,14 @@ const searchDetail = async () => { ...@@ -1409,15 +1391,14 @@ const searchDetail = async () => {
try { try {
const res = await getPodShipmentDetailsById({ const res = await getPodShipmentDetailsById({
...detailForm.value, ...detailForm.value,
startTime: detailForm.value.dateRange && detailForm.value.dateRange[0], // startTime: detailForm.value.dateRange && detailForm.value.dateRange[0],
endTime: detailForm.value.dateRange && detailForm.value.dateRange[1], // endTime: detailForm.value.dateRange && detailForm.value.dateRange[1],
page: detailPager.value.page, page: detailPager.value.page,
rows: detailPager.value.rows, rows: detailPager.value.rows,
infoId: currentRow.value?.id, infoId: currentRow.value?.id,
}) })
detailList.value = res.data.records || [] detailList.value = res.data.records || []
detailPager.value.total = res.data.total detailPager.value.total = res.data.total
// logList.value = res.data.logList || []
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }
...@@ -1426,7 +1407,6 @@ const getLogList = async () => { ...@@ -1426,7 +1407,6 @@ const getLogList = async () => {
try { try {
const res = await getPodLogListApi(currentRow.value?.id) const res = await getPodLogListApi(currentRow.value?.id)
logList.value = res.data logList.value = res.data
// logList.value = res.data.logList || []
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }
...@@ -1435,7 +1415,9 @@ const exportExcel = async () => { ...@@ -1435,7 +1415,9 @@ const exportExcel = async () => {
if (selections.value.length !== 1) { if (selections.value.length !== 1) {
return ElMessage.warning('请选择一条数据') return ElMessage.warning('请选择一条数据')
} }
const ids = selections.value.map((el) => el.id).join(',') const ids = selections.value
.map((el: AccountStatementNote) => el.id)
.join(',')
try { try {
const res = await exportPodExcelApi(ids) const res = await exportPodExcelApi(ids)
window.open(res.data) window.open(res.data)
...@@ -1522,7 +1504,8 @@ $border: solid 1px #ddd; ...@@ -1522,7 +1504,8 @@ $border: solid 1px #ddd;
} }
.dialog-footer { .dialog-footer {
text-align: center; display: flex;
justify-content: center;
} }
.delivery-note-list { .delivery-note-list {
......
<template>
<div class="page card h-100 flex-gap-10 overflow-hidden flex">
<div class="left">
<ElTree
ref="treeRef"
default-expand-all
:expand-on-click-node="false"
:default-expanded-keys="[]"
:highlight-current="true"
node-key="code"
:data="treeData"
:props="{ children: 'children', label: 'remark' }"
@node-click="nodeClick"
>
<template #default="{ data }">
<div class="tree-node">
<div class="tree-node-label">{{ data.remark }}</div>
<div v-if="data.count || data.count === 0" class="tree-node-count">
{{ `(${data.count})` }}
</div>
</div>
</template>
</ElTree>
</div>
<div class="right">
<div class="delivery-note-page flex-column card h-100 overflow-hidden">
<splitDiv size="50">
<template #top>
<div class="header-filter-form">
<ElForm :model="searchForm" inline>
<ElFormItem label="账期">
<el-date-picker
v-model="dateRange"
:default-time="[
new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59),
]"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
style="width: 260px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</ElFormItem>
<ElFormItem label="对账单号">
<ElInput
v-model="searchForm.recNumber"
clearable
placeholder="对账单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="发货单号">
<ElInput
v-model="searchForm.billNumber"
clearable
placeholder="发货单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem style="margin-right: 10px" label="订单号">
<ElInput
v-model="searchForm.orderNumber"
clearable
placeholder="订单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search">查询</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem>
</ElForm>
</div>
<div class="btn-list">
<el-button
v-if="nodeId === 10"
type="primary"
@click="confirmOrder"
>
确认对账单
</el-button>
<el-button
v-if="nodeId === 10"
type="warning"
@click="rejectOrder"
>
驳回
</el-button>
<el-button type="success" @click="exportExcel"> 导出 </el-button>
<el-button
v-if="nodeId === 30"
type="danger"
@click="auditOrder('archive')"
>
归档
</el-button>
</div>
<div
class="delivery-note-content flex-1 flex-column overflow-hidden"
>
<div class="delivery-note-list flex-1 overflow-hidden">
<ElTable
ref="singleTableRef"
highlight-current-row
:data="tableData"
show-summary
:summary-method="getSummaries"
default-expand-all
size="small"
style="width: 100%; height: 100%"
border
@current-change="rowClick"
@selection-change="handleSelectionChange"
>
<ElTableColumn
type="selection"
width="70"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
type="index"
label="序号"
width="60"
fixed="left"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="编码"
show-overflow-tooltip
prop="name"
width="200"
header-align="center"
align="center"
></ElTableColumn>
<!-- <ElTableColumn
label="客户"
show-overflow-tooltip
prop="user_mark"
width="200"
header-align="center"
align="center"
></ElTableColumn> -->
<ElTableColumn
label="对账单号"
show-overflow-tooltip
prop="rec_number"
min-width="200"
header-align="center"
align="center"
></ElTableColumn>
<!-- <ElTableColumn
label="订单号"
show-overflow-tooltip
prop="order_number"
width="200"
header-align="center"
align="center"
></ElTableColumn> -->
<!-- <ElTableColumn
label="ERP总价格"
show-overflow-tooltip
width="130"
prop="erp_total_amount"
header-align="center"
align="center"
></ElTableColumn> -->
<el-table-column
label="账期"
header-align="center"
align="center"
min-width="340"
>
<template #default="scope">
{{ scope.row.start_time }} - {{ scope.row.end_time }}
</template>
</el-table-column>
<el-table-column
label="商品总价格(¥)"
header-align="center"
prop="product_total_amount"
width="130"
align="center"
show-overflow-tooltip
>
</el-table-column>
<!-- <el-table-column
label="ERP总价格"
header-align="center"
prop="erp_total_amount"
width="120"
align="center"
show-overflow-tooltip
>
</el-table-column> -->
<el-table-column
label="物流总价(¥)"
header-align="center"
prop="carriage_total_amount"
width="130"
align="center"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="应付金额(¥)"
header-align="center"
width="130"
align="center"
show-overflow-tooltip
>
<template #default="{ row }">
<span>{{
row.carriage_total_amount + row.product_total_amount
}}</span>
</template>
</el-table-column>
<el-table-column
label="实付金额(¥)"
header-align="center"
prop="actual_amount"
width="130"
align="center"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="水单"
header-align="center"
prop="water_list"
width="100"
align="center"
show-overflow-tooltip
>
<template #default="{ row }">
<ImageView :src="row.water_list" />
</template>
</el-table-column>
<ElTableColumn
label="发货数量(件)"
show-overflow-tooltip
width="100"
prop="carriage_total_amount"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="总发货数量(件)"
show-overflow-tooltip
prop="num"
width="130"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="质检通过数量(件)"
show-overflow-tooltip
prop="pass_num"
width="130"
header-align="center"
align="center"
></ElTableColumn>
<!-- <ElTableColumn
label="ERP状态"
show-overflow-tooltip
width="130"
prop="erp_status"
header-align="center"
align="center"
></ElTableColumn> -->
<ElTableColumn
label="质检未通过数量(件)"
show-overflow-tooltip
width="140"
prop="not_pass_num"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="创建时间"
show-overflow-tooltip
width="200"
prop="create_time"
header-align="center"
align="center"
></ElTableColumn>
</ElTable>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
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>
</template>
<template #bottom>
<el-tabs v-model="tabsValue" @tab-click="tabsClick">
<el-tab-pane name="0" label="发货单详情">
<el-form :model="detailForm" inline>
<el-form-item label="发货单号">
<el-input
v-model="detailForm.billNumber"
placeholder="请输入发货单号"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item label="订单号">
<el-input
v-model="detailForm.orderNumber"
placeholder="请输入订单号"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item label="生产单号">
<el-input
v-model="detailForm.subOrderNumber"
placeholder="请输入订单号"
clearable
style="width: 130px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="searchDetail"
>查询</el-button
>
</el-form-item>
</el-form>
<div class="table-wrap">
<ElTable size="small" :data="detailList" height="100%" border>
<ElTableColumn
show-overflow-tooltip
width="60"
align="center"
label="序号"
type="index"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="单号"
prop="factory_order_number"
/>
<!-- <ElTableColumn
show-overflow-tooltip
align="center"
label="ERP单号"
prop="erp_order_number"
/> -->
<ElTableColumn
show-overflow-tooltip
align="center"
label="发货单号"
prop="bill_number"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="发货数(件)"
prop="num"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="质检通过(件)"
prop="pass_num"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="质检不通过(件)"
prop="not_pass_num"
/>
<!-- <ElTableColumn
show-overflow-tooltip
align="center"
label="ERP价格"
prop="erp_price"
/> -->
<ElTableColumn
show-overflow-tooltip
align="center"
label="成本价(¥)"
prop="price"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="物流价格(¥)"
prop="carriage_amount"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="发货时间"
prop="shipment_time"
/>
<ElTableColumn
width="100"
align="center"
header-align="center"
label="操作"
>
<template #default="{ row }">
<ElButton type="primary" link @click="onDetail(row)"
>查看详情
</ElButton>
</template>
</ElTableColumn>
</ElTable>
</div>
<ElPagination
v-model:current-page="detailPager.page"
v-model:page-size="detailPager.rows"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="detailPager.total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</el-tab-pane>
<el-tab-pane name="1" label="操作日志">
<ul
style="
color: #333;
font-size: 12px;
height: 100%;
overflow: auto;
"
>
<li
v-for="(item, index) in logList"
:key="index"
style="display: flex"
>
<span style="display: inline-block">
{{ item.create_time }}
</span>
<span style="margin: 0 5px 0 20px">{{
item.employee_account
}}</span>
<span style="display: inline-block">{{
item.description
}}</span>
</li>
</ul>
</el-tab-pane>
</el-tabs>
</template>
</splitDiv>
</div>
</div>
</div>
<ElDrawer
v-model="shipmentOrderDetailDrawerVisible"
title="发货单详情"
size="50%"
>
<shipmentOrderDetailInfo :detail="shipmentOrderDetail" />
</ElDrawer>
<ElDialog
v-model="confirmOrderVisible"
title="确认对账单"
width="500px"
:close-on-click-modal="false"
>
<ElForm ref="auditFormRef" :model="auditForm" label-width="80px">
<ElFormItem
label="意见"
prop="pass"
:rules="[{ required: true, message: '请选择' }]"
>
<ElRadioGroup v-model="auditForm.pass">
<ElRadio :label="1">通过</ElRadio>
<ElRadio :label="0">不通过</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
label="审核意见"
prop="description"
:rules="
auditForm.pass === 0
? [{ required: true, message: '请输入审核意见' }]
: []
"
>
<ElInput v-model="auditForm.description" type="textarea" />
</ElFormItem>
</ElForm>
<template #footer>
<span class="dialog-footer">
<el-button @click="confirmOrderVisible = false">取消</el-button>
<el-button type="primary" @click="submitConfirmOrder">确认</el-button>
</span>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import { ElMessage, ElRadioGroup, ElTree, TableColumnCtx } from 'element-plus'
import splitDiv from '@/components/splitDiv/splitDiv.vue'
import { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import {
customJomallReconciliation,
getReconciliationAmount,
getShipmentDetailsById,
auditOrderApi,
getShipmentOrderDetailById,
confirmOrderApi,
rejectOrderApi,
getLogListApi,
exportExcelApi,
} from '@/api/order'
import { ref, onMounted, watch, nextTick } from 'vue'
import 'element-plus/dist/index.css'
import {
CountStatus,
AccountStatementNote,
ItemList,
LogList,
AccountStatementNoteSearchForm,
} from '@/types/api/billOrder.ts'
import { DetailForm, ShipmentOrderDetailData } from '@/types/api/deliveryNote'
import shipmentOrderDetailInfo from '@/components/ShipmentOrderDetail.vue'
import ImageView from '@/components/ImageView.vue'
import { showConfirm } from '@/utils/ui'
// import { getUserMarkList } from '@/api/auth.ts'
interface Tree {
remark?: string
count?: number
code?: string
children?: Tree[]
}
interface SummaryMethodProps<T = AccountStatementNote> {
columns: TableColumnCtx<T>[]
data: T[]
}
// const nameSpaceList = ref<string[]>([])
const treeData = ref<CountStatus[]>()
const [searchForm, resetSearchForm] = useValue<AccountStatementNoteSearchForm>(
{},
)
const dateRange = ref<string[]>([])
const selections = ref<AccountStatementNote[]>([])
const detailList = ref<ItemList[]>([])
const tabsValue = ref<string>('0')
const singleTableRef = ref<InstanceType<typeof ElTable>>()
const currentRow = ref<AccountStatementNote | null>(null)
const logList = ref<LogList[]>([])
const nodeId = ref<number | string>(10)
const treeRef = ref<InstanceType<typeof ElTree>>()
const {
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
customJomallReconciliation(
{
...searchForm.value,
status: nodeId.value === -1 ? null : nodeId.value,
start_time: dateRange.value && dateRange.value[0],
end_time: dateRange.value && dateRange.value[1],
},
page,
pageSize,
).then((res) => res.data) as never,
})
onMounted(() => {
// getNameSpaceList()
})
// const dialogVisible = ref<boolean>(false)
// const getNameSpaceList = async () => {
// try {
// const res = await getUserMarkList()
// nameSpaceList.value = res.data
// } catch (e) {
// // showError(e)
// }
// }
const getTreeNum = async () => {
try {
const res = await getReconciliationAmount()
res.data = [{ code: -1, remark: '全部', children: res.data }]
treeData.value = res.data
await nextTick(() => {
treeRef.value!.setCurrentKey(nodeId.value, true)
})
} catch (e) {
console.error(e)
}
}
const rowClick = (row: AccountStatementNote) => {
if (!row) {
currentRow.value = null
}
currentRow.value = row
tabsClick()
}
const tabsClick = async () => {
if (!currentRow.value) {
detailList.value = []
logList.value = []
return
}
await nextTick()
if (tabsValue.value === '0') {
searchDetail()
} else {
getLogList()
}
}
const handleSelectionChange = (v: AccountStatementNote[]) => {
selections.value = v
}
const getSummaries = (param: SummaryMethodProps) => {
const { columns, data } = param
const sums: string[] = []
columns.forEach(
(column: TableColumnCtx<AccountStatementNote>, index: number) => {
if (index === 0) {
sums[index] = '合计'
return
}
const values = data.map((item: AccountStatementNote) => {
return Number(item[column.property as keyof AccountStatementNote])
})
if (!values.every((value: number) => !isNaN(value))) {
return
}
sums[index] = values
.reduce((prev: number, curr: number) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
.toString()
},
)
return sums
}
const confirmOrderVisible = ref<boolean>(false)
const auditForm = ref({
pass: 1,
description: '',
})
const auditFormRef = ref()
const auditOrder = (key: string) => {
let url = ''
let text = ''
switch (key) {
case 'pay':
url = 'reconciliation/payment'
text = '确认付款'
break
case 'archive':
url = 'reconciliation/archiving'
text = '确认归档'
break
}
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
ElMessageBox.confirm(`${text}对账单?`, '重要提示', {
confirmButtonText: '确定',
type: 'warning',
}).then(async () => {
const ids = selections.value.map((el) => el.id).join(',')
await auditOrderApi(url, ids)
ElMessage.success('操作成功')
search()
await getTreeNum()
})
}
const rejectOrder = () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
ElMessageBox.prompt('请输入驳回原因', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
inputPattern: /.+/,
customClass: 'reject',
inputErrorMessage: '请输入驳回原因',
inputPlaceholder: '驳回原因',
}).then(async ({ value }) => {
const ids = selections.value.map((el) => el.id).join(',')
try {
await rejectOrderApi({ ids: ids, description: value, pass: 0 })
ElMessage.success('操作成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
})
}
const confirmOrder = async () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
try {
await showConfirm('是否确认对账单?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
} catch {
return
}
const ids = selections.value.map((el) => el.id).join(',')
try {
await confirmOrderApi({
ids,
})
confirmOrderVisible.value = false
ElMessage.success('操作成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
// confirmOrderVisible.value = true
// auditForm.value = {
// pass: 1,
// description: '',
// }
// await nextTick()
// auditFormRef.value!.clearValidate()
}
const submitConfirmOrder = async () => {
try {
await auditFormRef.value?.validate()
} catch {
return
}
const ids = selections.value.map((el) => el.id).join(',')
await confirmOrderApi({
...auditForm.value,
pass: auditForm.value.pass === 0 ? 0 : undefined,
description:
auditForm.value.description === ''
? undefined
: auditForm.value.description,
ids,
})
confirmOrderVisible.value = false
ElMessage.success('操作成功')
search()
await getTreeNum()
if (singleTableRef.value) {
singleTableRef.value!.setCurrentRow(currentRow.value)
}
}
watch(
() => tableData.value,
() => {
if (tableData.value && tableData.value.length > 0) {
if (singleTableRef.value) {
singleTableRef.value!.setCurrentRow(tableData.value[0])
currentRow.value = (tableData.value as never)[0]
}
} else {
detailList.value = []
}
},
{ immediate: true },
)
const nodeClick = (data: Tree) => {
nodeId.value = data.code ?? ''
search()
}
const shipmentOrderDetailDrawerVisible = ref(false)
const shipmentOrderDetail = ref({} as ShipmentOrderDetailData)
const onDetail = async (row: ItemList) => {
try {
const res = await getShipmentOrderDetailById(row.shipment_id)
shipmentOrderDetail.value = res.data
shipmentOrderDetailDrawerVisible.value = true
} catch (e) {
console.error(e)
}
}
const detailForm = ref({} as DetailForm)
const detailPager = ref({
page: 1,
rows: 100,
total: 0,
})
const searchDetail = async () => {
try {
const res = await getShipmentDetailsById({
...detailForm.value,
page: detailPager.value.page,
rows: detailPager.value.rows,
infoId: currentRow.value?.id,
})
detailList.value = res.data.records || []
detailPager.value.total = res.data.total
// logList.value = res.data.logList || []
} catch (e) {
console.error(e)
}
}
const getLogList = async () => {
try {
const res = await getLogListApi(currentRow.value?.id)
logList.value = res.data
// logList.value = res.data.logList || []
} catch (e) {
console.error(e)
}
}
const exportExcel = async () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
const ids = selections.value.map((el) => el.id).join(',')
try {
const res = await exportExcelApi(ids)
window.open(res.data)
} catch (e) {
console.error(e)
}
}
onMounted(() => {
getTreeNum()
})
</script>
<style lang="scss" scoped>
.header-filter-form {
: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;
}
}
.left {
width: 160px;
:deep(.el-tree-node__content) {
height: 30px;
line-height: 30px;
}
:deep(.el-tree-node__label) {
font-size: 13px;
cursor: pointer;
display: inline-block;
width: 100%;
color: black !important;
padding: 3px 7px;
}
:deep(.el-tree-node__expand-icon) {
display: none;
}
:deep(.is-current) {
.tree-node-label,
.tree-node-count {
background-color: #ecf5ff;
color: #409eff !important;
}
.el-tree-node__children {
.tree-node-label,
.tree-node-count {
background-color: transparent !important;
color: black !important;
}
}
}
}
.tree-node {
display: flex;
color: #333;
font-weight: 500;
}
.right {
flex: 1;
flex-shrink: 0;
background: white;
overflow: hidden;
}
::v-deep(.el-tree-node__label) {
font-size: 13px;
color: rgb(96, 98, 102);
cursor: pointer;
}
::v-deep(.el-tree-node__expand-icon) {
display: none;
}
::v-deep(.el-tree-node__label) {
display: inline-block;
width: 100%;
color: black !important;
padding: 3px 7px;
}
::v-deep(.is-current) {
.el-tree-node__label {
background-color: #ecf5ff;
color: #409eff !important;
}
.el-tree-node__children {
.el-tree-node__label {
background-color: transparent !important;
color: black !important;
}
}
}
::v-deep(.splitpanes__pane) {
display: flex;
flex-direction: column;
}
::v-deep(.splitpanes--horizontal > .splitpanes__splitter) {
min-height: 5px;
margin-top: 10px;
}
.draw-line {
width: 100%;
height: 5px;
background: #eff3f6;
}
.btn-list {
margin-bottom: 10px;
}
::v-deep(.el-tree-node) {
cursor: pointer;
margin-bottom: 5px;
}
::v-deep(.el-tree-node__label) {
font-size: 14px;
}
::v-deep(.el-tabs) {
display: flex;
flex-direction: column;
height: 100%;
.el-tabs__content {
flex: 1;
flex-shrink: 0;
overflow: hidden;
.el-tab-pane {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
}
}
.delivery-note-page {
:deep(#top) {
height: 100%;
}
}
</style>
<template>
<div class="page card h-100 flex-gap-10 overflow-hidden flex">
<div class="left">
<ElTree
ref="treeRef"
default-expand-all
:expand-on-click-node="false"
:default-expanded-keys="[]"
:highlight-current="true"
node-key="code"
:data="treeData"
:props="{ children: 'children', label: 'name' }"
@node-click="nodeClick"
>
<template #default="{ data }">
<div class="tree-node">
<div class="tree-node-label">{{ data.name }}</div>
<div
v-if="data.countQuantity || data.countQuantity === 0"
class="tree-node-count"
>
{{ `(${data.countQuantity})` }}
</div>
</div>
</template>
</ElTree>
</div>
<div class="right">
<div class="delivery-note-page flex-column card h-100 overflow-hidden">
<splitDiv size="50">
<template #top>
<div class="header-filter-form">
<ElForm :model="searchForm" inline>
<ElFormItem label="采购仓库">
<ElSelect
v-model="searchForm.warehouseId"
clearable
placeholder="请选择仓库"
style="width: 160px"
>
<ElOption
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="入库时间">
<el-date-picker
v-model="tradingTime"
:shortcuts="pickerOptions.shortcuts"
:default-time="[
new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59),
]"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
style="width: 260px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</ElFormItem>
<ElFormItem label="单号">
<ElInput
v-model="searchForm.orderNumber"
clearable
placeholder="请输入入库单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="交货单号">
<ElInput
v-model="searchForm.batchNumber"
clearable
placeholder="请输入交货单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem style="margin-right: 10px" label="SKU">
<ElInput
v-model="searchForm.sku"
clearable
placeholder="请输入SKU"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search">查询</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem>
</ElForm>
</div>
<div class="btn-list">
<el-button type="primary" @click="addDialog(1)"> 新增 </el-button>
<el-button type="danger" @click="rejectOrder"> 驳回 </el-button>
<el-button type="danger" @click="rejectOrder"> 删除 </el-button>
<el-button type="warning" @click="importExcel"> 导入 </el-button>
<el-button type="success" @click="exportExcel"> 导出 </el-button>
<el-button type="primary" @click="exportExcel">
打印SKU标签
</el-button>
<el-button type="warning" @click="exportExcel"> 审核 </el-button>
<el-button type="success" @click="exportExcel">
提交审核
</el-button>
<el-button type="danger" @click="rejectOrder"> 作废 </el-button>
<el-button type="success" @click="auditOrder('archive')">
归档
</el-button>
</div>
<div
class="delivery-note-content flex-1 flex-column overflow-hidden"
>
<div class="delivery-note-list flex-1 overflow-hidden">
<ElTable
ref="singleTableRef"
highlight-current-row
:data="tableData"
default-expand-all
size="small"
style="width: 100%; height: 100%"
border
@current-change="rowClick"
@selection-change="handleSelectionChange"
>
<ElTableColumn
type="selection"
width="70"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
type="index"
label="序号"
width="60"
fixed="left"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="入库单号"
show-overflow-tooltip
prop="inNo"
width="110"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="单据状态"
show-overflow-tooltip
prop="billStatus"
width="80"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="仓库名称"
show-overflow-tooltip
prop="warehouseName"
min-width="100"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="工厂编号"
show-overflow-tooltip
prop="factoryCode"
min-width="100"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="物流单号"
show-overflow-tooltip
prop="shipmentNumber"
width="200"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="总金额(¥)"
show-overflow-tooltip
width="120"
prop="totalPrice"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="SKU数量"
header-align="center"
prop="skuAmount"
width="130"
align="center"
show-overflow-tooltip
>
</ElTableColumn>
<ElTableColumn
label="总数量"
header-align="center"
prop="total"
width="120"
align="center"
show-overflow-tooltip
>
</ElTableColumn>
<ElTableColumn
label="备注"
show-overflow-tooltip
width="240"
prop="remark"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
width="100"
align="center"
header-align="center"
label="操作"
>
<template #default="{ row }">
<ElButton type="primary" link @click="addDialog(2, row)"
>编辑
</ElButton>
</template>
</ElTableColumn>
</ElTable>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
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>
</template>
<template #bottom>
<el-tabs v-model="tabsValue" @tab-click="tabsClick">
<el-tab-pane name="0" label="入库商品">
<div class="table-wrap">
<ElTable size="small" :data="detailList" height="100%" border>
<ElTableColumn
show-overflow-tooltip
width="60"
align="center"
label="序号"
type="index"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="SKU图片"
prop="factory_order_number"
>
<template #default="{ row }">
<ImageView
:src="row.skuImage"
width="80px"
height="80px"
/>
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
label="商品SKU"
prop="warehouseSku"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="SKU名称"
prop="skuName"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="入库数量"
prop="buyStored"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="总成本(¥)"
prop="buyStored"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品数量"
prop="rejectsAmount"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品原因"
prop="rejectsAeason"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
width="240"
label="备注"
prop="remark"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="创建时间"
prop="createTime"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="更新时间"
prop="updateTime"
/>
</ElTable>
</div>
<ElPagination
v-model:current-page="detailPager.page"
v-model:page-size="detailPager.rows"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="detailPager.total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</el-tab-pane>
<!-- <el-tab-pane name="1" label="操作日志">
<ul
style="
color: #333;
font-size: 12px;
height: 100%;
overflow: auto;
"
>
<li
v-for="(item, index) in logList"
:key="index"
style="display: flex"
>
<span style="display: inline-block">
{{ item.createdTime }}
</span>
<span style="display: inline-block">{{
item.description
}}</span>
</li>
</ul>
</el-tab-pane>
<el-tab-pane name="2" label="物流轨迹">
<ul
v-if="logisticsData.length > 0"
style="
color: #333;
font-size: 12px;
height: 100%;
overflow: auto;
"
>
<li v-for="(item, index) in logisticsData" :key="index">
<span class="log-desc">
{{ item.time + ' ' + item.context }}
</span>
</li>
</ul>
<div v-else class="empty">{{ $t('暂无数据') }}</div>
</el-tab-pane> -->
</el-tabs>
</template>
</splitDiv>
</div>
</div>
</div>
<ElDialog
v-model="importDialogVisible"
title="导入"
width="500px"
:close-on-click-modal="false"
>
<div class="import-dialog">
<div class="import-header">
<el-button type="primary" link @click="downloadTemplate">
<el-icon><Download /></el-icon>
下载模板
</el-button>
</div>
<div class="import-content">
<UploadExcel v-model="importedFileUrl" />
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="importDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitConfirmOrder">确认</el-button>
</span>
</template>
</ElDialog>
<ElDialog
v-model="newDialogVisible"
:title="formId ? '编辑' : '新增'"
width="80%"
:close-on-click-modal="false"
>
<div class="dialog-form">
<ElForm
ref="editFormRef"
:model="editForm"
:rules="rules"
inline
label-width="90px"
>
<ElFormItem label="入库单号" prop="account">
<ElInput v-model="editForm.inNo" clearable disabled />
</ElFormItem>
<ElFormItem label="仓库" prop="warehouseId" required>
<ElSelect
v-model="editForm.warehouseId"
clearable
placeholder="请选择仓库"
style="width: 160px"
>
<ElOption
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="工厂:" prop="factoryCode">
<span>{{ editForm.factoryCode }}</span>
</ElFormItem>
<ElFormItem label="备注" prop="remark" style="width: 45%">
<ElInput
v-model="editForm.remark"
placeholder="请输入备注"
clearable
/>
</ElFormItem>
</ElForm>
<ElTable
size="small"
:data="otherPurchaseData"
height="500px"
border
@selection-change="productSelectionChange"
>
<ElTableColumn
type="selection"
width="70"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
width="100"
label="SKU图片"
prop="skuImage"
>
<template #default="{ row }">
<ImageView :src="row.skuImage" width="40px" height="40px" />
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
label="商品SKU"
prop="warehouseSku"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="SKU名称"
prop="skuName"
/>
<ElTableColumn align="center" label="入库数量" prop="buyStored">
<template #default="{ row }">
<el-input
v-model.number="row.buyStored"
@input="setCostPrice(row)"
placeholder="入库数量"
style="width: 120px"
clearable
size="small"
></el-input>
</template>
</ElTableColumn>
<ElTableColumn
width="100"
align="center"
label="成本价(¥)"
prop="costPrice"
/>
<ElTableColumn
align="center"
width="100"
label="总成本(¥)"
prop="totalPrice"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品数量"
prop="rejectsAmount"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="不良品原因"
prop="rejectsAeason"
/>
<ElTableColumn align="center" label="库位" prop="loacationCode">
<template #default="{ row }">
<!-- +后有就正常展示,没有则通过搜索接口自己添加 -->
<span v-if="row.loacationCode">{{ row.loacationCode }}</span>
<ElSelect
v-else
v-model="row.locationId"
clearable
placeholder="请输入库位"
style="width: 120px"
filterable
remote
:remote-method="(query) => handleLocationSearch(query, row)"
:loading="locationLoading"
@change="(val) => handleLocationChange(val, row)"
>
<ElOption
v-for="item in locationList"
:key="item.locationId"
:label="item.locationCode"
:value="item.locationId"
></ElOption>
</ElSelect>
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
width="240"
label="备注"
prop="remark"
/>
</ElTable>
</div>
<template #footer>
<div class="product-dialog-footer">
<div>
<el-input
v-model="selectSku"
placeholder="商品SKU"
style="width: 200px; margin: 0 10px"
clearable
size="small"
></el-input>
<el-popover placement="top-start" width="900" trigger="click">
<div v-if="skuData.length > 0" style="height: 50vh">
<ElTable size="small" :data="skuData" height="100%" border>
<ElTableColumn
show-overflow-tooltip
width="60"
align="center"
label="序号"
type="index"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="SKU图片"
width="100"
prop="image"
>
<template #default="{ row }">
<ImageView :src="row.image" width="40px" height="40px" />
</template>
</ElTableColumn>
<ElTableColumn
show-overflow-tooltip
align="center"
label="商品SKU"
width="200"
prop="skuName"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
width="200"
label="SKU名称"
prop="sku"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="成本价(¥)"
width="100"
prop="factoryPrice"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="库位"
prop="loacationCode"
/>
<ElTableColumn
width="100"
align="center"
header-align="center"
label="操作"
>
<template #default="{ row }">
<el-icon :size="32" color="#67C23A"
><CirclePlusFilled @click="skudblclick(row)"
/></el-icon>
</template>
</ElTableColumn>
</ElTable>
</div>
<template #reference>
<el-button
type="primary"
size="small"
style="width: 90px"
@click="selectbySku()"
>
查询
</el-button>
</template>
</el-popover>
<el-button
style="margin-left: 6px"
type="success"
size="small"
@click="addPurchase"
>
批量新增
</el-button>
<el-button
type="danger"
style="margin-left: 10px"
size="small"
@click="deleteOtherWarehousing()"
>
删除
</el-button>
<el-button
type="primary"
style="margin-left: 10px"
size="small"
@click="importData"
>
导入
</el-button>
</div>
<div>
<el-button
size="small"
style="margin-left: 10px"
@click="newDialogVisible = false"
>
取消
</el-button>
<el-button type="primary" size="small" @click="addOtherCurrency()">
保存
</el-button>
</div>
</div>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import { ElMessage, ElRadioGroup, ElTree, TableColumnCtx } from 'element-plus'
import { Download, CirclePlusFilled } from '@element-plus/icons-vue'
import splitDiv from '@/components/splitDiv/splitDiv.vue'
import { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import {
auditOrderApi,
rejectOrderApi,
getLogListApi,
exportExcelApi,
} from '@/api/order'
import {
getWarehouseStatusTree,
warehouseInRecordListPage,
getWarehouseInRecordDetail,
getBySku,
getWarehouseListApi,
getByWareHouseIdAndCode,
addInRecordApi,
updateInRecordApi,
} from '@/api/warehouse'
import BigNumber from 'bignumber.js'
import { ref, onMounted, watch, nextTick } from 'vue'
import 'element-plus/dist/index.css'
import { LogList } from '@/types/api/billOrder.ts'
import {
warehouseSearchForm,
InterWarehousePage,
InterWarehouseDetail,
InterWarehouseTree,
InterProductList,
InterskuList,
InterWarehouseList,
ILocation,
} from '@/types/api/warehouse'
import ImageView from '@/components/ImageView.vue'
import { showConfirm } from '@/utils/ui'
import UploadExcel from '@/components/UploadExcel.vue'
import { debounce } from 'lodash-es'
// import UploadExcel from '@/components/INgoVopy.vue'
const warehouseList = ref<InterWarehouseList[]>([])
const pickerOptions = {
shortcuts: [
{
text: '今日',
value: () => {
const start = new Date(new Date(getStartTime()).getTime())
const end = new Date()
return [start, end]
},
},
{
text: '昨天',
value: () => {
const start = new Date()
const end = new Date(new Date(getStartTime()).getTime() - 1)
start.setTime(end.getTime() - 3600 * 1000 * 24 * 1 + 1)
return [start, end]
},
},
{
text: '最近7天',
value: () => {
const end = new Date()
const start = new Date(getStartTime())
start.setTime(start.getTime() - 3600 * 1000 * 24 * 6)
return [start, end]
},
},
{
text: '最近14天',
value: () => {
const end = new Date()
const start = new Date(getStartTime())
start.setTime(start.getTime() - 3600 * 1000 * 24 * 13)
return [start, end]
},
},
{
text: '最近30天',
value: () => {
const end = new Date()
const start = new Date(getStartTime())
start.setTime(start.getTime() - 3600 * 1000 * 24 * 29)
return [start, end]
},
},
{
text: '本星期',
value: () => {
const end = new Date()
const start = new Date()
const nowDay = new Date().getDay() - 1
start.setTime(
new Date(getStartTime()).getTime() - 3600 * 1000 * 24 * nowDay,
)
return [start, end]
},
},
{
text: '上星期',
value: () => {
const end = new Date()
const start = new Date()
const nowDay = new Date().getDay() - 1
end.setTime(
new Date(getStartTime()).getTime() - 3600 * 1000 * 24 * nowDay - 1,
)
start.setTime(end.getTime() - 3600 * 1000 * 24 * 7 + 1)
return [start, end]
},
},
{
text: '这个月',
value: () => {
const end = new Date()
const start = new Date()
const nowDate = new Date().getDate() - 1
start.setTime(
new Date(getStartTime()).getTime() - 3600 * 1000 * 24 * nowDate,
)
return [start, end]
},
},
{
text: '上个月',
value: () => {
const date = new Date()
let year = date.getFullYear()
let month = date.getMonth()
const end = new Date(
new Date(`${year}-${month + 1}-1 00:00:00`).getTime() - 1,
)
if (month === 0) {
month = 12
year = year - 1
}
const start = new Date(
new Date(`${year}-${month}-1 00:00:00`).getTime(),
)
return [start, end]
},
},
{
text: '历史',
value: () => {
return ['', '']
},
},
],
}
function getStartTime() {
const date = new Date()
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
return `${year}-${month}-${day} 00:00:00`
}
interface Tree {
remark?: string
count?: number
code?: string
children?: Tree[]
}
const selectSku = ref('')
const treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
const tradingTime = ref<string[]>([])
const selections = ref<InterWarehousePage[]>([])
const detailList = ref<InterWarehouseDetail[]>([])
const tabsValue = ref<string>('0')
const singleTableRef = ref<InstanceType<typeof ElTable>>()
const currentRow = ref<InterWarehousePage | null>(null)
const logList = ref<LogList[]>([])
const rules = {
warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
}
const nodeId = ref<number | string>(10)
const treeRef = ref<InstanceType<typeof ElTree>>()
const {
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
warehouseInRecordListPage(
{
...searchForm.value,
// status: nodeId.value === -1 ? null : nodeId.value,
createTimeStart: tradingTime.value && tradingTime.value[0],
createTimeEnd: tradingTime.value && tradingTime.value[1],
},
page,
pageSize,
).then((res) => res.data) as never,
})
const setCostPrice = (item: InterProductList) => {
if (!item.costPrice) {
ElMessage.warning('商品成本价为空,请完善商品成本价')
return
}
const amount = new BigNumber(item.buyStored)
.multipliedBy(item.costPrice)
.toFixed(2)
item.totalPrice = Number(amount)
}
const getTreeNum = async () => {
try {
const res = await getWarehouseStatusTree()
res.data = [{ code: -1, name: '全部', children: res.data }]
treeData.value = res.data
await nextTick(() => {
treeRef.value!.setCurrentKey(nodeId.value, true)
})
} catch (e) {
console.error(e)
}
}
const getWarehouseList = async () => {
try {
const res = await getWarehouseListApi()
warehouseList.value = res.data
await nextTick(() => {
treeRef.value!.setCurrentKey(nodeId.value, true)
})
} catch (e) {
console.error(e)
}
}
const rowClick = (row: InterWarehousePage) => {
if (!row) {
currentRow.value = null
}
currentRow.value = row
tabsClick()
}
const skuData = ref<InterskuList[]>([])
const selectbySku = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
try {
const res = await getBySku(editForm.value.warehouseId, selectSku.value)
skuData.value = res.data || []
fetchLocationList('') //获取该仓库下的所有库位
} catch (e) {
console.error(e)
}
}
const skudblclick = (val: InterskuList) => {
// 使用可选链和空值合并运算符处理可能的null值
const {
locationCode = '',
factoryPrice = 0,
productNo = '',
sku = '',
skuName = '',
image = '',
locationId = '',
} = val || {}
otherPurchaseData.value = [
...otherPurchaseData.value,
{
skuImage: image,
warehouseSku: sku,
skuName,
productNo,
locationCode: locationCode ?? '', // 确保空值处理
locationId: locationId ?? '', // 确保空值处理
costPrice: factoryPrice, ////添加时成本价字段是啥?要提交吗?
buyStored: null,
totalPrice: null,
},
]
// 使用filter代替forEach+splice,时间复杂度从O(n^2)降到O(n)
const skuSet = new Set(
otherPurchaseData.value.map((item: InterProductList) => item.warehouseSku),
)
skuData.value = skuData.value.filter(
(item: InterskuList) => !skuSet.has(item.sku),
)
}
const tabsClick = async () => {
if (!currentRow.value) {
detailList.value = []
logList.value = []
return
}
await nextTick()
if (tabsValue.value === '0') {
searchDetail()
} else if (tabsValue.value === '1') {
getLogList()
} else {
getLogisticsData()
}
}
const [editForm, resetEditForm] = useValue({
inNo: '',
warehouseId: '',
remark: '',
factoryCode: '',
factoryId: '',
})
const newDialogVisible = ref(false)
const editFormRef = ref()
const editForm2 = ref({})
const formId = ref<number | undefined>(undefined)
const otherPurchaseData = ref<InterProductList[]>([])
const addDialog = async (i: number, v: InterWarehousePage) => {
if (i === 2) {
if (v) formId.value = v.id
// getProduct(v.id)
if (!formId.value) return ElMessage('请勾选至少一条记录')
// v.inWarehouseId = v.warehouseId
// v.inType = v.type
// v.handleUserId = v.makerUserId
editForm.value = JSON.parse(JSON.stringify(v))
} else {
await nextTick()
editForm.value = JSON.parse(JSON.stringify(editForm2.value))
resetEditForm()
const userJson = localStorage.getItem('user')
if (userJson) {
try {
const userData = JSON.parse(userJson)
editForm.value.factoryCode = userData.factoryCode || ''
editForm.value.factoryId = userData.factoryId || 0
} catch {
// ignore
}
}
otherPurchaseData.value = []
formId.value = undefined
}
newDialogVisible.value = true
}
// const getProduct = (id: number) => {
// let url = `otherInWarehouseProductDetails/getProductList?otherOutWarehouseId=${id}`
// get(url).then((res) => {
// if (res.code == 200) {
// otherPurchaseData.value = res.data;
// productData.value = res.data;
// } else {
// this.$alert(res.message, this.$t('错误提示'), {
// dangerouslyUseHTMLString: true,
// })
// }
// })
// }
const handleSelectionChange = (v: InterWarehousePage[]) => {
selections.value = v
}
const productSelection = ref<InterProductList[]>([])
const productSelectionChange = (v: InterProductList[]) => {
productSelection.value = v
}
const auditOrder = (key: string) => {
let url = ''
let text = ''
switch (key) {
case 'pay':
url = 'reconciliation/payment'
text = '确认付款'
break
case 'archive':
url = 'reconciliation/archiving'
text = '确认归档'
break
}
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
ElMessageBox.confirm(`${text}对账单?`, '重要提示', {
confirmButtonText: '确定',
type: 'warning',
}).then(async () => {
const ids = selections.value.map((el) => el.id).join(',')
await auditOrderApi(url, ids)
ElMessage.success('操作成功')
search()
await getTreeNum()
})
}
const rejectOrder = () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
ElMessageBox.prompt('请输入驳回原因', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
inputPattern: /.+/,
customClass: 'reject',
inputErrorMessage: '请输入驳回原因',
inputPlaceholder: '驳回原因',
}).then(async ({ value }) => {
const ids = selections.value.map((el) => el.id).join(',')
try {
await rejectOrderApi({ ids: ids, description: value, pass: 0 })
ElMessage.success('操作成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
})
}
watch(
() => tableData.value,
() => {
if (tableData.value && tableData.value.length > 0) {
if (singleTableRef.value) {
singleTableRef.value!.setCurrentRow(tableData.value[0])
currentRow.value = (tableData.value as never)[0]
}
} else {
detailList.value = []
}
},
{ immediate: true },
)
const addOtherCurrency = async () => {
try {
await editFormRef.value?.validate()
} catch {
return
}
const arr = otherPurchaseData.value
if (arr.length === 0) {
ElMessage.error('请至少选择一条数据')
return
}
for (let i = 0; i < arr.length; i++) {
if (!arr[i].buyStored) {
ElMessage.error('请输入入库数量')
return
}
if (!arr[i].locationId) {
ElMessage.error('请选择库位')
return
}
}
// 看新增后要不要打印标签
// try {
// if (!editId.value) {
// await addUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// } else {
// await updateUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// }
// ElMessage({
// message: '保存成功',
// type: 'success',
// offset: window.innerHeight / 2,
// })
// newDialogVisible.value = false
// search()
// } catch (e) {
// return
// }
if (!formId.value) {
addSection()
} else {
upSection()
}
}
const addSection = async () => {
const params = { ...editForm.value }
params.productList = otherPurchaseData.value
try {
await addInRecordApi(params)
ElMessage.success('保存成功')
newDialogVisible.value = false
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
// post(url, params).then((res: any) => {
// if (res.code === 200) {
// otherDialogVisible.value = false;
// ElConfirm('保存成功,是否打印标签?', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// type: 'warning',
// })
// .then(() => {
// if (res.message) {
// getPrintData(res.message, true);
// } else {
// ElMessage.warning('入口单号为空,无法打印');
// }
// })
// .catch((e: any) => {
// console.error(e);
// });
// getList();
// getStatusAmount();
// } else {
// ElAlert(res.message, '错误提示', {
// dangerouslyUseHTMLString: true,
// });
// }
// });
}
const upSection = async () => {
const params = { ...editForm.value }
params.productList = otherPurchaseData.value
try {
await updateInRecordApi(params)
newDialogVisible.value = false
ElMessage.success('修改成功')
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
}
const addPurchase = async () => {}
const deleteOtherWarehousing = async () => {}
const importData = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
}
const nodeClick = (data: Tree) => {
nodeId.value = data.code ?? ''
search()
}
const detailPager = ref({
page: 1,
rows: 100,
total: 0,
})
const searchDetail = async () => {
try {
const res = await getWarehouseInRecordDetail(currentRow.value?.id)
detailList.value = res.data.records || []
detailPager.value.total = res.data.total
} catch (e) {
console.error(e)
}
}
const getLogList = async () => {
try {
const res = await getLogListApi(currentRow.value?.id)
logList.value = res.data
} catch (e) {
console.error(e)
}
}
const logisticsData = ref([])
const getLogisticsData = async () => {
// try {
// const res = await getLogisticsDataApi(currentRow.value?.id)
// logisticsData.value = res.data
// } catch (e) {
// console.error(e)
// }
}
const importDialogVisible = ref(false)
const importedFileUrl = ref('')
const importExcel = () => {
importDialogVisible.value = true
}
const downloadTemplate = () => {
// TODO: 实现下载模板功能
window.open('/api/template/download')
}
const exportExcel = async () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
}
const ids = selections.value.map((el) => el.id).join(',')
try {
const res = await exportExcelApi(ids)
window.open(res.data)
} catch (e) {
console.error(e)
}
}
const locationList = ref<ILocation[]>([])
const locationLoading = ref(false)
const fetchLocationList = async (query: string) => {
// if (!query) {
// locationList.value = []
// return
// }
locationLoading.value = true
try {
const res = await getByWareHouseIdAndCode(editForm.value.warehouseId, query)
const result = res.data || []
locationList.value = result.map((item: ILocation) => {
return {
locationId: item.id,
locationCode: item.locationCode,
}
})
} catch (e) {
locationList.value = []
} finally {
locationLoading.value = false
}
}
// 输入2秒后再调用接口(节流)
const handleLocationSearch = debounce(fetchLocationList, 2000)
const handleLocationChange = (val: number, row: InterProductList) => {
const found = locationList.value.find(
(item: InterProductList) => item.locationId === val,
)
row.locationCode = found ? found.locationCode : ''
}
onMounted(() => {
getTreeNum()
getWarehouseList()
})
</script>
<style lang="scss" scoped>
.dialog-footer {
display: inline-block;
width: 500px;
text-align: center;
}
.header-filter-form {
:deep(.el-form-item) {
margin-right: 14px;
margin-bottom: 10px;
}
}
.product-dialog-footer {
display: flex;
justify-content: space-between;
margin: 8px 0;
}
$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;
}
.delivery-note-list {
:deep(.vertical-align-top) {
vertical-align: top;
}
}
.left {
width: 160px;
:deep(.el-tree-node__content) {
height: 30px;
line-height: 30px;
}
:deep(.el-tree-node__label) {
font-size: 13px;
cursor: pointer;
display: inline-block;
width: 100%;
color: black !important;
padding: 3px 7px;
}
:deep(.el-tree-node__expand-icon) {
display: none;
}
:deep(.is-current) {
.tree-node-label,
.tree-node-count {
background-color: #ecf5ff;
color: #409eff !important;
}
.el-tree-node__children {
.tree-node-label,
.tree-node-count {
background-color: transparent !important;
color: black !important;
}
}
}
}
.tree-node {
display: flex;
color: #333;
font-weight: 500;
}
.right {
flex: 1;
flex-shrink: 0;
background: white;
overflow: hidden;
}
::v-deep(.el-tree-node__label) {
font-size: 13px;
color: rgb(96, 98, 102);
cursor: pointer;
}
::v-deep(.el-tree-node__expand-icon) {
display: none;
}
::v-deep(.el-tree-node__label) {
display: inline-block;
width: 100%;
color: black !important;
padding: 3px 7px;
}
::v-deep(.is-current) {
.el-tree-node__label {
background-color: #ecf5ff;
color: #409eff !important;
}
.el-tree-node__children {
.el-tree-node__label {
background-color: transparent !important;
color: black !important;
}
}
}
::v-deep(.splitpanes__pane) {
display: flex;
flex-direction: column;
}
::v-deep(.splitpanes--horizontal > .splitpanes__splitter) {
min-height: 5px;
margin-top: 10px;
}
.draw-line {
width: 100%;
height: 5px;
background: #eff3f6;
}
.btn-list {
margin-bottom: 10px;
}
::v-deep(.el-tree-node) {
cursor: pointer;
margin-bottom: 5px;
}
::v-deep(.el-tree-node__label) {
font-size: 14px;
}
::v-deep(.el-tabs) {
display: flex;
flex-direction: column;
height: 100%;
.el-tabs__content {
flex: 1;
flex-shrink: 0;
overflow: hidden;
.el-tab-pane {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
}
}
.delivery-note-page {
:deep(#top) {
height: 100%;
}
}
.import-dialog {
.import-header {
display: flex;
justify-content: flex-end;
}
.import-content {
padding: 20px 0;
}
}
.import-success {
text-align: center;
padding: 20px 0;
.success-icon {
font-size: 48px;
margin-bottom: 16px;
}
.success-text {
font-size: 16px;
color: #67c23a;
margin-bottom: 16px;
}
.file-link {
a {
color: #409eff;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
</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