From be213b6b3119a416c52e850718b59578a5c3f276 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 May 2026 10:37:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(mes):=20=E8=BF=81=E7=A7=BB=20work=20task?= =?UTF-8?q?=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-antd/src/router/routes/modules/mes.ts | 2 +- .../mes/pro/task/components/gantt-chart.vue | 239 ++++++++++++++++++ .../pro/task/components/pro-task-select.vue | 13 +- apps/web-antd/src/views/mes/pro/task/data.ts | 9 + .../src/views/mes/pro/task/edit/index.vue | 98 +++++++ .../web-antd/src/views/mes/pro/task/index.vue | 151 +++++++++++ .../mes/pro/task/modules/schedule-form.vue | 148 +++++++++++ .../views/mes/pro/task/modules/task-form.vue | 113 +++++++++ .../views/mes/pro/task/modules/task-list.vue | 162 ++++++++++++ .../src/views/mes/wm/materialstock/data.ts | 20 +- apps/web-ele/src/router/routes/modules/mes.ts | 2 +- .../mes/pro/task/components/gantt-chart.vue | 239 ++++++++++++++++++ .../pro/task/components/pro-task-select.vue | 13 +- apps/web-ele/src/views/mes/pro/task/data.ts | 9 + .../src/views/mes/pro/task/edit/index.vue | 98 +++++++ apps/web-ele/src/views/mes/pro/task/index.vue | 152 +++++++++++ .../mes/pro/task/modules/schedule-form.vue | 154 +++++++++++ .../views/mes/pro/task/modules/task-form.vue | 113 +++++++++ .../views/mes/pro/task/modules/task-list.vue | 162 ++++++++++++ .../src/views/mes/wm/materialstock/data.ts | 20 +- 20 files changed, 1895 insertions(+), 22 deletions(-) create mode 100644 apps/web-antd/src/views/mes/pro/task/components/gantt-chart.vue create mode 100644 apps/web-antd/src/views/mes/pro/task/edit/index.vue create mode 100644 apps/web-antd/src/views/mes/pro/task/index.vue create mode 100644 apps/web-antd/src/views/mes/pro/task/modules/schedule-form.vue create mode 100644 apps/web-antd/src/views/mes/pro/task/modules/task-form.vue create mode 100644 apps/web-antd/src/views/mes/pro/task/modules/task-list.vue create mode 100644 apps/web-ele/src/views/mes/pro/task/components/gantt-chart.vue create mode 100644 apps/web-ele/src/views/mes/pro/task/edit/index.vue create mode 100644 apps/web-ele/src/views/mes/pro/task/index.vue create mode 100644 apps/web-ele/src/views/mes/pro/task/modules/schedule-form.vue create mode 100644 apps/web-ele/src/views/mes/pro/task/modules/task-form.vue create mode 100644 apps/web-ele/src/views/mes/pro/task/modules/task-list.vue diff --git a/apps/web-antd/src/router/routes/modules/mes.ts b/apps/web-antd/src/router/routes/modules/mes.ts index 4172fdbc9..cf0d1c418 100644 --- a/apps/web-antd/src/router/routes/modules/mes.ts +++ b/apps/web-antd/src/router/routes/modules/mes.ts @@ -40,7 +40,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/mes/wm/barcode/config/index.vue'), }, { - path: 'pro/task/edit', + path: 'pro/task/gantt-edit', name: 'MesProTaskGanttEdit', meta: { title: '甘特图编辑', diff --git a/apps/web-antd/src/views/mes/pro/task/components/gantt-chart.vue b/apps/web-antd/src/views/mes/pro/task/components/gantt-chart.vue new file mode 100644 index 000000000..573f68d51 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/components/gantt-chart.vue @@ -0,0 +1,239 @@ + + + + + diff --git a/apps/web-antd/src/views/mes/pro/task/components/pro-task-select.vue b/apps/web-antd/src/views/mes/pro/task/components/pro-task-select.vue index 60c5e1133..100a277c0 100644 --- a/apps/web-antd/src/views/mes/pro/task/components/pro-task-select.vue +++ b/apps/web-antd/src/views/mes/pro/task/components/pro-task-select.vue @@ -47,23 +47,19 @@ const showClear = computed(() => // 是否显示清空图标 props.allowClear && !props.disabled && hovering.value && - props.modelValue !== undefined, + props.modelValue != null, ); /** 根据任务编号回显选择器 */ async function resolveItemById(id: number | undefined) { - if (id === undefined) { + if (id == null) { selectedItem.value = undefined; return; } if (selectedItem.value?.id === id) { return; } - try { - selectedItem.value = await getTask(id); - } catch (error) { - console.error('[ProTaskSelect] resolveItemById failed:', error); - } + selectedItem.value = await getTask(id); } watch( @@ -92,8 +88,7 @@ function handleClick(event: MouseEvent) { clearSelected(); return; } - const selectedIds = - props.modelValue === undefined ? [] : [props.modelValue]; + const selectedIds = props.modelValue == null ? [] : [props.modelValue]; dialogRef.value?.open(selectedIds, { multiple: false, workOrderId: props.workOrderId, diff --git a/apps/web-antd/src/views/mes/pro/task/data.ts b/apps/web-antd/src/views/mes/pro/task/data.ts index baede0e30..1c1461e70 100644 --- a/apps/web-antd/src/views/mes/pro/task/data.ts +++ b/apps/web-antd/src/views/mes/pro/task/data.ts @@ -279,6 +279,15 @@ export function useScheduleFormSchema(): VbenFormSchema[] { valueFormat: 'x', }, }, + { + fieldName: 'status', + label: '工单状态', + component: 'Select', + componentProps: { + disabled: true, + options: getDictOptions(DICT_TYPE.MES_PRO_WORK_ORDER_STATUS, 'number'), + }, + }, { fieldName: 'remark', label: '备注', diff --git a/apps/web-antd/src/views/mes/pro/task/edit/index.vue b/apps/web-antd/src/views/mes/pro/task/edit/index.vue new file mode 100644 index 000000000..002bf57cc --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/edit/index.vue @@ -0,0 +1,98 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/task/index.vue b/apps/web-antd/src/views/mes/pro/task/index.vue new file mode 100644 index 000000000..c57faf175 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/index.vue @@ -0,0 +1,151 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/task/modules/schedule-form.vue b/apps/web-antd/src/views/mes/pro/task/modules/schedule-form.vue new file mode 100644 index 000000000..422142844 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/modules/schedule-form.vue @@ -0,0 +1,148 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/task/modules/task-form.vue b/apps/web-antd/src/views/mes/pro/task/modules/task-form.vue new file mode 100644 index 000000000..e95146c7f --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/modules/task-form.vue @@ -0,0 +1,113 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/task/modules/task-list.vue b/apps/web-antd/src/views/mes/pro/task/modules/task-list.vue new file mode 100644 index 000000000..0cd3b46ae --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/modules/task-list.vue @@ -0,0 +1,162 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/materialstock/data.ts b/apps/web-antd/src/views/mes/wm/materialstock/data.ts index 2281b6850..e23914a99 100644 --- a/apps/web-antd/src/views/mes/wm/materialstock/data.ts +++ b/apps/web-antd/src/views/mes/wm/materialstock/data.ts @@ -53,6 +53,12 @@ export function useGridFormSchema(): VbenFormSchema[] { warehouseId: values.warehouseId, placeholder: '请选择库区', }), + // 仓库切换时清空库区,避免旧库区条件残留 + trigger: (values, formApi) => { + if (values.locationId !== undefined) { + void formApi.setFieldValue('locationId', undefined); + } + }, }, }, { @@ -191,6 +197,12 @@ export function useSelectGridFormSchema(): VbenFormSchema[] { warehouseId: values.warehouseId, placeholder: '请选择库区', }), + // 仓库切换时清空库区 + trigger: (values, formApi) => { + if (values.locationId !== undefined) { + void formApi.setFieldValue('locationId', undefined); + } + }, }, }, { @@ -198,11 +210,17 @@ export function useSelectGridFormSchema(): VbenFormSchema[] { label: '库位', component: markRaw(WmWarehouseAreaSelect), dependencies: { - triggerFields: ['locationId'], + triggerFields: ['warehouseId', 'locationId'], componentProps: (values) => ({ locationId: values.locationId, placeholder: '请选择库位', }), + // 仓库或库区切换时清空库位 + trigger: (values, formApi) => { + if (values.areaId !== undefined) { + void formApi.setFieldValue('areaId', undefined); + } + }, }, }, ]; diff --git a/apps/web-ele/src/router/routes/modules/mes.ts b/apps/web-ele/src/router/routes/modules/mes.ts index 4172fdbc9..cf0d1c418 100644 --- a/apps/web-ele/src/router/routes/modules/mes.ts +++ b/apps/web-ele/src/router/routes/modules/mes.ts @@ -40,7 +40,7 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/mes/wm/barcode/config/index.vue'), }, { - path: 'pro/task/edit', + path: 'pro/task/gantt-edit', name: 'MesProTaskGanttEdit', meta: { title: '甘特图编辑', diff --git a/apps/web-ele/src/views/mes/pro/task/components/gantt-chart.vue b/apps/web-ele/src/views/mes/pro/task/components/gantt-chart.vue new file mode 100644 index 000000000..573f68d51 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/components/gantt-chart.vue @@ -0,0 +1,239 @@ + + + + + diff --git a/apps/web-ele/src/views/mes/pro/task/components/pro-task-select.vue b/apps/web-ele/src/views/mes/pro/task/components/pro-task-select.vue index 41ddaf20a..4eb0318fa 100644 --- a/apps/web-ele/src/views/mes/pro/task/components/pro-task-select.vue +++ b/apps/web-ele/src/views/mes/pro/task/components/pro-task-select.vue @@ -47,23 +47,19 @@ const showClear = computed(() => // 是否显示清空图标 props.clearable && !props.disabled && hovering.value && - props.modelValue !== undefined, + props.modelValue != null, ); /** 根据任务编号回显选择器 */ async function resolveItemById(id: number | undefined) { - if (id === undefined) { + if (id == null) { selectedItem.value = undefined; return; } if (selectedItem.value?.id === id) { return; } - try { - selectedItem.value = await getTask(id); - } catch (error) { - console.error('[ProTaskSelect] resolveItemById failed:', error); - } + selectedItem.value = await getTask(id); } watch( @@ -92,8 +88,7 @@ function handleClick(event: MouseEvent) { clearSelected(); return; } - const selectedIds = - props.modelValue === undefined ? [] : [props.modelValue]; + const selectedIds = props.modelValue == null ? [] : [props.modelValue]; dialogRef.value?.open(selectedIds, { multiple: false, workOrderId: props.workOrderId, diff --git a/apps/web-ele/src/views/mes/pro/task/data.ts b/apps/web-ele/src/views/mes/pro/task/data.ts index b78f2a030..969888d50 100644 --- a/apps/web-ele/src/views/mes/pro/task/data.ts +++ b/apps/web-ele/src/views/mes/pro/task/data.ts @@ -280,6 +280,15 @@ export function useScheduleFormSchema(): VbenFormSchema[] { valueFormat: 'x', }, }, + { + fieldName: 'status', + label: '工单状态', + component: 'Select', + componentProps: { + disabled: true, + options: getDictOptions(DICT_TYPE.MES_PRO_WORK_ORDER_STATUS, 'number'), + }, + }, { fieldName: 'remark', label: '备注', diff --git a/apps/web-ele/src/views/mes/pro/task/edit/index.vue b/apps/web-ele/src/views/mes/pro/task/edit/index.vue new file mode 100644 index 000000000..d84a771d9 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/edit/index.vue @@ -0,0 +1,98 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/task/index.vue b/apps/web-ele/src/views/mes/pro/task/index.vue new file mode 100644 index 000000000..d59becc30 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/index.vue @@ -0,0 +1,152 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/task/modules/schedule-form.vue b/apps/web-ele/src/views/mes/pro/task/modules/schedule-form.vue new file mode 100644 index 000000000..4fd73cc93 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/modules/schedule-form.vue @@ -0,0 +1,154 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/task/modules/task-form.vue b/apps/web-ele/src/views/mes/pro/task/modules/task-form.vue new file mode 100644 index 000000000..9821ed760 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/modules/task-form.vue @@ -0,0 +1,113 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/task/modules/task-list.vue b/apps/web-ele/src/views/mes/pro/task/modules/task-list.vue new file mode 100644 index 000000000..fcd3304f5 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/modules/task-list.vue @@ -0,0 +1,162 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/materialstock/data.ts b/apps/web-ele/src/views/mes/wm/materialstock/data.ts index ce1102efd..dac1d54c0 100644 --- a/apps/web-ele/src/views/mes/wm/materialstock/data.ts +++ b/apps/web-ele/src/views/mes/wm/materialstock/data.ts @@ -53,6 +53,12 @@ export function useGridFormSchema(): VbenFormSchema[] { placeholder: '请选择库区', warehouseId: values.warehouseId, }), + // 仓库切换时清空库区,避免旧库区条件残留 + trigger: (values, formApi) => { + if (values.locationId !== undefined) { + void formApi.setFieldValue('locationId', undefined); + } + }, }, }, { @@ -191,6 +197,12 @@ export function useSelectGridFormSchema(): VbenFormSchema[] { placeholder: '请选择库区', warehouseId: values.warehouseId, }), + // 仓库切换时清空库区 + trigger: (values, formApi) => { + if (values.locationId !== undefined) { + void formApi.setFieldValue('locationId', undefined); + } + }, }, }, { @@ -198,11 +210,17 @@ export function useSelectGridFormSchema(): VbenFormSchema[] { label: '库位', component: markRaw(WmWarehouseAreaSelect), dependencies: { - triggerFields: ['locationId'], + triggerFields: ['warehouseId', 'locationId'], componentProps: (values) => ({ locationId: values.locationId, placeholder: '请选择库位', }), + // 仓库或库区切换时清空库位 + trigger: (values, formApi) => { + if (values.areaId !== undefined) { + void formApi.setFieldValue('areaId', undefined); + } + }, }, }, ];