From f3cac4aa2db56d6017c1d1dc035bcfeaec76c3e2 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 05 十一月 2026 18:31:13 +0800
Subject: [PATCH] feat(crm): 投标保证金迁移到销售管理并接入销售台账

---
 /dev/null                              |  116 ----------
 src/views/crm/bidBond/index.vue        |   33 +-
 src/views/crm/bidBond/data.ts          |  290 ++++++++++++++++++++++++++
 src/views/crm/bidBond/modules/form.vue |  141 ++++++++++++
 src/api/crm/bidBond/index.ts           |   77 +++++++
 5 files changed, 526 insertions(+), 131 deletions(-)

diff --git a/src/api/crm/bidBond/index.ts b/src/api/crm/bidBond/index.ts
new file mode 100644
index 0000000..f306d97
--- /dev/null
+++ b/src/api/crm/bidBond/index.ts
@@ -0,0 +1,77 @@
+import type { PageParam, PageResult } from '@vben/request';
+
+import { requestClient } from '#/api/request';
+
+export namespace CrmBidBondApi {
+  /** 鎶曟爣淇濊瘉閲� */
+  export interface BidBond {
+    id?: number;
+    no?: string;
+    customerId?: number;
+    customerName?: string;
+    projectName?: string;
+    tenderNo?: string;
+    saleOrderId?: number;
+    saleOrderNo?: string;
+    saleOrderAmount?: number;
+    bondAmount?: number;
+    payDate?: string;
+    /** 涓爣缁撴灉锛�0 寰呭紑鏍囥��1 宸蹭腑鏍囥��2 鏈腑鏍� */
+    bidResult?: number;
+    /** 閫�鍥炵姸鎬侊細0 鏈��鍥炪��1 閮ㄥ垎閫�鍥炪��2 宸查��鍥炪��3 鏃犻渶閫�鍥� */
+    refundStatus?: number;
+    refundAmount?: number;
+    refundDate?: string;
+    remark?: string;
+    createTime?: string;
+  }
+
+  /** 鍙叧鑱旂殑閿�鍞鍗曪紙閿�鍞彴璐︼級 */
+  export interface SaleOrderOption {
+    id: number;
+    no: string;
+    customerId: number;
+    status: number;
+    statusName?: string;
+    totalPrice?: number;
+    contractNo?: string;
+  }
+}
+
+/** 鍒嗛〉鏌ヨ鎶曟爣淇濊瘉閲� */
+export function getBidBondPage(params: PageParam) {
+  return requestClient.get<PageResult<CrmBidBondApi.BidBond>>(
+    '/crm/bid-bond/page',
+    { params },
+  );
+}
+
+/** 鏌ヨ鎶曟爣淇濊瘉閲戣鎯� */
+export function getBidBond(id: number) {
+  return requestClient.get<CrmBidBondApi.BidBond>(
+    `/crm/bid-bond/get?id=${id}`,
+  );
+}
+
+/** 鍒涘缓鎶曟爣淇濊瘉閲� */
+export function createBidBond(data: CrmBidBondApi.BidBond) {
+  return requestClient.post<number>('/crm/bid-bond/create', data);
+}
+
+/** 鏇存柊鎶曟爣淇濊瘉閲� */
+export function updateBidBond(data: CrmBidBondApi.BidBond) {
+  return requestClient.put('/crm/bid-bond/update', data);
+}
+
+/** 鍒犻櫎鎶曟爣淇濊瘉閲� */
+export function deleteBidBond(id: number) {
+  return requestClient.delete('/crm/bid-bond/delete', { params: { id } });
+}
+
+/** 鏌ヨ瀹㈡埛涓嬪彲鍏宠仈鐨勯攢鍞鍗曪紙浠呭凡瀹℃牳锛� */
+export function getSaleOrderOptions(customerId: number) {
+  return requestClient.get<CrmBidBondApi.SaleOrderOption[]>(
+    '/crm/bid-bond/sale-order-list',
+    { params: { customerId } },
+  );
+}
diff --git a/src/api/srm/bidBond/index.ts b/src/api/srm/bidBond/index.ts
deleted file mode 100644
index 1f18660..0000000
--- a/src/api/srm/bidBond/index.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import type { PageParam, PageResult } from '@vben/request';
-
-import { requestClient } from '#/api/request';
-
-export namespace SrmBidBondApi {
-  /** 鎶曟爣淇濊瘉閲� */
-  export interface BidBond {
-    id?: number;
-    no?: string;
-    supplierId?: number;
-    supplierName?: string;
-    projectName?: string;
-    inquiryId?: number;
-    inquiryNo?: string;
-    purchaseOrderId?: number;
-    purchaseOrderNo?: string;
-    bondAmount?: number;
-    payDate?: string;
-    won?: boolean;
-    refundStatus?: number;
-    refundAmount?: number;
-    refundDate?: string;
-    remark?: string;
-    createTime?: string;
-  }
-}
-
-/** 鍒嗛〉鏌ヨ鎶曟爣淇濊瘉閲� */
-export function getBidBondPage(params: PageParam) {
-  return requestClient.get<PageResult<SrmBidBondApi.BidBond>>(
-    '/srm/bid-bond/page',
-    { params },
-  );
-}
-
-/** 鏌ヨ鎶曟爣淇濊瘉閲戣鎯� */
-export function getBidBond(id: number) {
-  return requestClient.get<SrmBidBondApi.BidBond>(
-    `/srm/bid-bond/get?id=${id}`,
-  );
-}
-
-/** 鍒涘缓鎶曟爣淇濊瘉閲� */
-export function createBidBond(data: SrmBidBondApi.BidBond) {
-  return requestClient.post<number>('/srm/bid-bond/create', data);
-}
-
-/** 鏇存柊鎶曟爣淇濊瘉閲� */
-export function updateBidBond(data: SrmBidBondApi.BidBond) {
-  return requestClient.put('/srm/bid-bond/update', data);
-}
-
-/** 鍒犻櫎鎶曟爣淇濊瘉閲� */
-export function deleteBidBond(id: number) {
-  return requestClient.delete('/srm/bid-bond/delete', { params: { id } });
-}
diff --git a/src/views/crm/bidBond/data.ts b/src/views/crm/bidBond/data.ts
new file mode 100644
index 0000000..48d362c
--- /dev/null
+++ b/src/views/crm/bidBond/data.ts
@@ -0,0 +1,290 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { getCustomerSimpleList } from '#/api/crm/customer';
+import { getSaleOrderOptions } from '#/api/crm/bidBond';
+
+export const BID_RESULT_OPTIONS = [
+  { label: '寰呭紑鏍�', value: 0, color: 'processing' },
+  { label: '宸蹭腑鏍�', value: 1, color: 'success' },
+  { label: '鏈腑鏍�', value: 2, color: 'default' },
+];
+
+export const REFUND_STATUS_OPTIONS = [
+  { label: '鏈��鍥�', value: 0, color: 'warning' },
+  { label: '閮ㄥ垎閫�鍥�', value: 1, color: 'processing' },
+  { label: '宸查��鍥�', value: 2, color: 'success' },
+  { label: '鏃犻渶閫�鍥�', value: 3, color: 'default' },
+];
+
+export function getBidResultLabel(result?: number) {
+  return BID_RESULT_OPTIONS.find((item) => item.value === result)?.label ?? '-';
+}
+
+export function getBidResultColor(result?: number) {
+  return BID_RESULT_OPTIONS.find((item) => item.value === result)?.color ?? 'default';
+}
+
+export function getRefundStatusLabel(status?: number) {
+  return REFUND_STATUS_OPTIONS.find((item) => item.value === status)?.label ?? '-';
+}
+
+export function getRefundStatusColor(status?: number) {
+  return REFUND_STATUS_OPTIONS.find((item) => item.value === status)?.color ?? 'default';
+}
+
+/** 鏂板/淇敼鎶曟爣淇濊瘉閲戠殑琛ㄥ崟 */
+export function useFormSchema(): VbenFormSchema[] {
+  return [
+    {
+      fieldName: 'customerId',
+      label: '瀹㈡埛锛堟嫑鏍囨柟锛�',
+      component: 'ApiSelect',
+      rules: 'required',
+      componentProps: {
+        placeholder: '璇烽�夋嫨瀹㈡埛',
+        allowClear: true,
+        showSearch: true,
+        api: getCustomerSimpleList,
+        labelField: 'name',
+        valueField: 'id',
+      },
+    },
+    {
+      fieldName: 'projectName',
+      label: '椤圭洰鍚嶇О',
+      component: 'Input',
+      componentProps: { placeholder: '璇疯緭鍏ユ湰娆℃姇鏍囬」鐩悕绉�' },
+    },
+    {
+      fieldName: 'tenderNo',
+      label: '鎷涙爣缂栧彿',
+      component: 'Input',
+      componentProps: { placeholder: '璇疯緭鍏ユ嫑鏍囨柟鍙戝竷鐨勬嫑鏍囩紪鍙�' },
+    },
+    {
+      fieldName: 'saleOrderId',
+      label: '鍏宠仈閿�鍞鍗�',
+      component: 'ApiSelect',
+      componentProps: {
+        placeholder: '璇峰厛閫夋嫨瀹㈡埛',
+        allowClear: true,
+        showSearch: true,
+        labelField: 'no',
+        valueField: 'id',
+        optionFilterProp: 'label',
+      },
+      dependencies: {
+        triggerFields: ['customerId'],
+        componentProps: (values) => {
+          const customerId = values.customerId as number | undefined;
+          return {
+            placeholder: customerId
+              ? '璇烽�夋嫨璇ュ鎴峰凡瀹℃牳鐨勯攢鍞鍗曪紙閿�鍞彴璐︼級'
+              : '璇峰厛閫夋嫨瀹㈡埛',
+            disabled: !customerId,
+            api: customerId
+              ? () => getSaleOrderOptions(customerId)
+              : () => Promise.resolve([]),
+          };
+        },
+      },
+    },
+    {
+      fieldName: 'bondAmount',
+      label: '淇濊瘉閲戦噾棰�',
+      component: 'InputNumber',
+      rules: 'required',
+      componentProps: {
+        class: '!w-full',
+        placeholder: '璇疯緭鍏ョ即绾崇殑淇濊瘉閲戦噾棰�',
+        min: 0,
+        precision: 2,
+      },
+    },
+    {
+      fieldName: 'payDate',
+      label: '缂寸撼鏃ユ湡',
+      component: 'DatePicker',
+      componentProps: {
+        class: 'w-full',
+        placeholder: '璇烽�夋嫨鍚戝鎴风即绾充繚璇侀噾鐨勬棩鏈�',
+        format: 'YYYY-MM-DD',
+        valueFormat: 'YYYY-MM-DD',
+      },
+    },
+    {
+      fieldName: 'bidResult',
+      label: '涓爣缁撴灉',
+      component: 'Select',
+      rules: 'required',
+      componentProps: {
+        placeholder: '璇烽�夋嫨涓爣缁撴灉',
+        options: BID_RESULT_OPTIONS.map(({ label, value }) => ({
+          label,
+          value,
+        })),
+      },
+      defaultValue: 0,
+    },
+    {
+      fieldName: 'refundStatus',
+      label: '閫�鍥炵姸鎬�',
+      component: 'Select',
+      componentProps: {
+        placeholder: '鏈腑鏍囨椂璺熻釜淇濊瘉閲戞槸鍚﹂��鍥�',
+        options: REFUND_STATUS_OPTIONS.map(({ label, value }) => ({
+          label,
+          value,
+        })),
+      },
+    },
+    {
+      fieldName: 'refundAmount',
+      label: '閫�鍥為噾棰�',
+      component: 'InputNumber',
+      componentProps: {
+        class: '!w-full',
+        placeholder: '宸查��鍥炴椂椤荤瓑浜庝繚璇侀噾閲戦锛涢儴鍒嗛��鍥炴椂椤诲皬浜庝繚璇侀噾閲戦',
+        min: 0,
+        precision: 2,
+      },
+    },
+    {
+      fieldName: 'refundDate',
+      label: '閫�鍥炴棩鏈�',
+      component: 'DatePicker',
+      componentProps: {
+        class: 'w-full',
+        placeholder: '璇烽�夋嫨瀹㈡埛瀹為檯閫�鍥炰繚璇侀噾鐨勬棩鏈�',
+        format: 'YYYY-MM-DD',
+        valueFormat: 'YYYY-MM-DD',
+      },
+    },
+    {
+      fieldName: 'remark',
+      label: '澶囨敞',
+      component: 'Textarea',
+      componentProps: { placeholder: '璇疯緭鍏ュ娉�', rows: 2 },
+      formItemClass: 'col-span-2',
+    },
+  ];
+}
+
+/** 鎼滅储琛ㄥ崟 */
+export function useGridFormSchema(): VbenFormSchema[] {
+  return [
+    {
+      fieldName: 'no',
+      label: '淇濊瘉閲戝崟鍙�',
+      component: 'Input',
+      componentProps: { placeholder: '璇疯緭鍏ヤ繚璇侀噾鍗曞彿', allowClear: true },
+    },
+    {
+      fieldName: 'customerId',
+      label: '瀹㈡埛',
+      component: 'ApiSelect',
+      componentProps: {
+        placeholder: '璇烽�夋嫨瀹㈡埛',
+        allowClear: true,
+        showSearch: true,
+        api: getCustomerSimpleList,
+        labelField: 'name',
+        valueField: 'id',
+      },
+    },
+    {
+      fieldName: 'projectName',
+      label: '椤圭洰鍚嶇О',
+      component: 'Input',
+      componentProps: { placeholder: '璇疯緭鍏ラ」鐩悕绉�', allowClear: true },
+    },
+    {
+      fieldName: 'saleOrderNo',
+      label: '閿�鍞鍗曞彿',
+      component: 'Input',
+      componentProps: { placeholder: '璇疯緭鍏ュ叧鑱旈攢鍞鍗曞彿', allowClear: true },
+    },
+    {
+      fieldName: 'bidResult',
+      label: '涓爣缁撴灉',
+      component: 'Select',
+      componentProps: {
+        placeholder: '璇烽�夋嫨',
+        allowClear: true,
+        options: BID_RESULT_OPTIONS.map(({ label, value }) => ({
+          label,
+          value,
+        })),
+      },
+    },
+    {
+      fieldName: 'refundStatus',
+      label: '閫�鍥炵姸鎬�',
+      component: 'Select',
+      componentProps: {
+        placeholder: '璇烽�夋嫨',
+        allowClear: true,
+        options: REFUND_STATUS_OPTIONS.map(({ label, value }) => ({
+          label,
+          value,
+        })),
+      },
+    },
+  ];
+}
+
+/** 琛ㄦ牸鍒� */
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+  return [
+    { field: 'no', title: '淇濊瘉閲戝崟鍙�', minWidth: 150 },
+    { field: 'customerName', title: '瀹㈡埛锛堟嫑鏍囨柟锛�', minWidth: 160 },
+    { field: 'projectName', title: '椤圭洰鍚嶇О', minWidth: 180 },
+    { field: 'tenderNo', title: '鎷涙爣缂栧彿', minWidth: 140 },
+    {
+      field: 'saleOrderNo',
+      title: '鍏宠仈閿�鍞鍗�',
+      minWidth: 160,
+      slots: { default: 'saleOrderNo' },
+    },
+    {
+      field: 'saleOrderAmount',
+      title: '璁㈠崟閲戦',
+      minWidth: 120,
+      formatter: 'formatAmount2',
+    },
+    {
+      field: 'bondAmount',
+      title: '淇濊瘉閲戦噾棰�',
+      minWidth: 120,
+      formatter: 'formatAmount2',
+    },
+    { field: 'payDate', title: '缂寸撼鏃ユ湡', minWidth: 110 },
+    {
+      field: 'bidResult',
+      title: '涓爣缁撴灉',
+      minWidth: 100,
+      slots: { default: 'bidResult' },
+    },
+    {
+      field: 'refundStatus',
+      title: '閫�鍥炵姸鎬�',
+      minWidth: 110,
+      slots: { default: 'refundStatus' },
+    },
+    {
+      field: 'refundAmount',
+      title: '閫�鍥為噾棰�',
+      minWidth: 120,
+      formatter: 'formatAmount2',
+    },
+    { field: 'refundDate', title: '閫�鍥炴棩鏈�', minWidth: 110 },
+    { field: 'remark', title: '澶囨敞', minWidth: 150 },
+    {
+      title: '鎿嶄綔',
+      width: 130,
+      fixed: 'right',
+      slots: { default: 'actions' },
+    },
+  ];
+}
diff --git a/src/views/srm/bidBond/index.vue b/src/views/crm/bidBond/index.vue
similarity index 77%
rename from src/views/srm/bidBond/index.vue
rename to src/views/crm/bidBond/index.vue
index 49b9a04..cb48e66 100644
--- a/src/views/srm/bidBond/index.vue
+++ b/src/views/crm/bidBond/index.vue
@@ -1,19 +1,18 @@
 <script lang="ts" setup>
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
-import type { SrmBidBondApi } from '#/api/srm/bidBond';
+import type { CrmBidBondApi } from '#/api/crm/bidBond';
 
 import { Page, useVbenModal } from '@vben/common-ui';
 
 import { message, Tag } from 'ant-design-vue';
 
 import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
