From e6927f46493e3e53cd14b81c9fd8a716eb378b6f Mon Sep 17 00:00:00 2001 From: shaoleiliu-netizen123 <480188199@qq.com> Date: Fri, 12 Jun 2026 10:09:04 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/biz/concessionApply/index.vue | 30 +----- src/views/biz/orderProcessPlan/index.vue | 10 +- src/views/biz/qualityTesting/detail.vue | 8 +- src/views/biz/qualityTesting/index.vue | 94 +++++++------------ src/views/biz/qualityTesting/submitDetail.vue | 9 +- src/views/biz/submitLog/index.vue | 15 +-- src/views/biz/submitLog/statistics.vue | 4 +- src/views/production/dispatchwork/index.vue | 10 +- src/views/production/myassigtask/index.vue | 2 +- 9 files changed, 65 insertions(+), 117 deletions(-) diff --git a/src/views/biz/concessionApply/index.vue b/src/views/biz/concessionApply/index.vue index c47be30..5d2c14f 100644 --- a/src/views/biz/concessionApply/index.vue +++ b/src/views/biz/concessionApply/index.vue @@ -394,9 +394,7 @@ const columns: DataTableColumns = [ { title: '审批完成时间', key: 'approveTime',align:"center",minWidth:"250" }, { title: '审批状态', key: 'approveStatus',align:"center",minWidth:"150" }, { title: '审批结果', key: 'approveResult',align:"center",minWidth:"150", - render(row:any){ - console.log(row.approveResult); - + render(row:any){ if(row.approveResult == '待审批') return h(NTag, { type: 'default', size: 'small' }, { default: () => row.approveResult }) if(row.approveResult == '已驳回') return h(NTag, { type: 'error', size: 'small' }, { default: () => row.approveResult }) if(row.approveResult == '已通过') return h(NTag, { type: 'success', size: 'small' }, { default: () => row.approveResult }) @@ -649,26 +647,9 @@ async function loadDictOptions() { approveStatusOptions.value = data.map(d => ({ label: d.dictLabel, value: (Number(d.dictValue) || d.dictValue),class: d.listClass })) } catch {} } - -const getTimelineType = (type) => { - console.log(type); - - const map = { - 'START_PROCESS_INSTANCE': 'info', //发起-蓝色 - 'AGREE': 'success',//通过-绿色 - 'REFUSE': 'error',//驳回-红色 - 'TERMINATE_PROCESS_INSTANCE':'warning',//撤回-橙黄 - 'grey':'default', //兼容grey - 'info':'default' - } - return map[type] || 'default' -} -const getTitleAttribute = (item) =>{ - return item.username +" "+item.operationResult -} -function getApproveResultColor(status) { +function getApproveResultColor(status:string) { switch(status){ case '已通过': return "green" @@ -679,11 +660,6 @@ function getApproveResultColor(status) { } } -const getRemark=(item) =>{ - console.log(item.remark); - -} - async function downloadOutline() { const model = detailModel.value if (!model) { @@ -827,7 +803,7 @@ async function downloadOutline() { } -async function handleCancel(row) { +async function handleCancel(row:any) { dialog.warning({ title: '提示', diff --git a/src/views/biz/orderProcessPlan/index.vue b/src/views/biz/orderProcessPlan/index.vue index 1ecef80..9d16686 100644 --- a/src/views/biz/orderProcessPlan/index.vue +++ b/src/views/biz/orderProcessPlan/index.vue @@ -502,7 +502,7 @@ const columns = [ minWidth: 150, title: '是否采购', key: 'procurement', - render(row) { + render(row:any) { const val = row.procurement const opt = procurementOptions.value.find(o => o.value === val || String(o.value) === String(val)) return opt ? opt.label : (val ?? '-') @@ -513,7 +513,7 @@ const columns = [ minWidth: 150, title: '是否委外', key: 'outsource', - render(row) { + render(row:any) { const val = row.outsource const opt = outsourceOptions.value.find(o => o.value === val || String(o.value) === String(val)) return opt ? opt.label : (val ?? '-') @@ -542,7 +542,7 @@ const columns = [ minWidth: 150, title: '是否质检', key: 'qualityInspection', - render(row) { + render(row:any) { const val = row.qualityInspection const opt = qualityInspectionOptions.value.find(o => o.value === val || String(o.value) === String(val)) return opt ? opt.label : (val ?? '-') @@ -553,7 +553,7 @@ const columns = [ minWidth: 150, title: '是否直接入库', key: 'storageEntry', - render(row) { + render(row:any) { const val = row.storageEntry const opt = storageEntryOptions.value.find(o => o.value === val || String(o.value) === String(val)) return opt ? opt.label : (val ?? '-') @@ -565,7 +565,7 @@ const columns = [ key: 'actions', width: 140, fixed: 'right', - render(row) { + render(row:any) { const buttons:any = [] diff --git a/src/views/biz/qualityTesting/detail.vue b/src/views/biz/qualityTesting/detail.vue index 1047bae..b635ee8 100644 --- a/src/views/biz/qualityTesting/detail.vue +++ b/src/views/biz/qualityTesting/detail.vue @@ -40,7 +40,7 @@ :data="tableData" :loading="loading" :pagination="pagination" - :row-key="(row) => row.id" + :row-key="(row:any) => row.id" :scroll-x="1200" @update:page="handlePageChange" @update:page-size="handlePageSizeChange" @@ -54,9 +54,9 @@ + + diff --git a/src/views/biz/orderProcessPlan/components/ProcessCard.vue b/src/views/biz/orderProcessPlan/components/ProcessCard.vue new file mode 100644 index 0000000..0046aea --- /dev/null +++ b/src/views/biz/orderProcessPlan/components/ProcessCard.vue @@ -0,0 +1,353 @@ + + + + + diff --git a/src/views/biz/orderProcessPlan/components/ProcessFlowStepper.vue b/src/views/biz/orderProcessPlan/components/ProcessFlowStepper.vue new file mode 100644 index 0000000..2390230 --- /dev/null +++ b/src/views/biz/orderProcessPlan/components/ProcessFlowStepper.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/src/views/biz/orderProcessPlan/index.vue b/src/views/biz/orderProcessPlan/index.vue index 9d16686..de5d200 100644 --- a/src/views/biz/orderProcessPlan/index.vue +++ b/src/views/biz/orderProcessPlan/index.vue @@ -55,16 +55,25 @@ --> - +
+ + {{ allExpanded ? '全部收起' : '全部展开' }} + +
+ +
({ }) // 表格数据 -const tableData = ref([]) +const tableData = ref([]) +const expandedRowKeys = ref>([]) const loading = ref(false) const selectedIds = ref([]) +const orderScrollX = 2090 +const processScrollX = 2620 + +function orderRowKey(row: OrderProcessPlanVO) { + return row.orderItemId ?? `order-${row.mainCode}-${row.orderCode}` +} + +function processRowKey(row: ProcessPlanItemVO) { + return row.planId ?? `proc-${row.processCode}-${row.operNumber}` +} + +const allExpanded = computed(() => { + const total = tableData.value.length + if (!total) return false + return expandedRowKeys.value.length >= total +}) + +function toggleExpandAll() { + if (allExpanded.value) { + expandedRowKeys.value = [] + } else { + expandedRowKeys.value = tableData.value.map(orderRowKey) + } +} + +function renderStatusTag( + val: number | null | undefined, + map: Record, +) { + if (val == null) return '-' + const opt = map[val] + if (!opt) return String(val) + return h(NTag, { size: 'small', type: opt.type, bordered: false }, { default: () => opt.label }) +} + +function renderYesNo(val: number | null | undefined, options: { label: string; value: unknown }[]) { + const opt = options.find(o => o.value === val || String(o.value) === String(val)) + return opt ? opt.label : (val ?? '-') +} + +function buildProcessActionColumn(order: OrderProcessPlanVO): DataTableColumns[number] { + return { + title: '操作', + key: 'actions', + width: 140, + fixed: 'right', + align: 'center', + render(row) { + const buttons: ReturnType[] = [] + if (hasPermission('biz:orderItem:edit')) { + buttons.push(h(NButton, { + size: 'small', + type: 'primary', + ghost: true, + onClick: () => handleEdit(row, order), + }, { default: () => '编辑' })) + } + if (hasPermission('biz:orderItem:assign')) { + buttons.push(h(NButton, { + size: 'small', + type: 'success', + ghost: true, + onClick: () => disphand(row, order), + }, { default: () => '派工' })) + } + return buttons.length > 0 ? h(NSpace, { justify: 'center' }, { default: () => buttons }) : '-' + }, + } +} + +function buildProcessColumns(order: OrderProcessPlanVO): DataTableColumns { + return [...processColumns.slice(0, -1), buildProcessActionColumn(order)] +} + +function renderProcessExpand(row: OrderProcessPlanVO) { + const list = row.processList ?? [] + if (!list.length) { + return h('div', { class: 'process-expand-empty' }, '暂无工序计划') + } + return h('div', { class: 'process-expand-wrap' }, [ + h(NDataTable, { + class: 'process-plan-table', + columns: buildProcessColumns(row), + data: list, + rowKey: processRowKey, + size: 'small', + bordered: true, + striped: true, + scrollX: processScrollX, + }), + ]) +} const pagination = reactive({ page: 1, pageSize: 10, @@ -458,149 +568,113 @@ const storageEntryOptions = ref<{ label: string; value: any }[]>([]) const formRules = { } -// 表格列 -const columns = [ - // { type: 'selection' }, - { - align:'center', - minWidth: 240, - title: '工序名称', - key: 'name' - }, - { - align:'center', - minWidth: 150, - title: '工序编码', - key: 'code' - }, - { - align:'center', - minWidth: 150, - title: '工序顺序', - key: 'sort' - }, - // { - // align:'center', - // minWidth: 150, - // title: '生产订单id', - // key: 'orderItemId' - // }, - { - align:'center', - minWidth: 150, - title: '生产开始时间', - key: 'beginTime' - }, - { - align:'center', - minWidth: 150, - title: '生产结束时间', - key: 'endTime' - }, - { - align:'center', - minWidth: 150, - title: '是否采购', - key: 'procurement', - render(row:any) { - const val = row.procurement - const opt = procurementOptions.value.find(o => o.value === val || String(o.value) === String(val)) - return opt ? opt.label : (val ?? '-') - } - }, - { - align:'center', - minWidth: 150, - title: '是否委外', - key: 'outsource', - render(row:any) { - const val = row.outsource - const opt = outsourceOptions.value.find(o => o.value === val || String(o.value) === String(val)) - return opt ? opt.label : (val ?? '-') - } - }, - { - align:'center', - minWidth: 150, - title: '生产总数', - key: 'quantity' - }, - { - align:'center', - minWidth: 150, - title: '转入数量', - key: 'transferNum' - }, - { - align:'center', - minWidth: 150, - title: '转出数量', - key: 'transferOutNum' - }, - { - align:'center', - minWidth: 150, - title: '是否质检', - key: 'qualityInspection', - render(row:any) { - const val = row.qualityInspection - const opt = qualityInspectionOptions.value.find(o => o.value === val || String(o.value) === String(val)) - return opt ? opt.label : (val ?? '-') - } - }, - { - align:'center', - minWidth: 150, - title: '是否直接入库', - key: 'storageEntry', - render(row:any) { - const val = row.storageEntry - const opt = storageEntryOptions.value.find(o => o.value === val || String(o.value) === String(val)) - return opt ? opt.label : (val ?? '-') - } +// 生产订单主表列(宽度按内容:编码/名称偏宽,数量/状态偏窄) +const orderColumns: DataTableColumns = [ + { + type: 'expand', + expandable: (row) => (row.processList?.length ?? 0) > 0, + renderExpand: (row) => renderProcessExpand(row), }, { - align:'center', + title: '类型', + key: 'rowType', + width: 88, + align: 'center', + render: () => h(NTag, { size: 'small', type: 'info', bordered: false }, { default: () => '生产订单' }), + }, + { title: '生产令号', key: 'mainCode', width: 140, align: 'center', ellipsis: { tooltip: true } }, + { title: '物料编码', key: 'materialCode', width: 130, align: 'center', ellipsis: { tooltip: true } }, + { title: '物料名称', key: 'materialName', width: 168, ellipsis: { tooltip: true } }, + { title: '生产订单编码', key: 'orderCode', width: 150, align: 'center', ellipsis: { tooltip: true } }, + { title: '数量', key: 'quantity', width: 72, align: 'center' }, + { title: '工艺路线', key: 'routeCode', width: 108, align: 'center', ellipsis: { tooltip: true } }, + { title: '生产车间', key: 'proWorkshop', width: 108, align: 'center', ellipsis: { tooltip: true } }, + { title: '计划开工', key: 'beginTime', width: 168, align: 'center', ellipsis: { tooltip: true } }, + { title: '计划完工', key: 'endTime', width: 168, align: 'center', ellipsis: { tooltip: true } }, + { title: '实际开工', key: 'actualStartTime', width: 168, align: 'center', ellipsis: { tooltip: true }, render: (row) => row.actualStartTime || '-' }, + { title: '实际完工', key: 'actualEndTime', width: 168, align: 'center', ellipsis: { tooltip: true }, render: (row) => row.actualEndTime || '-' }, + { title: '完成数量', key: 'completedQty', width: 88, align: 'center' }, + { + title: '订单状态', + key: 'orderStatus', + width: 96, + align: 'center', + render: (row) => renderStatusTag(row.orderStatus, ORDER_STATUS_MAP), + }, + { title: '当前工序', key: 'currentProcessName', width: 132, align: 'center', ellipsis: { tooltip: true } }, + { title: '当前工序号', key: 'currentOperNumber', width: 96, align: 'center' }, +] + +// 工序明细列(时间列 168,数量列 72,布尔/状态列 64~96) +const processColumns: DataTableColumns = [ + { + title: '类型', + key: 'rowType', + width: 68, + align: 'center', + render: () => h(NTag, { size: 'small', type: 'warning', bordered: false }, { default: () => '工序' }), + }, + { title: '工序号', key: 'operNumber', width: 72, align: 'center' }, + { title: '工序编码', key: 'processCode', width: 96, align: 'center', ellipsis: { tooltip: true } }, + { title: '工序名称', key: 'processName', width: 140, ellipsis: { tooltip: true } }, + { title: '工序说明', key: 'operDescription', width: 160, ellipsis: { tooltip: true } }, + { title: '工作中心', key: 'workCenterName', width: 112, align: 'center', ellipsis: { tooltip: true } }, + { title: '部门', key: 'departmentName', width: 112, align: 'center', ellipsis: { tooltip: true } }, + { title: '计划开工', key: 'planStartTime', width: 168, align: 'center', ellipsis: { tooltip: true } }, + { title: '计划完工', key: 'planFinishTime', width: 168, align: 'center', ellipsis: { tooltip: true } }, + { title: '实际开工', key: 'actualStartTime', width: 168, align: 'center', ellipsis: { tooltip: true }, render: (row) => row.actualStartTime || '-' }, + { title: '实际完工', key: 'actualFinishTime', width: 168, align: 'center', ellipsis: { tooltip: true }, render: (row) => row.actualFinishTime || '-' }, + { title: '数量', key: 'quantity', width: 72, align: 'center' }, + { title: '转入', key: 'transferInQty', width: 72, align: 'center' }, + { title: '转出', key: 'transferOutQty', width: 72, align: 'center' }, + { title: '完成', key: 'completedQty', width: 72, align: 'center' }, + { title: '报废', key: 'scrapQty', width: 72, align: 'center' }, + { title: '返工', key: 'reworkQty', width: 72, align: 'center' }, + { + title: '采购', + key: 'procurement', + width: 64, + align: 'center', + render: (row) => renderYesNo(row.procurement, procurementOptions.value), + }, + { + title: '委外', + key: 'outsource', + width: 64, + align: 'center', + render: (row) => renderYesNo(row.outsource, outsourceOptions.value), + }, + { + title: '质检', + key: 'qualityInspection', + width: 64, + align: 'center', + render: (row) => renderYesNo(row.qualityInspection, qualityInspectionOptions.value), + }, + { + title: '入库', + key: 'storageEntry', + width: 64, + align: 'center', + render: (row) => renderYesNo(row.storageEntry, storageEntryOptions.value), + }, + { + title: '工序状态', + key: 'processStatus', + width: 96, + align: 'center', + render: (row) => renderStatusTag(row.processStatus, PROCESS_STATUS_MAP), + }, + { title: '派工人', key: 'assignByName', width: 96, align: 'center', ellipsis: { tooltip: true }, render: (row) => row.assignByName || '-' }, + { title: '派工时间', key: 'assignTime', width: 168, align: 'center', ellipsis: { tooltip: true }, render: (row) => row.assignTime || '-' }, + { title: '操作', key: 'actions', - width: 140, + width: 136, fixed: 'right', - render(row:any) { - - const buttons:any = [] - - if(hasPermission('biz:orderItem:edit')){ - buttons.push(h(NButton, { - size: 'small', - type:'primary', - ghost:true, - onClick: () => { handleEdit(row) } }, - //{ default: () => [h(NIcon, null, { default: () => h(CreateOutline) }), ' 编辑' ]} - { default: () => '编辑'} - )) - } - if(hasPermission('biz:orderItem:assign')){ - buttons.push(h(NButton, { - size: 'small', - type:'success', - ghost:true, - onClick: () => { disphand(row) } }, - { default: () => '派工'} - )) - } - - return buttons.length > 0 ? h(NSpace, {justify:'center'}, { default: () => buttons }) : '-' - - // return h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'nowrap' } }, [ - // h(NButton, { size: 'small', quaternary: true, onClick: () => handleEdit(row) }, { - // default: () => [h(NIcon, null, { default: () => h(CreateOutline) }), ' 编辑'] - // }), - // h(NButton, { size: 'small', quaternary: true, type: 'error', onClick: () => handleDelete(row) }, { - // default: () => [h(NIcon, null, { default: () => h(TrashOutline) }), ' 删除'] - // }) - // ]) - } - } + align: 'center', + render: () => '-', + }, ] // 加载数据 @@ -665,19 +739,31 @@ function handleAdd() { modalVisible.value = true } -// 编辑 -function handleEdit(row:any) { +function parseDateTime(val: string | null | undefined) { + if (!val) return null + const ts = new Date(val.replace(' ', 'T')).getTime() + return Number.isNaN(ts) ? null : ts +} + +// 编辑(工序明细 -> 实体字段) +function handleEdit(process: ProcessPlanItemVO, order?: OrderProcessPlanVO) { modalTitle.value = '编辑工序计划' - Object.assign(formData, row) - if (formData.beginTime && typeof formData.beginTime === 'string') { - formData.beginTime = new Date(formData.beginTime.replace(' ', 'T')).getTime() - } - if (formData.endTime && typeof formData.endTime === 'string') { - formData.endTime = new Date(formData.endTime.replace(' ', 'T')).getTime() - } - if (formData.createTime && typeof formData.createTime === 'string') { - formData.createTime = new Date(formData.createTime.replace(' ', 'T')).getTime() - } + const entity = processItemToEntity(process, order?.orderItemId) + Object.assign(formData, { + ...defaultFormData, + ...entity, + sort: entity.sort != null ? String(entity.sort) : '', + orderItemId: entity.orderItemId != null ? String(entity.orderItemId) : '', + quantity: entity.quantity != null ? String(entity.quantity) : '', + transferNum: entity.transferNum != null ? String(entity.transferNum) : '', + transferOutNum: entity.transferOutNum != null ? String(entity.transferOutNum) : '', + procurement: entity.procurement != null ? entity.procurement : '', + outsource: entity.outsource != null ? entity.outsource : '', + qualityInspection: entity.qualityInspection != null ? entity.qualityInspection : '', + storageEntry: entity.storageEntry != null ? entity.storageEntry : '', + beginTime: parseDateTime(entity.beginTime), + endTime: parseDateTime(entity.endTime), + }) modalVisible.value = true } @@ -685,7 +771,7 @@ function handleEdit(row:any) { async function handleSubmit() { await formRef.value?.validate() try { - const submitData = { ...formData } + const submitData = toOrderProcessPlanPayload({ ...formData }) if (typeof submitData.beginTime === 'number') { submitData.beginTime = new Date(submitData.beginTime).toISOString().slice(0, 19).replace('T', ' ') } @@ -767,20 +853,20 @@ function deletenum(index:any) { -function disphand(v:any){ +function disphand(process: ProcessPlanItemVO, order?: OrderProcessPlanVO) { + const entity = processItemToEntity(process, order?.orderItemId) dispatchmodal.value = true dispatchformRef.value?.restoreValidation() - dispatchform.id = v.id - dispatchform.name = v.name - dispatchform.beginTime = v.beginTime - dispatchform.endTime = v.endTime - dispatchform.quantity = v.quantity + dispatchform.id = entity.id + dispatchform.name = entity.name + dispatchform.beginTime = entity.beginTime + dispatchform.endTime = entity.endTime + dispatchform.quantity = entity.quantity dispatchform.userid = '' dispatchform.list = [{ - userId:'', - quantity:'' + userId: '', + quantity: '', }] - //slehand() } function dispatchSubmit() { @@ -813,16 +899,16 @@ function dispatchSubmit() { } -// 删除 -function handleDelete(row: OrderProcessPlan) { +// 删除(工序计划 id) +function handleDelete(process: ProcessPlanItemVO) { dialog.warning({ title: '提示', - content: '确定要删除该记录吗?', + content: '确定要删除该工序计划吗?', positiveText: '确定', negativeText: '取消', onPositiveClick: async () => { try { - await orderProcessPlanApi.delete([row.id!]) + await orderProcessPlanApi.delete([process.planId!]) message.success('删除成功') loadData() } catch (error) { @@ -943,4 +1029,31 @@ onMounted(() => { .table-toolbar { margin-bottom: 16px; } + +:deep(.n-data-table-tr--expanded td) { + background-color: rgba(32, 128, 240, 0.06) !important; +} + +.process-expand-wrap { + margin: 4px 8px 8px 36px; + padding: 12px 14px 14px; + border: 1px solid var(--n-border-color); + border-left: 4px solid #18a058; + border-radius: 6px; + background: var(--n-action-color); +} + +:deep(.process-plan-table .n-data-table-th) { + background: rgba(24, 160, 88, 0.12) !important; +} + +.process-expand-empty { + margin: 4px 8px 8px 36px; + padding: 12px 14px; + font-size: 13px; + color: var(--n-text-color-3); + border: 1px dashed var(--n-border-color); + border-radius: 6px; + background: var(--n-action-color); +} diff --git a/src/views/biz/processRoute/index.vue b/src/views/biz/processRoute/index.vue new file mode 100644 index 0000000..a00f2be --- /dev/null +++ b/src/views/biz/processRoute/index.vue @@ -0,0 +1,455 @@ + + + + + diff --git a/src/views/biz/processRouteStep/index.vue b/src/views/biz/processRouteStep/index.vue new file mode 100644 index 0000000..bbbe30f --- /dev/null +++ b/src/views/biz/processRouteStep/index.vue @@ -0,0 +1,459 @@ + + + + + diff --git a/vite.config.ts b/vite.config.ts index 2669af7..560d187 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -16,12 +16,11 @@ export default defineConfig({ emptyOutDir: true }, server: { - host: "192.168.5.231", + host: true, port: 3000, proxy: { '/api': { - //target:'http://192.168.6.107:8080', //'http://192.168.5.230:8888', - target:'http://192.168.5.230:8888', + target:'http://localhost:8888', changeOrigin: true }, '/druid': {