瀏覽代碼

feat: 采购订单对账单静态

liujt 2 周之前
父節點
當前提交
363e9684e6

+ 72 - 39
src/views/purchasingManage/purchaseOrder/accountstatement/components/addAccountDialog.vue

@@ -16,39 +16,26 @@
       @handleSearch="handleSearch"
       :dataForm.sync="dataForm"
       :datasource.sync="datasource"
-      :recorpayList.sync="recorpayList"
-
       :dialogType="dialogType"
     ></purchase-form>
-    <headerTitle title="对账明细" style="margin-top: 30px">
-      <template v-slot>
-        <el-row style="font-weight: 700; color: red">
-          <span>总金额:</span>
-          <span>{{ dataForm.orderTotalAmount || 0 }}</span>
-          <el-divider direction="vertical"></el-divider>
-          <span>已对账金额:</span>
-          <span>{{ dataForm.amountCompletePrice || 0 }}</span>
-          <el-divider direction="vertical"></el-divider>
-          <span>未对账金额:</span>
-          <span>{{ dataForm.amountUnCompletePrice || 0 }}</span>
-          <el-divider direction="vertical"></el-divider>
-          <span>本次对账总金额:</span>
-          <span>{{ dataForm.amountTotalPrice || 0 }}</span>
-        </el-row>
-      </template>
-    </headerTitle>
-    <!-- <recorpayTableList
-      ref="recorpayListRef"
-      :dataForm="dataForm"
-      :recorpayList.sync="recorpayList"
-      :dialogType="dialogType"
-    ></recorpayTableList> -->
-    <inventoryTable
-      ref="inventoryTableref"
-      :datasource.sync="datasource"
+    <!-- 应付信息 -->
+    <headerTitle title="应付信息" style="margin-top: 30px"></headerTitle>
+    <payables-info
+      ref="payablesInfoRef"
+      :dataForm.sync="dataForm"
+      :payablesList="payablesList"
       :dialogType="dialogType"
-      type="purchase"
-    ></inventoryTable>
+    ></payables-info>
+    <headerTitle title="对账明细" style="margin-top: 30px"> </headerTitle>
+    <account-detail-table
+        ref="accountDetailTableRef"
+        :datasource.sync="datasource"
+        :dialogType="dialogType"
+        :queryDimension="dataForm.queryDimension"
+        @totalChange="handleTotalChange"
+        @countChange="handleCountChange"
+        @statementAmountChange="handleStatementAmountChange"
+      ></account-detail-table>
     <div slot="footer" class="footer">
       <el-button
         v-if="dialogType !== 'view'"
@@ -80,13 +67,17 @@
   // import InventoryTable from './inventoryTable.vue';
   import InventoryTable from '@/views/saleManage/saleOrder/accountstatement/components/inventoryTable.vue';
   import purchaseForm from './purchaseForm.vue';
+  import payablesInfo from './payablesInfo.vue';
+
   import {
-    getStatementRecordListAPI,
+    getStatementRecordSummaryAPI,
     createAccountStatementAPI,
     accountstatementInfoAPI,
     accountstatementUpdateAPI
   } from '@/api/saleManage/accountstatement';
   import processSubmitDialog from '@/BIZComponents/processSubmitDialog/processSubmitDialog.vue';
