🐛 修复预付驳回重提、预结算变更记录与收票多选结算单

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-20 01:50:54 +08:00
parent 31794bf26a
commit 4c9bbf1eb7
8 changed files with 397 additions and 134 deletions
@@ -53,7 +53,7 @@
<el-option
v-for="item in contracts"
:key="item.id"
:label="formatContractOptionLabel(item)"
:label="item.contractName || ''"
:value="item.id"
/>
</el-select>
@@ -1070,7 +1070,6 @@ import {
import { getDictionary } from '@/api/system/dictbiz';
import { h } from 'vue';
import { mapGetters } from 'vuex';
import { formatContractOptionLabel } from '@/utils/contract';
import { isTierUnitPrice, isUnitPriceAdjustable } from '@/utils/settlement-adjust-rule';
import { normalizeCurrencyCode } from '@/utils/currency';
import {
@@ -1389,7 +1388,6 @@ export default {
methods: {
isTierUnitPrice,
isUnitPriceAdjustable,
formatContractOptionLabel,
hasPermission(code) {
if (this.isAdmin) return true;
const action = String(code || '').replace(
@@ -251,29 +251,32 @@
:key="item.key"
:label="item.kind === 'fee' ? item.name : item.column.label"
:prop="item.kind === 'fee' ? undefined : item.column.prop"
:min-width="item.kind === 'fee' ? 130 : item.column.minWidth"
:min-width="item.kind === 'fee' ? 150 : item.column.minWidth"
align="center"
show-overflow-tooltip
>
<template #default="{ row }">
<span v-if="item.kind === 'fee'" class="pre-settlement-editor__billing-rule-cell">
<span>
{{
formatMoney(
parseFeeItems(row.feeItemsJson)[item.name],
row.currency || form.currency
)
}}
</span>
<template #header>
<span class="pre-settlement-editor__billing-rule-cell">
<span>{{ item.kind === 'fee' ? item.name : item.column.label }}</span>
<el-icon
v-if="hasDetailBillingRule(row)"
v-if="showDetailColumnRuleIcon(item)"
class="pre-settlement-editor__billing-rule-icon"
title="查看计费规则详情"
@click.stop="openDetailBillingRule(row, item.name)"
@click.stop="openDetailColumnRule(item)"
>
<InfoFilled />
</el-icon>
</span>
</template>
<template #default="{ row }">
<span v-if="item.kind === 'fee'">
{{
formatMoney(
parseFeeItems(row.feeItemsJson)[item.name],
row.currency || form.currency
)
}}
</span>
<el-link
v-else-if="item.column.link && row[item.column.prop] && !publicMode"
type="primary"
@@ -284,19 +287,8 @@
<span v-else-if="item.column.money && item.column.prop === 'unitPrice'">
{{ formatUnitPrice(row) }}
</span>
<span
v-else-if="item.column.prop === 'freightAmount'"
class="pre-settlement-editor__billing-rule-cell"
>
<span>{{ formatMoney(row[item.column.prop], row.currency || form.currency) }}</span>
<el-icon
v-if="hasDetailBillingRule(row)"
class="pre-settlement-editor__billing-rule-icon"
title="查看计费规则详情"
@click.stop="openDetailBillingRule(row, '运输费')"
>
<InfoFilled />
</el-icon>
<span v-else-if="item.column.prop === 'freightAmount'">
{{ formatMoney(row[item.column.prop], row.currency || form.currency) }}
</span>
<span v-else-if="item.column.money">
{{ formatMoney(row[item.column.prop], row.currency || form.currency) }}
@@ -499,6 +491,11 @@
<span v-else>{{ displayValue(row[column.prop]) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center" fixed="right">
<template #default="{ row }">
<el-link type="primary" @click="openAdjustChangeRecord(row)">查看</el-link>
</template>
</el-table-column>
</el-table>
</section-card>
</div>
@@ -824,25 +821,28 @@
min-width="160"
align="center"
>
<template #default="{ row }">
<div class="pre-settlement-editor__billing-rule-cell">
<el-input-number
v-model="row.feeItems[feeItem]"
:min="0"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
@change="recalculateAdjustRow(row, feeItem)"
/>
<template #header>
<span class="pre-settlement-editor__billing-rule-cell">
<span>{{ feeItem }}</span>
<el-icon
v-if="hasBillingRule(row)"
v-if="showAdjustFeeRuleIcon(feeItem)"
class="pre-settlement-editor__billing-rule-icon"
title="查看计费规则详情"
@click="openBillingRuleInfo(row, feeItem)"
@click.stop="openAdjustFeeRule(feeItem)"
>
<InfoFilled />
</el-icon>
</div>
</span>
</template>
<template #default="{ row }">
<el-input-number
v-model="row.feeItems[feeItem]"
:min="0"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
@change="recalculateAdjustRow(row, feeItem)"
/>
</template>
</el-table-column>
<el-table-column label="结算金额(含税)" min-width="170" align="center">
@@ -1522,7 +1522,9 @@ export default {
availableWriteOffAmount: Number(row.availableWriteOffAmount || 0),
createTime: row.paymentCreateTime || row.createTime,
}));
this.changeRecords = detail.changeRecords || [];
this.changeRecords = (detail.changeRecords || []).filter(
row => row.changeContent !== '预结算审批通过'
);
this.attachments = this.parseAttachments(detail.attachmentsJson);
this.sortAttachments();
this.selectedAttachmentRows = [];
@@ -2307,6 +2309,17 @@ export default {
},
formatAdjustChangeValue(value) {
if (value === undefined || value === null || value === '') return '空';
if (Array.isArray(value)) {
if (!value.length) return '空';
return value
.map(item => {
if (!item || typeof item !== 'object') return String(item);
return Object.entries(item)
.map(([key, itemValue]) => `${key}:${this.formatAdjustChangeValue(itemValue)}`)
.join(',');
})
.join('\n');
}
if (typeof value === 'object') return JSON.stringify(value);
return String(value);
},
@@ -2369,12 +2382,60 @@ export default {
ruleFeeName(rule = {}) {
return String(rule.feeItem || rule.feeItemName || rule.name || '').trim();
},
isHandlingFeeItem(name) {
return String(name || '').includes('装卸');
},
feeNamesMatch(left, right) {
const source = String(left || '').trim();
const target = String(right || '').trim();
if (!source || !target) return false;
if (source === target) return true;
return this.isFreightFeeItem(source) && this.isFreightFeeItem(target);
if (this.isFreightFeeItem(source) && this.isFreightFeeItem(target)) return true;
return this.isHandlingFeeItem(source) && this.isHandlingFeeItem(target);
},
detailColumnFeeName(item = {}) {
if (item.kind === 'fee') return item.name || '';
if (item.column?.prop === 'freightAmount') return '运输费';
return '';
},
showDetailColumnRuleIcon(item) {
const feeName = this.detailColumnFeeName(item);
if (!feeName) return false;
return this.details.some(row => this.rowHasNamedBillingRule(row, feeName));
},
openDetailColumnRule(item) {
const feeName = this.detailColumnFeeName(item);
const row =
this.details.find(detail => this.rowHasNamedBillingRule(detail, feeName)) ||
this.details[0];
if (row) this.openDetailBillingRule(row, feeName);
},
showAdjustFeeRuleIcon(feeName) {
return (this.adjustRows || []).some(row => this.sourceHasNamedBillingRule(row, feeName));
},
openAdjustFeeRule(feeName) {
const row =
(this.adjustRows || []).find(item => this.sourceHasNamedBillingRule(item, feeName)) ||
this.adjustRows[0];
if (row) this.openBillingRuleInfo(row, feeName);
},
rowHasNamedBillingRule(row, feeName) {
return [row, ...this.detailFeeRows(row)].some(source =>
this.sourceHasNamedBillingRule(source, feeName)
);
},
sourceHasNamedBillingRule(source = {}, feeName) {
const rules = [
...this.collectBillingRules(source),
...(Array.isArray(source.billingRule?.rules) ? source.billingRule.rules : []),
];
if (rules.some(rule => this.feeNamesMatch(this.ruleFeeName(rule), feeName))) return true;
if (!this.hasBillingRule(source)) return false;
const named = String(
source.billingFeeItem || source.feeItem || this.ruleFeeName(source.billingRule) || ''
).trim();
if (!named) return true;
return this.feeNamesMatch(named, feeName);
},
collectBillingRules(row = {}) {
const source = row || {};