From 70b7935fc261cd5e8eaaf1cfbc8078b04db576d2 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期六, 07 十一月 2026 14:51:06 +0800
Subject: [PATCH] fix(mes): 自动回填销售订单生产信息

---
 src/views/mes/md/item/index.vue                |   12 +++
 src/views/mes/pro/workorder/modules/form.vue   |    2 
 src/views/mes/pro/workorder/sale-order-fill.ts |   30 ++++++++++
 src/api/mes/md/item/index.ts                   |    8 ++
 src/views/mes/pro/workorder/data.ts            |   39 +++++++++++-
 src/views/mes/md/item/type/components/tree.vue |   31 +++++++++-
 6 files changed, 111 insertions(+), 11 deletions(-)

diff --git a/src/api/mes/md/item/index.ts b/src/api/mes/md/item/index.ts
index 4469943..309935c 100644
--- a/src/api/mes/md/item/index.ts
+++ b/src/api/mes/md/item/index.ts
@@ -6,6 +6,7 @@
   /** MES 鐗╂枡浜у搧 */
   export interface Item {
     id?: number; // 鐗╂枡缂栧彿
+    mdmItemId?: number; // MDM 鐗╂枡缂栧彿
     code?: string; // 鐗╂枡缂栫爜
     name?: string; // 鐗╂枡鍚嶇О
     specification?: string; // 瑙勬牸鍨嬪彿
@@ -45,6 +46,13 @@
   return requestClient.get<MesMdItemApi.Item>(`/mes/md/item/get?id=${id}`);
 }
 
+/** 鏍规嵁 MDM 鐗╂枡缂栧彿鏌ヨ MES 鐗╂枡浜у搧 */
+export function getItemByMdmItemId(mdmItemId: number) {
+  return requestClient.get<MesMdItemApi.Item>(
+    `/mes/md/item/get-by-mdm-item-id?mdmItemId=${mdmItemId}`,
+  );
+}
+
 /** 鏂板鐗╂枡浜у搧 */
 export function createItem(data: MesMdItemApi.Item) {
   return requestClient.post<number>('/mes/md/item/create', data);
diff --git a/src/views/mes/md/item/index.vue b/src/views/mes/md/item/index.vue
index 901c90c..bb1b68e 100644
--- a/src/views/mes/md/item/index.vue
+++ b/src/views/mes/md/item/index.vue
@@ -76,7 +76,11 @@
 
   /** 瀵煎嚭鐗╂枡 */
   async function handleExport() {
-    const data = await exportItem(await gridApi.formApi.getValues());
+    const data = await exportItem({
+      ...(await gridApi.formApi.getValues()),
+      itemTypeId: selectedItemTypeId.value,
+      excludeItemTypeCode: "EQUIPMENT",
+    });
     downloadFileFromBlobPart({ fileName: "鐗╂枡浜у搧.xls", source: data });
   }
 
@@ -107,6 +111,7 @@
               pageSize: page.pageSize,
               ...formValues,
               itemTypeId: selectedItemTypeId.value,
+              excludeItemTypeCode: "EQUIPMENT",
             });
           },
         },
@@ -132,7 +137,10 @@
         class="mr-4 h-full w-1/6"
         :body-style="{ height: '100%', overflow: 'hidden' }"
       >
-        <MdItemTypeTree @node-click="handleTypeNodeClick" />
+        <MdItemTypeTree
+          :exclude-codes="['EQUIPMENT']"
+          @node-click="handleTypeNodeClick"
+        />
       </Card>
       <div class="w-5/6">
         <Grid table-title="鐗╂枡浜у搧鍒楄〃">
diff --git a/src/views/mes/md/item/type/components/tree.vue b/src/views/mes/md/item/type/components/tree.vue
index be62a8c..f92ab02 100644
--- a/src/views/mes/md/item/type/components/tree.vue
+++ b/src/views/mes/md/item/type/components/tree.vue
@@ -12,11 +12,13 @@
 
 defineOptions({ name: 'MdItemTypeTree' });
 
