|
|
@@ -0,0 +1,627 @@
|
|
|
+<template>
|
|
|
+ <ele-modal
|
|
|
+ custom-class="ele-dialog-form long-dialog-form"
|
|
|
+ :centered="true"
|
|
|
+ :visible.sync="paymentDialogFlag"
|
|
|
+ :title="title"
|
|
|
+ :append-to-body="true"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ width="80%"
|
|
|
+ :before-close="cancel"
|
|
|
+ :maxable="true"
|
|
|
+ :resizable="true"
|
|
|
+ >
|
|
|
+ <div style="margin: 10px 0; font-size: 14px; color: #606266;">
|
|
|
+ <span>应付金额:{{ selectedPayableAmount }} 元</span>
|
|
|
+ <span style="margin-left: 20px;">本次付款金额:{{ paidAmount }} 元</span>
|
|
|
+ <span style="margin-left: 20px;">未付金额:{{ unpaidAmount }} 元</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="paidDate"
|
|
|
+ :rules="{ required: true, message: '请选择付款时间', trigger: 'change' }"
|
|
|
+ >
|
|
|
+ <el-date-picker
|
|
|
+ v-model="form.paidDate"
|
|
|
+ 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="paidAmount"
|
|
|
+ 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"
|
|
|
+
|
|
|
+ @header-dragend="handleHeaderDragend">
|
|
|
+ <!-- 本次对账金额:唯一可填写字段 -->
|
|
|
+ <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>
|
|
|
+
|
|
|
+ <template v-slot:taxRate="scope">
|
|
|
+ <span class="is-required">{{ scope.row.taxRate }}%</span>
|
|
|
+ </template>
|
|
|
+ </ele-pro-table>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div slot="footer">
|
|
|
+ <el-button type="primary" @click="save()">保存</el-button>
|
|
|
+ <el-button @click="cancel">返回</el-button>
|
|
|
+ </div>
|
|
|
+ </ele-modal>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import { pricingWayList } from '@/enum/dict.js';
|
|
|
+import { finPayableSaveSingleDetailAPI, getFinPayableInfoAPI } from "@/api/financialManage/payableManage";
|
|
|
+import tabMixins from '@/mixins/tableColumnsMixin';
|
|
|
+
|
|
|
+export default {
|
|
|
+ mixins: [tabMixins],
|
|
|
+ name: "paymentDialog1",
|
|
|
+ components: {},
|
|
|
+ props: {
|
|
|
+ paymentDialogFlag: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ isView() {
|
|
|
+ return this.dialogType === 'view';
|
|
|
+ },
|
|
|
+ // 应付金额 = 接口下发的 row.payableTotalPrice
|
|
|
+ selectedPayableAmount() {
|
|
|
+ return this.row.payableTotalPrice || 0;
|
|
|
+ },
|
|
|
+ // 已付金额 = 勾选的应付明细「折让合计」之和 || 接口下发的 row.payableTotalPrice
|
|
|
+ paidAmount() {
|
|
|
+ const sum = this.selection.reduce((pre, item) => {
|
|
|
+ const val = parseFloat(item.statementAmount);
|
|
|
+ return pre + (isNaN(val) ? 0 : val);
|
|
|
+ }, 0);
|
|
|
+ return sum.toFixed(2) || this.selectedPayableAmount;
|
|
|
+ },
|
|
|
+ // 未付金额 = 接口下发的 row.unpaidTotalPrice
|
|
|
+ unpaidAmount() {
|
|
|
+ return this.row.unpaidTotalPrice || 0;
|
|
|
+ },
|
|
|
+ queryDimension() {
|
|
|
+ return this.form.queryDimension != null ? this.form.queryDimension : 1;
|
|
|
+ },
|
|
|
+ columns() {
|
|
|
+ let columnsVersion = this.columnsVersion;
|
|
|
+ return this.applyColumnWidth([
|
|
|
+ {
|
|
|
+ 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: this.queryDimension == 3 ? 'statementSubOrderNo' : this.queryDimension == 1 ? 'statementSubOrderCode' : 'statementSubOrderNo',
|
|
|
+ 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: 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',
|
|
|
+ slot: 'taxRate'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ cacheKeyUrl: 'views_financialManage_payableManage_components_paymentDialog',
|
|
|
+ row: {},
|
|
|
+ dialogType: '',
|
|
|
+ title: '',
|
|
|
+ loading: false,
|
|
|
+ info: {},
|
|
|
+ form: {
|
|
|
+ id: '',
|
|
|
+ queryDimension: 1,
|
|
|
+ paidDate: '',
|
|
|
+ paymentType: '',
|
|
|
+ files: [],
|
|
|
+ remark: '',
|
|
|
+ },
|
|
|
+ rules: {},
|
|
|
+ datasource: [],
|
|
|
+ flatList: [],
|
|
|
+ selection: [],
|
|
|
+ totalAmount: 0,
|
|
|
+ totalCount: 0,
|
|
|
+ columnsVersion: 1
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 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' ? '付款详情' : '付款';
|
|
|
+ await this.getInfo(row.id);
|
|
|
+ },
|
|
|
+ // 获取详情
|
|
|
+ async getInfo(id) {
|
|
|
+ const data = await getFinPayableInfoAPI(id);
|
|
|
+ this.datasource = Array.isArray(data) ? data : (data?.productList || []);
|
|
|
+ // 把接口返回的已付/未付金额回填到 row,供顶部汇总和表单展示
|
|
|
+ this.row = {
|
|
|
+ ...this.row,
|
|
|
+ paidTotalPrice: data?.paidTotalPrice ?? this.row.paidTotalPrice ?? 0,
|
|
|
+ unpaidTotalPrice: data?.unpaidTotalPrice ?? this.row.unpaidTotalPrice ?? 0
|
|
|
+ };
|
|
|
+ this.form = {
|
|
|
+ ...this.form,
|
|
|
+ id: data?.id || '',
|
|
|
+ queryDimension: data?.queryDimension != null ? data.queryDimension : 1,
|
|
|
+ paidDate: data?.paidDate || '',
|
|
|
+ paymentType: String(data?.paymentType) ?? '',
|
|
|
+ files: data?.files || [],
|
|
|
+ remark: data?.remark || ''
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 构建单行派生字段
|
|
|
+ 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', item?.paidTotalPrice || 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;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 按 /eom/finpayable/saveSingleDetail 文档构造「应付付款-产品明细(物品清单)新增请求」
|
|
|
+ // 注意:不回传 id(文档注明新增时为空),本次付款金额落在 paidTotalPrice
|
|
|
+ buildDetailPayload(item) {
|
|
|
+ const num = (val) => (val === '' || val == null ? undefined : +val);
|
|
|
+ return {
|
|
|
+ // 必填
|
|
|
+ payableId: item.payableId ?? this.row.id,
|
|
|
+ payableCode: item.payableCode || this.row.code,
|
|
|
+ productName: item.productName || '',
|
|
|
+ singlePrice: num(item.singlePrice) ?? 0,
|
|
|
+ totalCount: num(item.totalCount) ?? 0,
|
|
|
+ totalPrice: num(item.totalPrice) ?? 0,
|
|
|
+ // 选填
|
|
|
+ paidTotalPrice: +(item.statementAmount || 0), // 已付金额-本次付款金额
|
|
|
+ payableProductId: item.payableProductId,
|
|
|
+ initId: item.initId,
|
|
|
+ discountRatio: num(item.discountRatio),
|
|
|
+ discountSinglePrice: num(item.discountSinglePrice),
|
|
|
+ discountTotalPrice: num(item.discountTotalPrice),
|
|
|
+ notaxSinglePrice: num(item.notaxSinglePrice ?? item.noTaxSinglePrice), // 不含税单价
|
|
|
+ notaxTotalPrice: num(item.notaxTotalPrice), // 不含税总价
|
|
|
+ taxRate: num(item.taxRate),
|
|
|
+ invoiceAmount: num(item.invoiceAmount),
|
|
|
+ totalWeight: num(item.totalWeight ?? item.sendTotalWeight),
|
|
|
+ productCode: item.productCode,
|
|
|
+ productBrand: item.productBrand,
|
|
|
+ productCategoryId: item.productCategoryId,
|
|
|
+ productCategoryName: item.productCategoryName,
|
|
|
+ specification: item.specification,
|
|
|
+ modelType: item.modelType,
|
|
|
+ measuringUnit: item.measuringUnit,
|
|
|
+ quoteWay: item.quoteWay,
|
|
|
+ orderId: item.orderId,
|
|
|
+ orderNo: item.orderNo,
|
|
|
+ statementId: item.statementId,
|
|
|
+ statementNo: item.statementNo,
|
|
|
+ statementSubOrderCode: item.statementSubOrderCode,
|
|
|
+ sourceOrderId: item.sourceOrderId,
|
|
|
+ sourceOrderDetailId: item.sourceOrderDetailId,
|
|
|
+ sourceOrderNo: item.sourceOrderNo,
|
|
|
+ contractId: item.contractId,
|
|
|
+ contractNo: item.contractNo,
|
|
|
+ contractNumber: item.contractNumber,
|
|
|
+ contractName: item.contractName,
|
|
|
+ customerId: item.customerId,
|
|
|
+ customerNo: item.customerNo,
|
|
|
+ customerName: item.customerName,
|
|
|
+ remark: item.remark
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 汇总
|
|
|
+ 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;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 校验勾选行的本次对账金额必填
|
|
|
+ validateSelection() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (!this.selection.length) {
|
|
|
+ this.$message.warning('请先勾选需要提交的应付明细');
|
|
|
+ reject(false);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ 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);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 本次录入付款金额之和 不能超过 历史未付金额
|
|
|
+ // 字段语义:statementAmount=本次录入;unpaidTotalPrice=接口下发的历史未付汇总
|
|
|
+ const totalStatementAmount = this.selection.reduce(
|
|
|
+ (pre, item) => pre + (+item.statementAmount || 0),
|
|
|
+ 0
|
|
|
+ );
|
|
|
+ const unpaid = +this.unpaidAmount || 0;
|
|
|
+ // 用「分」做整数比较,避开浮点精度(例:0.1+0.2 之类)
|
|
|
+ const totalCents = Math.round(totalStatementAmount * 100);
|
|
|
+ const unpaidCents = Math.round(unpaid * 100);
|
|
|
+ if (totalCents > unpaidCents) {
|
|
|
+ this.$message.warning(
|
|
|
+ `本次录入付款金额之和(${totalStatementAmount.toFixed(2)} 元)不能大于未付金额(${unpaid} 元)`
|
|
|
+ );
|
|
|
+ reject(false);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ 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. 提交:付款主信息 + 勾选的应付明细(本次付款金额 = 勾选行本次录入金额之和)
|
|
|
+ // 入参严格按 /eom/finpayable/saveSingleDetail 文档构造,不做整行透传,
|
|
|
+ // 避免把 buildRow 派生字段(isReturn/outboundCount 等)带进请求体
|
|
|
+ const statementAmount = +(
|
|
|
+ this.selection.reduce((pre, item) => pre + (+item.statementAmount || 0), 0)
|
|
|
+ ).toFixed(2);
|
|
|
+ const productList = this.selection.map((item) => this.buildDetailPayload(item));
|
|
|
+ const params = {
|
|
|
+ // —— 必填 ——
|
|
|
+ paidDate: this.form.paidDate, // 付款时间
|
|
|
+ paidTotalPrice: statementAmount, // 已付金额(本次付款金额)
|
|
|
+ payableId: this.row.id, // 应付ID
|
|
|
+ payableCode: this.row.code, // 应付编码
|
|
|
+ // —— 选填 ——
|
|
|
+ paymentType: this.form.paymentType, // 支付类型 1现金 2银行转账 3支票 4银行承兑汇票 5其他
|
|
|
+ files: this.form.files || [], // 凭证附件
|
|
|
+ remark: this.form.remark, // 备注
|
|
|
+ invoiceAmount: this.row.invoiceAmount, // 已收票金额
|
|
|
+ invoiceCode: this.row.invoiceCode, // 发票编码
|
|
|
+ invoiceId: this.row.invoiceId, // 发票ID
|
|
|
+ invoiceStatus: this.row.invoiceStatus, // 开票状态 0未开票 1已开票
|
|
|
+ productList
|
|
|
+ };
|
|
|
+ finPayableSaveSingleDetailAPI(params)
|
|
|
+ .then(() => {
|
|
|
+ this.loading = false;
|
|
|
+ this.$message.success('付款成功');
|
|
|
+ this.cancel();
|
|
|
+ this.done();
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 刷新主列表数据
|
|
|
+ done() {
|
|
|
+ this.$emit('reload');
|
|
|
+ },
|
|
|
+ // 关闭弹窗
|
|
|
+ cancel() {
|
|
|
+ this.$emit('update:paymentDialogFlag', false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style scoped lang="scss">
|
|
|
+ .detail-toolbar {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-start;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+</style>
|