-import {
-  deleteBidBond,
-  getBidBondPage,
-} from '#/api/srm/bidBond';
+import { deleteBidBond, getBidBondPage } from '#/api/crm/bidBond';
 import { $t } from '#/locales';
 
 import {
+  getBidResultColor,
+  getBidResultLabel,
   getRefundStatusColor,
   getRefundStatusLabel,
   useGridColumns,
@@ -21,7 +20,7 @@
 } from './data';
 import BidBondForm from './modules/form.vue';
 
-defineOptions({ name: 'SrmBidBond' });
+defineOptions({ name: 'CrmBidBond' });
 
 const [FormModal, formModalApi] = useVbenModal({
   connectedComponent: BidBondForm,
@@ -36,11 +35,11 @@
   formModalApi.setData(null).open();
 }
 
-function handleEdit(row: SrmBidBondApi.BidBond) {
+function handleEdit(row: CrmBidBondApi.BidBond) {
   formModalApi.setData({ id: row.id }).open();
 }
 
-async function handleDelete(row: SrmBidBondApi.BidBond) {
+async function handleDelete(row: CrmBidBondApi.BidBond) {
   await deleteBidBond(row.id!);
   message.success($t('ui.actionMessage.deleteSuccess', [row.no]));
   handleRefresh();
@@ -67,7 +66,7 @@
     },
     rowConfig: { keyField: 'id', isHover: true },
     toolbarConfig: { refresh: true, search: true },
-  } as VxeTableGridOptions<SrmBidBondApi.BidBond>,
+  } as VxeTableGridOptions<CrmBidBondApi.BidBond>,
 });
 </script>
 
