✨ 结算单业务模式运输方式与编辑体验优化
预结算/收付款结算支持业务模式与运输方式展示导出;完善结算调整、对账导入与变更记录;组织合同初始流水号未填不再显示-1。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -64,6 +64,20 @@
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
/>
|
||||
<el-select
|
||||
v-else-if="field.type === 'select' && editable"
|
||||
v-model="form[field.prop]"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in formSelectOptions(field)"
|
||||
:key="item.dictKey"
|
||||
:label="item.dictValue"
|
||||
:value="item.dictKey"
|
||||
/>
|
||||
</el-select>
|
||||
<span
|
||||
v-else-if="field.prop === 'formalSettlementNo'"
|
||||
:class="{ 'form-readonly--code': form.formalSettlementNo }"
|
||||
@@ -71,6 +85,9 @@
|
||||
{{ form.formalSettlementNo || (form.id ? '-' : '系统自动生成') }}
|
||||
</span>
|
||||
<span v-else-if="field.money">{{ formatMoney(form[field.prop]) }}</span>
|
||||
<span v-else-if="field.type === 'select'">{{
|
||||
formSelectLabel(field, form[field.prop])
|
||||
}}</span>
|
||||
<span v-else-if="field.type === 'contract'">{{
|
||||
displayValue(form.contractName)
|
||||
}}</span>
|
||||
@@ -424,26 +441,7 @@
|
||||
|
||||
<section-card title="发票信息">
|
||||
<div class="formal-editor__invoice-claim">
|
||||
<el-form inline label-position="right" label-width="auto" @submit.prevent>
|
||||
<el-form-item label="发票号码">
|
||||
<el-input
|
||||
v-model="invoiceClaimNo"
|
||||
clearable
|
||||
maxlength="32"
|
||||
placeholder="请输入发票号码"
|
||||
@keyup.enter="openInvoiceClaimDialog"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="invoiceClaimLoading"
|
||||
@click="openInvoiceClaimDialog"
|
||||
>
|
||||
认领查询
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button type="primary" @click="openInvoiceClaimDialog">认领查询</el-button>
|
||||
</div>
|
||||
<el-table :data="invoices" border>
|
||||
<el-table-column type="index" label="序号" width="64" align="center" />
|
||||
@@ -544,7 +542,6 @@
|
||||
title="查询可认领发票"
|
||||
confirm-text="确认认领"
|
||||
multiple
|
||||
:initial-invoice-no="String(invoiceClaimNo || '').trim()"
|
||||
:query-api="invoicePoolQueryApi"
|
||||
@confirm="handleInvoiceClaimConfirm"
|
||||
/>
|
||||
@@ -697,9 +694,19 @@
|
||||
<el-table-column prop="changeTime" label="变更时间" min-width="170" align="center">
|
||||
<template #default="{ row }">{{ displayValue(row.changeTime) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="openChangeRecordDetail(row)">详情</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section-card>
|
||||
</div>
|
||||
|
||||
<change-record-detail-dialog
|
||||
v-model="changeRecordDetailVisible"
|
||||
:rows="changeRecordDetailRows"
|
||||
/>
|
||||
<template v-if="!pageMode" #footer>
|
||||
<el-button v-if="editable" @click="handleSyncPlaceholder">同步</el-button>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
@@ -1071,6 +1078,7 @@ import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { h } from 'vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { isTierUnitPrice, isUnitPriceAdjustable } from '@/utils/settlement-adjust-rule';
|
||||
import { isApprovalSettlementChange } from '@/utils/settlement-change-record';
|
||||
import { normalizeCurrencyCode } from '@/utils/currency';
|
||||
import {
|
||||
settlementRecordTypeName,
|
||||
@@ -1083,6 +1091,7 @@ import {
|
||||
viewKingdeeInvoiceFile,
|
||||
} from '@/utils/kingdee-attachment';
|
||||
import KingdeeInvoicePoolDialog from '@/components/kingdee-invoice-pool-dialog/main.vue';
|
||||
import ChangeRecordDetailDialog from '@/components/change-record-detail-dialog/main.vue';
|
||||
import ProjectAdvanceWriteOff from './project-advance-write-off.vue';
|
||||
import * as XLSX from 'xlsx';
|
||||
import { isAdministrator } from '@/utils/auth';
|
||||
@@ -1093,7 +1102,12 @@ const LOCAL_CURRENCY_HIDDEN_FIELDS = ['exchangeRateDate', 'exchangeRate', 'local
|
||||
|
||||
export default {
|
||||
name: 'FormalSettlementEditor',
|
||||
components: { InfoFilled, KingdeeInvoicePoolDialog, ProjectAdvanceWriteOff },
|
||||
components: {
|
||||
InfoFilled,
|
||||
KingdeeInvoicePoolDialog,
|
||||
ChangeRecordDetailDialog,
|
||||
ProjectAdvanceWriteOff,
|
||||
},
|
||||
props: {
|
||||
modelValue: Boolean,
|
||||
recordId: [String, Number],
|
||||
@@ -1123,14 +1137,14 @@ export default {
|
||||
receiptClaims: [],
|
||||
adjustments: [],
|
||||
changeRecords: [],
|
||||
changeRecordDetailVisible: false,
|
||||
changeRecordDetailRows: [],
|
||||
projectAdvanceWriteOffs: [],
|
||||
attachments: [],
|
||||
selectedAttachmentRows: [],
|
||||
invoices: [],
|
||||
// 开票申请经金蝶回写的发票结果(只读展示,含板式文件/数电PDF下载地址)
|
||||
issuedInvoices: [],
|
||||
invoiceClaimNo: '',
|
||||
invoiceClaimLoading: false,
|
||||
// 金蝶侧发票附件查看/下载进行中(行组级 loading 守卫)
|
||||
kingdeeAttachmentBusy: false,
|
||||
invoiceClaimDialog: {
|
||||
@@ -1162,6 +1176,7 @@ export default {
|
||||
projects: [],
|
||||
feeOptions: [],
|
||||
feeCategoryOptions: [],
|
||||
businessModelOptions: [],
|
||||
transportTypeOptions: [],
|
||||
fields: formalSettlementFormFields,
|
||||
sourceTableColumns: sourceColumns,
|
||||
@@ -1438,7 +1453,9 @@ export default {
|
||||
this.receiptClaims = this.unwrapData(await getReceiptClaims(id)) || [];
|
||||
}
|
||||
this.adjustments = data.adjustments || [];
|
||||
this.changeRecords = data.changeRecords || [];
|
||||
this.changeRecords = (data.changeRecords || []).filter(
|
||||
row => !isApprovalSettlementChange(row.changeContent)
|
||||
);
|
||||
this.projectAdvanceWriteOffs = (data.projectAdvanceWriteOffs || []).map(row => ({
|
||||
...row,
|
||||
writeOffAmount: Number(row.writeOffAmount || 0),
|
||||
@@ -1476,13 +1493,14 @@ export default {
|
||||
this.receiptClaims = [];
|
||||
this.adjustments = [];
|
||||
this.changeRecords = [];
|
||||
this.changeRecordDetailVisible = false;
|
||||
this.changeRecordDetailRows = [];
|
||||
this.projectAdvanceWriteOffs = [];
|
||||
this.advancePayments = [];
|
||||
this.attachments = [];
|
||||
this.selectedAttachmentRows = [];
|
||||
this.invoices = [];
|
||||
this.issuedInvoices = [];
|
||||
this.invoiceClaimNo = '';
|
||||
this.invoiceClaimDialog.visible = false;
|
||||
this.invoiceClaimDialog.selected = [];
|
||||
this.attachmentUploadFiles = [];
|
||||
@@ -1499,6 +1517,7 @@ export default {
|
||||
this.loadFeeOptions(),
|
||||
this.loadFeeCategoryOptions(),
|
||||
this.loadAttachmentTypeOptions(),
|
||||
this.loadBusinessModelOptions(),
|
||||
this.loadTransportTypeOptions(),
|
||||
]);
|
||||
}
|
||||
@@ -2424,6 +2443,7 @@ export default {
|
||||
row.settlementAmountTax = Number(data.afterAmount || 0);
|
||||
} catch (error) {
|
||||
row.calculateError = error.message || '费用试算失败';
|
||||
this.$message.warning(row.calculateError);
|
||||
} finally {
|
||||
if (version === row.adjustCalculateVersion) row.calculating = false;
|
||||
}
|
||||
@@ -2796,6 +2816,8 @@ export default {
|
||||
sourceDetailId: row.sourcePreSettlementId ? undefined : row.sourceDetailId || row.id,
|
||||
adjustAmount: Number(row.adjustAmount || 0),
|
||||
})),
|
||||
businessModel: this.form.businessModel || undefined,
|
||||
transportType: this.form.transportType || undefined,
|
||||
exchangeRateDate: this.form.exchangeRateDate,
|
||||
exchangeRate: this.form.exchangeRate,
|
||||
summaryFees: this.summaryFees
|
||||
@@ -2886,6 +2908,55 @@ export default {
|
||||
const lineNo = row?.lineNo;
|
||||
return lineNo === -1 || String(lineNo) === '-1' ? '' : this.displayValue(lineNo);
|
||||
},
|
||||
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 {};
|
||||
}
|
||||
},
|
||||
formatChangeRecordValue(value) {
|
||||
if (value === undefined || value === null || value === '') return '空';
|
||||
if (Array.isArray(value)) {
|
||||
if (!value.length) return '空';
|
||||
return value
|
||||
.map(item => {
|
||||
if (!item || typeof item !== 'object') return String(item);
|
||||
return Object.entries(item)
|
||||
.map(([key, itemValue]) => `${key}:${this.formatChangeRecordValue(itemValue)}`)
|
||||
.join(',');
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
if (typeof value === 'object') return JSON.stringify(value);
|
||||
return String(value);
|
||||
},
|
||||
buildChangeRecordDetailRows(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.formatChangeRecordValue(before[field]),
|
||||
after: this.formatChangeRecordValue(after[field]),
|
||||
}));
|
||||
if (row.changeContent) {
|
||||
rows.unshift({ field: '变更内容', before: '空', after: row.changeContent });
|
||||
}
|
||||
if (row.changeReason) {
|
||||
rows.push({ field: '变更原因', before: '空', after: row.changeReason });
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
openChangeRecordDetail(row) {
|
||||
this.changeRecordDetailRows = this.buildChangeRecordDetailRows(row);
|
||||
this.changeRecordDetailVisible = true;
|
||||
},
|
||||
paymentMethodName(value) {
|
||||
const labels = {
|
||||
bank_transfer: '银行转账',
|
||||
@@ -2915,9 +2986,36 @@ export default {
|
||||
formatDetailMileage(value) {
|
||||
return this.readonly && Number(value) === -1 ? '-' : this.displayValue(value);
|
||||
},
|
||||
async loadBusinessModelOptions() {
|
||||
const { data } = await getDictionary({ code: 'business_model' });
|
||||
const records = Array.isArray(data?.data) ? data.data : data?.data?.records || [];
|
||||
this.businessModelOptions = records.map(item => ({
|
||||
dictKey: item.dictKey ?? item.value,
|
||||
dictValue: item.dictValue ?? item.label ?? item.name,
|
||||
}));
|
||||
},
|
||||
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,
|
||||
}));
|
||||
},
|
||||
formSelectOptions(field) {
|
||||
const key = field?.optionsKey;
|
||||
const options = key ? this[key] : [];
|
||||
return Array.isArray(options) ? options : [];
|
||||
},
|
||||
formSelectLabel(field, value) {
|
||||
if (value === undefined || value === null || value === '') return '-';
|
||||
const normalized = String(value).trim();
|
||||
const option = this.formSelectOptions(field).find(
|
||||
item =>
|
||||
String(item.dictKey ?? '').trim() === normalized ||
|
||||
String(item.dictValue ?? '').trim() === normalized
|
||||
);
|
||||
return option?.dictValue || normalized;
|
||||
},
|
||||
transportTypeName(value) {
|
||||
if (value === undefined || value === null || value === '') return '';
|
||||
@@ -3253,21 +3351,9 @@ export default {
|
||||
}
|
||||
.formal-editor__invoice-claim {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.formal-editor__invoice-claim-hint {
|
||||
color: var(--el-color-danger);
|
||||
font-size: 13px;
|
||||
}
|
||||
.formal-editor__invoice-claim :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.formal-editor__invoice-claim :deep(.el-input) {
|
||||
width: 360px;
|
||||
}
|
||||
.formal-editor__issued-invoices {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user