From dcde4b33fa739b09486c39faade9ed19b29a6d7a Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 03 八月 2026 14:58:35 +0800
Subject: [PATCH] feat(srm): 优化供应商选择组件功能

---
 src/api/srm/supplier/index.ts                       |    2 
 src/views/srm/supplier/components/select.vue        |    4 +
 src/views/srm/enums.ts                              |   31 ++++++++-------
 src/views/srm/supplier/components/select-dialog.vue |    7 +++
 src/views/srm/supplierApply/data.ts                 |    5 ++
 src/views/srm/tender/detail.vue                     |   44 +++++++++++++++++++++-
 6 files changed, 73 insertions(+), 20 deletions(-)

diff --git a/src/api/srm/supplier/index.ts b/src/api/srm/supplier/index.ts
index 27da1c2..60b176a 100644
--- a/src/api/srm/supplier/index.ts
+++ b/src/api/srm/supplier/index.ts
@@ -7,7 +7,7 @@
     id?: number;
     code: string;
     name: string;
-    type: number;
+    type: string;
     status: number;
     contactName?: string;
     contactMobile?: string;
diff --git a/src/views/srm/enums.ts b/src/views/srm/enums.ts
index 71712b5..4d014f1 100644
--- a/src/views/srm/enums.ts
+++ b/src/views/srm/enums.ts
@@ -36,29 +36,30 @@
   labels: { 0: '寮�鍚�', 1: '鍏抽棴' },
 };
 
-/** 渚涘簲鍟嗙被鍨� 鈥� 瀵归綈 SupplierTypeEnum (1=鐢熶骇鍨� 2=璐告槗鍨� 3=鏈嶅姟鍨� 4=鍏朵粬) */
+/** 渚涘簲鍟嗙被鍨� 鈥� 瀵归綈 SupplierTypeEnum (1=鐢熶骇鍨� 2=璐告槗鍨� 3=鏈嶅姟鍨� 4=鍏朵粬)
+ *  娉ㄦ剰锛氬悗绔� DO/RespVO 涓� type 涓� String 绫诲瀷锛屾澶勯�夐」鍊肩粺涓�鐢ㄥ瓧绗︿覆涓庡悗绔榻� */
 export const SUPPLIER_TYPE = {
-  PRODUCTION: 1,
-  TRADING: 2,
-  SERVICE: 3,
-  OTHER: 4,
+  PRODUCTION: '1',
+  TRADING: '2',
+  SERVICE: '3',
+  OTHER: '4',
 } as const;
 
 export const SUPPLIER_TYPE_OPTIONS: EnumOption[] = [
-  { label: '鐢熶骇鍨�', value: 1 },
-  { label: '璐告槗鍨�', value: 2 },
-  { label: '鏈嶅姟鍨�', value: 3 },
-  { label: '鍏朵粬', value: 4 },
+  { label: '鐢熶骇鍨�', value: '1' },
+  { label: '璐告槗鍨�', value: '2' },
+  { label: '鏈嶅姟鍨�', value: '3' },
+  { label: '鍏朵粬', value: '4' },
 ];
 
-export const SUPPLIER_TYPE_CELLTAG: { data: CellTagItem[]; labels: Record<number, string> } = {
+export const SUPPLIER_TYPE_CELLTAG: { data: CellTagItem[]; labels: Record<string, string> } = {
   data: [
-    { value: 1, color: 'blue' },
-    { value: 2, color: 'green' },
-    { value: 3, color: 'orange' },
-    { value: 4, color: 'default' },
+    { value: '1', color: 'blue' },
+    { value: '2', color: 'green' },
+    { value: '3', color: 'orange' },
+    { value: '4', color: 'default' },
   ],
-  labels: { 1: '鐢熶骇鍨�', 2: '璐告槗鍨�', 3: '鏈嶅姟鍨�', 4: '鍏朵粬' },
+  labels: { '1': '鐢熶骇鍨�', '2': '璐告槗鍨�', '3': '鏈嶅姟鍨�', '4': '鍏朵粬' },
 };
 
 // ========== 鍑嗗叆鐢宠 鈥� 瀵归綈 SupplierApplyStatusEnum (0/10/20/30/40/50) ==========
diff --git a/src/views/srm/supplier/components/select-dialog.vue b/src/views/srm/supplier/components/select-dialog.vue
index 1f3c614..431b1cf 100644
--- a/src/views/srm/supplier/components/select-dialog.vue
+++ b/src/views/srm/supplier/components/select-dialog.vue
@@ -20,6 +20,7 @@
 const open = ref(false);
 const multiple = ref(true);
 const approvalFilter = ref(true);
+const excludeApproved = ref(false);
 const selectedRows = ref<SrmSupplierApi.SupplierVO[]>([]);
 const preSelectedIds = ref<number[]>([]);
 
@@ -178,6 +179,9 @@
           if (approvalFilter.value) {
             params.approved = true;
           }
+          if (excludeApproved.value) {
+            params.excludeApproved = true;
+          }
           return await getSupplierPage(params);
         },
       },
