1、新增结算模块
2、调整业务模块 3、调整客商模块
This commit is contained in:
@@ -0,0 +1,396 @@
|
||||
<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 class="settlement-adjustment-editor__section">
|
||||
<div class="dialog-section-title">基本信息</div>
|
||||
<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>
|
||||
|
||||
<section class="settlement-adjustment-editor__section">
|
||||
<div class="settlement-adjustment-editor__section-head">
|
||||
<div class="dialog-section-title">调整费用</div>
|
||||
<el-button
|
||||
v-if="editable && form.formalSettlementId"
|
||||
type="primary"
|
||||
plain
|
||||
@click="openFeeDialog"
|
||||
>添加费用</el-button
|
||||
>
|
||||
</div>
|
||||
<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>
|
||||
</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__section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.settlement-adjustment-editor__section-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.dialog-section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 22px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.dialog-section-title::before {
|
||||
width: 4px;
|
||||
height: 18px;
|
||||
margin-right: 8px;
|
||||
background: #409eff;
|
||||
content: '';
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user