|
|
@@ -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>
|