@@ -82,15 +81,19 @@
               label: $t('ui.actionTitle.create', ['鎶曟爣淇濊瘉閲�']),
               type: 'primary',
               icon: ACTION_ICON.ADD,
-              auth: ['srm:bid-bond:create'],
+              auth: ['crm:bid-bond:create'],
               onClick: handleCreate,
             },
           ]"
         />
       </template>
-      <template #won="{ row }">
-        <Tag :color="row.won ? 'success' : 'default'">
-          {{ row.won ? '涓爣' : '鏈腑鏍�' }}
+      <template #saleOrderNo="{ row }">
+        <span v-if="row.saleOrderNo">{{ row.saleOrderNo }}</span>
+        <span v-else class="text-gray-400">鏈叧鑱�</span>
+      </template>
+      <template #bidResult="{ row }">
+        <Tag :color="getBidResultColor(row.bidResult)">
+          {{ getBidResultLabel(row.bidResult) }}
         </Tag>
       </template>
       <template #refundStatus="{ row }">
@@ -105,7 +108,7 @@
               label: $t('common.edit'),
               type: 'link',
               icon: ACTION_ICON.EDIT,
-              auth: ['srm:bid-bond:update'],
+              auth: ['crm:bid-bond:update'],
               onClick: handleEdit.bind(null, row),
             },
             {
@@ -113,7 +116,7 @@
               type: 'link',
               danger: true,
               icon: ACTION_ICON.DELETE,
-              auth: ['srm:bid-bond:delete'],
+              auth: ['crm:bid-bond:delete'],
               popConfirm: {
                 title: $t('ui.actionMessage.deleteConfirm', [row.no]),
                 confirm: handleDelete.bind(null, row),
diff --git a/src/views/crm/bidBond/modules/form.vue b/src/views/crm/bidBond/modules/form.vue
new file mode 100644
index 0000000..a68a07d
--- /dev/null
+++ b/src/views/crm/bidBond/modules/form.vue
@@ -0,0 +1,141 @@
+<script lang="ts" setup>
+import type { CrmBidBondApi } from '#/api/crm/bidBond';
+
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+import {
+  createBidBond,
+  getBidBond,
+  updateBidBond,
+} from '#/api/crm/bidBond';
+import { $t } from '#/locales';
+
+import { useFormSchema } from '../data';
+
+const emit = defineEmits(['success']);
+const formData = ref<CrmBidBondApi.BidBond>();
+/** 鎵撳紑寮圭獥鍥炲~鏁版嵁鏃朵笉瑙﹀彂瀛楁鑱斿姩锛岄伩鍏嶅洖濉妸宸查�夐攢鍞鍗曟竻绌� */
+const loading = ref(false);
+
+const getTitle = computed(() => {
+  return formData.value?.id
+    ? $t('ui.actionTitle.edit', ['鎶曟爣淇濊瘉閲�'])
+    : $t('ui.actionTitle.create', ['鎶曟爣淇濊瘉閲�']);
+});
+
+const [Form, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: { class: 'w-full' },
+    labelWidth: 120,
+  },
+  wrapperClass: 'grid-cols-2',
+  layout: 'horizontal',
+  schema: useFormSchema(),
+  showDefaultActions: false,
+  handleValuesChange: async (values, changedFields) => {
+    if (loading.value) {
+      return;
+    }
+    // 鎹㈠鎴峰悗锛屽師閿�鍞鍗曚竴瀹氫笉鍐嶅睘浜庤瀹㈡埛锛屽繀椤绘竻绌洪噸閫�
+    if (changedFields.includes('customerId') && values.saleOrderId) {
+      await formApi.setValues({ saleOrderId: undefined });
+      return;
+    }
+    // 閫変簡閿�鍞鍗曡鏄庡凡涓爣锛涙竻绌鸿鍗曞垯閫�鍥炲緟寮�鏍�
+    if (changedFields.includes('saleOrderId')) {
+      if (values.saleOrderId && values.bidResult !== 1) {
+        await formApi.setValues({ bidResult: 1 });
+        return;
+      }
+      if (!values.saleOrderId && values.bidResult === 1) {
+        await formApi.setValues({ bidResult: 0 });
+        return;
+      }
+    }
+    // 鏈腑鏍囦笉鍙兘鏈夐攢鍞鍗曪紝娓呯┖璁㈠崟閬垮厤鍚庣鏍¢獙澶辫触
+    if (changedFields.includes('bidResult') && values.bidResult === 2) {
+      if (values.saleOrderId) {
+        await formApi.setValues({ saleOrderId: undefined });
+      }
+      if (values.refundStatus === 3) {
+        await formApi.setValues({ refundStatus: 0 });
+      }
+      return;
+    }
+    // 宸蹭腑鏍囦笉瀛樺湪閫�娆惧満鏅�
+    if (changedFields.includes('bidResult') && values.bidResult === 1) {
+      if (values.refundStatus !== 3) {
+        await formApi.setValues({
+          refundStatus: 3,
+          refundAmount: undefined,
+          refundDate: undefined,
+        });
+      }
+    }
+  },
+});
+
+const [Modal, modalApi] = useVbenModal({
+  async onConfirm() {
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = (await formApi.getValues()) as CrmBidBondApi.BidBond;
+    // 鏈��鍥� / 鏃犻渶閫�鍥炰笉鍏佽甯﹂��娆鹃噾棰濅笌鏃ユ湡锛岄伩鍏嶅悗绔姸鎬佷笌閲戦鍐茬獊鏍¢獙
+    if (
+      data.refundStatus === 0 ||
+      data.refundStatus === 3 ||
+      data.refundStatus === undefined ||
+      data.refundStatus === null
+    ) {
+      data.refundAmount = undefined;
+      data.refundDate = undefined;
+    }
+    modalApi.lock();
+    try {
+      await (formData.value?.id
+        ? updateBidBond({ ...data, id: formData.value.id })
+        : createBidBond(data));
+      await modalApi.close();
+      emit('success');
+      message.success($t('ui.actionMessage.operationSuccess'));
+    } finally {
+      modalApi.unlock();
+    }
+  },
+  async onOpenChange(isOpen: boolean) {
+    if (!isOpen) {
+      formData.value = undefined;
+      return;
+    }
+    const data = modalApi.getData<{ id?: number }>();
+    if (!data?.id) {
+      formData.value = undefined;
+      return;
+    }
+    modalApi.lock();
+    loading.value = true;
+    try {
+      formData.value = await getBidBond(data.id);
+      await formApi.setValues(formData.value);
+    } finally {
+      loading.value = false;
+      modalApi.unlock();
+    }
+  },
+});
+
+defineExpose({ modalApi });
+</script>
+
+<template>
+  <Modal :title="getTitle" class="w-3/4">
+    <Form class="mx-4" />
+  </Modal>
+</template>
diff --git a/src/views/srm/bidBond/data.ts b/src/views/srm/bidBond/data.ts
deleted file mode 100644
index bc47f5e..0000000
--- a/src/views/srm/bidBond/data.ts
+++ /dev/null
@@ -1,255 +0,0 @@
-import type { VbenFormSchema } from '#/adapter/form';
-import type { VxeTableGridOptions } from '#/adapter/vxe-table';
-
-import { z } from '#/adapter/form';
-import { getPurchaseOrderPage } from '#/api/erp/purchase/order';
-import { getInquirySimpleList } from '#/api/srm/inquiry';
-import { getSupplierSimpleList } from '#/api/srm/supplier';
-
-export const REFUND_STATUS_OPTIONS = [
-  { label: '鏈��鍥�', value: 0, color: 'warning' },
-  { label: '閮ㄥ垎閫�鍥�', value: 1, color: 'processing' },
-  { label: '宸查��鍥�', value: 2, color: 'success' },
-  { label: '鏃犻渶閫�鍥�', value: 3, color: 'default' },
-];
-
-export function getRefundStatusLabel(status?: number) {
-  return REFUND_STATUS_OPTIONS.find((item) => item.value === status)?.label ?? '-';
-}
-
-export function getRefundStatusColor(status?: number) {
-  return REFUND_STATUS_OPTIONS.find((item) => item.value === status)?.color ?? 'default';
-}
-
-/** 閲囪喘璁㈠崟涓嬫媺鏁版嵁 */
-async function getPurchaseOrderOptions() {
-  const result = await getPurchaseOrderPage({ pageNo: 1, pageSize: 200 });
-  return result.list ?? [];
-}
-
-/** 鏂板/淇敼鎶曟爣淇濊瘉閲戠殑琛ㄥ崟 */
-export function useFormSchema(): VbenFormSchema[] {
-  return [
-    {
-      fieldName: 'supplierId',
-      label: '渚涘簲鍟�',
-      component: 'ApiSelect',
-      rules: 'required',
-      componentProps: {
-        placeholder: '璇烽�夋嫨渚涘簲鍟�',
-        allowClear: true,
-        showSearch: true,
-        api: getSupplierSimpleList,
-        labelField: 'name',
-        valueField: 'id',
-      },
-    },
-    {
-      fieldName: 'projectName',
-      label: '椤圭洰鍚嶇О',
-      component: 'Input',
-      componentProps: { placeholder: '閫夋嫨璇环鍗曞悗鑷姩甯﹀嚭锛屼篃鍙墜宸ュ~鍐�' },
-    },
-    {
-      fieldName: 'inquiryId',
-      label: '鍏宠仈璇环鍗�',
-      component: 'ApiSelect',
-      componentProps: {
-        placeholder: '璇烽�夋嫨璇环鍗�',
-        allowClear: true,
-        showSearch: true,
-        api: getInquirySimpleList,
-        labelField: 'title',
-        valueField: 'id',
-      },
-    },
-    {
-      fieldName: 'purchaseOrderId',
-      label: '鍏宠仈閲囪喘璁㈠崟',
-      component: 'ApiSelect',
-      componentProps: {
-        placeholder: '璇烽�夋嫨閲囪喘璁㈠崟',
-        allowClear: true,
-        showSearch: true,
-        api: getPurchaseOrderOptions,
-        labelField: 'no',
-        valueField: 'id',
-      },
-    },
-    {
-      fieldName: 'bondAmount',
-      label: '淇濊瘉閲戦噾棰�',
-      component: 'InputNumber',
-      rules: 'required',
-      componentProps: {
-        class: '!w-full',
-        placeholder: '璇疯緭鍏ヤ繚璇侀噾閲戦',
-        min: 0,
-        precision: 2,
-      },
-    },
-    {
-      fieldName: 'payDate',
-      label: '缂寸撼鏃ユ湡',
-      component: 'DatePicker',
-      componentProps: {
-        class: 'w-full',
-        placeholder: '璇烽�夋嫨缂寸撼鏃ユ湡',
-        format: 'YYYY-MM-DD',
-        valueFormat: 'YYYY-MM-DD',
-      },
-    },
-    {
-      fieldName: 'won',
-      label: '鏄惁涓爣',
-      component: 'Switch',
-      componentProps: {
-        checkedChildren: '涓爣',
-        unCheckedChildren: '鏈腑鏍�',
-      },
-      rules: z.boolean().default(false),
-    },
-    {
-      fieldName: 'refundStatus',
-      label: '閫�鍥炵姸鎬�',
-      component: 'Select',
-      componentProps: {
-        placeholder: '璇烽�夋嫨閫�鍥炵姸鎬�',
-        options: REFUND_STATUS_OPTIONS.map(({ label, value }) => ({
-          label,
-          value,
-        })),
-      },
-    },
-    {
-      fieldName: 'refundAmount',
-      label: '閫�鍥為噾棰�',
-      component: 'InputNumber',
-      componentProps: {
-        class: '!w-full',
-        placeholder: '璇疯緭鍏ラ��鍥為噾棰�',
-        min: 0,
-        precision: 2,
-      },
-    },
-    {
-      fieldName: 'refundDate',
-      label: '閫�鍥炴棩鏈�',
-      component: 'DatePicker',
-      componentProps: {
-        class: 'w-full',
-        placeholder: '璇烽�夋嫨閫�鍥炴棩鏈�',
-        format: 'YYYY-MM-DD',
-        valueFormat: 'YYYY-MM-DD',
-      },
-    },
-    {
-      fieldName: 'remark',
-      label: '澶囨敞',
-      component: 'Textarea',
-      componentProps: { placeholder: '璇疯緭鍏ュ娉�', rows: 2 },
-      formItemClass: 'col-span-2',
-    },
-  ];
-}
-
-/** 鎼滅储琛ㄥ崟 */
-export function useGridFormSchema(): VbenFormSchema[] {
-  return [
-    {
-      fieldName: 'no',
-      label: '淇濊瘉閲戝崟鍙�',
-      component: 'Input',
-      componentProps: { placeholder: '璇疯緭鍏ヤ繚璇侀噾鍗曞彿', allowClear: true },
-    },
-    {
-      fieldName: 'supplierId',
-      label: '渚涘簲鍟�',
-      component: 'ApiSelect',
-      componentProps: {
-        placeholder: '璇烽�夋嫨渚涘簲鍟�',
-        allowClear: true,
-        showSearch: true,
-        api: getSupplierSimpleList,
-        labelField: 'name',
-        valueField: 'id',
-      },
-    },
-    {
-      fieldName: 'projectName',
-      label: '椤圭洰鍚嶇О',
-      component: 'Input',
-      componentProps: { placeholder: '璇疯緭鍏ラ」鐩悕绉�', allowClear: true },
-    },
-    {
-      fieldName: 'won',
-      label: '鏄惁涓爣',
-      component: 'Select',
-      componentProps: {
-        placeholder: '璇烽�夋嫨',
-        allowClear: true,
-        options: [
-          { label: '涓爣', value: true },
-          { label: '鏈腑鏍�', value: false },
-        ],
-      },
-    },
-    {
-      fieldName: 'refundStatus',
-      label: '閫�鍥炵姸鎬�',
-      component: 'Select',
-      componentProps: {
-        placeholder: '璇烽�夋嫨閫�鍥炵姸鎬�',
-        allowClear: true,
-        options: REFUND_STATUS_OPTIONS.map(({ label, value }) => ({
-          label,
-          value,
-        })),
-      },
-    },
-  ];
-}
-
-/** 琛ㄦ牸鍒� */
-export function useGridColumns(): VxeTableGridOptions['columns'] {
-  return [
-    { field: 'no', title: '淇濊瘉閲戝崟鍙�', minWidth: 150 },
-    { field: 'supplierName', title: '渚涘簲鍟�', minWidth: 150 },
-    { field: 'projectName', title: '椤圭洰鍚嶇О', minWidth: 180 },
-    { field: 'inquiryNo', title: '鍏宠仈璇环鍗�', minWidth: 150 },
-    { field: 'purchaseOrderNo', title: '鍏宠仈閲囪喘璁㈠崟', minWidth: 160 },
-    {
-      field: 'bondAmount',
-      title: '淇濊瘉閲戦噾棰�',
-      minWidth: 120,
-      formatter: 'formatAmount2',
-    },
-    { field: 'payDate', title: '缂寸撼鏃ユ湡', minWidth: 110 },
-    {
-      field: 'won',
-      title: '鏄惁涓爣',
-      minWidth: 90,
-      slots: { default: 'won' },
-    },
-    {
-      field: 'refundStatus',
-      title: '閫�鍥炵姸鎬�',
-      minWidth: 110,
-      slots: { default: 'refundStatus' },
-    },
-    {
-      field: 'refundAmount',
-      title: '閫�鍥為噾棰�',
-      minWidth: 120,
-      formatter: 'formatAmount2',
-    },
-    { field: 'refundDate', title: '閫�鍥炴棩鏈�', minWidth: 110 },
-    { field: 'remark', title: '澶囨敞', minWidth: 150 },
-    {
-      title: '鎿嶄綔',
-      width: 130,
-      fixed: 'right',
-      slots: { default: 'actions' },
-    },
-  ];
-}
diff --git a/src/views/srm/bidBond/modules/form.vue b/src/views/srm/bidBond/modules/form.vue
deleted file mode 100644
index a0c39ab..0000000
--- a/src/views/srm/bidBond/modules/form.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-<script lang="ts" setup>
-import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
-import type { SrmBidBondApi } from '#/api/srm/bidBond';
-
-import { computed, ref } from 'vue';
-
-import { useVbenModal } from '@vben/common-ui';
-
-import { message } from 'ant-design-vue';
-
-import { useVbenForm } from '#/adapter/form';
-import { getPurchaseOrder } from '#/api/erp/purchase/order';
-import {
-  createBidBond,
-  getBidBond,
-  updateBidBond,
-} from '#/api/srm/bidBond';
-import { getInquiry } from '#/api/srm/inquiry';
-import { $t } from '#/locales';
-
-import { useFormSchema } from '../data';
-
-const emit = defineEmits(['success']);
-const formData = ref<SrmBidBondApi.BidBond>();
-const getTitle = computed(() => {
-  return formData.value?.id
-    ? $t('ui.actionTitle.edit', ['鎶曟爣淇濊瘉閲�'])
-    : $t('ui.actionTitle.create', ['鎶曟爣淇濊瘉閲�']);
-});
-
-const [Form, formApi] = useVbenForm({
-  commonConfig: {
-    componentProps: { class: 'w-full' },
-    labelWidth: 110,
-  },
-  wrapperClass: 'grid-cols-2',
-  layout: 'horizontal',
-  schema: useFormSchema(),
-  showDefaultActions: false,
-  handleValuesChange: async (values, changedFields) => {
-    if (changedFields.includes('inquiryId') && values.inquiryId) {
-      try {
-        const inquiry = await getInquiry(values.inquiryId);
-        await formApi.setValues({
-          projectName: inquiry.title,
-        });
-      } catch {
-        // 璇环鍗曡鍙栧け璐ユ椂涓嶉樆鏂墜宸ュ綍鍏�
-      }
-    }
-    if (changedFields.includes('purchaseOrderId') && values.purchaseOrderId) {
-      try {
-        const order: ErpPurchaseOrderApi.PurchaseOrder =
-          await getPurchaseOrder(values.purchaseOrderId);
-        await formApi.setValues({
-          supplierId: order.supplierId,
-          projectName: values.projectName || order.no,
-          won: true,
-        });
-      } catch {
-        // 閲囪喘璁㈠崟璇诲彇澶辫触鏃朵笉闃绘柇鎵嬪伐褰曞叆
-      }
-    }
-  },
-});
-
-const [Modal, modalApi] = useVbenModal({
-  async onConfirm() {
-    const { valid } = await formApi.validate();
-    if (!valid) {
-      return;
-    }
-    const data = (await formApi.getValues()) as SrmBidBondApi.BidBond;
-    if (data.won && data.refundStatus === undefined) {
-      data.refundStatus = 3;
-    }
-    modalApi.lock();
-    try {
-      await (formData.value?.id
-        ? updateBidBond({ ...data, id: formData.value.id })
-        : createBidBond(data));
-      await modalApi.close();
-      emit('success');
-      message.success($t('ui.actionMessage.operationSuccess'));
-    } finally {
-      modalApi.unlock();
-    }
-  },
-  async onOpenChange(isOpen: boolean) {
-    if (!isOpen) {
-      formData.value = undefined;
-      return;
-    }
-    const data = modalApi.getData<{ id?: number }>();
-    if (!data?.id) {
-      formData.value = undefined;
-      return;
-    }
-    modalApi.lock();
-    try {
-      formData.value = await getBidBond(data.id);
-      await formApi.setValues(formData.value);
-    } finally {
-      modalApi.unlock();
-    }
-  },
-});
-
-defineExpose({ modalApi });
-</script>
-
-<template>
-  <Modal :title="getTitle" class="w-3/4">
-    <Form class="mx-4" />
-  </Modal>
-</template>

--
Gitblit v1.9.3