fix
This commit is contained in:
@@ -60,7 +60,7 @@
|
||||
v-else-if="field.type === 'number' && editable"
|
||||
v-model="form[field.prop]"
|
||||
:min="0.000001"
|
||||
:precision="6"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
/>
|
||||
<span v-else-if="field.money">{{ formatMoney(form[field.prop]) }}</span>
|
||||
@@ -153,8 +153,7 @@
|
||||
<span
|
||||
v-else-if="isSummaryMoney(column.prop)"
|
||||
:class="{
|
||||
'formal-editor__negative-amount':
|
||||
column.prop === 'adjustAmount' && Number(row[column.prop] || 0) < 0,
|
||||
'formal-editor__negative-amount': isNegativeAdjustedAmount(row, column.prop),
|
||||
}"
|
||||
>
|
||||
{{ formatMoney(row[column.prop]) }}
|
||||
@@ -224,7 +223,10 @@
|
||||
<template #default="{ row }">
|
||||
<span v-if="column.money">{{ formatMoney(row[column.prop]) }}</span>
|
||||
<span v-else-if="column.prop === 'transportQuantity'">
|
||||
{{ formatQuantity(row[column.prop]) }}
|
||||
{{ formatDetailTransportQuantity(row[column.prop]) }}
|
||||
</span>
|
||||
<span v-else-if="column.prop === 'mileage'">
|
||||
{{ formatDetailMileage(row[column.prop]) }}
|
||||
</span>
|
||||
<span v-else-if="column.prop === 'transportType'">
|
||||
{{ transportTypeName(row[column.prop]) }}
|
||||
@@ -235,11 +237,9 @@
|
||||
<el-table-column v-if="editable" label="操作" width="150" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<div class="formal-editor__links">
|
||||
<el-link v-if="row.formalSettlementId" type="primary" @click="openAdjustDialog(row)"
|
||||
>调整</el-link
|
||||
>
|
||||
<el-link type="primary" @click="openAdjustDialog(row)">调整</el-link>
|
||||
<el-link v-if="!row.sourcePreSettlementId" type="danger" @click="removeDetail(row)"
|
||||
>删除</el-link
|
||||
>踢出</el-link
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
@@ -254,7 +254,13 @@
|
||||
{{ missingAttachmentTypeText }}
|
||||
</span>
|
||||
</template>
|
||||
<el-table :data="attachments" border>
|
||||
<div class="formal-editor__attachment-actions">
|
||||
<el-button type="primary" :disabled="!attachments.length" @click="downloadAttachments">
|
||||
批量下载
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="attachments" border @selection-change="handleAttachmentSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
<el-table-column label="类型" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
@@ -323,7 +329,7 @@
|
||||
</section-card>
|
||||
|
||||
<section-card title="发票信息">
|
||||
<div v-if="editable" class="formal-editor__invoice-claim">
|
||||
<div class="formal-editor__invoice-claim">
|
||||
<el-form inline label-position="right" label-width="auto" @submit.prevent>
|
||||
<el-form-item label="发票号码">
|
||||
<el-input
|
||||
@@ -394,9 +400,7 @@
|
||||
<div class="formal-editor__links">
|
||||
<el-link type="primary" @click="viewInvoiceAttachment(row)">查看</el-link>
|
||||
<el-link type="primary" @click="downloadInvoiceAttachment(row)">下载</el-link>
|
||||
<el-link v-if="editable" type="danger" @click="removeInvoice($index)">
|
||||
删除
|
||||
</el-link>
|
||||
<el-link type="danger" @click="removeInvoice($index)">删除</el-link>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -626,6 +630,39 @@
|
||||
>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="detailAmountAdjust.visible"
|
||||
title="结算明细调整"
|
||||
width="520px"
|
||||
append-to-body
|
||||
>
|
||||
<el-form
|
||||
:model="detailAmountAdjust"
|
||||
label-position="right"
|
||||
label-width="auto"
|
||||
class="formal-editor__amount-adjust"
|
||||
>
|
||||
<el-form-item label="原金额">
|
||||
<span>{{ formatMoney(detailAmountAdjust.originalAmount) }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整金额" required>
|
||||
<el-input-number
|
||||
v-model="detailAmountAdjust.adjustAmount"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="结算金额">
|
||||
<span>{{ formatMoney(detailAmountAdjustSettlementAmount) }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="detailAmountAdjust.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmDetailAmountAdjustment">提交</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="adjust.visible" title="结算明细调整" width="92%" append-to-body>
|
||||
<el-table v-loading="adjust.loading" :data="adjust.rows" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
@@ -671,14 +708,6 @@
|
||||
:precision="2"
|
||||
:controls="false" /></template
|
||||
></el-table-column>
|
||||
<el-table-column label="结算金额(不含税)" min-width="180" align="center"
|
||||
><template #default="{ row }"
|
||||
><el-input-number
|
||||
v-model="row.settlementAmountNoTax"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false" /></template
|
||||
></el-table-column>
|
||||
<el-table-column label="备注" min-width="180" align="center"
|
||||
><template #default="{ row }"><el-input v-model="row.remark" maxlength="200" /></template
|
||||
></el-table-column>
|
||||
@@ -723,6 +752,7 @@ import {
|
||||
summaryColumns,
|
||||
} from '@/option/settlement/formalSettlementTable';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { h } from 'vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { downloadFileByUrl } from '@/utils/util';
|
||||
import * as XLSX from 'xlsx';
|
||||
@@ -752,6 +782,7 @@ export default {
|
||||
adjustments: [],
|
||||
changeRecords: [],
|
||||
attachments: [],
|
||||
selectedAttachmentRows: [],
|
||||
invoices: [],
|
||||
invoiceClaimNo: '',
|
||||
invoiceClaimLoading: false,
|
||||
@@ -815,6 +846,12 @@ export default {
|
||||
reason: '',
|
||||
rows: [],
|
||||
},
|
||||
detailAmountAdjust: {
|
||||
visible: false,
|
||||
row: null,
|
||||
originalAmount: 0,
|
||||
adjustAmount: 0,
|
||||
},
|
||||
detailCollapsed: false,
|
||||
detailQuery: {
|
||||
documentNo: '',
|
||||
@@ -865,6 +902,14 @@ export default {
|
||||
summaryTotal() {
|
||||
return this.summaryFees.reduce((total, row) => total + Number(row.settlementAmount || 0), 0);
|
||||
},
|
||||
detailAmountAdjustSettlementAmount() {
|
||||
return Number(
|
||||
(
|
||||
Number(this.detailAmountAdjust.originalAmount || 0) +
|
||||
Number(this.detailAmountAdjust.adjustAmount || 0)
|
||||
).toFixed(2)
|
||||
);
|
||||
},
|
||||
filteredDetails() {
|
||||
return this.details.filter(row =>
|
||||
Object.entries(this.appliedDetailQuery).every(([field, keyword]) => {
|
||||
@@ -901,7 +946,14 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async initialize() {
|
||||
const newRecordAudit = this.recordId
|
||||
? null
|
||||
: {
|
||||
createUserName: this.userInfo?.realName || this.userInfo?.userName || '',
|
||||
createTime: this.$dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
};
|
||||
this.form = createFormalSettlementForm();
|
||||
if (newRecordAudit) Object.assign(this.form, newRecordAudit);
|
||||
this.sources = [];
|
||||
this.details = [];
|
||||
this.summaryFees = [];
|
||||
@@ -909,9 +961,16 @@ export default {
|
||||
this.adjustments = [];
|
||||
this.changeRecords = [];
|
||||
this.attachments = [];
|
||||
this.selectedAttachmentRows = [];
|
||||
this.invoices = [];
|
||||
this.invoiceClaimNo = '';
|
||||
this.attachmentUploadFiles = [];
|
||||
this.detailAmountAdjust = {
|
||||
visible: false,
|
||||
row: null,
|
||||
originalAmount: 0,
|
||||
adjustAmount: 0,
|
||||
};
|
||||
this.detailCollapsed = false;
|
||||
this.resetDetailQuery(false);
|
||||
await Promise.all([
|
||||
@@ -923,6 +982,7 @@ export default {
|
||||
if (!this.recordId) {
|
||||
this.form.exchangeRateDate = this.$dayjs().format('YYYY-MM-DD');
|
||||
if (this.initialData) await this.applyInitialData();
|
||||
Object.assign(this.form, newRecordAudit);
|
||||
await this.refreshFormalSettlementNo();
|
||||
return;
|
||||
}
|
||||
@@ -945,6 +1005,7 @@ export default {
|
||||
this.adjustments = data.adjustments || [];
|
||||
this.changeRecords = data.changeRecords || [];
|
||||
this.attachments = this.parseAttachments(data.attachmentsJson);
|
||||
this.selectedAttachmentRows = [];
|
||||
this.invoices = data.invoices || [];
|
||||
this.sortAttachments();
|
||||
this.contracts = this.allContracts.filter(
|
||||
@@ -1272,7 +1333,8 @@ export default {
|
||||
this.buildSummaryFeesFromDetails();
|
||||
this.detailCandidate.visible = false;
|
||||
},
|
||||
removeDetail(row) {
|
||||
async removeDetail(row) {
|
||||
await this.$confirm('确认将该明细踢出正式结算单?', '提示', { type: 'warning' });
|
||||
const index = this.details.indexOf(row);
|
||||
if (index < 0) return;
|
||||
this.details.splice(index, 1);
|
||||
@@ -1309,16 +1371,26 @@ export default {
|
||||
isSummaryMoney(prop) {
|
||||
return ['originalAmount', 'adjustAmount', 'settlementAmount'].includes(prop);
|
||||
},
|
||||
isNegativeAdjustedAmount(row, prop) {
|
||||
return (
|
||||
Number(row.adjustAmount || 0) < 0 && ['adjustAmount', 'settlementAmount'].includes(prop)
|
||||
);
|
||||
},
|
||||
recalculateSummaryRow(row) {
|
||||
row.settlementAmount = Number(row.originalAmount || 0) + Number(row.adjustAmount || 0);
|
||||
},
|
||||
getSummarySums({ columns, data }) {
|
||||
const sumProps = ['originalAmount', 'adjustAmount', 'settlementAmount'];
|
||||
const hasNegativeAdjustment = data.some(row => Number(row.adjustAmount || 0) < 0);
|
||||
return columns.map((column, index) => {
|
||||
if (index === 0) return '合计';
|
||||
if (!sumProps.includes(column.property)) return '';
|
||||
const total = data.reduce((sum, row) => sum + Number(row[column.property] || 0), 0);
|
||||
return this.formatMoney(total);
|
||||
const totalText = this.formatMoney(total);
|
||||
if (column.property === 'settlementAmount' && hasNegativeAdjustment) {
|
||||
return h('span', { style: { color: 'var(--el-color-danger)' } }, totalText);
|
||||
}
|
||||
return totalText;
|
||||
});
|
||||
},
|
||||
buildSummaryFeesFromDetails() {
|
||||
@@ -1406,6 +1478,20 @@ export default {
|
||||
);
|
||||
},
|
||||
async openAdjustDialog(row) {
|
||||
if (!row.formalSettlementId) {
|
||||
const originalAmount = Number(
|
||||
row.originalAmount ??
|
||||
row.totalAmount ??
|
||||
Number(row.settlementAmountTax || 0) - Number(row.adjustAmount || 0)
|
||||
);
|
||||
this.detailAmountAdjust = {
|
||||
visible: true,
|
||||
row,
|
||||
originalAmount: Number(originalAmount.toFixed(2)),
|
||||
adjustAmount: Number(row.adjustAmount || 0),
|
||||
};
|
||||
return;
|
||||
}
|
||||
this.adjust = {
|
||||
visible: true,
|
||||
loading: true,
|
||||
@@ -1425,6 +1511,20 @@ export default {
|
||||
this.adjust.loading = false;
|
||||
}
|
||||
},
|
||||
confirmDetailAmountAdjustment() {
|
||||
const settlementAmount = this.detailAmountAdjustSettlementAmount;
|
||||
if (!Number.isFinite(settlementAmount) || settlementAmount < 0) {
|
||||
return this.$message.warning('调整后的结算金额不能小于0');
|
||||
}
|
||||
const row = this.detailAmountAdjust.row;
|
||||
if (!row) return;
|
||||
row.originalAmount = this.detailAmountAdjust.originalAmount;
|
||||
row.adjustAmount = Number(this.detailAmountAdjust.adjustAmount || 0);
|
||||
row.settlementAmountTax = settlementAmount;
|
||||
row.pendingDetailAdjustment = true;
|
||||
this.buildSummaryFeesFromDetails();
|
||||
this.detailAmountAdjust.visible = false;
|
||||
},
|
||||
async saveAdjustment() {
|
||||
if (!this.adjust.reason.trim()) return this.$message.warning('请输入调整原因');
|
||||
this.adjust.saving = true;
|
||||
@@ -1586,6 +1686,17 @@ export default {
|
||||
settlementType: this.form.settlementType,
|
||||
sourcePreSettlementIds: this.form.sourcePreSettlementIds,
|
||||
sourceDetailIds: this.form.sourceDetailIds,
|
||||
detailAdjustments: this.details
|
||||
.filter(row => row.pendingDetailAdjustment)
|
||||
.map(row => ({
|
||||
sourcePreSettlementDetailId:
|
||||
row.sourcePreSettlementDetailId ||
|
||||
(row.sourcePreSettlementId ? row.id : undefined),
|
||||
sourceDetailId: row.sourcePreSettlementId
|
||||
? undefined
|
||||
: row.sourceDetailId || row.id,
|
||||
adjustAmount: Number(row.adjustAmount || 0),
|
||||
})),
|
||||
exchangeRateDate: this.form.exchangeRateDate,
|
||||
exchangeRate: this.form.exchangeRate,
|
||||
summaryFees: this.summaryFees
|
||||
@@ -1639,6 +1750,12 @@ export default {
|
||||
const quantity = Number(value);
|
||||
return Number.isFinite(quantity) ? quantity.toFixed(2) : '-';
|
||||
},
|
||||
formatDetailTransportQuantity(value) {
|
||||
return this.readonly && Number(value) === -1 ? '-' : this.formatQuantity(value);
|
||||
},
|
||||
formatDetailMileage(value) {
|
||||
return this.readonly && Number(value) === -1 ? '-' : this.displayValue(value);
|
||||
},
|
||||
async loadTransportTypeOptions() {
|
||||
const { data } = await getDictionary({ code: 'transport_type' });
|
||||
this.transportTypeOptions = data?.data || [];
|
||||
@@ -1736,12 +1853,46 @@ export default {
|
||||
});
|
||||
this.sortAttachments();
|
||||
},
|
||||
handleAttachmentSelectionChange(rows) {
|
||||
this.selectedAttachmentRows = rows || [];
|
||||
},
|
||||
removeAttachment(index) {
|
||||
this.attachments.splice(index, 1);
|
||||
this.selectedAttachmentRows = this.selectedAttachmentRows.filter(file =>
|
||||
this.attachments.includes(file)
|
||||
);
|
||||
},
|
||||
getAttachmentUrl(file = {}) {
|
||||
return file.url || file.link || file.src || file.domain || '';
|
||||
},
|
||||
getAttachmentName(file = {}) {
|
||||
return (
|
||||
file.originalName || file.name || this.getAttachmentFileName(this.getAttachmentUrl(file))
|
||||
);
|
||||
},
|
||||
downloadAttachment(file) {
|
||||
const url = this.getAttachmentUrl(file);
|
||||
if (!url) {
|
||||
this.$message.warning('附件地址为空,无法下载');
|
||||
return;
|
||||
}
|
||||
downloadFileByUrl(url, this.getAttachmentName(file) || '附件');
|
||||
},
|
||||
downloadAttachments() {
|
||||
const files = this.selectedAttachmentRows.length
|
||||
? this.selectedAttachmentRows
|
||||
: this.attachments;
|
||||
const downloadableFiles = files.filter(file => this.getAttachmentUrl(file));
|
||||
if (!downloadableFiles.length) {
|
||||
this.$message.warning(
|
||||
this.selectedAttachmentRows.length ? '所选附件无法下载' : '暂无可下载附件'
|
||||
);
|
||||
return;
|
||||
}
|
||||
downloadableFiles.forEach((file, index) => {
|
||||
window.setTimeout(() => this.downloadAttachment(file), index * 200);
|
||||
});
|
||||
},
|
||||
previewAttachment(file) {
|
||||
const url = this.getAttachmentUrl(file);
|
||||
if (!url) return this.$message.warning('附件地址为空,无法预览');
|
||||
@@ -1844,7 +1995,7 @@ export default {
|
||||
}
|
||||
.formal-editor__detail-filter-actions {
|
||||
grid-column: 1 / -1;
|
||||
justify-self: start;
|
||||
justify-self: end;
|
||||
}
|
||||
.formal-editor__page-actions {
|
||||
display: flex;
|
||||
@@ -1892,12 +2043,20 @@ export default {
|
||||
.formal-editor__adjust-reason {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.formal-editor__amount-adjust :deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
.formal-editor__attachment-missing {
|
||||
margin-left: 12px;
|
||||
color: var(--el-color-danger);
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.formal-editor__attachment-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.formal-editor__attachment-upload {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user