diff --git a/src/api/ConcessionApply.ts b/src/api/ConcessionApply.ts index 7049991..b4d082f 100644 --- a/src/api/ConcessionApply.ts +++ b/src/api/ConcessionApply.ts @@ -20,7 +20,7 @@ export interface ConcessionApply { instanceId?: string - approveStatus?: number + approveStatus?: string createTime?: string @@ -61,7 +61,7 @@ export const concessionApplyApi = { }, // 删除 - delete(ids: string[]) { + delete(ids: number[]) { return request({ url: `/biz/concessionApply/${ids.join(',')}`, method: 'delete' }) }, diff --git a/src/api/orderProcessPlan.ts b/src/api/orderProcessPlan.ts index 739ba32..9b0da35 100644 --- a/src/api/orderProcessPlan.ts +++ b/src/api/orderProcessPlan.ts @@ -1,20 +1,24 @@ import { request } from '@/utils/request' -// 工序计划 类型定义 + + +/** 工序计划实体(新增/修改/派工) */ + export interface OrderProcessPlan { + id?: number - name?: string + name?: string - code?: string + code?: string sort?: number orderItemId?: number - beginTime?: string + beginTime?: string - endTime?: string + endTime?: string procurement?: number @@ -26,9 +30,9 @@ export interface OrderProcessPlan { transferOutNum?: number - createTime?: string + createTime?: string - createBy?: string + createBy?: string qualityInspection?: number @@ -36,63 +40,407 @@ export interface OrderProcessPlan { } + + +/** 派工明细 */ + +export interface AssignWorkItem { + + userId?: number | string + + quantity?: number | string + + assingStatus?: number + + [key: string]: unknown + +} + + + +/** 工序计划明细 VO(processList 项) */ + +export interface ProcessPlanItemVO { + + planId?: number + + processCode?: string + + operNumber?: number + + workCenterName?: string + + departmentName?: string + + processName?: string + + operDescription?: string + + activityUnit?: string + + optCtrlCodeName?: string + + activityQty?: number + + planStartTime?: string + + planFinishTime?: string + + actualStartTime?: string | null + + actualFinishTime?: string | null + + quantity?: number + + transferInQty?: number + + transferOutQty?: number + + completedQty?: number + + scrapQty?: number + + reworkQty?: number + + procurement?: number + + outsource?: number + + qualityInspection?: number + + storageEntry?: number + + assign?: number + + assignByName?: string | null + + assignTime?: string | null + + processStatus?: number + + prevPlanId?: number | null + + nextPlanId?: number | null + + assignWorkList?: AssignWorkItem[] + +} + + + +/** 按生产订单分组的工序计划 VO(分页/详情) */ + +export interface OrderProcessPlanVO { + + orderItemId?: number + + mainCode?: string + + materialCode?: string + + materialName?: string + + orderCode?: string + + quantity?: number + + routeCode?: string + + proWorkshop?: string + + beginTime?: string + + endTime?: string + + actualStartTime?: string | null + + actualEndTime?: string | null + + completedQty?: number + + orderStatus?: number + + currentProcessName?: string + + currentOperNumber?: number + + processList?: ProcessPlanItemVO[] + +} + + + +export const ORDER_STATUS_MAP: Record = { + + 0: { label: '未开始', type: 'default' }, + + 1: { label: '进行中', type: 'info' }, + + 2: { label: '已完成', type: 'success' }, + +} + + + +export const PROCESS_STATUS_MAP: Record = { + + 0: { label: '待派工', type: 'default' }, + + 1: { label: '待执行', type: 'info' }, + + 2: { label: '执行中', type: 'warning' }, + + 3: { label: '质检中', type: 'warning' }, + + 4: { label: '已完成', type: 'success' }, + +} + + + +export const ASSIGN_STATUS_MAP: Record = { + + 1: { label: '待执行', type: 'info' }, + + 2: { label: '执行中', type: 'warning' }, + + 3: { label: '质检中', type: 'warning' }, + + 4: { label: '已汇报', type: 'success' }, + + 5: { label: '已关闭', type: 'default' }, + +} + + + +/** 工序 VO 转实体(编辑/派工提交用) */ + +export function processItemToEntity( + + item: ProcessPlanItemVO, + + orderItemId?: number, + +): OrderProcessPlan { + + return { + + id: item.planId, + + name: item.processName, + + code: item.processCode, + + sort: item.operNumber, + + orderItemId, + + beginTime: item.planStartTime, + + endTime: item.planFinishTime, + + procurement: item.procurement, + + outsource: item.outsource, + + quantity: item.quantity, + + transferNum: item.transferInQty, + + transferOutNum: item.transferOutQty, + + qualityInspection: item.qualityInspection, + + storageEntry: item.storageEntry, + + } + +} + + + +/** 提交前剔除展示字段,保留 OrderProcessPlan 实体 */ + +export function toOrderProcessPlanPayload(data: Record): OrderProcessPlan { + + const payload = { ...data } + + const displayKeys = [ + + 'mainCode', 'materialCode', 'materialName', 'orderCode', 'routeCode', 'proWorkshop', + + 'actualStartTime', 'actualEndTime', 'completedQty', 'orderStatus', 'currentProcessName', + + 'currentOperNumber', 'processList', 'planId', 'processName', 'processCode', 'operNumber', + + 'workCenterName', 'departmentName', 'operDescription', 'activityUnit', 'optCtrlCodeName', + + 'activityQty', 'planStartTime', 'planFinishTime', 'actualFinishTime', 'transferInQty', + + 'transferOutQty', 'scrapQty', 'reworkQty', 'assign', 'assignByName', 'assignTime', + + 'processStatus', 'prevPlanId', 'nextPlanId', 'assignWorkList', + + ] + + for (const key of displayKeys) { + + delete payload[key] + + } + + return payload as OrderProcessPlan + +} + + + // 工序计划 API + export const orderProcessPlanApi = { - // 分页查询 - page(params:any) { //{ page: number; pageSize: number; id?: number; name?: string; code?: string; orderItemId?: number } - return request({ url: '/biz/orderProcessPlan/page', method: 'get', params }) + + // 分页查询(按生产订单分组) + + page(params: { + + page: number + + pageSize: number + + id?: number | string + + name?: string + + code?: string + + orderItemId?: number | string + + }) { + + return request<{ list: OrderProcessPlanVO[]; total: number; page: number; pageSize: number }>({ + + url: '/biz/orderProcessPlan/page', + + method: 'get', + + params, + + }) + }, - // 获取详情 - detail(id: string) { - return request({ url: `/biz/orderProcessPlan/${id}`, method: 'get' }) + + + // 获取详情(路径参数为生产订单 id) + + detail(orderItemId: number | string) { + + return request({ + + url: `/biz/orderProcessPlan/${orderItemId}`, + + method: 'get', + + }) + }, + + // 新增 - create(data: any) { + + create(data: OrderProcessPlan) { + return request({ url: '/biz/orderProcessPlan', method: 'post', data }) + }, + + // 修改 - update(data: any) { + + update(data: OrderProcessPlan) { + return request({ url: '/biz/orderProcessPlan', method: 'put', data }) + }, - // 删除 - delete(ids: string[]) { + + + // 删除(工序计划 id) + + delete(ids: (number | string)[]) { + return request({ url: `/biz/orderProcessPlan/${ids.join(',')}`, method: 'delete' }) + }, - //派工 - assignWork(data: any) { + + + // 派工 + + assignWork(data: OrderProcessPlan & { list?: AssignWorkItem[] }) { + return request({ url: '/biz/orderProcessPlan/assignWork', method: 'put', data }) + }, + + // 导出 - export(params?: { ids?: string[]; id?: number; name?: string; code?: string; orderItemId?: number }) { - const p: Record = {} + + export(params?: { ids?: string[]; id?: number; name?: string; code?: string; orderItemId?: number }) { + + const p: Record = {} + if (params?.ids?.length) p.ids = params.ids.join(',') + if (params?.id !== undefined && params?.id !== null) p.id = params.id + if (params?.name !== undefined && params?.name !== null) p.name = params.name + if (params?.code !== undefined && params?.code !== null) p.code = params.code + if (params?.orderItemId !== undefined && params?.orderItemId !== null) p.orderItemId = params.orderItemId - return request({ url: `/biz/orderProcessPlan/export`, method: 'get', params: p, responseType: 'blob' }) + + return request({ url: '/biz/orderProcessPlan/export', method: 'get', params: p, responseType: 'blob' }) + }, + + // 导入 + importData(file: File) { + const formData = new FormData() + formData.append('file', file) + return request<{ success: number; fail: number; errors: string[] }>({ - url: `/biz/orderProcessPlan/import`, + + url: '/biz/orderProcessPlan/import', + method: 'post', + data: formData, - headers: { 'Content-Type': 'multipart/form-data' } + + headers: { 'Content-Type': 'multipart/form-data' }, + }) + }, + + // 下载导入模板 + downloadTemplate() { - return request({ url: `/biz/orderProcessPlan/template`, method: 'get', responseType: 'blob' }) - } + + return request({ url: '/biz/orderProcessPlan/template', method: 'get', responseType: 'blob' }) + + }, + } + diff --git a/src/api/processRoute.ts b/src/api/processRoute.ts new file mode 100644 index 0000000..c266812 --- /dev/null +++ b/src/api/processRoute.ts @@ -0,0 +1,88 @@ +import { request } from '@/utils/request' + +// 工艺路线主表 类型定义 +export interface ProcessRoute { + id?: number + + code?: string + + name?: string + + materialCode?: string + + materialName?: string + + version?: string + + status?: number + + source?: number + + sourceId?: string + + remark?: string + + createTime?: string + + createBy?: string + + changeTime?: string + + changeBy?: string + +} + +// 工艺路线主表 API +export const processRouteApi = { + // 分页查询 + page(params: { page: number; pageSize: number; id?: number; name?: string; status?: number }) { + return request({ url: '/biz/processRoute/page', method: 'get', params }) + }, + + // 获取详情 + detail(id: string) { + return request({ url: `/biz/processRoute/${id}`, method: 'get' }) + }, + + // 新增 + create(data: ProcessRoute) { + return request({ url: '/biz/processRoute', method: 'post', data }) + }, + + // 修改 + update(data: ProcessRoute) { + return request({ url: '/biz/processRoute', method: 'put', data }) + }, + + // 删除 + delete(ids: string[]) { + return request({ url: `/biz/processRoute/${ids.join(',')}`, method: 'delete' }) + }, + + // 导出 + export(params?: { ids?: string[]; id?: number; name?: string; status?: number }) { + const p: Record = {} + if (params?.ids?.length) p.ids = params.ids.join(',') + if (params?.id !== undefined && params?.id !== null) p.id = params.id + if (params?.name !== undefined && params?.name !== null) p.name = params.name + if (params?.status !== undefined && params?.status !== null) p.status = params.status + return request({ url: `/biz/processRoute/export`, method: 'get', params: p, responseType: 'blob' }) + }, + + // 导入 + importData(file: File) { + const formData = new FormData() + formData.append('file', file) + return request<{ success: number; fail: number; errors: string[] }>({ + url: `/biz/processRoute/import`, + method: 'post', + data: formData, + headers: { 'Content-Type': 'multipart/form-data' } + }) + }, + + // 下载导入模板 + downloadTemplate() { + return request({ url: `/biz/processRoute/template`, method: 'get', responseType: 'blob' }) + } +} diff --git a/src/api/processRouteStep.ts b/src/api/processRouteStep.ts new file mode 100644 index 0000000..bf1ae4b --- /dev/null +++ b/src/api/processRouteStep.ts @@ -0,0 +1,89 @@ +import { request } from '@/utils/request' + +// 工艺路线工序明细 类型定义 +export interface ProcessRouteStep { + id?: number + + routeId?: number + + operNumber?: number + + processName?: string + + operDescription?: string + + workCenterName?: string + + departmentName?: string + + activityUnit?: string + + optCtrlCodeName?: string + + activityQty?: string + + sort?: number + + isOutsource?: number + + status?: number + + createTime?: string + + changeTime?: string + +} + +// 工艺路线工序明细 API +export const processRouteStepApi = { + // 分页查询 + page(params: { page: number; pageSize: number; id?: number; status?: number }) { + return request({ url: '/biz/processRouteStep/page', method: 'get', params }) + }, + + // 获取详情 + detail(id: number) { + return request({ url: `/biz/processRouteStep/${id}`, method: 'get' }) + }, + + // 新增 + create(data: ProcessRouteStep) { + return request({ url: '/biz/processRouteStep', method: 'post', data }) + }, + + // 修改 + update(data: ProcessRouteStep) { + return request({ url: '/biz/processRouteStep', method: 'put', data }) + }, + + // 删除 + delete(ids: number[]) { + return request({ url: `/biz/processRouteStep/${ids.join(',')}`, method: 'delete' }) + }, + + // 导出 + export(params?: { ids?: number[]; id?: number; status?: number }) { + const p: Record = {} + if (params?.ids?.length) p.ids = params.ids.join(',') + if (params?.id !== undefined && params?.id !== null) p.id = params.id + if (params?.status !== undefined && params?.status !== null) p.status = params.status + return request({ url: `/biz/processRouteStep/export`, method: 'get', params: p, responseType: 'blob' }) + }, + + // 导入 + importData(file: File) { + const formData = new FormData() + formData.append('file', file) + return request<{ success: number; fail: number; errors: string[] }>({ + url: `/biz/processRouteStep/import`, + method: 'post', + data: formData, + headers: { 'Content-Type': 'multipart/form-data' } + }) + }, + + // 下载导入模板 + downloadTemplate() { + return request({ url: `/biz/processRouteStep/template`, method: 'get', responseType: 'blob' }) + } +} diff --git a/src/api/qcResultDetail.ts b/src/api/qcResultDetail.ts index 331347e..ae8cd70 100644 --- a/src/api/qcResultDetail.ts +++ b/src/api/qcResultDetail.ts @@ -8,7 +8,7 @@ export interface QcResultDetail { resultType?: number - qty?: string + qty?: number traceCode?: string diff --git a/src/api/submitLog.ts b/src/api/submitLog.ts index 2bfbcf7..d01d31c 100644 --- a/src/api/submitLog.ts +++ b/src/api/submitLog.ts @@ -14,6 +14,14 @@ export interface SubmitLog { createBy?: string + materialName?:string + + materialCode?:string + + materialQty?:number + + assingStatus?: number + } // 派工工单汇报记录 API @@ -39,7 +47,7 @@ export const submitLogApi = { }, // 删除 - delete(ids: string[]) { + delete(ids: number[]) { return request({ url: `/biz/submitLog/${ids.join(',')}`, method: 'delete' }) }, diff --git a/src/components/SiteLogoMark.vue b/src/components/SiteLogoMark.vue index a19d00a..1daae11 100644 --- a/src/components/SiteLogoMark.vue +++ b/src/components/SiteLogoMark.vue @@ -1,31 +1,31 @@ - - + + - + + 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 1ecef80..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) { - 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) { - 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) { - 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) { - 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) { - - 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/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 @@