+  import { paymentTypeOp } from '@/enum/dict';
+  import AccountDetailTable from '@/views/saleManage/saleOrder/accountstatement/components/accountDetailTable.vue';
 
   export default {
     name: 'addAccountDialog',
@@ -95,6 +86,8 @@
       processSubmitDialog,
       InventoryTable,
       purchaseForm,
+      payablesInfo,
+      AccountDetailTable
       // recorpayTableList
     },
     data() {
@@ -103,6 +96,8 @@
         fullscreen: false,
         datasource: [],
         recorpayList: [],
+        // 应付信息初始明细(查询/编辑回填),由 payablesInfo 本地维护,提交时取回
+        payablesList: [],
         dataForm: {
           sourceType: 1,
           dateType: 1,
@@ -131,6 +126,18 @@
     },
     computed: {},
     methods: {
+      handleTotalChange(total) {
+        this.dataForm.amountTotalPrice = total;
+      },
+      handleCountChange(count) {
+        this.dataForm.totalStatementCount = count;
+      },
+      // 明细表本次对账金额变化时,按销售单号同步到应收信息对应行
+      handleStatementAmountChange(summaryMap) {
+        if (this.$refs.payablesInfoRef) {
+          this.$refs.payablesInfoRef.syncStatementAmount(summaryMap);
+        }
+      },
       open(dialogType, row, type = '') {
         this.businessId = row?.id || '';
         this.dialogType = dialogType;
@@ -154,6 +161,11 @@
         data.amountCompletePrice = data.orderList.reduce((pre, cur) => pre + Math.round(+cur.statementedAmount * 100), 0) / 100;
         data.amountUnCompletePrice = data.orderList.reduce((pre, cur) => pre + Math.round(+cur.unStatementAmount * 100), 0) / 100;
         this.datasource = data.orderList || [];
+        // 编辑详情回填应付信息(兼容 payablesList / statPayable 两种字段)
+        this.payablesList =
+          data.payablesList ||
+          (data.statPayable && data.statPayable.statPayableDetailList) ||
+          [];
         this.dataForm = data;
         switch (this.dataForm.dateType) {
           case 1:
@@ -194,36 +206,48 @@
           queryDimension: params.queryDimension,
           type: 2
         };
-        let data = await getStatementRecordListAPI(searchQuery);
+        let data = await getStatementRecordSummaryAPI(searchQuery);
         // this.recorpayList = data.recorpayList || [];
-        this.datasource = data || [];
+        this.datasource = data.productList || [];
+        // 查询接口暂未返回预付信息时,先置空(由 payablesInfo 本地维护)
+        this.payablesList = data.payablesList ||
+          (data.statPayable && data.statPayable.statPayableDetailList) ||
+          [];
         this.dataForm = {
           ...this.dataForm,
+          ...data
           // amountPayablePrice: data.amountPayablePrice,
           // amountReceivablePrice: data.amountReceivablePrice,
           // amountTotalPrice: data.amountTotalPrice,
           // amountPayablePass: data.amountPayablePass,
           // amountReceivablePass: data.amountReceivablePass
-          orderTotalAmount: data.reduce((pre, cur) => pre + Math.round(+cur.orderAmount * 100), 0) / 100,
-          amountTotalPrice: data.reduce((pre, cur) => pre + Math.round(+cur.statementAmount * 100), 0) / 100,
-          amountCompletePrice: data.reduce((pre, cur) => pre + Math.round(+cur.statementedAmount * 100), 0) / 100,
-          amountUnCompletePrice: data.reduce((pre, cur) => pre + Math.round(+cur.unStatementAmount * 100), 0) / 100
+          // orderTotalAmount: data.reduce((pre, cur) => pre + Math.round(+cur.orderAmount * 100), 0) / 100,
+          // amountTotalPrice: data.reduce((pre, cur) => pre + Math.round(+cur.statementAmount * 100), 0) / 100,
+          // amountCompletePrice: data.reduce((pre, cur) => pre + Math.round(+cur.statementedAmount * 100), 0) / 100,
+          // amountUnCompletePrice: data.reduce((pre, cur) => pre + Math.round(+cur.unStatementAmount * 100), 0) / 100
         };
         // if (!this.datasource.length) this.$message.warning('暂无订单信息');
       },
       //保存
       async save(is) {
-        if (!this.datasource.length&&!this.recorpayList.length)
+        if (!this.datasource.length && !this.recorpayList.length && !this.payablesList.length)
         return this.$message.warning('暂无对账信息');
 
         let api =
           this.dialogType == 'add'
             ? createAccountStatementAPI
             : accountstatementUpdateAPI;
+        // 提交时一次性取回应付信息(本地明细 + 汇总)
+        const payablesData = this.$refs.payablesInfoRef
+          ? this.$refs.payablesInfoRef.getSubmitData()
+          : { payablesList: [], statementAdvanceTotalPrice: 0, receivedTotalPrice: 0 };
         let params = {
           ...this.dataForm,
           orderList: this.datasource,
-          recorpayList:this.recorpayList
+          recorpayList: this.recorpayList,
+          payablesList: payablesData.payablesList,
+          totalAdvanceConfirmAmount: payablesData.statementAdvanceTotalPrice,
+          totalPayableAmount: payablesData.receivedTotalPrice
         };
         let data = await api(params);
         if (is == 'sub') {
@@ -264,6 +288,15 @@
           this.$refs.processSubmitDialogRef.init(params);
         });
       },
+      // 对账明细本次对账金额变化时,按采购订单号同步到应付信息对应行
+      handleDiscountPriceChange(statementAmount, tableIndex) {
+        const order = this.datasource[tableIndex];
+        if (!order || !order.orderNo) return;
+        const summaryMap = { [order.orderNo]: statementAmount };
+        if (this.$refs.payablesInfoRef) {
+          this.$refs.payablesInfoRef.syncStatementAmount(summaryMap);
+        }
+      },
       reload() {
         this.cancel();
         //刷新主页面

+ 387 - 0
src/views/purchasingManage/purchaseOrder/accountstatement/components/payablesInfo.vue

@@ -0,0 +1,387 @@
+<template>
+  <div class="payables-info">
+    <el-form ref="form" :model="dataForm" :rules="rules" label-width="170px">
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="总对账预付款确收金额">
+            <el-input disabled v-model="statementAdvanceTotalPrice">
+              <template slot="append">元</template>
+            </el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="8">
+          <el-form-item label="总应付金额">
+            <el-input disabled v-model="receivedTotalPrice">
+              <template slot="append">元</template>
+            </el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <el-form :model="{ payablesList: localList }" ref="tableForm">
+      <ele-pro-table
+        ref="payablesTable"
+        row-key="id"
+        :needPage="false"
+        :columns="columns"
+        max-height="400px"
+        :datasource="localList"
+        :cache-key="cacheKeyUrl"
+        class="time-form"
+      >
+        <template v-slot:fundType="scope">
+          <el-select
+            v-model="scope.row.fundType"
+            placeholder="请选择"
+            class="ele-block"
+            :disabled="isView"
+            @change="(val) => updateRowField(scope.$index, 'fundType', val)"
+          >
+            <el-option
+              v-for="item in paymentTypeOp"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </template>
+
+        <template v-slot:transactionMode="scope">
+          <el-select
+            v-model="scope.row.transactionMode"
+            placeholder="请选择"
+            class="ele-block"
+            :disabled="isView"
+            @change="(val) => updateRowField(scope.$index, 'transactionMode', val)"
+          >
+            <el-option
+              v-for="item in transactionMethodsOp"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </template>
+
+        <template v-slot:paymentConditionName="scope">
+          <el-input
+            clearable
+            :value="scope.row.paymentConditionName"
+            @click.native="openPaymentTerms(scope.$index)"
+            :placeholder="isView ? '' : '请选择'"
+            :disabled="isView"
+            readonly
+          />
+        </template>
+
+        <template v-slot:statementAdvanceConfirmAmount="scope">
+          <el-form-item
+            :prop="'payablesList.' + scope.$index + '.statementAdvanceConfirmAmount'"
+            :rules="{
+              validator: (rule, value, cb) =>
+                validateConfirmAmount(rule, value, cb, scope.row),
+              trigger: 'change'
+            }"
+          >
+            <el-input
+              v-model="scope.row.statementAdvanceConfirmAmount"
+              type="number"
+              :disabled="isView"
+              @input="handleConfirmAmountChange(scope.row, scope.$index)"
+            />
+          </el-form-item>
+        </template>
+
+        <template v-slot:action="scope">
+          <el-link
+            v-if="!isView"
+            type="danger"
+            :underline="false"
+            icon="el-icon-delete"
+            @click="removeRow(scope.$index)"
+            >删除</el-link
+          >
+        </template>
+      </ele-pro-table>
+    </el-form>
+  </div>
+</template>
+
+<script>
+  import {
+    paymentTypeOp,
+    transactionMethodsOp,
+    paymentStatus
+  } from '@/enum/dict';
+
+  export default {
+    name: 'payablesInfo',
+    components: {},
+    props: {
+      dataForm: {
+        type: Object,
+        default: () => ({})
+      },
+      // 父组件传入的初始应付明细,仅作为初始化值,修改不再回写父
+      payablesList: {
+        type: Array,
+        default: () => []
+      },
+      dialogType: {
+        type: String,
+        default: 'add'
+      }
+    },
+    data() {
+      return {
+        cacheKeyUrl: 'eom-202608181000-purchase-payables-table',
+        paymentTypeOp,
+        transactionMethodsOp,
+        paymentStatusOp: paymentStatus,
+        rules: {},
+        // 本地维护的应付明细,避免每次编辑都同步回父组件
+        localList: [],
+        columns: [
+          {
+            width: 60,
+            label: '序号',
+            type: 'index',
+            columnKey: 'index',
+            align: 'center',
+            fixed: 'left'
+          },
+          {
+            minWidth: 140,
+            prop: 'purchaseCode',
+            label: '采购订单编码',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'advanceCode',
+            label: '预付编码',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'fundType',
+            minWidth: 140,
+            label: '款项类型',
+            align: 'center',
+            slot: 'fundType'
+          },
+          {
+            prop: 'transactionMode',
+            minWidth: 140,
+            label: '交易方式',
+            align: 'center',
+            slot: 'transactionMode'
+          },
+          {
+            prop: 'paymentConditionName',
+            minWidth: 160,
+            label: '付款条件',
+            align: 'center',
+            slot: 'paymentConditionName'
+          },
+          {
+            minWidth: 170,
+            prop: 'unreconciledAdvanceConfirmAmount',
+            label: '未对账预付款确收金额',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 190,
+            prop: 'statementAdvanceConfirmAmount',
+            label: '本次对账预付款确收金额',
+            align: 'center',
+            slot: 'statementAdvanceConfirmAmount'
+          },
+          {
+            minWidth: 120,
+            prop: 'statementAmount',
+            label: '本次对账金额',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'payablePrice',
+            label: '本次应付金额',
+            align: 'center',
+            showOverflowTooltip: true
+          }
+        ]
+      };
+    },
+    computed: {
+      isView() {
+        return this.dialogType === 'view';
+      },
+      statementAdvanceTotalPrice() {
+        return (
+          this.localList.reduce(
+            (pre, cur) =>
+              pre + Math.round((+cur.statementAdvanceConfirmAmount || 0) * 100),
+            0
+          ) / 100
+        );
+      },
+      receivedTotalPrice() {
+        return (
+          Math.round(
+            ((+this.dataForm.amountTotalPrice || 0) -
+              this.statementAdvanceTotalPrice) *
+              100
+          ) / 100
+        );
+      }
+    },
+    watch: {
+      // 父传入初始值(查询/编辑回填)时同步到本地副本
+      payablesList: {
+        handler(val) {
+          this.localList = (val || []).map((item) => ({ ...item }));
+          this.recalcAllRows();
+        },
+        immediate: true
+      },
+      'dataForm.amountTotalPrice': {
+        handler() {
+          this.recalcAllRows();
+        },
+        immediate: true
+      }
+    },
+    methods: {
+      openPaymentTerms(index) {
+        // 暂存当前行索引,便于后续接入付款条件选择器写回对应行
+        this.currentRowIndex = index;
+        this.$message.info('付款条件选择器待接入');
+      },
+      // 行内字段修改:仅更新本地副本
+      updateRowField(index, key, val) {
+        const item = this.localList[index];
+        if (!item) return;
+        this.localList[index] = { ...item, [key]: val };
+        this.recalcRow(item);
+      },
+      // 新增一行空白预付
+      addRow() {
+        this.localList.push({
+          id: 'local_' + Date.now() + '_' + this.localList.length,
+          purchaseCode: '',
+          advanceCode: '',
+          fundType: '',
+          transactionMode: '',
+          paymentConditionId: '',
+          paymentConditionName: '',
+          unreconciledAdvanceConfirmAmount: 0,
+          statementAdvanceConfirmAmount: 0,
+          statementAmount: 0,
+          payablePrice: 0
+        });
+      },
+      // 由父组件预付款选择器回调调用:追加一行已映射好的应付明细(本地维护)
+      addPayableRow(row) {
+        this.localList.push({ ...row });
+      },
+      removeRow(index) {
+        if (index < 0 || index >= this.localList.length) return;
+        this.localList.splice(index, 1);
+      },
+      // 本次对账预付款确收金额上限 = min(未对账预付款确收金额, 本次对账金额)
+      getMaxConfirmAmount(row) {
+        return Math.min(
+          +row.unreconciledAdvanceConfirmAmount || 0,
+          +row.statementAmount || 0
+        );
+      },
+      handleConfirmAmountChange(row, index) {
+        // 限制本次确收金额不能超过未对账金额和本次对账金额
+        let val = +row.statementAdvanceConfirmAmount || 0;
+        const max = this.getMaxConfirmAmount(row);
+        if (val > max) {
+          val = max;
+          this.$set(row, 'statementAdvanceConfirmAmount', val);
+          this.$message.warning(
+            '本次对账预付款确收金额不能超过未对账金额和本次对账金额'
+          );
+        }
+        this.recalcRow(row);
+      },
+      // 根据本次对账金额重算单行:确收金额 = min(未对账预付款确收金额, 本次对账金额);应付金额 = 本次对账金额 - 确收金额
+      recalcRow(row) {
+        const statementAmount = +row.statementAmount || 0;
+        let val = +row.statementAdvanceConfirmAmount || 0;
+        const max = this.getMaxConfirmAmount(row);
+        if (val > max) val = max;
+        this.$set(row, 'statementAdvanceConfirmAmount', val);
+        this.$set(
+          row,
+          'payablePrice',
+          Math.round((statementAmount - val) * 100) / 100
+        );
+      },
+      // 明细表按采购单号汇总本次对账金额后,同步到对应采购单号的应付行
+      syncStatementAmount(summaryMap) {
+        if (!summaryMap || !Object.keys(summaryMap).length) return;
+        this.localList.forEach((row) => {
+          const amount = summaryMap[row.purchaseCode];
+          if (amount !== undefined) {
+            this.$set(row, 'statementAmount', amount);
+            this.recalcRow(row);
+          }
+        });
+      },
+      recalcAllRows() {
+        this.localList.forEach((row) => {
+          this.recalcRow(row);
+        });
+      },
+      validateConfirmAmount(rule, value, callback, row) {
+        const val = +value || 0;
+        const max = this.getMaxConfirmAmount(row);
+        if (val < 0) {
+          callback(new Error('不能小于0'));
+        } else if (val > max) {
+          callback(new Error(`不能超过${max}`));
+        } else {
+          callback();
+        }
+      },
+      // 提交时由父组件调用,一次性取回整个应付表单(本地明细 + 汇总)
+      getSubmitData() {
+        return {
+          payablesList: this.localList.map((item) => ({ ...item })),
+          statementAdvanceTotalPrice: this.statementAdvanceTotalPrice,
+          receivedTotalPrice: this.receivedTotalPrice
+        };
+      },
+      validate() {
+        return new Promise((resolve, reject) => {
+          const promises = [this.$refs.form.validate()];
+          if (this.$refs.tableForm) {
+            promises.push(this.$refs.tableForm.validate());
+          }
+          Promise.all(promises)
+            .then(() => resolve(true))
+            .catch(() => reject(false));
+        });
+      }
+    }
+  };
+</script>
+
+<style scoped lang="scss">
+  .payables-info {
+    .payables-table-header {
+      display: flex;
+      justify-content: flex-end;
+      margin-bottom: 10px;
+    }
+  }
+</style>

+ 6 - 3
src/views/purchasingManage/purchaseOrder/accountstatement/components/purchaseForm.vue

@@ -265,11 +265,14 @@
     computed: {
       //计算未对账金额
       accountStatementPrice() {
-        return this.datasource.reduce((pre, cur) => pre + +cur.amountTotalPrice, 0);
+        return this.datasource.reduce(
+          (pre, cur) => pre + +cur.statementAmount,
+          0
+        );
       },
       //计算相关订单号
       relatedOrderNumber() {
-        return this.datasource.map((item) => item.orderNo).join(',');
+        return [...new Set(this.datasource.map((item) => item.orderNo))].join(',');
       }
     },
     data() {
@@ -417,7 +420,7 @@
       },
       reloadTableData() {
         this.$emit('update:datasource', []);
-        this.$emit('update:recorpayList', []);
+        // this.$emit('update:recorpayList', []);
         // let params = Object.assign(
         //   {},
         //   {