Files
tms-erp-web/src/views/settlement/components/settlement-adjustment-editor.vue
T
gxwebsoft 8f35e6b265 style(ui): 统一全站 el-table 表头背景色及弹窗卡片化风格
- 将所有 el-table 表头背景色统一设为浅灰 #fafafa,覆盖普通表格、avue-crud 和固定列
- 移除业务组件内冗余的表头样式,改由全局样式统一控制
- 调整多处弹窗(预结算单、正式结算单、运输对账单、应收明细等)内容板块,改用全局 section-card 组件实现白底卡片分组
- 为多个弹窗内的搜索区域增加白底、圆角和阴影样式,提升视觉层次感
- 缩减多处表格“操作”列宽度以适配新布局
- 付款申请弹窗按钮由主色调 primary 改为 success,符合全站按钮风格规范
- 统一调整弹窗内表单、按钮、间距及背景细节,改善界面体验和视觉一致性
2026-08-20 14:47:29 +08:00

372 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-dialog v-model="visible" :title="title" width="94%" top="3vh" append-to-body destroy-on-close>
<div v-loading="loading" class="settlement-adjustment-editor">
<section-card title="基本信息">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-position="right"
label-width="auto"
>
<el-row :gutter="24">
<el-col v-for="field in fields" :key="field.prop" :span="8"
><el-form-item :label="field.label" :prop="field.prop"
><el-select
v-if="field.prop === 'formalSettlementId' && editable"
v-model="form.formalSettlementId"
filterable
remote
clearable
:remote-method="loadFormalSettlements"
placeholder="请选择正式结算单"
@change="handleFormalChange"
><el-option
v-for="item in candidates"
:key="item.id"
:label="`${item.formalSettlementNo} / ${item.projectName || ''}`"
:value="item.id" /></el-select
><el-input
v-else-if="field.prop === 'adjustmentNo'"
v-model="form[field.prop]"
disabled
/><el-input-number
v-else-if="field.money && editable"
v-model="form[field.prop]"
:precision="2"
:controls="false"
disabled
/><span v-else>{{
displayValue(
field.prop === 'settlementTypeName' ? settlementTypeName : form[field.prop]
)
}}</span></el-form-item
></el-col
>
<el-col :span="24"
><el-form-item label="备注" prop="remark"
><el-input
v-if="editable"
v-model="form.remark"
type="textarea"
maxlength="200"
show-word-limit
/><span v-else>{{ displayValue(form.remark) }}</span></el-form-item
></el-col
>
</el-row>
</el-form>
</section-card>
<section-card title="调整费用">
<template #extra>
<el-button
v-if="editable && form.formalSettlementId"
type="primary"
plain
@click="openFeeDialog"
>添加费用</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
prop="originalAmountTax"
label="原金额(含税)"
min-width="145"
align="center"
><template #default="{ row }">{{
formatMoney(row.originalAmountTax)
}}</template></el-table-column
>
<el-table-column label="调整金额(含税)" min-width="160" align="center"
><template #default="{ row }"
><el-input-number
v-if="editable"
v-model="row.adjustmentAmountTax"
:precision="2"
:controls="false"
@change="recalculate"
/><span v-else :class="{ negative: Number(row.adjustmentAmountTax) < 0 }">{{
formatMoney(row.adjustmentAmountTax)
}}</span></template
></el-table-column
>
<el-table-column label="调整金额(不含税)" min-width="170" align="center"
><template #default="{ row }"
><el-input-number
v-if="editable"
v-model="row.adjustmentAmountNoTax"
:precision="2"
:controls="false"
/><span v-else>{{ formatMoney(row.adjustmentAmountNoTax) }}</span></template
></el-table-column
>
<el-table-column label="备注" min-width="180" align="center"
><template #default="{ row }"
><el-input v-if="editable" v-model="row.remark" maxlength="200" /><span v-else>{{
displayValue(row.remark)
}}</span></template
></el-table-column
>
<el-table-column v-if="editable" label="操作" width="90" align="center"
><template #default="{ $index }"
><el-link
type="danger"
@click="
details.splice($index, 1);
recalculate();
"
>删除</el-link
></template
></el-table-column
>
<template #empty><el-empty description="请选择调整费用明细" /></template>
</el-table>
<div class="settlement-adjustment-editor__summary">
调整金额合计:<strong :class="{ negative: Number(form.adjustmentAmount) < 0 }">{{
formatMoney(form.adjustmentAmount)
}}</strong
>;调整后结算金额:<strong>{{ formatMoney(form.adjustedSettlementAmount) }}</strong>
</div>
</section-card>
</div>
<template #footer
><el-button @click="visible = false">取消</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>
<script>
import * as api from '@/api/settlement/settlementAdjustment';
import {
createSettlementAdjustmentForm,
settlementAdjustmentFormFields,
} from '@/option/settlement/settlementAdjustmentForm';
export default {
name: 'SettlementAdjustmentEditor',
props: { modelValue: Boolean, recordId: [String, Number], readonly: Boolean },
emits: ['update:modelValue', 'success'],
data: () => ({
loading: false,
saving: false,
form: createSettlementAdjustmentForm(),
fields: settlementAdjustmentFormFields,
details: [],
candidates: [],
feeRows: [],
rules: {
formalSettlementId: [{ required: true, message: '请选择关联正式结算单', trigger: 'change' }],
},
feeDialog: { visible: false, selected: [] },
}),
computed: {
visible: {
get() {
return this.modelValue;
},
set(value) {
this.$emit('update:modelValue', value);
},
},
editable() {
return !this.readonly;
},
title() {
return this.readonly ? '查看结算调整单' : this.recordId ? '编辑结算调整单' : '新增结算调整单';
},
settlementTypeName() {
return this.form.settlementType === 'receivable'
? '应收'
: this.form.settlementType === 'payable'
? '应付'
: '';
},
},
watch: {
modelValue(value) {
if (value) this.initialize();
},
},
methods: {
async initialize() {
this.form = createSettlementAdjustmentForm();
this.details = [];
this.candidates = [];
this.feeRows = [];
if (!this.recordId) {
await this.loadFormalSettlements('');
return;
}
this.loading = true;
try {
const { data } = await api.getDetail(this.recordId);
this.form = { ...createSettlementAdjustmentForm(), ...data };
this.details = (data.details || []).map(item => ({
...item,
adjustmentAmountTax: Number(item.adjustmentAmountTax || 0),
adjustmentAmountNoTax:
item.adjustmentAmountNoTax == null ? null : Number(item.adjustmentAmountNoTax),
}));
await this.loadFormalSettlements(this.form.formalSettlementNo || '');
} finally {
this.loading = false;
}
},
async loadFormalSettlements(keyword = '') {
const { data } = await api.getFormalSettlements(keyword);
this.candidates = data?.data || data || [];
},
async handleFormalChange(id) {
const item = this.candidates.find(row => String(row.id) === String(id));
if (!item) return;
Object.assign(this.form, item, {
formalSettlementId: id,
formalSettlementNo: item.formalSettlementNo,
originalSettlementAmount: Number(item.settlementAmount || 0),
settlementTypeName: item.settlementTypeName,
});
this.details = [];
this.recalculate();
},
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: [] };
},
confirmFees() {
this.feeDialog.selected.forEach(item =>
this.details.push({
...item,
adjustmentAmountTax: 0,
adjustmentAmountNoTax: null,
remark: '',
})
);
this.recalculate();
this.feeDialog.visible = false;
},
recalculate() {
const total = this.details.reduce(
(sum, row) => sum + Number(row.adjustmentAmountTax || 0),
0
);
this.form.adjustmentAmount = Number(total.toFixed(2));
this.form.adjustedSettlementAmount = Number(
(Number(this.form.originalSettlementAmount || 0) + total).toFixed(2)
);
},
async handleSave() {
await this.$refs.formRef.validate();
if (!this.details.length) return this.$message.warning('请至少添加一条调整费用');
this.saving = true;
try {
await api.save({
id: this.form.id,
formalSettlementId: this.form.formalSettlementId,
remark: this.form.remark,
details: this.details.map(item => ({
formalSettlementDetailId: item.formalSettlementDetailId,
formalSettlementDetailFeeId: item.formalSettlementDetailFeeId,
feeType: item.feeType,
feeItem: item.feeItem,
adjustmentAmountTax: item.adjustmentAmountTax,
adjustmentAmountNoTax: item.adjustmentAmountNoTax,
remark: item.remark,
})),
});
this.$message.success('保存成功');
this.visible = false;
this.$emit('success');
} finally {
this.saving = false;
}
},
displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value;
},
formatMoney(value) {
return Number(value || 0).toFixed(2);
},
},
};
</script>
<style scoped lang="scss">
.settlement-adjustment-editor__summary {
padding: 12px 0;
text-align: right;
}
.settlement-adjustment-editor :deep(.el-form-item) {
margin-bottom: 16px;
}
.settlement-adjustment-editor :deep(.el-table) {
--el-table-border-color: #eff1f7;
}
.settlement-adjustment-editor :deep(.el-table__body tr:nth-child(even) > td.el-table__cell) {
background: #fafafa;
}
.negative {
color: #f56c6c;
}
</style>