Browse Source

fix:调整采购订单对账单中选择供应商与选择订单逻辑,使用对账池相关接口

xieyong 1 tuần trước cách đây
mục cha
commit
4909812a10

+ 115 - 3
src/views/purchasingManage/purchaseOrder/accountstatement/components/orderListDialog.vue

@@ -11,7 +11,7 @@
     width="70%"
     width="70%"
   >
   >
     <el-card shadow="never">
     <el-card shadow="never">
-      <searchTable @search="reload"></searchTable>
+      <searchTable :fields="searchFields" @search="reload"></searchTable>
       <ele-pro-table
       <ele-pro-table
         ref="table"
         ref="table"
         :columns="columns"
         :columns="columns"
@@ -48,14 +48,60 @@ import tabMixins from '@/mixins/tableColumnsMixin';
       searchTable
       searchTable
     },
     },
 
 
+    props: {
+      /**
+       * 自定义列表数据源。默认(不传)走采购订单列表 getTableList;
+       * 一旦传入就完全接管请求,组件只负责拼装
+       * { pageNum, size, ...queryParams, ...where }。
+       *
+       * 例:对账池发起对账时选「有可对账数据的订单」,
+       * 传 getAccountPoolOrderList(/eom/accountstatementpool/orders)。
+       */
+      dataSourceApi: {
+        type: Function,
+        default: null
+      },
+      /** 固定查询参数,如对账池接口必填的 type(1 销售订单 / 2 采购订单) */
+      queryParams: {
+        type: Object,
+        default: () => ({})
+      },
+      /** 自定义搜索项,透传给 searchTable;不传用默认的采购订单搜索项 */
+      searchFields: {
+        type: Array,
+        default: null
+      },
+      /** 自定义表格列(列对象浅拷贝,不污染父组件传入的数组);不传用默认采购订单列 */
+      tableColumns: {
+        type: Array,
+        default: null
+      }
+    },
+
+    computed: {
+      columns() {
+        this.columnsVersion; // mixin 改列宽/列显隐时触发重算
+        const cols = (this.tableColumns || this.defaultColumns).map((c) => ({
+          ...c
+        }));
+        return this.applyColumnWidth(cols);
+      },
+      cacheKeyUrl() {
+        // 两套列必须用不同的缓存 key,否则 mixin 的 columnsContrast
+        // 会把另一套列当成「已删除列」洗掉(localStorage + 服务端 table-config 都按它存)
+        return this.tableColumns
+          ? 'views_purchasingManage_purchaseOrder_accountstatement_components_orderListDialog_custom'
+          : 'views_purchasingManage_purchaseOrder_accountstatement_components_orderListDialog';
+      }
+    },
+
     data() {
     data() {
       return {
       return {
-      cacheKeyUrl: 'views_purchasingManage_purchaseOrder_accountstatement_components_orderListDialog',
         visible: false,
         visible: false,
         current: null,
         current: null,
         pageList: new Map(),
         pageList: new Map(),
         currentIndex: null,
         currentIndex: null,
-        columns: [
+        defaultColumns: [
           {
           {
             columnKey: 'index',
             columnKey: 'index',
             label: '序号',
             label: '序号',
@@ -181,6 +227,15 @@ import tabMixins from '@/mixins/tableColumnsMixin';
 
 
       /* 表格数据源 */
       /* 表格数据源 */
       datasource({ page, limit, where, order }) {
       datasource({ page, limit, where, order }) {
+        if (this.dataSourceApi) {
+          // 自定义数据源:由调用方决定请求字段(对账池订单列表等)
+          return this.dataSourceApi({
+            pageNum: page,
+            size: limit,
+            ...this.queryParams,
+            ...(where || {})
+          }).then((res) => this.normalizeList(res, page));
+        }
         return getTableList({
         return getTableList({
           pageNum: page,
           pageNum: page,
           size: limit,
           size: limit,
@@ -195,6 +250,63 @@ import tabMixins from '@/mixins/tableColumnsMixin';
         })
         })
       },
       },
 
 
+      /**
+       * 字段归一化 + 分页字段兜底。
+       *
+       * ⚠️ /eom/accountstatementpool/orders 后端 schema 标的是 Pagination«object»,
+       *    没定义任何字段,所以这里对每个字段都做了多来源兜底:
+       *    采购订单列表返回 orderNo/partbId/partbName,对账池返回的是
+       *    往来单位那套 contactId/contactCode/contactName 和来源订单 sourceCode/sourceId。
+       *    归一化后统一成 id / orderNo / partbId / partbName / partbCode,
+       *    父组件的 getOrderInfo(obj) 和单选回显都不用改。
+       *
+       * count/total 两个分页字段名后端都用过,统一成 ele-pro-table 认的 count。
+       */
+      normalizeRow(row) {
+        return {
+          ...row,
+          id: row.id != null ? row.id : row.sourceId != null ? row.sourceId : row.orderId,
+          orderNo: row.orderNo != null ? row.orderNo : row.sourceCode,
+          partbId: row.partbId != null ? row.partbId : row.contactId,
+          partbName: row.partbName != null ? row.partbName : row.contactName,
+          partbCode: row.partbCode != null ? row.partbCode : row.contactCode,
+          // 沿用原「应付金额」列:对账池没有应付金额概念,
+          // 用可对账金额 / 剩余可对账金额兜底
+          payAmount:
+            row.payAmount != null
+              ? row.payAmount
+              : row.accountableAmount != null
+              ? row.accountableAmount
+              : row.availableAmount,
+          // 时间列同理:优先 createTime,其次单据日期、最后最近更新时间
+          createTime:
+            row.createTime != null
+              ? row.createTime
+              : row.docDate != null
+              ? row.docDate
+              : row.updateTime
+        };
+      },
+
+      normalizeList(res, page) {
+        // /orders 的响应 schema 后端没定义(Pagination«object»),
+        // 原始响应打出来方便核对表格列该绑哪些字段名
+        console.log('[对账池] 订单列表原始响应:', res);
+        const list = ((res && res.list) || []).map((row) =>
+          this.normalizeRow(row)
+        );
+        if (!this.pageList.has(page)) {
+          this.pageList.set(page, list);
+        }
+        const count =
+          res && res.count != null
+            ? res.count
+            : res && res.total != null
+            ? res.total
+            : list.length;
+        return { ...res, list, count };
+      },
+
       /* 刷新表格 */
       /* 刷新表格 */
       reload(where) {
       reload(where) {
         console.log(where);
         console.log(where);

+ 307 - 0
src/views/purchasingManage/purchaseOrder/accountstatement/components/purchaseForm.vue

@@ -228,10 +228,19 @@
     <supplierList
     <supplierList
       ref="supplierListRef"
       ref="supplierListRef"
       :classType="2"
       :classType="2"
+      :dataSourceApi="getAccountPoolCustomerList"
+      :queryParams="poolCustomerQuery"
+      :searchFields="poolCustomerSearch"
+      :showCategoryTree="false"
+      :tableColumns="poolCustomerColumns"
       @changeParent="getCusInfo"
       @changeParent="getCusInfo"
     ></supplierList>
     ></supplierList>
     <orderListDialog
     <orderListDialog
       ref="orderListDialogRef"
       ref="orderListDialogRef"
+      :dataSourceApi="getAccountPoolOrderList"
+      :queryParams="poolOrderQuery"
+      :searchFields="poolOrderSearch"
+      :tableColumns="poolOrderColumns"
       @changeParent="getOrderInfo"
       @changeParent="getOrderInfo"
     ></orderListDialog>
     ></orderListDialog>
     <contractListDialog
     <contractListDialog
@@ -247,6 +256,7 @@
   import parentList from '@/views/saleManage/contact/components/parentList.vue';
   import parentList from '@/views/saleManage/contact/components/parentList.vue';
   import OrderListDialog from './orderListDialog.vue';
   import OrderListDialog from './orderListDialog.vue';
   import { getSearchMergeListByTypeAPI } from '@/api/saleManage/accountstatement';
   import { getSearchMergeListByTypeAPI } from '@/api/saleManage/accountstatement';
+  import { getAccountPoolCustomerList, getAccountPoolOrderList } from '@/api/saleManage/accountPool';
   import { getFile } from '@/api/system/file';
   import { getFile } from '@/api/system/file';
   import supplierList from '@/views/purchasingManage/supplierManage/components/parentList.vue';
   import supplierList from '@/views/purchasingManage/supplierManage/components/parentList.vue';
   // import fileMain from '@/components/addDoc/index.vue';
   // import fileMain from '@/components/addDoc/index.vue';
@@ -263,6 +273,23 @@
     },
     },
     props: ['dataForm', 'datasource', 'dialogType','recorpayList'],
     props: ['dataForm', 'datasource', 'dialogType','recorpayList'],
     computed: {
     computed: {
+      // 对账池客户列表的必填参数:2 = 采购订单(采购侧对账只能选供应商)
+      poolCustomerQuery() {
+        return { type: 2 };
+      },
+      /**
+       * 对账池订单列表参数:2 = 采购订单。
+       * contactId 是当前已选的供应商 —— 接口文档没定义这个字段,
+       * 后端支持就按供应商过滤,不支持会忽略掉;不加的话选完供应商还能选到别家的订单。
+       */
+      poolOrderQuery() {
+        const params = { type: 2 };
+        const contactId = this.dataForm && this.dataForm.contactId;
+        if (contactId) {
+          params.contactId = contactId;
+        }
+        return params;
+      },
       //计算未对账金额
       //计算未对账金额
       accountStatementPrice() {
       accountStatementPrice() {
         return this.datasource.reduce(
         return this.datasource.reduce(
@@ -286,6 +313,274 @@
         },
         },
         startTime: '-01-01 00:00:00',
         startTime: '-01-01 00:00:00',
         endTime: '23:59:59',
         endTime: '23:59:59',
+        /**
+         * 供应商选择弹框的搜索项。
+         * 对账池客户接口只支持 供应商编码 / 名称 / 订单编码 三个条件,
+         * value 直接就是接口参数名(contactCode/contactName/orderNo),
+         * 所以不需要再做字段名映射,searchFields 传进来就按原样发给接口。
+         * 默认那套(关键字/产品编码/产品名称/创建时间)对账池没有对应参数,
+         * 展示了也只是输了不起作用,所以这里换成接口真正支持的。
+         * 3 项以内 seekPage 会平铺显示,不会折进「更多」下拉。
+         */
+        poolCustomerSearch: [
+          {
+            label: '供应商编码:',
+            value: 'contactCode',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '供应商名称:',
+            value: 'contactName',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '订单编码:',
+            value: 'orderNo',
+            type: 'input',
+            placeholder: '请输入'
+          },
+        ],
+        // 供应商选择弹框的列:对账池客户接口只返回往来单位本身,
+        // 供应商档案的版本号/电话/注册地址/联系人等字段一律没有,就不展示了
+        poolCustomerColumns: [
+          {
+            action: 'action',
+            slot: 'action',
+            align: 'center',
+            label: '选择'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'code',
+            label: '供应商编码',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160
+          },
+          {
+            prop: 'name',
+            label: '供应商名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 240
+          },
+          {
+            // 请求参数里有 orderNo,说明接口是按关联订单筛的,
+            // 返回里大概率也带订单编码。schema 未定义,给不出就留空。
+            prop: 'orderNo',
+            label: '关联订单编码',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 170
+          },
+          // 以下沿用供应商档案的列。normalizeRow 会把 contactCode/contactName
+          // 补成 code/name;其余列直接绑 row 上的同名字段,
+          // 接口给得出就有值、给不出就留空,
+          // 打开弹框看一眼哪些列全是空的,就知道哪些可以删。
+          {
+            prop: 'serialNo',
+            label: '供应商代号',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130
+          },
+          {
+            prop: 'phone',
+            label: '供应商电话',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130
+          },
+          {
+            prop: 'addressName',
+            label: '注册地址',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160,
+            formatter: (_row) =>
+              `${(_row.addressName || '').replaceAll(',', '')}${
+                _row.address || ''
+              }`
+          },
+          {
+            prop: 'otherAddressName',
+            label: '联系地址',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160,
+            formatter: (_row) =>
+              `${(_row.otherAddressName || '').replaceAll(',', '')}${
+                _row.otherAddress || ''
+              }`
+          },
+          {
+            prop: 'linkName',
+            label: '联系人',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 110
+          },
+          {
+            prop: 'linkPhone',
+            label: '联系人电话',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          }
+        ],
+        /**
+         * 订单选择弹框的搜索项。
+         * 与客户弹框同一套:对账池订单接口只认 contactCode / contactName / orderNo,
+         * value 直接就是接口参数名,不需要字段名映射。
+         * 默认采购订单那套(订单类型/审核状态/订单进度/创建时间)对账池没有对应参数。
+         */
+        poolOrderSearch: [
+          {
+            label: '订单编码:',
+            value: 'orderNo',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '供应商编码:',
+            value: 'contactCode',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '供应商名称:',
+            value: 'contactName',
+            type: 'input',
+            placeholder: '请输入'
+          }
+        ],
+        // 订单选择弹框的列:只保留对账池订单接口给得出的字段。
+        // 采购订单的合同名称/采购方/联系人/应付金额等一律不展示。
+        // prop 用归一化后的字段名(orderNo / partbCode / partbName),
+        // orderListDialog 的 normalizeRow 会把 contactCode/contactName 补成它们。
+        poolOrderColumns: [
+          {
+            width: 60,
+            type: 'action',
+            slot: 'action',
+            label: '选择',
+            columnKey: 'action',
+            align: 'center'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'orderNo',
+            label: '订单编码',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 200
+          },
+          {
+            prop: 'partbCode',
+            label: '供应商编码',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160
+          },
+          {
+            prop: 'partbName',
+            label: '供应商名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 220
+          },
+          // 以下沿用采购订单的列。normalizeRow 已把往来单位/来源订单那套字段
+          // 补成 orderNo / partbId / partbName;其余列直接绑 row 同名字段,
+          // 接口给得出就有值、给不出就留空,
+          // 打开弹框看一眼哪些列全是空的,就知道哪些可以删。
+          {
+            prop: 'contractName',
+            label: '合同名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 180
+          },
+          {
+            prop: 'partbLinkName',
+            label: '供应商联系人',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'partbTel',
+            label: '供应商联系电话',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130
+          },
+          {
+            prop: 'partaName',
+            label: '采购方名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 180
+          },
+          {
+            prop: 'partaLinkName',
+            label: '采购方联系人',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'partaTel',
+            label: '采购方联系电话',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130
+          },
+          {
+            // 原「应付金额」列。对账池口径下 normalizeRow 会用
+            // accountableAmount / availableAmount 兜底;都没有就留空。
+            prop: 'payAmount',
+            label: '应付金额(元)',
+            align: 'right',
+            showOverflowTooltip: true,
+            minWidth: 150,
+            formatter: (_row) => {
+              const raw = _row.payAmount;
+              if (raw == null || raw === '') return '';
+              const num = Number(raw);
+              return Number.isFinite(num)
+                ? num.toLocaleString('zh-CN', {
+                    minimumFractionDigits: 2,
+                    maximumFractionDigits: 2
+                  })
+                : '';
+            }
+          },
+          {
+            prop: 'createTime',
+            label: '单据/创建时间',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160
+          }
+        ],
         rules: {
         rules: {
           sourceType: { required: true, message: '请选择', trigger: 'change' },
           sourceType: { required: true, message: '请选择', trigger: 'change' },
           contactId: { required: true, message: '请选择', trigger: 'change' },
           contactId: { required: true, message: '请选择', trigger: 'change' },
@@ -307,6 +602,18 @@
       };
       };
     },
     },
     methods: {
     methods: {
+      /**
+       * 对账池客户列表接口,作为 prop 传给供应商选择弹框当数据源。
+       * Vue 2 的模板表达式只能访问实例上的属性,import 进来的模块函数必须挂到 methods,
+       * 否则渲染时会报 "not defined on the instance"。Vue 2 的 methods 已自动 bind 到实例,
+       * 直接用方法引用传给 prop 即可,不用再包一层箭头函数。
+       */
+      getAccountPoolCustomerList,
+      /**
+       * 对账池订单列表接口(/eom/accountstatementpool/orders),同上:
+       * 模板只能用实例属性,必须挂到 methods。
+       */
+      getAccountPoolOrderList,
       //查询
       //查询
       handleSearch() {
       handleSearch() {
         //
         //

+ 15 - 1
src/views/purchasingManage/purchaseOrder/components/searchTable.vue

@@ -6,12 +6,26 @@
 import { reviewStatusSelect, purchaseOrderProgressStatusEnum, requirementSourceType } from '@/enum/dict';
 import { reviewStatusSelect, purchaseOrderProgressStatusEnum, requirementSourceType } from '@/enum/dict';
 
 
 export default {
 export default {
+  props: {
+    /**
+     * 自定义搜索项;不传用下面的默认采购订单搜索项。
+     * 列表数据源换接口时(可筛维度不一样)由调用方传,
+     * item.value 直接就是提交给接口的参数名。
+     */
+    fields: {
+      type: Array,
+      default: null
+    }
+  },
   data() {
   data() {
     return {};
     return {};
   },
   },
   computed: {
   computed: {
-    // 表格列配置
     seekList() {
     seekList() {
+      return this.fields || this.defaultSeekList;
+    },
+    // 默认搜索项:对接采购订单列表接口(/eom/purchaseorder/table/list)
+    defaultSeekList() {
       return [
       return [
         {
         {
           label: '关键字:',
           label: '关键字:',

+ 16 - 1
src/views/purchasingManage/supplierManage/components/contactSearch.vue

@@ -6,12 +6,27 @@
   import { StateType } from '@/enum/dict';
   import { StateType } from '@/enum/dict';
 
 
   export default {
   export default {
+    props: {
+      /**
+       * 自定义搜索项;不传用下面的默认客户档案搜索项。
+       * 列表数据源换接口时(字段名、可筛维度都不一样)由调用方传,
+       * item.value 直接就是提交给接口的参数名,
+       * 所以这里不用再做字段名映射,传进来的 key 怎么写就怎么发。
+       */
+      fields: {
+        type: Array,
+        default: null
+      }
+    },
     data() {
     data() {
       return {};
       return {};
     },
     },
     computed: {
     computed: {
-      // 表格列配置
       seekList() {
       seekList() {
+        return this.fields || this.defaultSeekList;
+      },
+      // 默认搜索项:对接客户/供应商档案接口(/eom/contact/page2Usages)
+      defaultSeekList() {
         return [
         return [
           {
           {
             label: '关键字:',
             label: '关键字:',

+ 120 - 5
src/views/purchasingManage/supplierManage/components/parentList.vue

@@ -10,14 +10,17 @@
     width="70%"
     width="70%"
   >
   >
     <el-card shadow="never">
     <el-card shadow="never">
-      <contact-search @search="reload"></contact-search>
+      <contact-search :fields="searchFields" @search="reload"></contact-search>
 
 
       <ele-split-layout
       <ele-split-layout
-        width="244px"
+        :width="treeWidth"
         allow-collapse
         allow-collapse
         :right-style="{ overflow: 'hidden' }"
         :right-style="{ overflow: 'hidden' }"
       >
       >
-        <div class="ele-border-lighter split-layout-right-content">
+        <div
+          v-if="showCategoryTree"
+          class="ele-border-lighter split-layout-right-content"
+        >
           <AssetTree
           <AssetTree
             @handleNodeClick="handleNodeClick"
             @handleNodeClick="handleNodeClick"
             id="19"
             id="19"
@@ -71,15 +74,79 @@ import tabMixins from '@/mixins/tableColumnsMixin';
       classType: {
       classType: {
         type: Number,
         type: Number,
         default: 1
         default: 1
+      },
+      /**
+       * 自定义列表数据源。默认(不传)走客户/供应商档案 contactPageUsages;
+       * 一旦传入就完全接管请求,组件只负责拼装
+       * { pageNum, size, ...queryParams, ...paramMapper(where) }。
+       *
+       * 例:对账池发起对账时要选「有可对账数据的往来单位」,
+       * 传 getAccountPoolCustomerList(/eom/accountstatementpool/customers)。
+       */
+      dataSourceApi: {
+        type: Function,
+        default: null
+      },
+      /** 固定查询参数,如对账池接口必填的 type(1 销售订单 / 2 采购订单) */
+      queryParams: {
+        type: Object,
+        default: () => ({})
+      },
+      /**
+       * 搜索条件字段名映射:接收搜索表单的 where,返回自定义接口认识的字段名。
+       * 不传时原样透传 where(适用于参数名与搜索项一致的场景)。
+       */
+      paramMapper: {
+        type: Function,
+        default: null
+      },
+      /** 左侧客户类别树。接口不支持 categoryId 过滤时传 false 隐藏 */
+      showCategoryTree: {
+        type: Boolean,
+        default: true
+      },
+      /**
+       * 自定义搜索项,透传给 contact-search;不传用默认的客户档案搜索项。
+       * 搜索项的 value 就是提交给列表接口的参数名。
+       */
+      searchFields: {
+        type: Array,
+        default: null
+      },
+      /** 自定义表格列(列对象浅拷贝,不污染父组件传入的数组);不传用默认供应商档案列 */
+      tableColumns: {
+        type: Array,
+        default: null
+      }
+    },
+    computed: {
+      columns() {
+        this.columnsVersion; // mixin 改列宽/列显隐时触发重算
+        // 拷贝一层:applyColumnWidth 会往列对象上写 width,
+        // 直接改父组件传进来的数组会污染调用方的数据
+        const cols = (this.tableColumns || this.defaultColumns).map((c) => ({
+          ...c
+        }));
+        return this.applyColumnWidth(cols);
+      },
+      cacheKeyUrl() {
+        // 两套列(供应商档案列 / 调用方自定义列)必须用不同的缓存 key:
+        // mixin 的 columnsContrast 按 label 比对,共用一个 key 会把另一套列
+        // 当成「已删除列」洗掉(localStorage + 服务端 table-config 都按它存)
+        return this.tableColumns
+          ? 'views_purchasingManage_supplierManage_components_parentList_custom'
+          : 'views_purchasingManage_supplierManage_components_parentList';
+      },
+      treeWidth() {
+        return this.showCategoryTree ? '244px' : '0px';
       }
       }
     },
     },
     data() {
     data() {
       return {
       return {
-      cacheKeyUrl: 'views_purchasingManage_supplierManage_components_parentList',
         visible: false,
         visible: false,
         current: null,
         current: null,
         pageList: new Map(),
         pageList: new Map(),
-        columns: [
+        defaultColumns: [
           {
           {
             action: 'action',
             action: 'action',
             slot: 'action',
             slot: 'action',
@@ -201,6 +268,19 @@ import tabMixins from '@/mixins/tableColumnsMixin';
 
 
       /* 表格数据源 */
       /* 表格数据源 */
       datasource({ page, limit, where, order }) {
       datasource({ page, limit, where, order }) {
+        console.log("dataSourceApi",this.dataSourceApi);
+        if (this.dataSourceApi) {
+          // 自定义数据源:由调用方决定请求字段(对账池客户列表等)
+          const mapped = this.paramMapper
+            ? this.paramMapper(where || {})
+            : where;
+          return this.dataSourceApi({
+            pageNum: page,
+            size: limit,
+            ...this.queryParams,
+            ...(mapped || {})
+          }).then((res) => this.normalizeList(res, page));
+        }
         return contactPageUsages({
         return contactPageUsages({
           pageNum: page,
           pageNum: page,
           size: limit,
           size: limit,
@@ -216,6 +296,41 @@ import tabMixins from '@/mixins/tableColumnsMixin';
         });
         });
       },
       },
 
 
+      /**
+       * 字段归一化 + 分页字段兜底。
+       * 各接口的往来单位字段名不一样(对账池返回 contactId/contactCode/contactName,
+       * 客户档案返回 id/code/name),这里补齐成 id/code/name,
+       * 单选回显、open(item) 预选、父组件拿到的对象都不用改。
+       * count/total 两个分页字段名后端都用过,统一成 ele-pro-table 认的 count。
+       */
+      normalizeRow(row) {
+        return {
+          ...row,
+          id: row.id != null ? row.id : row.contactId,
+          code: row.code != null ? row.code : row.contactCode,
+          name: row.name != null ? row.name : row.contactName
+        };
+      },
+
+      normalizeList(res, page) {
+        // 对账池两个列表接口的响应字段后端文档都没定义全,
+        // 这里把原始响应打出来,方便核对表格列到底该绑哪些字段名
+        console.log('[对账池] 列表原始响应:', res);
+        const list = ((res && res.list) || []).map((row) =>
+          this.normalizeRow(row)
+        );
+        if (!this.pageList.has(page)) {
+          this.pageList.set(page, list);
+        }
+        const count =
+          res && res.count != null
+            ? res.count
+            : res && res.total != null
+            ? res.total
+            : list.length;
+        return { ...res, list, count };
+      },
+
       /* 刷新表格 */
       /* 刷新表格 */
       reload(where) {
       reload(where) {
         this.$refs.table.reload({ page: 1, where });
         this.$refs.table.reload({ page: 1, where });