调整业务模块

This commit is contained in:
2026-09-05 23:26:37 +08:00
parent 3bac9b6472
commit 6a6d10dc79
6 changed files with 437 additions and 138 deletions
@@ -82,12 +82,7 @@
添加费用
</el-button>
</template>
<el-table
:data="summaryFees"
border
show-summary
:summary-method="getSummarySums"
>
<el-table :data="summaryFees" border show-summary :summary-method="getSummarySums">
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column
v-for="column in summaryColumns"
@@ -261,7 +256,7 @@
<span v-else-if="pageMode && column.prop === 'mileage'">
{{ formatDetailMileage(row[column.prop]) }}
</span>
<span v-else-if="pageMode && column.prop === 'transportType'">
<span v-else-if="column.prop === 'transportType'">
{{ transportTypeName(row[column.prop]) }}
</span>
<span v-else>{{ displayValue(row[column.prop]) }}</span>
@@ -374,6 +369,12 @@
<span v-else-if="column.prop === 'billStatus'">
{{ advanceStatusName(row.billStatus) }}
</span>
<span v-else-if="column.prop === 'createUserName'">
{{ advanceCreateUserName(row) }}
</span>
<span v-else-if="column.prop === 'createTime'">
{{ advanceCreateTime(row) }}
</span>
<span v-else>{{ displayValue(row[column.prop]) }}</span>
</template>
</el-table-column>
@@ -381,7 +382,7 @@
</section-card>
<section-card v-if="form.id && readonly" title="变更记录">
<el-table :data="changeRecords" border>
<el-table :data="adjustChangeRecords" border>
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column
v-for="column in changeTableColumns"
@@ -671,103 +672,131 @@
append-to-body
destroy-on-close
>
<el-table v-loading="adjustDialog.loading" :data="adjustRows" border>
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column prop="cargoName" label="货物名称" min-width="140" align="center" />
<el-table-column prop="cargoType" label="货物类型" min-width="130" align="center" />
<el-table-column label="计费规则" min-width="190" align="center">
<template #default="{ row }">
<div class="pre-settlement-editor__billing-rule-cell">
<span>{{ displayValue(billingRuleName(row)) }}</span>
<el-icon
class="pre-settlement-editor__billing-rule-icon"
title="查看计费规则详情"
@click="openBillingRuleInfo(row)"
>
<InfoFilled />
</el-icon>
</div>
</template>
</el-table-column>
<el-table-column label="运输总量" min-width="150" align="center">
<template #default="{ row }">
<span v-if="adjustDialog.readonly">{{ formatQuantity(row) }}</span>
<el-input-number
v-else
v-model="row.transportQuantity"
:min="0"
:precision="2"
:controls="false"
<el-tabs v-model="adjustDialog.activeTab" class="pre-settlement-editor__adjust-tabs">
<el-tab-pane label="结算明细调整" name="adjust">
<el-table v-loading="adjustDialog.loading" :data="adjustRows" border>
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
<el-table-column prop="cargoName" label="货物名称" min-width="140" align="center" />
<el-table-column prop="cargoType" label="货物类型" min-width="130" align="center" />
<el-table-column label="计费规则" min-width="190" align="center">
<template #default="{ row }">
<div class="pre-settlement-editor__billing-rule-cell">
<span>{{ displayValue(billingRuleName(row)) }}</span>
<el-icon
class="pre-settlement-editor__billing-rule-icon"
title="查看计费规则详情"
@click="openBillingRuleInfo(row)"
>
<InfoFilled />
</el-icon>
</div>
</template>
</el-table-column>
<el-table-column label="运输总量" min-width="150" align="center">
<template #default="{ row }">
<span v-if="adjustDialog.readonly">{{ formatQuantity(row) }}</span>
<el-input-number
v-else
v-model="row.transportQuantity"
:min="0"
:precision="2"
:controls="false"
/>
</template>
</el-table-column>
<el-table-column label="里程(KM)" min-width="140" align="center">
<template #default="{ row }">
<el-input-number
v-model="row.mileage"
:min="0"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
/>
</template>
</el-table-column>
<el-table-column label="运输单价" min-width="140" align="center">
<template #default="{ row }">
<el-input-number
v-model="row.unitPrice"
:min="0"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
/>
</template>
</el-table-column>
<el-table-column
v-for="feeItem in adjustFeeItemNames"
:key="feeItem"
:label="feeItem"
min-width="140"
align="center"
>
<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">
<template #default="{ row }">
<el-input-number
v-model="row.settlementAmountTax"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
/>
</template>
</el-table-column>
<el-table-column label="备注" min-width="200" align="center">
<template #default="{ row }">
<el-input v-model="row.remark" maxlength="200" :disabled="adjustDialog.readonly" />
</template>
</el-table-column>
</el-table>
<el-form
v-if="!adjustDialog.readonly"
:model="adjustDialog"
label-position="right"
label-width="auto"
class="pre-settlement-editor__adjust-reason"
>
<el-form-item label="调整原因">
<el-input v-model="adjustDialog.reason" maxlength="200" show-word-limit />
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="变更记录" name="records">
<el-table :data="changeRecords" border>
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="changeTime" label="变更日期" min-width="170" align="center" />
<el-table-column prop="operatorName" label="经办人" min-width="140" align="center" />
<el-table-column prop="changeType" label="变更类型" min-width="160" align="center" />
<el-table-column
prop="changeReason"
label="变更原因"
min-width="240"
align="center"
show-overflow-tooltip
/>
</template>
</el-table-column>
<el-table-column label="里程(KM)" min-width="140" align="center">
<template #default="{ row }">
<el-input-number
v-model="row.mileage"
:min="0"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
/>
</template>
</el-table-column>
<el-table-column label="运输单价" min-width="140" align="center">
<template #default="{ row }">
<el-input-number
v-model="row.unitPrice"
:min="0"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
/>
</template>
</el-table-column>
<el-table-column
v-for="feeItem in adjustFeeItemNames"
:key="feeItem"
:label="feeItem"
min-width="140"
align="center"
>
<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">
<template #default="{ row }">
<el-input-number
v-model="row.settlementAmountTax"
:precision="2"
:controls="false"
:disabled="adjustDialog.readonly"
/>
</template>
</el-table-column>
<el-table-column label="备注" min-width="200" align="center">
<template #default="{ row }">
<el-input v-model="row.remark" maxlength="200" :disabled="adjustDialog.readonly" />
</template>
</el-table-column>
</el-table>
<el-form
v-if="!adjustDialog.readonly"
:model="adjustDialog"
label-position="right"
label-width="auto"
class="pre-settlement-editor__adjust-reason"
>
<el-form-item label="调整原因">
<el-input v-model="adjustDialog.reason" maxlength="200" show-word-limit />
</el-form-item>
</el-form>
<el-table-column label="状态" min-width="120" align="center">
<template #default>已生效</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center" fixed="right">
<template #default="{ row }">
<el-link type="primary" @click="openAdjustChangeRecord(row)">查看详情</el-link>
</template>
</el-table-column>
</el-table>
<el-empty v-if="!adjustChangeRecords.length" description="暂无变更记录" :image-size="60" />
</el-tab-pane>
</el-tabs>
<template #footer>
<el-button @click="adjustDialog.visible = false">取消</el-button>
<el-button
@@ -781,6 +810,36 @@
</template>
</el-dialog>
<el-dialog
v-model="adjustChangeRecordVisible"
title="变更记录详情"
append-to-body
destroy-on-close
width="1100px"
top="10px"
class="pre-settlement-change-record-detail-dialog"
>
<div v-if="adjustChangeRecord" class="pre-settlement-change-record-detail-meta">
<span>变更日期:{{ adjustChangeRecord.changeTime || '-' }}</span>
<span>经办人:{{ adjustChangeRecord.operatorName || '-' }}</span>
<span>变更类型:{{ adjustChangeRecord.changeType || '-' }}</span>
<span>状态:已生效</span>
</div>
<el-table :data="adjustChangeRecordDetailRows" border :show-overflow-tooltip="false">
<el-table-column prop="field" label="变更字段" min-width="220" />
<el-table-column prop="before" label="变更前" min-width="330" />
<el-table-column prop="after" label="变更后" min-width="420" />
</el-table>
<el-empty
v-if="!adjustChangeRecordDetailRows.length"
description="暂无变更内容"
:image-size="60"
/>
<template #footer>
<el-button type="primary" @click="adjustChangeRecordVisible = false">关闭</el-button>
</template>
</el-dialog>
<el-dialog
v-model="billingRuleDialog.visible"
title="计费规则详情"
@@ -1010,10 +1069,15 @@ export default {
loading: false,
saving: false,
readonly: false,
activeTab: 'adjust',
detailId: '',
detailLineNo: '',
reason: '',
},
adjustRows: [],
adjustChangeRecordVisible: false,
adjustChangeRecord: null,
adjustChangeRecordDetailRows: [],
billingRuleDialog: {
visible: false,
rule: null,
@@ -1105,7 +1169,7 @@ export default {
);
},
visibleDetailColumns() {
if (!this.pageMode) return this.detailColumns;
if (!this.readonly && !this.pageMode) return this.detailColumns;
return this.detailColumns.filter(column => column.prop !== 'settlementAmountNoTax');
},
detailFeeItemNames() {
@@ -1132,6 +1196,13 @@ export default {
});
return Array.from(names);
},
adjustChangeRecords() {
return this.changeRecords.filter(
row =>
row.changeType === '结算明细项' &&
String(row.lineNo ?? '') === String(this.adjustDialog.detailLineNo ?? '')
);
},
},
watch: {
modelValue: {
@@ -1229,6 +1300,12 @@ export default {
this.attachments = [];
this.selectedAttachmentRows = [];
this.adjustRows = [];
this.adjustDialog.activeTab = 'adjust';
this.adjustDialog.detailId = '';
this.adjustDialog.detailLineNo = '';
this.adjustChangeRecordVisible = false;
this.adjustChangeRecord = null;
this.adjustChangeRecordDetailRows = [];
this.billingRuleDialog.visible = false;
this.billingRuleDialog.rule = null;
this.contractOptions = [];
@@ -1247,7 +1324,11 @@ export default {
this.form = { ...emptyPreSettlementForm(), ...detail };
this.summaryFees = (detail.summaryFees || []).map(row => ({ ...row }));
this.details = (detail.details || []).map(row => ({ ...row }));
this.advances = detail.advances || [];
this.advances = (detail.advances || []).map(row => ({
...row,
createUserName: row.createUserName || detail.createUserName,
createTime: row.createTime || detail.createTime,
}));
this.changeRecords = detail.changeRecords || [];
this.attachments = this.parseAttachments(detail.attachmentsJson);
this.selectedAttachmentRows = [];
@@ -1360,7 +1441,11 @@ export default {
},
async loadTransportTypeOptions() {
const { data } = await getDictionary({ code: 'transport_type' });
this.transportTypeOptions = data?.data || [];
const records = Array.isArray(data?.data) ? data.data : data?.data?.records || [];
this.transportTypeOptions = records.map(item => ({
dictKey: item.dictKey ?? item.value,
dictValue: item.dictValue ?? item.label ?? item.name,
}));
},
handleContractChange(id) {
const contract = this.contractOptions.find(item => String(item.id) === String(id));
@@ -1720,7 +1805,9 @@ export default {
this.adjustDialog.visible = true;
this.adjustDialog.loading = true;
this.adjustDialog.readonly = readonly;
this.adjustDialog.activeTab = 'adjust';
this.adjustDialog.detailId = detailRow.id;
this.adjustDialog.detailLineNo = detailRow.lineNo;
this.adjustDialog.reason = '';
try {
const { data } = await getDetailFees(detailRow.id);
@@ -1733,6 +1820,42 @@ export default {
this.adjustDialog.loading = false;
}
},
parseChangeRecordData(value) {
if (!value) return {};
if (typeof value === 'object') return value;
try {
const parsed = JSON.parse(value);
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
} catch (error) {
return {};
}
},
formatAdjustChangeValue(value) {
if (value === undefined || value === null || value === '') return '空';
if (typeof value === 'object') return JSON.stringify(value);
return String(value);
},
buildAdjustChangeRecordRows(row = {}) {
const before = this.parseChangeRecordData(row.beforeData);
const after = this.parseChangeRecordData(row.afterData);
const fields = [...new Set([...Object.keys(before), ...Object.keys(after)])];
const rows = fields
.filter(field => JSON.stringify(before[field]) !== JSON.stringify(after[field]))
.map(field => ({
field,
before: this.formatAdjustChangeValue(before[field]),
after: this.formatAdjustChangeValue(after[field]),
}));
if (row.changeContent)
rows.unshift({ field: '变更内容', before: '空', after: row.changeContent });
if (row.changeReason) rows.push({ field: '变更原因', before: '空', after: row.changeReason });
return rows;
},
openAdjustChangeRecord(row) {
this.adjustChangeRecord = row;
this.adjustChangeRecordDetailRows = this.buildAdjustChangeRecordRows(row);
this.adjustChangeRecordVisible = true;
},
billingRuleName(row) {
return this.normalizeBillingRule(row).name;
},
@@ -2035,6 +2158,14 @@ export default {
}[status] || this.displayValue(status)
);
},
advanceCreateUserName(row) {
return this.displayValue(
row?.createUserName || row?.advanceCreateUserName || row?.applyUserName
);
},
advanceCreateTime(row) {
return this.displayValue(row?.createTime || row?.advanceCreateTime || row?.applyTime);
},
changeRecordLineNo(row) {
if (row.changeType !== '结算明细项') return '';
if (row.lineNo !== undefined && row.lineNo !== null && row.lineNo !== '') return row.lineNo;
@@ -2225,6 +2356,23 @@ export default {
}
}
.pre-settlement-change-record-detail-meta {
display: flex;
flex-wrap: wrap;
gap: 8px 32px;
margin-bottom: 16px;
color: #606266;
}
:deep(.pre-settlement-change-record-detail-dialog .el-dialog__body) {
padding-top: 12px;
}
:deep(.pre-settlement-change-record-detail-dialog .el-table .cell) {
white-space: pre-wrap;
word-break: break-all;
}
:deep(.pre-settlement-editor .el-dialog__body) {
padding: 12px 16px;
}