This commit is contained in:
2026-08-31 10:38:21 +08:00
parent a10eea247f
commit a75ac1cfa4
13 changed files with 864 additions and 161 deletions
@@ -42,6 +42,8 @@
? settlementTypeName
: field.prop === 'formalSettlementId'
? form.formalSettlementNo || form.formalSettlementId
: field.prop === 'createTime'
? formatCreateDate(form[field.prop])
: form[field.prop]
)
}}</span></el-form-item
@@ -68,23 +70,55 @@
v-if="editable && form.formalSettlementId"
type="primary"
plain
@click="openFeeDialog"
@click="addFeeRow"
>添加费用</el-button
>
</template>
<el-table :data="details" border>
<el-table-column type="index" label="序号" width="64" align="center" /><el-table-column
prop="feeType"
label="费用类型"
min-width="150"
align="center"
/><el-table-column
prop="feeItem"
label="费用项目"
min-width="180"
align="center"
show-overflow-tooltip
/><el-table-column
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column prop="feeType" label="费用类型" min-width="180" align="center">
<template #default="{ row }">
<el-select
v-if="editable && row.manualFlag === 1"
v-model="row.feeType"
filterable
allow-create
default-first-option
clearable
placeholder="请选择或输入"
>
<el-option
v-for="item in feeOptions"
:key="item.feeType"
:label="item.feeTypeName || item.feeType"
:value="item.feeType"
/>
</el-select>
<span v-else>{{ displayValue(feeTypeName(row.feeType)) }}</span>
</template>
</el-table-column>
<el-table-column prop="feeItem" label="费用项目" min-width="200" align="center">
<template #default="{ row }">
<el-select
v-if="editable && row.manualFlag === 1"
v-model="row.feeItem"
filterable
allow-create
default-first-option
clearable
placeholder="请选择或输入"
>
<el-option
v-for="item in feeItemOptions(row.feeType)"
:key="item"
:label="item"
:value="item"
/>
</el-select>
<span v-else>{{ displayValue(row.feeItem) }}</span>
</template>
</el-table-column>
<el-table-column
prop="originalAmountTax"
label="原金额(含税)"
min-width="145"
@@ -98,7 +132,9 @@
><el-input-number
v-if="editable"
v-model="row.adjustmentAmountTax"
:class="{ negative: Number(row.adjustmentAmountTax) < 0 }"
:precision="2"
:step="0.01"
:controls="false"
@change="recalculate"
/><span v-else :class="{ negative: Number(row.adjustmentAmountTax) < 0 }">{{
@@ -134,7 +170,7 @@
></template
></el-table-column
>
<template #empty><el-empty description="请选择调整费用明细" /></template>
<template #empty><el-empty description="暂无调整费用" /></template>
</el-table>
<div class="settlement-adjustment-editor__summary">
调整金额合计:<strong :class="{ negative: Number(form.adjustmentAmount) < 0 }">{{
@@ -210,53 +246,19 @@
</div>
<template #footer
><el-button @click="visible = false">取消</el-button
><el-button
v-if="editable"
type="primary"
plain
:loading="syncing"
:disabled="!form.formalSettlementId"
@click="handleSync"
>同步</el-button
><el-button v-if="editable" type="primary" :loading="saving" @click="handleSave"
>保存</el-button
></template
>
<el-dialog v-model="feeDialog.visible" title="选择调整费用" width="88%" append-to-body>
<el-table
ref="feeTable"
:data="feeRows"
border
@selection-change="feeDialog.selected = $event"
><el-table-column type="selection" width="52" align="center" /><el-table-column
type="index"
label="序号"
width="64"
align="center"
/><el-table-column
prop="documentNo"
label="单据号"
min-width="150"
align="center"
/><el-table-column
prop="feeType"
label="费用类型"
min-width="140"
align="center"
/><el-table-column
prop="feeItem"
label="费用项目"
min-width="180"
align="center"
show-overflow-tooltip
/><el-table-column
prop="originalAmountTax"
label="原金额(含税)"
min-width="145"
align="center"
><template #default="{ row }">{{
formatMoney(row.originalAmountTax)
}}</template></el-table-column
></el-table
>
<template #footer
><el-button @click="feeDialog.visible = false">取消</el-button
><el-button type="primary" @click="confirmFees">确定</el-button></template
>
</el-dialog>
</el-dialog>
</template>
@@ -274,6 +276,7 @@ export default {
data: () => ({
loading: false,
saving: false,
syncing: false,
form: createSettlementAdjustmentForm(),
fields: settlementAdjustmentFormFields,
details: [],
@@ -296,11 +299,10 @@ export default {
'zip',
],
candidates: [],
feeRows: [],
feeOptions: [],
rules: {
formalSettlementId: [{ required: true, message: '请选择关联正式结算单', trigger: 'change' }],
},
feeDialog: { visible: false, selected: [] },
}),
computed: {
visible: {
@@ -333,22 +335,29 @@ export default {
methods: {
async initialize() {
this.form = createSettlementAdjustmentForm();
const userInfo = this.$store.getters.userInfo || {};
this.form.createTime = this.$dayjs().format('YYYY-MM-DD');
this.form.createUserName = userInfo.realName || userInfo.userName || userInfo.account || '';
this.details = [];
this.attachments = [];
this.selectedAttachments = [];
this.candidates = [];
this.feeRows = [];
this.feeOptions = [];
if (!this.recordId) {
await this.loadFormalSettlements('');
await Promise.all([this.loadFormalSettlements(''), this.loadFeeOptions()]);
return;
}
this.loading = true;
try {
const response = await api.getDetail(this.recordId);
const [response] = await Promise.all([api.getDetail(this.recordId), this.loadFeeOptions()]);
const data = response?.data?.data || response?.data || response || {};
this.form = { ...createSettlementAdjustmentForm(), ...data };
this.details = (data.details || []).map(item => ({
...item,
manualFlag:
item.formalSettlementDetailId == null && item.formalSettlementDetailFeeId == null
? 1
: 0,
adjustmentAmountTax: Number(item.adjustmentAmountTax || 0),
adjustmentAmountNoTax:
item.adjustmentAmountNoTax == null ? null : Number(item.adjustmentAmountNoTax),
@@ -363,6 +372,10 @@ export default {
const { data } = await api.getFormalSettlements(keyword);
this.candidates = data?.data || data || [];
},
async loadFeeOptions() {
const { data } = await api.getFeeOptions();
this.feeOptions = data?.data || data || [];
},
async handleFormalChange(id) {
if (!id) {
Object.assign(this.form, {
@@ -397,6 +410,7 @@ export default {
if (String(this.form.formalSettlementId) !== String(formalSettlementId)) return;
this.details = (data?.data || data || []).map(fee => ({
...fee,
manualFlag: 0,
originalAmountTax: Number(fee.originalAmountTax || 0),
adjustmentAmountTax: 0,
adjustmentAmountNoTax: null,
@@ -407,25 +421,28 @@ export default {
this.loading = false;
}
},
async openFeeDialog() {
const { data } = await api.getFormalDetails(this.form.formalSettlementId);
const used = new Set(this.details.map(item => String(item.formalSettlementDetailFeeId)));
this.feeRows = (data?.data || data || []).filter(
item => !used.has(String(item.formalSettlementDetailFeeId))
);
this.feeDialog = { visible: true, selected: [] };
addFeeRow() {
this.details.push({
formalSettlementDetailId: null,
formalSettlementDetailFeeId: null,
feeType: '',
feeItem: '',
originalAmountTax: 0,
adjustmentAmountTax: 0,
adjustmentAmountNoTax: null,
remark: '',
manualFlag: 1,
});
},
confirmFees() {
this.feeDialog.selected.forEach(item =>
this.details.push({
...item,
adjustmentAmountTax: 0,
adjustmentAmountNoTax: null,
remark: '',
})
feeTypeName(value) {
return (
this.feeOptions.find(item => String(item.feeType) === String(value))?.feeTypeName || value
);
},
feeItemOptions(feeType) {
return (
this.feeOptions.find(item => String(item.feeType) === String(feeType))?.feeItems || []
);
this.recalculate();
this.feeDialog.visible = false;
},
recalculate() {
const total = this.details.reduce(
@@ -437,13 +454,65 @@ export default {
(Number(this.form.originalSettlementAmount || 0) + total).toFixed(2)
);
},
async handleSync() {
const formalSettlementId = this.form.formalSettlementId;
if (!formalSettlementId) return this.$message.warning('请先选择正式结算单');
this.syncing = true;
try {
const [candidateResponse, detailResponse] = await Promise.all([
api.getFormalSettlements(this.form.formalSettlementNo || ''),
api.getFormalDetails(formalSettlementId),
]);
if (String(this.form.formalSettlementId) !== String(formalSettlementId)) return;
const candidateData = candidateResponse?.data?.data || candidateResponse?.data || [];
const formalSettlements = Array.isArray(candidateData) ? candidateData : [];
const formalSettlement = formalSettlements.find(
item => String(item.id) === String(formalSettlementId)
);
if (formalSettlement) {
const { id, ...formalInformation } = formalSettlement;
Object.assign(this.form, formalInformation, {
formalSettlementId: id,
formalSettlementNo: formalSettlement.formalSettlementNo,
originalSettlementAmount: Number(formalSettlement.settlementAmount || 0),
settlementTypeName: formalSettlement.settlementTypeName,
});
}
const existingDetailMap = new Map(
this.details
.filter(item => item.formalSettlementDetailFeeId != null)
.map(item => [String(item.formalSettlementDetailFeeId), item])
);
const manualDetails = this.details.filter(item => Number(item.manualFlag) === 1);
const detailData = detailResponse?.data?.data || detailResponse?.data || [];
const formalDetails = Array.isArray(detailData) ? detailData : [];
this.details = formalDetails
.map(fee => {
const existing = existingDetailMap.get(String(fee.formalSettlementDetailFeeId));
return {
...fee,
manualFlag: 0,
originalAmountTax: Number(fee.originalAmountTax || 0),
adjustmentAmountTax: Number(existing?.adjustmentAmountTax || 0),
adjustmentAmountNoTax:
existing?.adjustmentAmountNoTax == null
? null
: Number(existing.adjustmentAmountNoTax),
remark: existing?.remark || '',
};
})
.concat(manualDetails);
this.recalculate();
this.$message.success('同步成功');
} finally {
this.syncing = false;
}
},
async handleSave() {
await this.$refs.formRef.validate();
if (!this.details.length) return this.$message.warning('请至少添加一条调整费用');
this.saving = true;
try {
await api.save({
...(this.recordId ? { id: this.form.id } : {}),
const { data } = await api.save({
id: this.form.id || undefined,
formalSettlementId: this.form.formalSettlementId,
attachmentsJson: JSON.stringify(this.attachments || []),
remark: this.form.remark,
@@ -452,11 +521,13 @@ export default {
formalSettlementDetailFeeId: item.formalSettlementDetailFeeId,
feeType: item.feeType,
feeItem: item.feeItem,
originalAmountTax: item.originalAmountTax,
adjustmentAmountTax: item.adjustmentAmountTax,
adjustmentAmountNoTax: item.adjustmentAmountNoTax,
remark: item.remark,
})),
});
this.form.id = data?.data || data || this.form.id;
this.$message.success('保存成功');
this.visible = false;
this.$emit('success');
@@ -470,6 +541,11 @@ export default {
formatMoney(value) {
return Number(value || 0).toFixed(2);
},
formatCreateDate(value) {
if (!value) return '';
const date = this.$dayjs(value);
return date.isValid() ? date.format('YYYY-MM-DD') : value;
},
handleAttachmentChange(files) {
const userInfo = this.$store.getters.userInfo || {};
const uploadUserName = userInfo.realName || userInfo.userName || '';
@@ -573,4 +649,7 @@ export default {
.negative {
color: #f56c6c;
}
.settlement-adjustment-editor :deep(.el-input-number.negative .el-input__inner) {
color: #f56c6c;
}
</style>