瀏覽代碼

feat: 发票功能

liujt 1 月之前
父節點
當前提交
3fc6747932

+ 7 - 3
src/BIZComponents/collectTableForm/index.vue

@@ -3,7 +3,7 @@
 <template>
   <div>
     <!-- 收款信息汇总区 -->
-    <headerTitle title="收款信息" size="16px"></headerTitle>
+    <headerTitle :title="title"></headerTitle>
     <div style="margin: 10px 0; font-size: 14px; color: #606266;">
       <span>{{ totalLabel }}:{{ totalPrice || 0 }} 元</span>
       <span style="margin-left: 20px;">已收金额:{{ receivedAmount }} 元</span>
@@ -79,9 +79,9 @@
               dictName="支付类型"
               placeholder="请选择"
               class="payment-select"
-              
+              :disabled="isView || r?.id"
             />
-            <!-- :disabled="isView || r?.id" -->
+            
           </el-form-item>
         </template>
         <!-- 附件 -->
@@ -124,6 +124,10 @@
       fileMain
     },
     props: {
+      title: {
+        type: String,
+        default: '收款详情'
+      },
       // 表单数据(含 tableData),.sync 双向,父组件传入
       form: {
         type: Object,

+ 10 - 1
src/api/financialManage/receivableManage/index.js

@@ -24,7 +24,16 @@ export async function receivableBill(data) {
 
 //保存收款记录
 export async function finReceivableSaveAPI(data) {
-  const res = await request.post(`/eom/finreceivable/saveDetail`, data);
+  const res = await request.post(`/eom/finreceivable/saveSingleDetail`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 收款信息
+export async function getDetailList(id) {
+  const res = await request.get(`/eom/finreceivable/getDetailList/${id}`);
   if (res.data.code == 0) {
     return res.data.data;
   }

+ 35 - 38
src/views/financialManage/collectionPlan/components/detailDialog.vue

@@ -84,6 +84,20 @@
         :menu="menu"
         type="view"
       ></paymentCollectionPlanDetail>
+
+      <!-- <headerTitle
+        :title="menu === 'purchase' ? '付款详情' : '收款详情'"
+        style="margin-top: 30px"
+      ></headerTitle> -->
+      <collect-table-form
+        ref="collectTableFormRef"
+        :title="menu === 'purchase' ? '付款详情' : '收款详情'"
+        style="margin-top: 30px"
+        :form.sync="collectForm"
+        :total-price="collectForm.planPaymentAmount"
+        dialog-type="view"
+        total-label="应收金额"
+      ></collect-table-form>
     </div>
     <bpmDetail
       v-if="activeComp === 'bpm' && form.processInstanceId"
@@ -105,6 +119,7 @@
   import paymentCollectionPlanDetail from '@/BIZComponents/paymentCollectionPlan/Detail.vue';
   import { receiptPaymentPlanById } from '@/api/financialManage/payAndCollectPlan';
   import { shippingModeOp, shippingModePurchaseOp, transactionMethodsOp } from '@/enum/dict.js';
+  import collectTableForm from '@/BIZComponents/collectTableForm/index.vue';
 
   export default {
     mixins: [dictMixins],
@@ -117,7 +132,8 @@
     components: {
       inventoryTabledetail,
       bpmDetail,
-      paymentCollectionPlanDetail
+      paymentCollectionPlanDetail,
+      collectTableForm
     },
     data() {
       return {
@@ -139,43 +155,8 @@
         form: {},
         rules: {},
         detailData: {},
-        sourceTypeList: [
-          {
-            code: 1,
-            name: '报价单',
-            parentId: '1'
-          },
-          {
-            code: 2,
-            name: '核价单',
-            parentId: '2'
-          },
-          {
-            code: 3,
-            name: '采购计划',
-            parentId: '2'
-          },
-          {
-            code: 4,
-            name: '商机',
-            parentId: '1'
-          },
-          {
-            code: 5,
-            name: '退货单',
-            parentId: '1'
-          },
-          {
-            code: 6,
-            name: '客户',
-            parentId: '1'
-          },
-          {
-            code: 7,
-            name: '销售订单',
-            parentId: '1'
-          }
-        ]
+        collectForm: {},
+        currentRow: {}
       };
     },
     created() {
@@ -189,6 +170,7 @@
       },
       async open(row) {
         console.log(row);
+        this.currentRow = row;
         this.form = row;
         this.activeComp = 'main';
         this.visible = true;
@@ -247,6 +229,21 @@
           data.deliveryModeName = this.menu === 'purchase' ? this.shippingModePurchaseOp.find(item => item.value == data.deliveryMode)?.label || '' : this.shippingModeOp.find(item => item.value == data.deliveryMode)?.label || '';
           data.sourceOrderTypeName = data.sourceOrderType == 1 ? '销售订单' : '采购订单';
           this.form = data;
+
+          const detail = this.form.details.filter(item => item.detailNo === this.currentRow.detailNo)?.[0]
+          console.log('detail~~~', detail)
+          if(detail) {
+            this.collectForm = {
+              ...detail,
+              tableData: detail?.confirmList?.map(item => {
+                return {
+                  ...item,
+                  receivedDate: item.paymentDate,
+                  receivedTotalPrice: item.paymentTotalPrice,
+                }
+              }) || []
+            }
+          }
           
           this.$nextTick(() => {
             this.$refs.paymentCollectionPlanDetailRef &&

+ 55 - 10
src/views/financialManage/invoiceManage/components/addOrEditDialogNew.vue

@@ -38,7 +38,7 @@
           <el-form-item label="来源类型" prop="sourceType">
             <el-select
               v-model="form.sourceType"
-              @change="handleSelType()"
+              @change="handleSelType('sourceType')"
               :disabled="!isEditType"
               clearable
               style="width: 100%"
@@ -285,7 +285,7 @@
         </el-col>
       </el-row>
     
-      <div class="payinfo" style="margin-top: 20px;">
+      <div v-if="form.sourceType != 99" class="payinfo" style="margin-top: 20px;">
         <headerTitle title="来源清单"></headerTitle>
         <!-- <el-form ref="form" :model="tableForm"> -->
           <ele-pro-table
@@ -353,12 +353,22 @@
     <div style="margin-top: 20px;">
       <headerTitle title="关联物品清单信息"></headerTitle>
       <table-info-new
+        v-if="form.sourceType != 99"
         :dialogType="dialogType"
         :contactData="contactData"
         ref="tableInfoRef"
         :invoiceAmount="form.invoiceAmount"
         @invoiceAmountChange="invoiceAmountChange"
       ></table-info-new>
+
+      <table-info
+        v-else
+        :dialogType="dialogType"
+        :contactData="contactData"
+        ref="tableInfoNoOrderRef"
+        @setPrice="setPrice"
+      ></table-info>
+
     </div>
     <div slot="footer">
       <el-button type="primary" v-click-once @click="handleSave(0)">保存</el-button>
@@ -414,6 +424,7 @@
       @receivableDone="receivableDone"
       v-if="receivableDialogFlag"
       :receivableDialogFlag.sync="receivableDialogFlag"
+      :multiple="true"
     ></receivableDialog>
     <!-- 应付 -->
     <paymentListDialog
@@ -440,6 +451,7 @@
   import { mapGetters } from 'vuex';
   import fileUpload from '@/components/upload/fileUpload.vue';
   import tableInfoNew from './tableInfoNew.vue';
+  import tableInfo from './tableInfo.vue';
   import { getTreeByPid } from '@/api/classifyManage';
   import {
     invoiceApplyInfoV2API,
@@ -465,6 +477,7 @@
   import { updateContractStatus } from '@/api/contractManage/contractBook';
   import { getMergeInvoiceInfoAPI } from '@/api/financialManage/payAndCollectPlan';
   import { paymentTypeOp } from '@/enum/dict';
+  import inventoryTable from '@/BIZComponents/inventoryTable.vue';
   
 
   const defForm = {
@@ -519,7 +532,9 @@
       // fileMain,
       receivableDialog,
       paymentListDialog,
-      collectionPlanDialog
+      collectionPlanDialog,
+      tableInfo,
+      inventoryTable
     },
     props: {
       isEditType: {
@@ -651,6 +666,7 @@
     },
     data() {
       return {
+        cacheKeyUrl: 'eom-202608251804-inventoryTable',
         // 1-对账单,2-合同,3-订单,4-应付,5-应收,99-其他无订单无合同
         sourceTypeList: [
           {
@@ -936,7 +952,11 @@
         // this.$set(this.form, 'type', Number(data.type));
         // this.$set(this.form, 'sourceType', data.sourceType);
         // this.payableManage(data.data);
-        this.getPlanData(data)
+
+        const tempIds = data.map((item) => item.detailId);
+        const tempNames = data.map((item) => item.detailCode);
+        console.log(data)
+        this.getPlanData(tempIds, tempNames)
       },
       // 收/付款计划回调
       async getPlanData(tempIds, tempNames) {
@@ -1015,9 +1035,17 @@
         // this.$set(this.form, 'sourceCode', tempIds);
 
         await this.init({}, 'add');
+        let tempIds = []
+        let tempNames = []
+        if(sourceType == 5) {
+          tempIds = data.map((item) => item.detailId);
+          tempNames = data.map((item) => item.detailCode);
+        } else {
+          tempIds = data.map((item) => item.id);
+          tempNames = data.map((item) => item.statementNo);
+        }
 
-        const tempIds = data.map((item) => item.id);
-        const tempNames = data.map((item) => item.statementNo);
+        
 
         this.getPlanData(tempIds, tempNames);
         // if (sourceType == 2) {
@@ -1052,7 +1080,12 @@
       async getInfo(id) {
         this.form = await invoiceApplyInfoV2API(id);
         this.$nextTick(() => {
-          this.$refs.tableInfoRef.putValue(this.form);
+          // 根据来源类型设置数据源:99 用 tableInfo(setValue),非 99 用 tableInfoNew(putValue)
+          if (this.form.sourceType == 99) {
+            this.$refs.tableInfoNoOrderRef?.setValue(this.form);
+          } else {
+            this.$refs.tableInfoRef?.putValue(this.form);
+          }
         })
       },
 
@@ -1109,12 +1142,19 @@
 
       //
       handleSelType(val) {
+        console.log('val~~~', val);
         this.form = Object.assign({}, this.form, defForm);
         if (val == 'isType') {
           this.$set(this.form, 'sourceType', '');
         }
+        if(val == 'sourceType') {
+          this.$nextTick(() => {
+            this.$refs.tableInfoNoOrderRef?.setValue(this.form);
+          })
+        }
         this.form.relatedList = [];
-        this.$refs.tableInfoRef.clearTable();
+        this.$refs.tableInfoRef?.clearTable();
+        this.$refs.tableInfoNoOrderRef?.clearTable();
         this.enterpriseChange(this.enterprisePage[0]?.name);
       },
       setPrice(val) {
@@ -1230,13 +1270,18 @@
           //     resolve(valid);
           //   });
           // });
-          const tableValid = await this.$refs.tableInfoRef.getTableValidate();
+          // 根据来源类型选择对应表格:99 用 tableInfo(tableInfoNoOrderRef),非 99 用 tableInfoNew(tableInfoRef)
+          const tableRef =
+            this.form.sourceType == 99
+              ? this.$refs.tableInfoNoOrderRef
+              : this.$refs.tableInfoRef;
+          const tableValid = await tableRef.getTableValidate();
           console.log('tableValid~~~',tableValid);
           // if (!tableValid) {
           //   return;
           // }
 
-          let tableData = this.$refs.tableInfoRef.getTableData();
+          let tableData = tableRef.getTableData();
           // this.form.link = tableData.link;
           this.form.productMap = tableData;
           console.log('commitData~~~',this.form);

+ 7 - 1
src/views/financialManage/invoiceManage/components/detailDialog.vue

@@ -216,7 +216,7 @@
           </el-col>
         </el-row>
       </el-form>
-      <div class="payinfo" style="margin-top: 20px;">
+      <div v-if="form.sourceType != 99" class="payinfo" style="margin-top: 20px;">
         <headerTitle title="来源清单"></headerTitle>
         <!-- <el-form ref="form" :model="tableForm"> -->
           <ele-pro-table
@@ -283,9 +283,15 @@
       <div style="margin-top: 20px;">
         <headerTitle title="关联物品清单信息"></headerTitle>
         <table-info-new
+          v-if="form.sourceType != 99"
           dialogType="view"
           ref="tableInfoNewRef"
         ></table-info-new>
+        <table-info
+          v-else
+          dialogType="view"
+          ref="tableInfoNoOrderRef"
+        ></table-info>
       </div>
     </div>
     <bpmDetail

+ 526 - 136
src/views/financialManage/invoiceManage/components/tableInfo.vue

@@ -7,14 +7,15 @@
         :columns="columns"
         :datasource="tableForm.detailList"
         row-key="id"
+        :selection.sync="selection"
         class="time-form"
       >
         <template v-slot:toolbar>
-          <el-button type="text" @click="addRow">新增</el-button>
-          <el-button type="text" @click="removeRow(scope.row)">选择商品</el-button>
-          <el-button type="text" @click="removeRow(scope.row)">批量设置税率</el-button>
-          <el-button type="text" @click="removeRow(scope.row)">批量设置单价</el-button>
-          <el-button type="text" @click="removeRow(scope.row)">批量设置折让比例</el-button>
+          <el-button type="primary" @click="handParent('', -1)">新增</el-button>
+          <el-button type="primary" @click="handGoods(-1)">选择商品</el-button>
+          <setAllValue :disabled="!selection.length" inputType="number" title="税率" valueKey="taxRate" @success="confirmBatchSet" />
+          <setAllValue :disabled="!selection.length" inputType="number" title="单价" valueKey="singlePrice" @success="confirmBatchSet" />
+          <setAllValue :disabled="!selection.length" inputType="number" title="折让比例" valueKey="discountRatio" @success="confirmBatchSet" />
         </template>
         
         <template v-slot:totalCount="scope">
@@ -42,18 +43,107 @@
           ]"
         > 
           <span v-if="dialogType === 'view'">{{ scope.row.totalCount }}</span>
-          <el-input v-else v-model="scope.row.totalCount" type="number" @input="updateTotalPrice(scope.row)"></el-input>
+          <el-input v-else v-model="scope.row.totalCount" type="number" @input="recalcDetailList(scope.row, scope.$index)"></el-input>
         </el-form-item>
       </template>
 
+      <!-- 单价 -->
+      <template v-slot:singlePrice="scope">
+        <span v-if="dialogType === 'view'">{{ scope.row.singlePrice }}</span>
+        <el-input v-else v-model="scope.row.singlePrice" type="number" @input="recalcDetailList(scope.row, scope.$index)"></el-input>
+      </template>
+
+      <!-- 计价方式 -->
+      <template v-slot:pricingWay="scope">
+        <span v-if="dialogType === 'view'">{{ pricingWayLabel(scope.row.pricingWay) }}</span>
+        <el-select
+          v-else
+          v-model="scope.row.pricingWay"
+          placeholder="请选择"
+          style="width: 100%"
+          @change="recalcDetailList(scope.row, scope.$index)"
+        >
+          <el-option
+            v-for="item in pricingWayList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
+      </template>
+
+      <!-- 税率 -->
+      <template v-slot:taxRate="scope">
+        <span v-if="dialogType === 'view'">{{ scope.row.taxRate }}</span>
+        <el-input
+          v-else
+          v-model="scope.row.taxRate"
+          type="number"
+          @input="recalcDetailList(scope.row, scope.$index)"
+        ></el-input>
+      </template>
+
+      <!-- 折让比例 -->
+      <template v-slot:discountRatio="scope">
+        <span v-if="dialogType === 'view'">{{ scope.row.discountRatio }}</span>
+        <el-input
+          v-else
+          v-model="scope.row.discountRatio"
+          type="number"
+          :min="0"
+          :max="100"
+          placeholder="请输入"
+        ></el-input>
+      </template>
+
+      <!-- 工艺路线 -->
+      <template v-slot:technologyRouteName="scope">
+        <span v-if="dialogType === 'view'">{{ scope.row.technologyRouteName }}</span>
+        <el-input
+          v-else
+          :value="scope.row.technologyRouteName"
+          placeholder="请选择"
+          readonly
+          @click.native="openVersion(scope.$index)"
+        ></el-input>
+      </template>
+
+      <!-- 操作:删除 -->
+      <template v-slot:action="scope">
+        <el-link
+          v-if="dialogType !== 'view'"
+          type="danger"
+          :underline="false"
+          icon="el-icon-delete"
+          @click="removeRow(scope.$index)"
+        >删除</el-link>
+      </template>
+
       </ele-pro-table>
     </el-form>
+    <product-list ref="productListRef" classType="1" :is-get-inventory-total="true" @changeParent="changeParent" :isSupplier="true"></product-list>
+    <commodityPriceListDialog ref="commodityPriceListDialogRef" @changeParent="changeParent"></commodityPriceListDialog>
+    <ProductionVersion ref="versionRefs" @changeProduct="changeProduct"></ProductionVersion>
   </div>
 </template>
 <script>
+import setAllValue from '@/BIZComponents/setAllValue.vue'; //批量修改
+import productList from '@/BIZComponents/product-list.vue';
+import commodityPriceListDialog from '@/views/commodityManagement/commodityPriceList/components/commodityPriceListDialog.vue';
+import ProductionVersion from '@/components/ProductionVersion2/index.vue';
+import { pricingWayList } from '@/enum/dict.js';
+const dayjs = require('dayjs');
+
+import {
+  changeCount,
+  getAllPrice,
+  getAllDiscountPrice,
+  formatPrice,
+  getAllQuantity
+} from '@/BIZComponents/setProduct.js';
   export default {
     name: 'tableInfo',
-    components: {},
+    components: { setAllValue, productList, commodityPriceListDialog, ProductionVersion },
     props: {
       form: {
         type: Object,
@@ -80,11 +170,51 @@
       invoiceAmount: {
         type: Number,
         default: 0
-      }
+      },
+      contractBookType: {
+        //合同类型 1销售 2采购
+        type: [String, Number],
+        default: 1
+      },
+      //是否商品
+      isGoods: {
+        type: Boolean,
+        default: false
+      },
     },
     data() {
+      const defaultForm = {
+            key: null,
+            endTime: '',
+            isFirst: 0,
+            name: '',
+            startTime: '',
+            workHour: '',
+            guaranteePeriodUnitCode: '',
+            technicalDrawings: [],
+            arrivalWay: 1,
+            // 生产加工类型特有字段
+            thickNess: '',
+            squareNumber: '',
+            processingFeeBeforeTax: '',
+            packagingFeeNotTaxed: '',
+            transportationFeeWithoutTax: '',
+            extraTax: '',
+            quotationSubtotalTax: '',
+            // 新增未税小记字段
+            quotationSubtotalBeforeTax: '',
+            quoteWay: 1,
+            discountRatio: 100
+          };
       return {
         columns: [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center',
+            fixed: 'left'
+          },
           {
             width: 45,
             type: 'index',
@@ -92,62 +222,70 @@
             align: 'center',
             fixed: 'left'
           },
-
+          // {
+          //   width: 150,
+          //   prop: 'key',
+          //   label: '来源编码',
+          //   align: 'center'
+          // },
           // {
           //   width: 100,
-          //   prop: 'typeName',
-          //   label: '类型',
-          //   slot: 'typeName',
+          //   prop: 'key',
+          //   label: '对账日期',
           //   align: 'center'
           // },
           // {
-          //   minWidth: 100,
-          //   prop: 'sourceCode',
-          //   label: '类型编码',
-          //   slot: 'sourceCode',
+          //   width: 150,
+          //   prop: 'sourceOrderNo',
+          //   label: '销售订单编码',
           //   align: 'center'
           // },
           // {
           //   width: 100,
-          //   prop: 'productCategoryName',
-          //   label: '分类',
-          //   slot: 'productCategoryName',
-          //   align: "center"
+          //   prop: 'key',
+          //   label: '发货单编码',
+          //   align: 'center'
+          // },
+          // {
+          //   width: 100,
+          //   prop: 'key',
+          //   label: '发货日期',
+          //   align: 'center'
           // },
           {
             width: 100,
             prop: 'productCode',
             label: '产品编码',
-            align: "center"
+            align: 'center'
           },
           {
-            minWidth: 100,
+            minWidth: 150,
             prop: 'productName',
             label: '产品名称',
+            slot: 'productName',
             align: 'center'
           },
-          {
+           {
             minWidth: 100,
-            prop: 'batchNo',
-            label: '批次号',
+            prop: 'modelType',
+            label: '型号',
+            slot: 'modelType',
             align: 'center'
           },
+
           {
             minWidth: 100,
             prop: 'specification',
             label: '规格',
+            slot: 'specification',
             align: 'center'
           },
+
           {
             minWidth: 100,
-            prop: 'modelType',
-            label: '型号',
-            align: 'center'
-          },
-          {
-            minWidth: 100,
-            prop: 'colorKey',
-            label: '颜色',
+            prop: 'batchNo',
+            label: '批次号',
+            slot: 'batchNo',
             align: 'center'
           },
           {
@@ -157,108 +295,115 @@
             slot: 'totalCount',
             align: 'center',
           },
-
+          
           {
-            width: 100,
-            prop: 'measuringUnit',
+            minWidth: 130,
+            prop: 'unit',
             label: '计量单位',
-            slot: 'measuringUnit',
+            slot: 'unit',
             align: 'center'
           },
           {
-            width: 80,
-            prop: 'singleWeight',
-            label: '重量',
-            align: 'center'
-          },
-          {
-            width: 80,
-            prop: 'singleWeight',
-            label: '重量单位',
-            align: 'center'
-          },
-          {
-            width: 150,
+            minWidth: 130,
             prop: 'pricingWay',
             label: '计价方式',
-            formatter: (row, column) => {
-              return row.pricingWay == 1
-                ? '按数量计价'
-                : row.pricingWay == 2
-                ? '按重量计价'
-                : '';
-            },
+            slot: 'pricingWay',
             align: 'center'
           },
           {
-            minWidth: 80,
-            prop: 'singlePrice',
+            minWidth: 130,
+            prop: 'technologyRouteName',
             label: '工艺路线',
-            slot: 'singlePrice',
+            slot: 'technologyRouteName',
             align: 'center'
           },
           {
-            minWidth: 80,
+            minWidth: 130,
             prop: 'singlePrice',
             label: '单价',
             slot: 'singlePrice',
             align: 'center'
           },
-          
           {
-            minWidth: 80,
+            minWidth: 130,
             prop: 'taxRate',
-            slot: 'taxRate',
             label: '税率',
             align: 'center',
-            formatter: (_row, _column, cellValue) => {
-              return _row.taxRate
-                ? _row.taxRate+'%'
-                : '';
-            },
+            slot: 'taxRate',
+            // formatter: (_row, _column, cellValue) => {
+            //   return _row.taxRate
+            //     ? _row.taxRate+'%'
+            //     : '';
+            // },
           },
           {
-            minWidth: 80,
-            prop: 'singlePrice',
+            minWidth: 100,
+            prop: 'noTaxSinglePrice',
             label: '不含税单价',
-            slot: 'singlePrice',
+            slot: 'noTaxSinglePrice',
+            align: 'center'
+          },
+          {
+            minWidth: 130,
+            prop: 'weight',
+            label: '重量',
             align: 'center'
           },
           {
-            minWidth: 80,
+            minWidth: 130,
+            prop: 'unInvoiceAmount',
+            label: '重量单位',
+            align: 'center'
+          },
+          // {
+          //   width: 150,
+          //   prop: 'quoteWay',
+          //   label: '报价方式',
+          //   formatter: (row, column) => {
+          //     return row.quoteWay == 1
+          //       ? '常规价'
+          //       : row.quoteWay == 2
+          //       ? '内部价'
+          //       : row.quoteWay == 3 ? '议价' : '';
+          //   },
+          //   align: 'center'
+
+          // },
+          
+          {
+            width: 100,
             prop: 'totalPrice',
             label: '合计',
-            slot: 'totalPrice',
             align: 'center'
           },
           {
-            minWidth: 80,
-            prop: 'totalPrice',
+            width: 100,
+            prop: 'discountRatio',
             label: '折让比例',
-            slot: 'totalPrice',
+            slot: 'discountRatio',
             align: 'center'
           },
           {
-            minWidth: 80,
-            prop: 'totalPrice',
+            width: 100,
+            prop: 'discountSinglePrice',
             label: '折让单价',
-            slot: 'totalPrice',
             align: 'center'
           },
           {
-            minWidth: 80,
-            prop: 'totalPrice',
+            width: 100,
+            prop: 'discountAmount',
             label: '折让合计',
-            slot: 'totalPrice',
             align: 'center'
           },
           {
-            minWidth: 80,
-            prop: 'action',
+            width: 100,
+            columnKey: 'action',
             label: '操作',
             slot: 'action',
-            align: 'center'
+            align: 'center',
+            fixed: 'right'
           },
+         
           // {
           //   width: 100,
           //   prop: 'sourceType',
@@ -274,6 +419,18 @@
           detailList: [],
           link: []
         },
+        defaultForm,
+        // 计数单位字段映射(本页数量字段为 totalCount)
+        countObj: {
+          countKey: 'totalCount',
+          unitKey: 'measuringUnit',
+          unitIdKey: 'measuringUnitId'
+        },
+        allPrice: 0,
+        allQuantity: 0,
+        allDiscountPrice: 0,
+        selection: [],
+        pricingWayList,
         typeList: [
           {
             label: '销售发货',
@@ -303,53 +460,267 @@
       }
     },
     methods: {
-      //获取选择的对账单数据
-      async getAccountData(params) {
-        if (params.children.orderType == 6) {
-          this.tableForm.detailList = params.children.detailList;
-          this.tableForm.detailList.forEach((item, index) => {
-            item.sourceCode = params.children.orderNo;
-            item.sourceId = params.children.id;
-            item.sourceType = params.type == 1 ? 2 : 3;
-            item.type = 12;
-            item.singlePrice = item.discountSinglePrice;
-            item.totalPrice = item.discountTotalPrice;
-            item.typeName = '销售赔付';
+      guaranteePeriodUnit(code) {
+        return code == 3
+          ? 'day'
+          : code == 4
+          ? 'month'
+          : code == 5
+          ? 'year'
+          : 'second';
+      },
+      // 改变数量(适配本页面:数据源为 tableForm.detailList,数量字段为 totalCount)
+      // 参考 inventoryTable.changeCount 逻辑,独立实现,不依赖原方法
+      recalcDetailList(row, index, weightType) {
+        if (!row) {
+          // 全量重算
+          this.tableForm.detailList = this.tableForm.detailList.map((item) => {
+            const updated = changeCount(item, this.countObj, false);
+            return this.syncDiscountAmount(updated);
           });
         } else {
-          this.tableForm.detailList = [];
-          params.children.subList.forEach((item, index) => {
-            item.detailList.forEach((i, n) => {
-              i.sourceCode = item.statementSubOrderCode;
-              i.sourceId = params.children.id;
-              i.sourceType = params.type == 1 ? 2 : 3;
-              i.type = item.subType;
-              console.log(item.subType);
-              i.typeName = this.typeList.find(
-                (i) => i.value == item.subType
-              ).label;
-              // i.singlePrice = item.discountSinglePrice
-              i.totalPrice = i.discountTotalPrice;
-            });
-            this.tableForm.detailList.push(...item.detailList);
-          });
-          this.$refs.table.reload();
+          // 单行重算
+          const updatedRow = changeCount(row, this.countObj, false, weightType);
+          this.$set(this.tableForm.detailList, index, this.syncDiscountAmount(updatedRow));
+        }
+        this.$nextTick(() => {
+          this.getNotaxSinglePrice();
+          this.calcAllTotal();
+        });
+      },
+      // 同步折让合计:changeCount 输出 discountTotalPrice,表格列用 discountAmount
+      syncDiscountAmount(row) {
+        this.$set(row, 'discountAmount', row.discountTotalPrice ?? '');
+        return row;
+      },
+      // 删除行并重新计算
+      removeRow(index) {
+        if (index < 0 || index >= this.tableForm.detailList.length) return;
+        this.tableForm.detailList.splice(index, 1);
+        this.$nextTick(() => {
+          this.calcAllTotal();
+        });
+      },
+      // 计算不含税单价
+      getNotaxSinglePrice() {
+        this.tableForm.detailList.forEach((item, index) => {
+          if (item.singlePrice && item.taxRate) {
+            this.$set(
+              this.tableForm.detailList[index],
+              'noTaxSinglePrice',
+              +((+item.singlePrice / (1 + +item.taxRate / 100)).toFixed(2))
+            );
+          } else {
+            this.$set(this.tableForm.detailList[index], 'noTaxSinglePrice', '');
+          }
+        });
+      },
+      // 汇总金额与数量
+      calcAllTotal() {
+        this.allPrice = getAllPrice(this.tableForm.detailList) || 0;
+        this.allQuantity = getAllQuantity(this.tableForm.detailList, this.countObj) || 0;
+        this.allDiscountPrice =
+          getAllDiscountPrice(this.tableForm.detailList) || 0;
+        // 通知父组件金额变化
+        this.$emit('setPrice', this.allPrice);
+      },
+      setDay(addDay, dateType = 'day', item) {
+        let tiem =
+          this.contractBookType == 1
+            ? item.produceDeliveryDeadline
+            : item.customerExpectDeliveryDeadline;
+        return dayjs(tiem || new Date())
+          .add(addDay, dateType)
+          .format('YYYY-MM-DD');
+      },
+      //选择产品回调
+    changeParent(obj, idx) {
+      console.log(obj, idx);
+      obj.forEach((item, index) => {
+        let i = idx == -1 ? index : idx;
+        let row = JSON.parse(JSON.stringify(this.defaultForm));
+        console.log(row);
+        row.key = this.tableForm.detailList.length + 1;
+        let parasm = idx == -1 ? row : this.tableForm.detailList[i];
+
+        this.$set(parasm, 'productId', item.id);
+        this.$set(parasm, 'categoryName', item.name);
+        this.$set(parasm, 'productCategoryId', item.categoryLevelId);
+        this.$set(parasm, 'productBrand', item.brandNum);
+        this.$set(parasm, 'productCategoryName', item.categoryLevelPath);
+        this.$set(parasm, 'productCode', item.code);
+        this.$set(parasm, 'productName', item.name);
+        this.$set(parasm, 'modelType', item.modelType);
+        this.$set(parasm, 'availableCountBase', item.availableCountBase);
+        this.$set(parasm, 'measuringUnit', item.measuringUnit);
+        this.$set(parasm, 'specification', item.specification);
+        this.$set(parasm, 'weightUnit', item.weightUnit);
+        this.$set(parasm, 'singleWeight', item.netWeight);
+        this.$set(parasm, 'pricingWay', 1);
+        this.$set(parasm, 'goodsLevel', item.goodsLevel);
+        this.$set(parasm, 'guaranteePeriod', item.warrantyPeriod);
+        this.$set(
+          parasm,
+          'customerExpectDeliveryDeadline',
+          dayjs(new Date()).format('YYYY-MM-DD')
+        );
+        // console.log('colorKey~~', item.colorKey);
+        this.$set(parasm, 'modelKey', item.modelKey?.split(',')?.[0] || '');
+        this.$set(parasm, 'colorKey', item.colorKey?.split(',')?.[0] || '');
+        this.$set(parasm, 'technologyRouteName', item.technologyRouteName || '');
+        this.$set(parasm, 'technologyRouteId', item.technologyRouteId || '');
+       
+          this.$set(
+            parasm,
+            'taxRate',
+            parasm.taxRate
+          );
+        
+        // this.$set(
+        //   parasm,
+        //   'guaranteePeriodUnitCode',
+        //   item.warrantyPeriodUnit ? item.warrantyPeriodUnit + '' : ''
+        // );
+        // if (item.warrantyPeriod && item.warrantyPeriodUnit) {
+        //   this.$set(
+        //     parasm,
+        //     'guaranteePeriodDeadline',
+        //     this.setDay(
+        //       item.warrantyPeriod,
+        //       this.guaranteePeriodUnit(item.warrantyPeriodUnit),
+        //       {}
+        //     )
+        //   );
+        // }
+
+        this.$set(
+          parasm,
+          'packageDispositionList',
+          item.packageDispositionList
+        );
+        if (item.packageDispositionList?.length) {
+          this.$set(
+            parasm,
+            this.countObj.unitIdKey,
+            item.packageDispositionList[0].id
+          );
+          this.$set(
+            parasm,
+            this.countObj.unitKey,
+            item.packageDispositionList[0].conversionUnit
+          );
         }
-        this.$emit(
-          'setPrice',
-          params.children.amountTotalPrice - this.invoiceAmount
+
+        this.$set(parasm, 'arrivalWay', item.arrivalWay || 1);
+
+        this.$set(parasm, 'imgCode', item.imgCode);
+        this.$set(parasm, 'produceType', item.componentAttribute);
+   
+        if (this.isGoods && item.goodsId) {
+          this.$set(parasm, 'goodsId', item.goodsId);
+          this.$set(parasm, 'goodsPriceId', item.goodsPriceId);
+          this.$set(parasm, 'goodsPriceType', item.goodsPriceType);
+          this.$set(parasm, 'singlePrice', item.singlePrice);
+          this.$set(parasm, 'notaxSinglePrice', item.notaxSinglePrice);
+          this.$set(parasm, 'taxRate', item.taxRate);
+          this.$set(parasm, 'discountSinglePrice', item.singlePrice);
+          this.$set(parasm, 'totalCount', '');
+          this.$set(parasm, 'discountRatio', item.discountRatio);
+          this.$set(parasm, 'quoteWay', item.quoteWay || 1);
+        } else {
+          this.$set(parasm, 'singlePrice', parasm.singlePrice || 0);
+          this.$set(parasm, 'discountRatio', parasm.discountRatio || 100);
+          this.$set(parasm, 'quoteWay', parasm.quoteWay || 1);
+        }
+
+
+      
+          this.$set(
+            parasm,
+            'entrustedEnterpriseIdList',
+            item.entrustedEnterpriseIdList
+          );
+          this.$set(
+            parasm,
+            'entrustedEnterpriseId',
+            item.entrustedEnterpriseId
+          );
+        
+        this.$set(parasm, 'approvalNumber', item.extField?.approvalNumber);
+        this.$set(
+          parasm,
+          'packingSpecification',
+          item.extField.packingSpecification
         );
-        let row = {
-          id: params.id,
-          name: params.statementNo,
-          code: params.statementNo,
-          linkType: params.type == 1 ? 190 : 290,
-          linkTypeName: params.type == 1 ? '销售对账单' : '采购对账单'
-        };
-        this.setSelectData(row);
+        this.$set(parasm, 'customerMark', this.customerMark);
+        if (item.purchaseOrigins?.length > 0) {
+          item.purchaseOrigins = item.purchaseOrigins.map((val) => val + '');
+        }
+        this.$set(parasm, 'provenance', item.purchaseOrigins || []);
+
+        if (idx == -1) {
+          this.tableForm.detailList.push(row);
+        }
+      });
+
+      console.log('changeParent~~~', this.tableForm.detailList);
+      this.recalcDetailList();
+    },
+      //选择产品
+    handParent(row, index) {
+      let item = {
+        id: row?.productCode
+      };
+      if (row?.goodsId) {
+        this.handGoods(index);
+        return;
+      }
+      
+      this.$refs.productListRef.open(item, index);
+  
+    },
+    handGoods(index) {
+      this.$refs.commodityPriceListDialogRef.open(index);
+    },
+      confirmBatchSet({ key, value }) {
+        if (!this.selection.length) {
+          this.$message.warning('请先勾选需要批量设置的行');
+          return;
+        }
+        // 批量设置选中行字段,并重算金额(合并回原对象,保持勾选引用不失效)
+        this.selection.forEach((item) => {
+          this.$set(item, key, value);
+          const updated = changeCount(item, this.countObj, false);
+          Object.keys(updated).forEach((k) => {
+            this.$set(item, k, updated[k]);
+          });
+          // 同步折让合计字段
+          this.$set(item, 'discountAmount', item.discountTotalPrice ?? '');
+        });
+        this.$nextTick(() => {
+          this.getNotaxSinglePrice();
+          this.calcAllTotal();
+        });
       },
       setValue(data) {
-        this.tableForm.detailList = data;
+        console.log('data~~~', data);
+        // 将 productMap(对象,key 为订单号,值为明细数组)转换为扁平行数组
+        this.tableForm.detailList = this.convertProductMapToArray(data);
+      },
+      // productMap -> 扁平行数组(表格展示用),key 固定为 99
+      convertProductMapToArray(data) {
+        const productMap = data?.productMap || {};
+        const result = [];
+        Object.keys(productMap).forEach((key) => {
+          const details = productMap[key] || [];
+          details.forEach((detail) => {
+            result.push({
+              key: 'UNKNOWN_ORDER', // 固定 key 99,提交时用于还原分组
+              ...detail
+            });
+          });
+        });
+        return result;
       },
       clearTable() {
         this.tableForm = {
@@ -363,6 +734,23 @@
           row.totalPrice = (parseFloat(row.totalCount) * parseFloat(row.singlePrice)).toFixed(2);
         }
       },
+      // 计价方式 label
+      pricingWayLabel(value) {
+        const item = this.pricingWayList.find((i) => i.id == value);
+        return item ? item.name : '';
+      },
+      // 打开工艺路线选择弹窗
+      openVersion(index) {
+        this.$refs.versionRefs.open(index);
+      },
+      // 工艺路线选择回调
+      changeProduct(data, index) {
+        if (data && this.tableForm.detailList[index]) {
+          this.$set(this.tableForm.detailList[index], 'technologyRouteName', data.name);
+          this.$set(this.tableForm.detailList[index], 'technologyRouteId', data.id);
+          this.$set(this.tableForm.detailList[index], 'technologyRouteVersion', data.version);
+        }
+      },
       getTableValidate() {
         return new Promise((resolve, reject) => {
           if (
@@ -385,15 +773,17 @@
           callback(valid);
         });
       },
-      setSelectData(val) {
-        this.tableForm.link = [{}];
-        this.$set(this.tableForm.link[0], 'linkId', val.id);
-        this.$set(this.tableForm.link[0], 'linkName', val.name);
-        this.$set(this.tableForm.link[0], 'linkCode', val.code);
-        this.$set(this.tableForm.link[0], 'linkType', val.linkType);
-        this.$set(this.tableForm.link[0], 'linkTypeName', val.linkTypeName);
-      },
-      getTableData() {}
+  
+      // 扁平行数组 -> productMap(提交格式),key 固定为 99
+      getTableData() {
+        const data = JSON.parse(JSON.stringify(this.tableForm.detailList));
+        const productMap = { UNKNOWN_ORDER: [] };
+        data.forEach((item) => {
+          const { key, ...detail } = item;
+          productMap['UNKNOWN_ORDER'].push(detail);
+        });
+        return productMap;
+      }
     }
   };
 </script>

+ 1 - 0
src/views/financialManage/paidManagement/index.vue

@@ -496,6 +496,7 @@
       datasource({ page, limit, where, order }) {
         return finPayablePageListAPI({
           paymentStatus: 1,
+          receiptStatus: 1,
           pageNum: page,
           size: limit,
           ...where

+ 488 - 79
src/views/financialManage/receivableManage/components/collectionDialog.vue

@@ -6,43 +6,347 @@
     :title="title"
     :append-to-body="true"
     :close-on-click-modal="false"
-    width="60%"
+    width="80%"
     :before-close="cancel"
     :maxable="true"
     :resizable="true"
   >
-    <collect-table-form
-      ref="collectTableFormRef"
-      :form.sync="form"
-      :total-price="form.receivableTotalPrice"
-      :dialog-type="dialogType"
-      total-label="应收金额"
-    ></collect-table-form>
+    <div style="margin: 10px 0; font-size: 14px; color: #606266;">
+      <span>应收金额:{{ row.receivableTotalPrice || 0 }} 元</span>
+      <span style="margin-left: 20px;">已收金额:{{ receivedAmount }} 元</span>
+      <span style="margin-left: 20px;">未收金额:{{ unreceivedAmount }} 元</span>
+    </div>
+    <el-form ref="form" :model="form" class="table-form" label-width="100px">
+      <el-row :gutter="12">
+        <el-col :span="8">
+          <el-form-item
+            label="收款时间"
+            prop="receivedDate"
+            :rules="{ required: true, message: '请选择收款时间', trigger: 'change' }"
+          >
+            <el-date-picker
+              v-model="form.receivedDate"
+              type="date"
+              placeholder="年/月/日"
+              value-format="yyyy-MM-dd"
+              style="width: 100%"
+              size="small"
+              :disabled="isView"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="已收金额">
+            <el-input
+              :value="receivedAmount"
+              placeholder="0"
+              size="small"
+              disabled
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="支付类型" prop="paymentType" :rules="{ required: true, message: '请选择支付类型', trigger: 'change' }">
+            <DictSelection
+              v-model="form.paymentType"
+              dictName="支付类型"
+              placeholder="请选择"
+              class="payment-select"
+              :disabled="isView"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="16">
+          <el-form-item label="备注" prop="remark">
+            <el-input
+              v-model="form.remark"
+              placeholder="请输入"
+              size="small"
+              :disabled="isView"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="附件" prop="files">
+            <fileMain v-model="form.files" :limit="1" :type="isView ? 'view' : 'add'"></fileMain>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <headerTitle title="应收明细" style="margin-top: 30px"></headerTitle>
+
+    <el-form ref="detailForm" :model="{ flatList }">
+      <ele-pro-table
+        ref="detailTable"
+        row-key="id"
+        :needPage="false"
+        :columns="columns"
+        max-height="500px"
+        :datasource="flatList"
+        :selection.sync="selection"
+        class="time-form"
+      >
+        <!-- 本次对账金额:唯一可填写字段 -->
+        <template v-slot:statementAmount="scope">
+          <el-input
+            v-model="scope.row.statementAmount"
+            type="number"
+            placeholder="请输入"
+            size="small"
+            :disabled="isView"
+            @input="handleAmountChange(scope.row, scope.$index)"
+          />
+        </template>
+
+        <template v-slot:headerRequired="{ column }">
+          <span class="is-required">{{ column.label }}</span>
+        </template>
+      </ele-pro-table>
+    </el-form>
+
     <div slot="footer">
-      <el-button type="primary" @click="save(0)">保存</el-button>
+      <el-button type="primary" @click="save()">保存</el-button>
       <el-button @click="cancel">返回</el-button>
     </div>
-
   </ele-modal>
 </template>
 <script>
-import infoTable from "./infoTable.vue";
-import collectTableForm from '@/BIZComponents/collectTableForm/index.vue';
-import {finReceivableSaveAPI, getFinReceivableInfoAPI, finReceivableUpdateAmountAPI} from "@/api/financialManage/receivableManage";
+import { pricingWayList } from '@/enum/dict.js';
+import { finReceivableSaveAPI, getFinReceivableInfoAPI } from "@/api/financialManage/receivableManage";
 
 export default {
   name: "collectionDialog",
-  components: {
-    infoTable,
-    collectTableForm
-  },
+  components: {},
   props: {
     collectionDialogFlag: {
       type: Boolean,
       default: false
     },
+    // 汇总区总金额(如预收金额/应收金额)
+    totalPrice: {
+      type: [Number, String],
+      default: 0
+    },
+    // 汇总区总金额标签(如"预收金额"/"应收金额")
+    totalLabel: {
+      type: String,
+      default: '预收金额'
+    }
+  },
+  computed: {
+    isView() {
+      return this.dialogType === 'view';
+    },
+    // 已收金额 = 勾选的应收明细「本次对账金额」之和
+    receivedAmount() {
+      const sum = this.selection.reduce((pre, item) => {
+        const val = parseFloat(item.statementAmount);
+        return pre + (isNaN(val) ? 0 : val);
+      }, 0);
+      return sum.toFixed(2);
+    },
+    // 未收金额 = 应收金额 - 已收金额
+    unreceivedAmount() {
+      const total = parseFloat(this.row.receivableTotalPrice) || 0;
+      const received = parseFloat(this.receivedAmount) || 0;
+      return (total - received).toFixed(2);
+    },
+    queryDimension() {
+      return this.form.queryDimension != null ? this.form.queryDimension : 1;
+    },
+    columns() {
+      let columnsVersion = this.columnsVersion;
+      return [
+        {
+          width: 45,
+          type: 'selection',
+          columnKey: 'selection',
+          align: 'center',
+          fixed: 'left'
+        },
+        {
+          width: 60,
+          label: '序号',
+          type: 'index',
+          columnKey: 'index',
+          align: 'center',
+          fixed: 'left'
+        },
+        {
+          minWidth: 140,
+          prop: 'orderNo',
+          label: this.queryDimension == 3 ? '采购订单编码' : '销售订单编码',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 140,
+          prop: 'statementSubOrderNo',
+          label: this.queryDimension == 3 ? '收货单编码' : this.queryDimension == 1 ? '发货单编码' : '调拨单编码',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 120,
+          prop: 'productOperateTime',
+          label: this.queryDimension == 3 ? '收货日期' : this.queryDimension == 1 ? '发货日期' : '调拨单日期',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 120,
+          prop: 'productCode',
+          label: '产品编码',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 140,
+          prop: 'productName',
+          label: '产品名称',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 120,
+          prop: 'batchNo',
+          label: '批次号',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 110,
+          prop: 'historicalStatementCount',
+          label: '已对账数量',
+          align: 'center'
+        },
+        {
+          minWidth: 140,
+          prop: 'statementCount',
+          label: '数量',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          headerSlot: 'headerRequired',
+          prop: 'statementAmount',
+          label: '本次已收金额',
+          align: 'center',
+          slot: 'statementAmount'
+        },
+        {
+          minWidth: 120,
+          prop: 'totalCount',
+          label: this.queryDimension == 3 ? '收货数量' : this.queryDimension == 1 ? '发货数量' : '调拨数量',
+          align: 'center'
+        },
+        {
+          minWidth: 140,
+          prop: 'technologyRouteName',
+          label: '工艺路线',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 120,
+          prop: 'singlePrice',
+          label: '单价',
+          align: 'center'
+        },
+        {
+          minWidth: 100,
+          prop: 'taxRate',
+          label: '税率',
+          align: 'center'
+        },
+        {
+          minWidth: 100,
+          prop: 'noTaxSinglePrice',
+          label: '不含税单价',
+          align: 'center'
+        },
+        {
+          minWidth: 100,
+          prop: 'totalPrice',
+          label: '合计',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          prop: 'discountRatio',
+          label: '折让比例',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          prop: 'discountSinglePrice',
+          label: '折让单价',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          prop: 'discountTotalPrice',
+          label: '折让合计',
+          align: 'center'
+        },
+        {
+          minWidth: 100,
+          prop: 'specification',
+          label: '规格',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 100,
+          prop: 'modelType',
+          label: '型号',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 80,
+          prop: 'color',
+          label: '颜色',
+          align: 'center',
+          showOverflowTooltip: true
+        },
+        {
+          minWidth: 120,
+          prop: 'outInCount',
+          label: '出库数量',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          prop: 'measuringUnit',
+          label: '计量单位',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          prop: 'sendTotalWeight',
+          label: '出库重量',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          prop: 'weightUnit',
+          label: '重量单位',
+          align: 'center'
+        },
+        {
+          minWidth: 120,
+          prop: 'pricingWay',
+          label: '计价方式',
+          align: 'center',
+          formatter: (row, column) => {
+            return pricingWayList.find((item) => item.id == row.pricingWay)?.name;
+          }
+        }
+      ];
+    }
   },
-  computed: {},
   data() {
     return {
       row: {},
@@ -52,90 +356,195 @@ export default {
       info: {},
       form: {
         id: '',
-        tableData: []
+        queryDimension: 1,
+        receivedDate: '',
+        paymentType: '',
+        files: [],
+        remark: '',
       },
-      rules: {}
+      rules: {},
+      datasource: [],
+      flatList: [],
+      selection: [],
+      totalAmount: 0,
+      totalCount: 0,
+      columnsVersion: 1
     }
   },
-  created() {
-
+  watch: {
+    datasource: {
+      handler(newVal) {
+        this.$nextTick(() => {
+          const list = (newVal || []).map((item) => this.buildRow(item, item.orderNo || '', false));
+          this.flatList = list;
+          this.calcTotals();
+        });
+      },
+      immediate: true
+    }
   },
+  created() {},
   methods: {
-    //初始化
+    // 初始化
     async open(row, type) {
       this.row = row || {};
       this.dialogType = type || 'update';
       this.title = this.dialogType === 'view' ? '收款详情' : '收款';
-      this.info = await getFinReceivableInfoAPI(row.id);
-      // 直接替换整个 form,保证 tableData 等字段响应式更新
+      await this.getInfo(row.id);
+    },
+    // 获取详情
+    async getInfo(id) {
+      const data = await getFinReceivableInfoAPI(id);
+      this.datasource = data.productList || [];
       this.form = {
-        ...this.info,
-        tableData: this.info.detailList || []
+        ...this.form,
+        id: data.id || '',
+        queryDimension: data.queryDimension != null ? data.queryDimension : 1,
+        receivedDate: data.receivedDate || '',
+        paymentType: data.paymentType ?? '',
+        files: data.files || [],
+        remark: data.remark || ''
       };
     },
-    //获取详情
-    async getInfo(id) {
-      this.form = await getFinReceivableInfoAPI(id)
+
+    // 构建单行派生字段
+    buildRow(item, orderNo, isReturn) {
+      const outboundCount = +item.totalCount || 0;
+      const count = isReturn ? -Math.abs(outboundCount) : outboundCount;
+      const statemented = +item.statementedCount || 0;
+      let statementCount = item.statementCount;
+      if (statementCount === undefined || statementCount === null || statementCount === '') {
+        statementCount = count;
+      }
+      const singlePrice = +item.singlePrice;
+      const discountRatio =
+        item.discountRatio === undefined || item.discountRatio === null || item.discountRatio === ''
+          ? 100
+          : +item.discountRatio;
+      const taxRate =
+        item.taxRate === undefined || item.taxRate === null || item.taxRate === ''
+          ? ''
+          : +item.taxRate;
+      const amount =
+        Math.round(statementCount * singlePrice * (discountRatio / 100) * 100) / 100;
+      const noTaxSinglePrice =
+        singlePrice && taxRate ? +((singlePrice / (1 + taxRate / 100)).toFixed(4)) : '';
+      const totalPrice = Math.round(statementCount * singlePrice * 100) / 100;
+      const discountSinglePrice = Math.round(singlePrice * (discountRatio / 100) * 100) / 100;
+      const discountTotalPrice = Math.round(totalPrice * (discountRatio / 100) * 100) / 100;
+      this.$set(item, 'saleOrderNo', orderNo);
+      this.$set(item, 'statementSubOrderNo', item.statementSubOrderNo || item.subOrderNo || '');
+      this.$set(item, 'productOperateTime', item.productOperateTime || item.deliveryDate || '');
+      this.$set(item, 'outboundCount', count);
+      this.$set(item, 'statementedCount', statemented);
+      this.$set(item, 'statementCount', statementCount);
+      this.$set(item, 'singlePrice', singlePrice);
+      this.$set(item, 'taxRate', taxRate);
+      this.$set(item, 'discountRatio', discountRatio);
+      this.$set(item, 'statementAmount', amount);
+      this.$set(item, 'noTaxSinglePrice', noTaxSinglePrice);
+      this.$set(item, 'totalPrice', totalPrice);
+      this.$set(item, 'discountSinglePrice', discountSinglePrice);
+      this.$set(item, 'discountTotalPrice', discountTotalPrice);
+      this.$set(item, 'isReturn', isReturn);
+      return item;
     },
 
-    save() {
-        // 先校验公共组件内的表单
-        this.$refs.collectTableFormRef.validate().then(() => {
-          // 取整个表单数据
-          const data = this.$refs.collectTableFormRef.getData();
-          this.loading = true;
-          const params = data.tableData.map((item) => {
-            return {
-              ...item,
-              receivableId: this.row.id,
-              receivableCode: this.row.code
-            };
-          });
-          finReceivableSaveAPI(params)
-            .then(() => {
-              this.loading = false;
-              this.$message.success('收款成功');
-              this.cancel()
-              this.done()
-            })
-            .catch(() => {
-              this.loading = false;
-            });
-        }).catch(() => {});
-      },
+    // 汇总
+    calcTotals() {
+      const amount =
+        this.flatList.reduce((pre, cur) => pre + Math.round((+cur.statementAmount || 0) * 100), 0) / 100;
+      const count = this.flatList.reduce((pre, cur) => pre + (+cur.statementCount || 0), 0);
+      this.totalAmount = amount;
+      this.totalCount = count;
+    },
+
+    // 本次对账金额变化(唯一可编辑字段)
+    handleAmountChange(row, index) {
+      this.calcTotals();
+    },
+
+    // 获取勾选行数据
+    getSelection() {
+      return this.selection;
+    },
 
-      updateVisible(value) {
-        this.collectionDialogFlag = value;
-        if (!value) {
-          this.row = {};
-          this.form.tableData = [];
+    // 校验勾选行的本次对账金额必填
+    validateSelection() {
+      return new Promise((resolve, reject) => {
+        if (!this.selection.length) {
+          this.$message.warning('请先勾选需要提交的应收明细');
+          reject(false);
+          return;
         }
-      },
-    //
-    async handleSave() {
-      let data = await this.$refs.feeRelatedInfoTable.getTableValidate()
-      console.log('data~~~', data)
-      let detailList = data[0]
-      let receivableTotalPrice = data[1]
-      // await finReceivableUpdateAmountAPI(this.form.id, {
-      //   receivableTotalPrice: receivableTotalPrice
-      // })
-     await finReceivableSaveAPI(detailList)
-      this.$message.success('操作成功')
-      this.done()
-      this.cancel()
+        const tips = [];
+        this.selection.forEach((row, i) => {
+          if (row.statementAmount === '' || row.statementAmount == null) {
+            tips.push(`第${i + 1}行「本次对账金额」未填写`);
+          }
+        });
+        if (tips.length) {
+          this.$message.warning('勾选的应收明细存在未填写项:' + tips.join('、'));
+          reject(false);
+        } else {
+          resolve(true);
+        }
+      });
     },
-    //刷新主列表数据
+
+    async save() {
+      // 1. 校验收款信息表单
+      const formValid = await new Promise((resolve) => {
+        this.$refs.form.validate((valid) => resolve(valid));
+      });
+      if (!formValid) {
+        return this.$message.warning('请填写完整收款信息');
+      }
+      // 2. 获取勾选的应收明细并校验必填
+      const selection = this.getSelection();
+      if (!selection.length) {
+        return this.$message.warning('请先勾选需要提交的应收明细');
+      }
+      const selectionValid = await this.validateSelection().catch(() => false);
+      if (!selectionValid) return;
+
+      this.loading = true;
+      // 3. 提交:收款信息 + 勾选的应收明细(已收金额 = 勾选行本次对账金额之和)
+      const params = {
+        ...this.form,
+        receivedTotalPrice: this.receivedAmount,
+        receivableId: this.row.id,
+        receivableCode: this.row.code,
+        productList: selection
+      };
+      finReceivableSaveAPI(params)
+        .then(() => {
+          this.loading = false;
+          this.$message.success('收款成功');
+          this.cancel();
+          this.done();
+        })
+        .catch(() => {
+          this.loading = false;
+        });
+    },
+
+    // 刷新主列表数据
     done() {
-      this.$emit('reload')
+      this.$emit('reload');
     },
-    //关闭弹窗
+    // 关闭弹窗
     cancel() {
-      this.$emit('update:collectionDialogFlag', false)
+      this.$emit('update:collectionDialogFlag', false);
     }
   }
 }
 </script>
 <style scoped lang="scss">
-
+  .detail-toolbar {
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    margin-bottom: 10px;
+  }
 </style>

+ 105 - 5
src/views/financialManage/receivableManage/components/detailDialog.vue

@@ -158,6 +158,27 @@
       v-if="activeComp === 'bpm' && dataForm.processInstanceId"
       :id="dataForm.processInstanceId"
     ></bpmDetail>
+    <div v-if="activeComp === 'collection'">
+      <!-- <ele-pro-table
+        ref="detailTable"
+        row-key="id"
+        :needPage="false"
+        :columns="columns"
+        max-height="500px"
+        class="time-form"
+        :datasource="detailList"
+      >
+        
+      </ele-pro-table> -->
+
+      <collect-table-form
+        ref="collectTableFormRef"
+        :form.sync="collectionForm"
+        :total-price="collectionForm.receivedTotalPrice"
+        :dialog-type="dialogType"
+        total-label="应收金额"
+      ></collect-table-form>
+    </div>
     <div slot="footer">
       <el-button @click="cancel">返回</el-button>
     </div>
@@ -169,7 +190,7 @@
   import dictMixins from '@/mixins/dictMixins';
   // import fileMain from '@/components/addDoc/index.vue';
 
-  import { getFinReceivableInfoAPI } from '@/api/financialManage/receivableManage';
+  import { getFinReceivableInfoAPI, getDetailList } from '@/api/financialManage/receivableManage';
   import { getTreeByPid } from '@/api/classifyManage';
   import infoTable from '@/views/financialManage/receivableManage/components/infoTable.vue';
   import bpmDetail from '@/views/bpm/processInstance/detail.vue';
@@ -177,6 +198,7 @@
 
   import AccountDetailTable from '@/views/saleManage/saleOrder/accountstatement/components/accountDetailTable.vue';
   import ReceivableInfo from '@/views/saleManage/saleOrder/accountstatement/components//receivableInfo.vue';
+  import collectTableForm from '@/BIZComponents/collectTableForm/index.vue';
 
   export default {
     mixins: [dictMixins],
@@ -184,19 +206,82 @@
       bpmDetail,
       infoTable,
       AccountDetailTable,
-      ReceivableInfo
+      ReceivableInfo,
+      collectTableForm
       // fileMain
     },
-
+    computed: {
+      columns() {
+        return [
+          {
+            type: 'index',
+            label: '序号',
+            width: 55,
+            align: 'center',
+            fixed: 'left'
+          },
+          {
+            prop: 'receivedDate',
+            headerSlot: 'columnRequired',
+            label: '收款时间',
+            align: 'center',
+            minWidth: 160,
+            slot: 'receivedDate'
+          },
+          {
+            prop: 'receivedTotalPrice',
+            headerSlot: 'columnRequired',
+            label: '已收金额',
+            align: 'center',
+            minWidth: 140,
+            slot: 'receivedTotalPrice'
+          },
+          {
+            prop: 'paymentType',
+            headerSlot: 'columnRequired',
+            label: '支付类型',
+            align: 'center',
+            minWidth: 140,
+            slot: 'paymentType'
+          },
+          {
+            prop: 'files',
+            label: '附件',
+            align: 'center',
+            minWidth: 120,
+            slot: 'files'
+          },
+          {
+            prop: 'remark',
+            label: '备注',
+            align: 'center',
+            minWidth: 140,
+            slot: 'remark'
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 80,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            fixed: 'right',
+            show: !this.isView
+          }
+        ];
+      },
+    },
     data() {
       return {
         activeComp: 'main',
         tabOptions: [
-          { key: 'main', name: '收款详情' },
-          { key: 'bpm', name: '流程详情' }
+          { key: 'main', name: '应收详情' },
+          { key: 'bpm', name: '流程详情' },
+          { key: 'collection', name: '收款详情' },
         ],
         payAndReceiveEnum,
         dialogType: '',
+        detailList: [],
         dataForm: {
           accountingSubjectCode: '',
           accountingSubjectId: '',
@@ -217,6 +302,7 @@
         },
         accountingSubjectList: [],
         datasource: [],
+        collectionForm: {},
         statReceipt: null,
         receivableList: [],
         rules: {
@@ -258,6 +344,20 @@
         (data.statReceipt && data.statReceipt.statReceiptDetailList) || [];
 
         this.datasource = data.productList || [];
+
+        this.detailList = await getDetailList(id);
+
+        this.collectionForm = {
+          ...this.dataForm,
+          tableData: this.detailList.map(item => {
+            return {
+              ...item,
+              paymentType: item.paymentType?.toString() || '',
+            }
+          }) || []
+        }
+
+        console.log(this.detailList)
         
         // this.$nextTick(() => {
         //   this.$refs.feeRelatedInfoTable.init();

+ 102 - 30
src/views/financialManage/receivableManage/components/receivableDialog.vue

@@ -20,19 +20,30 @@
       tool-class="ele-toolbar-form"
       cache-key="eomContactPageTable"
       :page-size="20"
+      :selection.sync="selection"
+      @cell-click="cellClick"
     >
+      <!-- 单选 radio 列 -->
+      <template v-slot:radioSelect="{ row }">
+        <el-radio
+          v-model="radio"
+          :label="row.id"
+          @change="(val) => selectRow(val, row)"
+          ><i></i
+        ></el-radio>
+      </template>
       <!-- 操作 -->
-      <template v-slot:action="{ row }">
+      <!-- <template v-slot:action="{ row }">
         <el-link
           type="primary"
           :underline="false"
           icon="el-icon-plus"
           v-if="canAddInvoice(row)"
-          @click="done(row, 'view')"
+          @click="handleDetail(row)"
         >
           新增发票
         </el-link>
-      </template>
+      </template> -->
     </ele-pro-table>
     <detail-dialog1
       ref="detailDialogRef"
@@ -43,6 +54,7 @@
   
     ></detail-dialog1>
     <div slot="footer">
+      <el-button type="primary" size="small" @click="selected">选择</el-button>
       <el-button @click="cache">返回</el-button>
     </div>
   </ele-modal>
@@ -59,13 +71,25 @@
       columns() {
         // 当columnsVersion变化时会重新计算,用作更新列配置
         const version = this.columnsVersion;
+        // 选择列:多选(复选框)或单选(radio)
+        const selectColumn = this.multiple
+          ? {
+              width: 45,
+              type: 'selection',
+              columnKey: 'selection',
+              align: 'center',
+              fixed: 'left'
+            }
+          : {
+              width: 55,
+              label: '选择',
+              columnKey: 'radioSelect',
+              align: 'center',
+              slot: 'radioSelect',
+              fixed: 'left'
+            };
         return [
-          {
-            width: 45,
-            type: 'selection',
-            columnKey: 'selection',
-            align: 'center'
-          },
+          selectColumn,
           {
             width: 60,
             label: '序号',
@@ -75,20 +99,28 @@
           },
           {
             minWidth: 150,
-            prop: 'code',
-            label: '应收编码',
+            prop: 'detailCode',
+            label: '已收编码',
             align: 'center',
             // slot: 'code',
             showOverflowTooltip: true
           },
           {
-            minWidth: 160,
-            prop: 'receiptPlanOrderNo',
-            label: '收款计划编码',
+            minWidth: 150,
+            prop: 'code',
+            label: '应收编码',
             align: 'center',
-            slot: 'receiptPlanOrderNo',
+            // slot: 'code',
             showOverflowTooltip: true
           },
+          // {
+          //   minWidth: 160,
+          //   prop: 'receiptPlanOrderNo',
+          //   label: '收款计划编码',
+          //   align: 'center',
+          //   slot: 'receiptPlanOrderNo',
+          //   showOverflowTooltip: true
+          // },
           {
             minWidth: 160,
             prop: 'saleOrderNo',
@@ -302,16 +334,16 @@
             }
           },
           
-          {
-            columnKey: 'action',
-            label: '操作',
-            width: 150,
-            align: 'center',
-            resizable: false,
-            slot: 'action',
-            showOverflowTooltip: true,
-            fixed: 'right'
-          }
+          // {
+          //   columnKey: 'action',
+          //   label: '操作',
+          //   width: 150,
+          //   align: 'center',
+          //   resizable: false,
+          //   slot: 'action',
+          //   showOverflowTooltip: true,
+          //   fixed: 'right'
+          // }
         ];
       },
       canAddInvoice() {
@@ -323,11 +355,14 @@
     },
     data() {
       return {
-        title: '应收列表',
+        title: '已收列表',
         transactionMethodsOp,
         detailDialogFlag1: false,
         paymentStatus,
         invoiceStatusOp,
+        selection: [],
+        current: null,
+        radio: null,
         statusList: [
           {
             label: '未收款',
@@ -346,10 +381,15 @@
     },
     props: {
       receivableDialogFlag: {
-      type: Boolean,
-      default: false,
+        type: Boolean,
+        default: false,
+      },
+      // 是否多选:true 多选(复选框),false 单选(radio)
+      multiple: {
+        type: Boolean,
+        default: false
+      },
     },
-  },
     created() {},
     methods: {
       handleDetail(row = {}, type) {
@@ -359,6 +399,34 @@
         });
       },
 
+      // 单选:点击行记录当前行
+      cellClick(row) {
+        if (this.multiple) return;
+        this.current = row;
+        this.radio = row.id;
+      },
+      // 单选:radio 选中记录当前行
+      selectRow(val, row) {
+        this.current = row;
+        this.radio = row.id;
+      },
+
+      // 选择:根据单选/多选返回数据
+      selected() {
+        if (this.multiple) {
+          if (!this.selection.length) {
+            return this.$message.warning('请至少选择一条数据');
+          }
+          this.$emit('receivableDone', this.selection);
+        } else {
+          if (!this.current) {
+            return this.$message.warning('请至少选择一条数据');
+          }
+          this.$emit('receivableDone', [this.current]);
+        }
+        this.cache();
+      },
+
       done(data){
         console.log(data,'data')
 
@@ -366,6 +434,9 @@
         this.cache()
       },
       cache(){
+        this.radio = null;
+        this.current = null;
+        this.selection = [];
         this.$emit('update:receivableDialogFlag', false)
       },
       /* 表格数据源 */
@@ -374,7 +445,8 @@
           pageNum: page,
           size: limit,
           approvalStatus:2,
-          transactionMode:2,
+          receiptStatus: 1,
+          // transactionMode:2,
           ...where
         });
       }

+ 8 - 8
src/views/financialManage/receivedManaged/index.vue

@@ -226,14 +226,14 @@
             slot: 'code',
             showOverflowTooltip: true
           },
-          {
-            minWidth: 160,
-            prop: 'receiptPlanOrderNo',
-            label: '收款计划编码',
-            align: 'center',
-            slot: 'receiptPlanOrderNo',
-            showOverflowTooltip: true
-          },
+          // {
+          //   minWidth: 160,
+          //   prop: 'receiptPlanOrderNo',
+          //   label: '收款计划编码',
+          //   align: 'center',
+          //   slot: 'receiptPlanOrderNo',
+          //   showOverflowTooltip: true
+          // },
           {
             minWidth: 160,
             prop: 'saleOrderNo',

+ 6 - 6
src/views/purchasingManage/purchaseOrder/components/addDialogNew.vue

@@ -253,7 +253,7 @@
             >
             </el-date-picker>
           </el-form-item>
-          <el-form-item label="付款条件" prop="collectionConditionName">
+          <!-- <el-form-item label="付款条件" prop="collectionConditionName">
             <el-input
               clearable
               readonly
@@ -261,18 +261,18 @@
               @click.native="handlePaymentConditionBtn"
               placeholder="请输入"
             />
-          </el-form-item>
+          </el-form-item> -->
           <el-form-item prop="orderFiles" label="附件">
             <fileMain v-model="form.orderFiles"></fileMain>
           </el-form-item>
         </el-col>
         <el-col :span="8">
-          <el-form-item label="生成付款计划表" prop="isGenerateReceiptPlan">
+          <!-- <el-form-item label="生成付款计划表" prop="isGenerateReceiptPlan">
             <el-radio-group v-model="form.isGenerateReceiptPlan" @change="generatePlanChange">
               <el-radio :label="1">是</el-radio>
               <el-radio :label="0">否</el-radio>
             </el-radio-group>
-          </el-form-item>
+          </el-form-item> -->
           <el-form-item label="交易方式" prop="transactionMode">
             <el-select
               v-model="form.transactionMode"
@@ -872,7 +872,7 @@
         saleType: '',
         saleTypeName: '',
         totalAmount: '',
-        isGenerateReceiptPlan: 0,
+        isGenerateReceiptPlan: 1,
         settlementMode: '4',
         settlementModeName: '分期付款',
         partaUnifiedSocialCreditCode: '',
@@ -2171,7 +2171,7 @@
             })
           }
           this.form.contractStartDate = formatDate(new Date(), 'yyyy-MM-dd');
-          this.form.isGenerateReceiptPlan = +this.isGenReceiptPlan;
+          // this.form.isGenerateReceiptPlan = +this.isGenReceiptPlan;
         } else {
           this.isUpdate = true;
           await this.getpurchaseorderDetail(row.id);

+ 78 - 6
src/views/saleManage/saleOrder/accountstatement/components/accountDetailTable.vue

@@ -191,6 +191,7 @@
   import { pricingWayList } from '@/enum/dict.js';
   import ProductionVersion from '@/components/ProductionVersion2/index.vue';
   import setAllValue from '@/BIZComponents/setAllValue.vue'; //批量修改
+  import { getGoodsById } from '@/api/goodsManage/index';
 
   export default {
     name: 'accountDetailTable',
@@ -718,6 +719,51 @@
           });
         });
       },
+      // 获取勾选的行数据(供父组件提交时使用)
+      getSelection() {
+        return this.selection;
+      },
+      // 校验勾选行的必填字段
+      validateSelection() {
+        return new Promise((resolve, reject) => {
+          if (!this.selection.length) {
+            this.$message.warning('请先勾选需要提交的对账明细');
+            reject(false);
+            return;
+          }
+          const fieldLabelMap = {
+            statementCount: '本次对账数量',
+            singlePrice: '单价',
+            taxRate: '税率',
+            discountRatio: '折让比例'
+          };
+          const tips = [];
+          this.selection.forEach((row) => {
+            // 本次对账数量必填
+            if (row.statementCount === '' || row.statementCount == null) {
+              tips.push(`「${fieldLabelMap.statementCount}」未填写`);
+            }
+            // 单价必填
+            if (row.singlePrice === '' || row.singlePrice == null) {
+              tips.push(`「${fieldLabelMap.singlePrice}」未填写`);
+            }
+            // 折让比例必填
+            if (row.discountRatio === '' || row.discountRatio == null) {
+              tips.push(`「${fieldLabelMap.discountRatio}」未填写`);
+            }
+            // 税率(isTaxRate == 1 时必填)
+            if (this.isTaxRate == 1 && (row.taxRate === '' || row.taxRate == null)) {
+              tips.push(`「${fieldLabelMap.taxRate}」未填写`);
+            }
+          });
+          if (tips.length) {
+            this.$message.warning('勾选的对账明细存在未填写项:' + tips.join('、'));
+            reject(false);
+          } else {
+            resolve(true);
+          }
+        });
+      },
       // 根据校验失败字段生成具体提示
       buildValidateTip(invalidFields) {
         const fieldLabelMap = {
@@ -749,12 +795,38 @@
         this.$refs.versionRefs.open(index);
       },
       // 工艺路线选择回调(参考 inventoryTable.changeProduct)
-      changeProduct(data, index) {
-        if (this.flatList[index]) {
-          this.$set(this.flatList[index], 'technologyRouteName', data.name);
-          this.$set(this.flatList[index], 'technologyRouteId', data.id);
-          this.$set(this.flatList[index], 'technologyRouteVersion', data.version);
-          this.emitChange();
+      async changeProduct(data, index) {
+        const row = this.flatList[index];
+        if (!row) return;
+        // 先回填工艺路线信息
+        this.$set(row, 'technologyRouteName', data.name);
+        this.$set(row, 'technologyRouteId', data.id);
+        // 根据工艺路线带出默认单价
+        if (row.goodsId) {
+          await this.setDefaultPrice(row, data.id);
+        }
+        // 单价变化后重算金额与汇总
+        this.calcRow(row);
+        this.calcTotals();
+        this.emitChange();
+      },
+      // 根据商品 + 工艺路线匹配默认单价(有效期内)
+      async setDefaultPrice(row, technologyRouteId) {
+        try {
+          const goodsInfo = await getGoodsById(row.goodsId);
+          const priceList = goodsInfo?.goodsPriceList || [];
+          // 命中当前工艺路线,且为默认价、在有效期内的价目
+          const defaultItem = priceList.find((item) => {
+            if (item.technologyRouteId != technologyRouteId) return false;
+            if (item.isDefault != 1) return false;
+            const expiry = new Date(item.priceExpiryDate);
+            return !isNaN(expiry.getTime()) && expiry >= new Date();
+          });
+          if (defaultItem) {
+            this.$set(row, 'singlePrice', defaultItem.singlePrice);
+          }
+        } catch (e) {
+          console.error('获取商品价目失败:', e);
         }
       }
     }