From 3f0856494e2265305b33a06d41796237c6eeda9f Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 29 七月 2026 17:45:33 +0800
Subject: [PATCH] 银川 1.生产任务 - 选工作站自动计算生产时长 2.生产流程 - 查看产品设计归档及附件
---
src/views/mes/pro/feedback/index.vue | 11 +++++
src/views/mes/pro/task/data.ts | 44 ++++++++++++++++++---
src/views/mes/pro/task/index.vue | 8 ++++
src/api/mes/pro/task/index.ts | 8 ++++
src/views/mes/dv/machinery/data.ts | 24 +----------
src/views/mes/pro/workorder/index.vue | 12 +++++-
src/views/mes/pro/workorder-center/index.vue | 8 ++++
7 files changed, 85 insertions(+), 30 deletions(-)
diff --git a/src/api/mes/pro/task/index.ts b/src/api/mes/pro/task/index.ts
index 2e36c40..515185b 100644
--- a/src/api/mes/pro/task/index.ts
+++ b/src/api/mes/pro/task/index.ts
@@ -166,3 +166,11 @@
{ params },
);
}
+
+/** 鏍规嵁宸ヤ綔绔欏拰鏁伴噺璁$畻鐢熶骇鏃堕暱 */
+export function calculateTaskDuration(workstationId: number, quantity: number) {
+ return requestClient.get<{ duration: number }>(
+ '/mes/pro/task/calculate-duration',
+ { params: { workstationId, quantity } },
+ );
+}
diff --git a/src/views/mes/dv/machinery/data.ts b/src/views/mes/dv/machinery/data.ts
index 5be398e..8b39782 100644
--- a/src/views/mes/dv/machinery/data.ts
+++ b/src/views/mes/dv/machinery/data.ts
@@ -15,7 +15,7 @@
import { z } from '#/adapter/form';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
-import { MdWorkshopSelect, MdWorkstationSelect } from '#/views/mes/md/workstation/components';
+import { MdWorkshopSelect } from '#/views/mes/md/workstation/components';
import { DvMachineryTypeSelect } from './type/components';
@@ -120,7 +120,7 @@
class: '!w-full',
min: 0,
precision: 2,
- placeholder: '璇疯緭鍏ョ敓浜ф晥鐜�(姣忓垎閽�)',
+ placeholder: '璇疯緭鍏ョ敓浜ф晥鐜�(姣忓皬鏃�)',
},
},
{
@@ -134,14 +134,6 @@
placeholder: '璇疯緭鍏ヤ紶閫佸饱甯︽暟閲�',
},
help: '2浠h〃鍙屽�嶆晥鐜�',
- },
- {
- fieldName: 'workstationId',
- label: '宸ヤ綔绔�',
- component: markRaw(MdWorkstationSelect),
- componentProps: {
- placeholder: '璇烽�夋嫨宸ヤ綔绔�',
- },
},
{
fieldName: 'specification',
@@ -236,15 +228,6 @@
placeholder: '璇烽�夋嫨璁惧鐘舵��',
},
},
- {
- fieldName: 'workstationId',
- label: '宸ヤ綔绔�',
- component: markRaw(MdWorkstationSelect),
- componentProps: {
- allowClear: true,
- placeholder: '璇烽�夋嫨宸ヤ綔绔�',
- },
- },
];
}
@@ -273,9 +256,8 @@
props: { type: DICT_TYPE.MES_DV_MACHINERY_STATUS },
},
},
- { field: 'productionEfficiency', title: '鐢熶骇鏁堢巼', width: 120 },
+ { field: 'productionEfficiency', title: '鐢熶骇鏁堢巼(/h)', width: 120 },
{ field: 'conveyorBelt', title: '浼犻�佸饱甯�', width: 100 },
- { field: 'workstationName', title: '宸ヤ綔绔�', minWidth: 140 },
{
field: 'lastCheckTime',
title: '鏈�杩戠偣妫�鏃堕棿',
diff --git a/src/views/mes/pro/feedback/index.vue b/src/views/mes/pro/feedback/index.vue
index 239da4a..1793ebb 100644
--- a/src/views/mes/pro/feedback/index.vue
+++ b/src/views/mes/pro/feedback/index.vue
@@ -17,10 +17,13 @@
} from '#/api/mes/pro/feedback';
import { $t } from '#/locales';
+import { ref } from 'vue';
+
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
import QuickFeedbackForm from '../workorder-center/modules/quick-feedback.vue';
import BatchFeedbackForm from './modules/batch-feedback.vue';
+import ArchiveDetail from '#/views/mes/pd/archive/modules/detail.vue';
const userStore = useUserStore();
const currentUserId = userStore.userInfo?.id; // 褰撳墠鐧诲綍鐢ㄦ埛 ID锛岀敤浜庡鎵逛汉鏉冮檺鍒ゆ柇
@@ -39,6 +42,8 @@
connectedComponent: BatchFeedbackForm,
destroyOnClose: true,
});
+
+const archiveDetailRef = ref<InstanceType<typeof ArchiveDetail>>();
/** 鍒锋柊琛ㄦ牸 */
function handleRefresh() {
@@ -205,9 +210,15 @@
confirm: handleDelete.bind(null, row),
},
},
+ {
+ label: '褰掓。',
+ type: 'link',
+ onClick: () => archiveDetailRef.value?.open(row.itemCode),
+ },
]"
/>
</template>
</Grid>
+ <ArchiveDetail ref="archiveDetailRef" />
</Page>
</template>
diff --git a/src/views/mes/pro/task/data.ts b/src/views/mes/pro/task/data.ts
index bba413d..a24e576 100644
--- a/src/views/mes/pro/task/data.ts
+++ b/src/views/mes/pro/task/data.ts
@@ -10,7 +10,10 @@
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
+import { message } from 'ant-design-vue';
+
import CrmCustomerSelect from '#/components/crm-customer-select.vue';
+import { calculateTaskDuration } from '#/api/mes/pro/task';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
@@ -386,6 +389,7 @@
component: markRaw(MdWorkstationSelect),
componentProps: {
placeholder: '璇烽�夋嫨宸ヤ綔绔�',
+ onChange: () => recalcDuration(formApi),
},
rules: 'selectRequired',
},
@@ -399,6 +403,7 @@
min: 0.01,
placeholder: '璇疯緭鍏ユ帓浜ф暟閲�',
precision: 2,
+ onChange: () => recalcDuration(formApi),
},
rules: 'required',
},
@@ -413,11 +418,17 @@
component: 'DatePicker',
componentProps: {
class: '!w-full',
- placeholder: '璇烽�夋嫨寮�濮嬫椂闂�',
+ placeholder: '璇峰厛閫夋嫨宸ヤ綔绔�',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
- // 寮�濮嬫椂闂村彉鏇达細閲嶆柊璁$畻缁撴潫鏃堕棿
onChange: () => recalcEndTime(formApi),
+ },
+ dependencies: {
+ triggerFields: ['workstationId'],
+ componentProps: (values) => ({
+ disabled: !values.workstationId,
+ placeholder: values.workstationId ? '璇烽�夋嫨寮�濮嬫椂闂�' : '璇峰厛閫夋嫨宸ヤ綔绔�',
+ }),
},
rules: 'required',
},
@@ -459,6 +470,24 @@
];
}
+/** 閫夋嫨宸ヤ綔绔欐垨淇敼鏁伴噺鍚庯紝鑷姩璁$畻鐢熶骇鏃堕暱 */
+async function recalcDuration(formApi?: VbenFormApi) {
+ if (!formApi) return;
+ const values = await formApi.getValues();
+ if (!values.workstationId || !values.quantity) return;
+ try {
+ const res = await calculateTaskDuration(values.workstationId, values.quantity);
+ await formApi.setFieldValue('duration', res.duration);
+ if (res.duration === 0) {
+ message.warning('璇ュ伐浣滅珯鏈粦瀹氳澶囷紝鎴栫粦瀹氳澶囨湭閰嶇疆鐢熶骇鏁堢巼');
+ }
+ // 閲嶆柊璁$畻缁撴潫鏃堕棿
+ await recalcEndTime(formApi);
+ } catch {
+ // 璁$畻澶辫触涓嶉樆濉炵敤鎴锋搷浣�
+ }
+}
+
/** 璁$畻缁撴潫鏃堕棿锛氬紑濮嬫椂闂� + 鐢熶骇鏃堕暱锛堝皬鏃讹級 */
async function recalcEndTime(formApi?: VbenFormApi) {
if (!formApi) {
@@ -466,11 +495,12 @@
}
const values = await formApi.getValues();
if (values.startTime && values.duration) {
- const start = Number(values.startTime);
- await formApi.setFieldValue(
- 'endTime',
- start + values.duration * 3600 * 1000,
- );
+ const start = new Date(values.startTime).getTime();
+ const endTime = start + values.duration * 3600 * 1000;
+ const pad = (n: number) => String(n).padStart(2, '0');
+ const d = new Date(endTime);
+ const formatted = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
+ await formApi.setFieldValue('endTime', formatted);
}
}
diff --git a/src/views/mes/pro/task/index.vue b/src/views/mes/pro/task/index.vue
index f062c80..e4002ea 100644
--- a/src/views/mes/pro/task/index.vue
+++ b/src/views/mes/pro/task/index.vue
@@ -17,6 +17,7 @@
import { getGanttTaskList, previewAutoGenerate, autoGenerateTasks } from '#/api/mes/pro/task';
import { getWorkOrderPage } from '#/api/mes/pro/workorder';
+import ArchiveDetail from '#/views/mes/pd/archive/modules/detail.vue';
import { GanttChart } from './components';
import { useGridColumns, useGridFormSchema } from './data';
import ScheduleForm from './modules/schedule-form.vue';
@@ -24,6 +25,7 @@
const router = useRouter();
const ganttTasks = ref<any[]>([]); // 鐢樼壒鍥鹃瑙堟暟鎹�
+const archiveDetailRef = ref<InstanceType<typeof ArchiveDetail>>();
const [ScheduleModal, scheduleModalApi] = useVbenModal({
connectedComponent: ScheduleForm,
@@ -166,9 +168,15 @@
ifShow: row.status === MesProWorkOrderStatusEnum.CONFIRMED,
onClick: handleSchedule.bind(null, row),
},
+ {
+ label: '褰掓。',
+ type: 'link',
+ onClick: () => archiveDetailRef.value?.open(row.productCode),
+ },
]"
/>
</template>
</Grid>
+ <ArchiveDetail ref="archiveDetailRef" />
</Page>
</template>
diff --git a/src/views/mes/pro/workorder-center/index.vue b/src/views/mes/pro/workorder-center/index.vue
index 74b05b7..99ada7d 100644
--- a/src/views/mes/pro/workorder-center/index.vue
+++ b/src/views/mes/pro/workorder-center/index.vue
@@ -18,11 +18,13 @@
} from '#/api/mes/pro/workorder';
import { previewAutoGenerate, autoGenerateTasks } from '#/api/mes/pro/task';
+import ArchiveDetail from '#/views/mes/pd/archive/modules/detail.vue';
import { useGridColumns, useGridFormSchema, useTaskGridColumns } from './data';
import QuickFeedbackForm from './modules/quick-feedback.vue';
import SchedulePreviewModal from './modules/schedule-preview.vue';
defineOptions({ name: 'WorkorderCenter' });
+const archiveDetailRef = ref<InstanceType<typeof ArchiveDetail>>();
const router = useRouter();
@@ -207,6 +209,11 @@
confirm: handleScheduleExecute.bind(null, row),
},
},
+ {
+ label: '褰掓。',
+ type: 'link',
+ onClick: () => archiveDetailRef.value?.open(row.productCode),
+ },
]"
/>
</template>
@@ -309,5 +316,6 @@
</Collapse.Panel>
</Collapse>
</Card>
+ <ArchiveDetail ref="archiveDetailRef" />
</Page>
</template>
diff --git a/src/views/mes/pro/workorder/index.vue b/src/views/mes/pro/workorder/index.vue
index 6510afd..e3c8248 100644
--- a/src/views/mes/pro/workorder/index.vue
+++ b/src/views/mes/pro/workorder/index.vue
@@ -22,7 +22,8 @@
getWorkOrderPage,
} from "#/api/mes/pro/workorder";
import { $t } from "#/locales";
- import { BarcodeDetail } from "#/views/wls/barcode/components";
+ import ArchiveDetail from '#/views/mes/pd/archive/modules/detail.vue';
+import { BarcodeDetail } from '#/views/wls/barcode/components';
import { useGridColumns, useGridFormSchema } from "./data";
import Form from "./modules/form.vue";
@@ -32,7 +33,8 @@
destroyOnClose: true,
});
- const barcodeDetailRef = ref<InstanceType<typeof BarcodeDetail>>(); // 鏉$爜璇︽儏寮圭獥
+ const archiveDetailRef = ref<InstanceType<typeof ArchiveDetail>>();
+const barcodeDetailRef = ref<InstanceType<typeof BarcodeDetail>>(); // 鏉$爜璇︽儏寮圭獥
/** 鍒锋柊琛ㄦ牸 */
function handleRefresh() {
@@ -225,9 +227,15 @@
auth: ['mes:pro-work-order:query'],
onClick: handleBarcode.bind(null, row),
},
+ {
+ label: '褰掓。',
+ type: 'link',
+ onClick: () => archiveDetailRef.value?.open(row.productCode),
+ },
]" />
</template>
</Grid>
<BarcodeDetail ref="barcodeDetailRef" />
+ <ArchiveDetail ref="archiveDetailRef" />
</Page>
</template>
--
Gitblit v1.9.3