-withDefaults(
+const props = withDefaults(
   defineProps<{
+    excludeCodes?: string[];
     filterPlaceholder?: string;
   }>(),
   {
+    excludeCodes: () => [],
     filterPlaceholder: '鎼滅储鍒嗙被',
   },
 );
@@ -32,13 +34,36 @@
 const itemTypeList = ref<MesMdItemTypeApi.ItemType[]>([]); // 鐗╂枡鍒嗙被鍒楄〃
 const itemTypeTree = ref<any[]>([]); // 鐗╂枡鍒嗙被鏍�
 
+/** 鎸夊垎绫荤紪鐮佹帓闄ゅ垎绫诲強鍏跺叏閮ㄥ瓙鍒嗙被 */
+function filterExcludedTypes(data: MesMdItemTypeApi.ItemType[]) {
+  const excludedIds = new Set<number>();
+  let changed = true;
+  while (changed) {
+    changed = false;
+    for (const item of data) {
+      if (
+        item.id !== undefined &&
+        (props.excludeCodes.includes(item.code ?? '') ||
+          (item.parentId !== undefined && excludedIds.has(item.parentId))) &&
+        !excludedIds.has(item.id)
+      ) {
+        excludedIds.add(item.id);
+        changed = true;
+      }
+    }
+  }
+  return data.filter(
+    (item) => item.id === undefined || !excludedIds.has(item.id),
+  );
+}
+
 /** 鍔犺浇鍒嗙被鏍� */
 async function loadTree() {
   loading.value = true;
   try {
     const data = await getItemTypeSimpleList();
-    itemTypeList.value = data;
-    itemTypeTree.value = handleTree(data, 'id', 'parentId');
+    itemTypeList.value = filterExcludedTypes(data);
+    itemTypeTree.value = handleTree(itemTypeList.value, 'id', 'parentId');
   } finally {
     loading.value = false;
   }
diff --git a/src/views/mes/pro/workorder/data.ts b/src/views/mes/pro/workorder/data.ts
index 1006dd8..73721e3 100644
--- a/src/views/mes/pro/workorder/data.ts
+++ b/src/views/mes/pro/workorder/data.ts
@@ -15,9 +15,11 @@
 } from '@vben/constants';
 import { getDictOptions } from '@vben/hooks';
 
-import { Button } from 'ant-design-vue';
+import { Button, message } from 'ant-design-vue';
 
 import { generateAutoCode } from '#/api/mes/md/autocode/record';
+import { getItemByMdmItemId } from '#/api/mes/md/item';
+import { getSaleOrderItemListByOrderId } from '#/api/erp/sale/order';
 import CrmCustomerSelect from '#/components/crm-customer-select.vue';
 import { getRangePickerDefaultProps } from '#/utils';
 import {
@@ -25,6 +27,8 @@
 } from '#/views/mes/md/item/components';
 import { SrmSupplierSelect } from '#/views/srm/supplier/components';
 import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components';
+
+import { summarizeProductionProduct } from './sale-order-fill';
 
 /** 琛ㄥ崟绫诲瀷 */
 export type FormType = 'confirm' | 'create' | 'detail' | 'finish' | 'update';
@@ -208,15 +212,40 @@
       componentProps: {
         disabled: headerReadonly,
         placeholder: '璇烽�夋嫨钀ラ攢璁㈠崟锛圗RP閿�鍞鍗曪級',
-        // 閫変腑钀ラ攢璁㈠崟鍚庤嚜鍔ㄥ甫鍏ュ鎴�
+        // 閫変腑钀ラ攢璁㈠崟鍚庤嚜鍔ㄥ甫鍏ュ鎴枫�佹潵婧愬崟鍙枫�佷骇鍝佸拰鏁伴噺
         onChange: async (item?: ErpSaleOrderApi.SaleOrder) => {
           if (!item) {
             return;
           }
-          const values = (await formApi?.getValues()) ?? {};
-          if (values.clientId == null && item.customerId) {
-            await formApi?.setFieldValue('clientId', item.customerId);
+          await formApi?.setValues({
+            clientId: item.customerId,
+            orderSourceCode: item.no,
+            productId: undefined,
+            quantity: undefined,
+          });
+          if (!item.id) {
+            return;
           }
+          const orderItems = await getSaleOrderItemListByOrderId(item.id);
+          const products = summarizeProductionProduct(orderItems ?? []);
+          if (products.length === 0) {
+            message.warning('璇ラ攢鍞鍗曟病鏈夐渶瑕佺敓浜х殑浜у搧鏄庣粏');
+            return;
+          }
+          if (products.length > 1) {
+            message.warning('璇ラ攢鍞鍗曞寘鍚涓敓浜т骇鍝侊紝璇烽�夋嫨鍏蜂綋浜у搧骞跺~鍐欐暟閲�');
+            return;
+          }
+          const [product] = products;
+          const mesItem = await getItemByMdmItemId(product!.mdmProductId);
+          if (!mesItem?.id) {
+            message.warning('閿�鍞鍗曚骇鍝佸皻鏈悓姝ュ埌鐢熶骇鐗╂枡锛岃鍏堝悓姝ヤ骇鍝佷富鏁版嵁');
+            return;
+          }
+          await formApi?.setValues({
+            productId: mesItem.id,
+            quantity: product!.quantity,
+          });
         },
       },
       dependencies: {
diff --git a/src/views/mes/pro/workorder/modules/form.vue b/src/views/mes/pro/workorder/modules/form.vue
index 1b24e67..4a2e9c6 100644
--- a/src/views/mes/pro/workorder/modules/form.vue
+++ b/src/views/mes/pro/workorder/modules/form.vue
@@ -90,7 +90,7 @@
       // 浜у搧鍙樻洿鏃讹紝瑙﹀彂宸ュ簭鍔犺浇
       if (isCreateMode.value && fieldsChanged.includes('productId')) {
         const newProductId = values.productId;
-        if (newProductId && newProductId !== currentProductId.value) {
+        if (newProductId !== currentProductId.value) {
           currentProductId.value = newProductId;
         }
       }
diff --git a/src/views/mes/pro/workorder/sale-order-fill.ts b/src/views/mes/pro/workorder/sale-order-fill.ts
new file mode 100644
index 0000000..c07287a
--- /dev/null
+++ b/src/views/mes/pro/workorder/sale-order-fill.ts
@@ -0,0 +1,30 @@
+import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
+
+export interface SaleOrderProductSummary {
+  mdmProductId: number;
+  quantity: number;
+}
+
+/**
+ * 姹囨�婚攢鍞鍗曚腑闇�瑕佺敓浜х殑浜у搧銆�
+ * 鍚屼竴浜у搧鍙瓨鍦ㄥ琛岋紝鐢熶骇宸ュ崟鍙渶瑕佷竴鏉′骇鍝佸強鍚堣鏁伴噺銆�
+ */
+export function summarizeProductionProduct(
+  items: ErpSaleOrderApi.SaleOrderItem[],
+): SaleOrderProductSummary[] {
+  const productionItems = items.filter(
+    (item) => item.needProduction === 1 && item.productId != null,
+  );
+  const quantityByProduct = new Map<number, number>();
+  for (const item of productionItems) {
+    const productId = item.productId!;
+    quantityByProduct.set(
+      productId,
+      (quantityByProduct.get(productId) ?? 0) + Number(item.count ?? 0),
+    );
+  }
+  return [...quantityByProduct.entries()].map(([mdmProductId, quantity]) => ({
+    mdmProductId,
+    quantity,
+  }));
+}

--
Gitblit v1.9.3