@@ -211,11 +215,12 @@
 
 async function openModal(
   selectedIds?: number[],
-  options?: { multiple?: boolean; approvalFilter?: boolean },
+  options?: { multiple?: boolean; approvalFilter?: boolean; excludeApproved?: boolean },
 ) {
   open.value = true;
   multiple.value = options?.multiple ?? true;
   approvalFilter.value = options?.approvalFilter ?? true;
+  excludeApproved.value = options?.excludeApproved ?? false;
   preSelectedIds.value = selectedIds || [];
   await nextTick();
   gridApi.setGridOptions({
diff --git a/src/views/srm/supplier/components/select.vue b/src/views/srm/supplier/components/select.vue
index 0da35fd..25f7dd3 100644
--- a/src/views/srm/supplier/components/select.vue
+++ b/src/views/srm/supplier/components/select.vue
@@ -16,6 +16,7 @@
     allowClear?: boolean;
     approvalFilter?: boolean;
     disabled?: boolean;
+    excludeApproved?: boolean;
     modelValue?: number;
     placeholder?: string;
     supplierName?: string;
@@ -24,6 +25,7 @@
     allowClear: true,
     approvalFilter: true,
     disabled: false,
+    excludeApproved: false,
     modelValue: undefined,
     placeholder: '璇烽�夋嫨渚涘簲鍟�',
     supplierName: undefined,
@@ -66,7 +68,7 @@
   const selectedIds = (
     props.modelValue === null ? [] : [props.modelValue]
   ) as number[];
-  dialogRef.value?.open(selectedIds, { multiple: false, approvalFilter: props.approvalFilter });
+  dialogRef.value?.open(selectedIds, { multiple: false, approvalFilter: props.approvalFilter, excludeApproved: props.excludeApproved });
 }
 
 function handleSelected(rows: SrmSupplierApi.SupplierVO[]) {
diff --git a/src/views/srm/supplierApply/data.ts b/src/views/srm/supplierApply/data.ts
index 0e172a0..6b99c4c 100644
--- a/src/views/srm/supplierApply/data.ts
+++ b/src/views/srm/supplierApply/data.ts
@@ -27,6 +27,7 @@
       component: markRaw(SrmSupplierSelect),
       componentProps: {
         approvalFilter: false,
+        excludeApproved: true,
         placeholder: '璇烽�夋嫨SRM渚涘簲鍟嗭紙鎴栫洿鎺ュ~鍐欎緵搴斿晢鍚嶇О锛�',
         onChange: async (supplier?: SrmSupplierApi.SupplierVO) => {
           if (!supplier || !formApi) return;
@@ -37,6 +38,9 @@
             contactEmail: supplier.contactEmail || '',
             taxNo: supplier.taxNo || '',
             address: supplier.address || '',
+            bankName: supplier.bankName || '',
+            bankAccount: supplier.bankAccount || '',
+            remark: supplier.remark || '',
           });
         },
       },
@@ -44,6 +48,7 @@
         triggerFields: ['supplierName'],
         componentProps: (values) => ({
           approvalFilter: false,
+          excludeApproved: true,
           placeholder: '璇烽�夋嫨SRM渚涘簲鍟嗭紙鎴栫洿鎺ュ~鍐欎緵搴斿晢鍚嶇О锛�',
           supplierName: values.supplierName as string,
         }),
diff --git a/src/views/srm/tender/detail.vue b/src/views/srm/tender/detail.vue
index 772d2eb..7de94be 100644
--- a/src/views/srm/tender/detail.vue
+++ b/src/views/srm/tender/detail.vue
@@ -6,7 +6,7 @@
 
 import { Page } from '@vben/common-ui';
 
-import { message } from 'ant-design-vue';
+import { message, Modal } from 'ant-design-vue';
 import { IconifyIcon } from '@vben/icons';
 
 import {
@@ -63,6 +63,25 @@
 const materialLoading = ref(false);
 const materialFormVisible = ref(false);
 const materialForm = ref<SrmTenderApi.TenderMaterialVO>({ tenderProjectId: projectId });
+
+// 宸叉坊鍔犵殑鐗╂枡浜у搧ID闆嗗悎锛岄伩鍏嶉噸澶嶆坊鍔�
+const addedProductIds = computed(() => {
+  const ids = new Set(
+    materialList.value
+      .filter((m) => m.productId !== undefined)
+      .map((m) => m.productId!),
+  );
+  // 缂栬緫鏃跺厑璁镐繚鐣欏綋鍓嶇墿鏂欑殑 productId
+  if (materialForm.value.id && materialForm.value.productId) {
+    ids.delete(materialForm.value.productId);
+  }
+  return ids;
+});
+
+// 鐗╂枡涓嬫媺鍙�夊垪琛紙鎺掗櫎宸叉坊鍔犵殑锛�
+const availableMdmItems = computed(() =>
+  mdmItemList.value.filter((item) => !addedProductIds.value.has(item.id!)),
+);
 
 async function loadProject() {
   project.value = await getTenderProject(projectId);
@@ -150,6 +169,27 @@
   try { quoteList.value = await getQuoteList(bidId); } finally { quoteLoading.value = false; }
 }
 async function handleSaveQuote() {
+  // 鏍¢獙锛氭姤浠烽噾棰濅笌鎶曟爣閲戦涓�鑷存��
+  const bid = bidList.value.find((b) => b.id === quoteForm.value.bidId);
+  if (bid?.bidTotalAmount != null) {
+    const otherQuotesTotal = quoteList.value
+      .filter((q) => q.id !== quoteForm.value.id)
+      .reduce((sum, q) => sum + (q.quotePrice ?? 0), 0);
+    const newTotal = otherQuotesTotal + (quoteForm.value.quotePrice ?? 0);
+    if (newTotal !== bid.bidTotalAmount) {
+      await new Promise<void>((resolve, reject) => {
+        Modal.confirm({
+          title: '閲戦涓嶄竴鑷存彁绀�',
+          content: `鎶ヤ环鎬婚噾棰濓紙${newTotal.toLocaleString()}锛変笌鎶曟爣閲戦锛�${bid.bidTotalAmount!.toLocaleString()}锛変笉涓�鑷达紝鏄惁缁х画鎻愪氦锛焋,
+          okText: '缁х画鎻愪氦',
+          cancelText: '鍙栨秷',
+          onOk: () => { resolve(); },
+          onCancel: () => { reject(new Error('cancel')); },
+        });
+      });
+    }
+  }
+
   if (quoteForm.value.id) {
     await updateQuote(quoteForm.value);
   } else {
@@ -685,7 +725,7 @@
         <a-form layout="vertical" class="mt-4">
           <a-form-item label="MDM鐗╂枡" required>
             <a-select v-model:value="materialForm.productId" show-search placeholder="鎼滅储骞堕�夋嫨MDM鐗╂枡" :filter-option="filterOption" option-label-prop="label" @change="onMaterialSelect">
-              <a-select-option v-for="item in mdmItemList" :key="item.id" :value="item.id" :label="`${item.code} ${item.name}`">
+              <a-select-option v-for="item in availableMdmItems" :key="item.id" :value="item.id" :label="`${item.code} ${item.name}`">
                 <div class="flex flex-col">
                   <span class="font-medium">{{ item.code }}</span>
                   <span class="text-xs text-gray-400">{{ item.name }}{{ item.specification ? ` 路 ${item.specification}` : '' }}</span>

--
Gitblit v1.9.3