From 858df78951d5c29e8d4217cffcf81d2cc4fabcd4 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 03 八月 2026 14:58:59 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro2.0' into dev_pro2.0
---
src/views/mes/pro/workorder/modules/form.vue | 159 +++++++++++++++++++++++++++++++----------------------
1 files changed, 93 insertions(+), 66 deletions(-)
diff --git a/src/views/mes/pro/workorder/modules/form.vue b/src/views/mes/pro/workorder/modules/form.vue
index bc00c84..5da9d79 100644
--- a/src/views/mes/pro/workorder/modules/form.vue
+++ b/src/views/mes/pro/workorder/modules/form.vue
@@ -2,7 +2,6 @@
import type { FormType } from "../data";
import type { MesProWorkOrderApi } from "#/api/mes/pro/workorder";
- import type { MesProWorkOrderBomApi } from "#/api/mes/pro/workorder/bom";
import type { MesProWorkOrderProcessApi } from "#/api/mes/pro/workorder/process";
import { computed, ref } from "vue";
@@ -23,12 +22,15 @@
getWorkOrder,
updateWorkOrder,
} from "#/api/mes/pro/workorder";
- import { batchSaveWorkOrderProcess } from "#/api/mes/pro/workorder/process";
+ import { batchSaveWorkOrderProcess, getWorkOrderProcessListByWorkOrderId } from "#/api/mes/pro/workorder/process";
import { $t } from "#/locales";
import { BarcodeDetail } from "#/views/wls/barcode/components";
import { useFormSchema } from "../data";
- import BomList from "./bom-list.vue";
+ import PredictDelivery from "./ai/predict-delivery.vue";
+ import PredictDuration from "./ai/predict-duration.vue";
+ import PredictMaterial from "./ai/predict-material.vue";
+ import PredictRisk from "./ai/predict-risk.vue";
import ItemList from "./item-list.vue";
import ProcessList from "./process-list.vue";
@@ -36,7 +38,7 @@
const formType = ref<FormType>("create");
const formData = ref<MesProWorkOrderApi.WorkOrder>();
const originalSnapshot = ref("");
- const subTabsName = ref("bom");
+ const subTabsName = ref("process");
const barcodeDetailRef = ref<InstanceType<typeof BarcodeDetail>>();
const processListRef = ref<InstanceType<typeof ProcessList>>();
const currentProductId = ref<number>(); // 褰撳墠閫変腑鐨勪骇鍝� ID锛堢敤浜庡伐搴忓姞杞斤級
@@ -52,6 +54,12 @@
() =>
formType.value === "update" &&
formData.value?.status === MesProWorkOrderStatusEnum.PREPARE
+ );
+ const canUseAi = computed(
+ () =>
+ formData.value?.id &&
+ (formData.value?.status === MesProWorkOrderStatusEnum.PREPARE ||
+ formData.value?.status === MesProWorkOrderStatusEnum.CONFIRMED)
);
const getTitle = computed(() => {
const isChild = !!formData.value?.parentId;
@@ -101,17 +109,41 @@
});
/** 閲嶆柊鎸傝浇 schema 骞舵寜琛ㄥ崟鎬佹帶鍒跺簳閮ㄦ寜閽� */
+ const mainActionText = computed(() => {
+ if (isConfirm.value) return '纭';
+ if (isFinish.value) return '瀹屾垚';
+ return '鎻愪氦';
+ });
+
+ const showMainBtn = computed(() => isEditable.value || isConfirm.value || isFinish.value);
+
function applySchema() {
formApi.setState({ schema: useFormSchema(formType.value, formApi) });
- const showBtn = isEditable.value || isConfirm.value || isFinish.value;
- modalApi.setState({
- showConfirmButton: showBtn,
- confirmText: isConfirm.value || canConfirm.value
- ? '纭'
- : isFinish.value
- ? '瀹屾垚'
- : undefined,
- });
+ modalApi.setState({ showCancelButton: false, showConfirmButton: false });
+ }
+
+ /** 浠呬繚瀛橈紙涓嶆敼鍙樼姸鎬侊級 */
+ async function handleSave() {
+ const { valid } = await formApi.validate();
+ if (!valid || !formData.value?.id) return;
+ modalApi.lock();
+ try {
+ const data = (await formApi.getValues()) as MesProWorkOrderApi.WorkOrder;
+ await updateWorkOrder({ ...formData.value, ...data });
+ if (tempProcessList.value.length > 0) {
+ const processList = tempProcessList.value.map(item => ({
+ ...item,
+ workOrderId: formData.value!.id,
+ }));
+ await batchSaveWorkOrderProcess(processList);
+ }
+ formData.value = { ...formData.value, ...data };
+ originalSnapshot.value = JSON.stringify(await formApi.getValues());
+ emit('success');
+ message.success($t('ui.actionMessage.operationSuccess'));
+ } finally {
+ modalApi.unlock();
+ }
}
/** 鏌ョ湅璁㈠崟鏉$爜 */
@@ -125,39 +157,6 @@
formData.value.code,
formData.value.name
);
- }
-
- /** 浠� BOM 鐗╂枡琛岄濉瓙璁㈠崟 */
- async function handleGenerateWorkOrder(
- bomRow: MesProWorkOrderBomApi.WorkOrderBom
- ) {
- const current = formData.value;
- if (!current) {
- return;
- }
- formData.value = undefined;
- formType.value = "create";
- subTabsName.value = "bom";
- applySchema();
- await formApi.resetForm();
- await formApi.setValues({
- clientId: current.clientId,
- name: `${bomRow.itemName}銆�${bomRow.quantity}銆�${
- bomRow.unitMeasureName || ""
- }`,
- orderSourceCode: current.orderSourceCode,
- orderSourceType: current.orderSourceType,
- parentId: current.id,
- productId: bomRow.itemId,
- quantity: bomRow.quantity,
- requestDate: current.requestDate,
- type: current.type,
- vendorId: current.vendorId,
- });
- // 璁剧疆褰撳墠浜у搧 ID锛岃Е鍙戝伐搴忓姞杞�
- currentProductId.value = bomRow.itemId;
- originalSnapshot.value = JSON.stringify(await formApi.getValues());
- message.info("宸蹭粠 BOM 鐗╂枡棰勫~瀛愯鍗曪紝璇疯ˉ鍏呰鍗曠紪鐮佺瓑淇℃伅鍚庝繚瀛�");
}
/** 宸ュ簭鍒楄〃鍙樺寲鍥炶皟 */
@@ -195,7 +194,13 @@
}));
await batchSaveWorkOrderProcess(processList);
}
- // 3. 纭宸ュ崟
+ // 3. 鏍¢獙鏄惁鏈夊伐搴�
+ const processes = await getWorkOrderProcessListByWorkOrderId(formData.value.id);
+ if (!processes || processes.length === 0) {
+ message.warning('褰撳墠璁㈠崟鏈厤缃伐搴忥紝璇峰厛鍦ㄥ伐鍗曚腑缁存姢宸ュ簭淇℃伅鍚庡啀纭');
+ return;
+ }
+ // 4. 纭宸ュ崟
await confirmWorkOrder(formData.value.id);
message.success('璁㈠崟宸茬‘璁�');
await modalApi.close();
@@ -208,6 +213,12 @@
// ---- 瀹屾垚璁㈠崟妯″紡 ----
if (isFinish.value) {
if (!formData.value?.id) return;
+ // 鏍¢獙鏄惁鏈夊伐搴�
+ const processes = await getWorkOrderProcessListByWorkOrderId(formData.value.id);
+ if (!processes || processes.length === 0) {
+ message.warning('褰撳墠璁㈠崟鏈厤缃伐搴忥紝璇峰厛鍦ㄥ伐鍗曚腑缁存姢宸ュ簭淇℃伅鍚庡啀瀹屾垚');
+ return;
+ }
try {
await confirm('纭瑕佸畬鎴愯璁㈠崟鍚楋紵');
} catch {
@@ -289,7 +300,7 @@
parentRow?: MesProWorkOrderApi.WorkOrder;
}>();
formType.value = data.formType;
- subTabsName.value = "bom";
+ subTabsName.value = "process";
tempProcessList.value = [];
applySchema();
if (data?.id) {
@@ -320,25 +331,16 @@
<template>
<Modal :title="getTitle"
- class="w-3/5">
+ class="w-3/5"
+ content-class="!max-h-[80vh] overflow-y-auto">
<Form class="mx-4" />
- <!-- BOM / 宸ュ簭 / 鐗╂枡闇�姹� Tab -->
+ <!-- 宸ュ簭 / 鐗╂枡闇�姹� Tab -->
<template v-if="showTabs">
<Tabs v-model:active-key="subTabsName"
class="mx-4">
- <Tabs.TabPane key="bom"
- tab="璁㈠崟 BOM">
- <BomList v-if="formData?.id"
- :form-type="formType"
- :work-order="formData"
- :work-order-id="formData.id"
- @generate-work-order="handleGenerateWorkOrder" />
- <div v-else class="text-gray-400 text-center py-8">
- 璇峰厛淇濆瓨宸ュ崟鍚庡啀閰嶇疆 BOM
- </div>
- </Tabs.TabPane>
<Tabs.TabPane key="process"
- tab="宸ュ簭">
+ tab="宸ュ簭"
+ forceRender>
<ProcessList
ref="processListRef"
:form-type="formType"
@@ -359,10 +361,35 @@
</Tabs>
</template>
<template #prepend-footer>
- <Button v-if="formType === 'detail' && formData?.id"
- @click="handleBarcode">
- 鏌ョ湅鏉$爜
- </Button>
+ <div class="flex flex-auto flex-col gap-2">
+ <div v-if="canUseAi" class="flex items-center gap-2">
+ <PredictMaterial :work-order-id="formData!.id" />
+ <PredictDuration :work-order-id="formData!.id" />
+ <PredictRisk :work-order-id="formData!.id" />
+ <PredictDelivery :work-order-id="formData!.id" />
+ </div>
+ <div v-if="canUseAi && showMainBtn" class="border-t border-gray-200" />
+ <div class="flex items-center">
+ <Button v-if="showMainBtn"
+ type="primary"
+ @click="modalApi.onConfirm()">
+ {{ mainActionText }}
+ </Button>
+ </div>
+ </div>
+ </template>
+ <template #append-footer>
+ <div class="flex gap-2">
+ <Button v-if="canConfirm"
+ @click="handleSave">
+ 淇濆瓨淇敼
+ </Button>
+ <Button v-if="formType === 'detail' && formData?.id"
+ @click="handleBarcode">
+ 鏌ョ湅鏉$爜
+ </Button>
+ <Button @click="modalApi.close()">鍙栨秷</Button>
+ </div>
</template>
</Modal>
<BarcodeDetail ref="barcodeDetailRef" />
--
Gitblit v1.9.3