调整收付款问题

This commit is contained in:
2026-08-31 12:40:35 +08:00
parent 2451efdfcb
commit dea760ea1c
12 changed files with 544 additions and 164 deletions
@@ -51,9 +51,9 @@
<vehicle-attachment-upload <vehicle-attachment-upload
:model-value="rows" :model-value="rows"
:file-types="attachmentFileTypes" :file-types="attachmentFileTypes"
:max-size="500" :max-size="maxSize"
:show-tip="true" :show-tip="true"
tip="支持pdfbmpjpegpngjpgdocdocxpptpptxxlsxxlsemlmsgzip的文件格式单个文件不超过500M" :tip="`支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip的文件格式单个文件不超过${maxSize}MB`"
:show-file-list="false" :show-file-list="false"
button-text="上传附件" button-text="上传附件"
@update:model-value="handleUploadChange" @update:model-value="handleUploadChange"
@@ -149,6 +149,10 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
maxSize: {
type: Number,
default: 500,
},
}, },
emits: ['update:modelValue'], emits: ['update:modelValue'],
data() { data() {
+1 -1
View File
@@ -1,5 +1,5 @@
export const receiptFlowTableColumns = [ export const receiptFlowTableColumns = [
{ prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150 }, { prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150, link: true },
{ prop: 'payerName', label: '付款人', minWidth: 130 }, { prop: 'payerName', label: '付款人', minWidth: 130 },
{ prop: 'receiptAmount', label: '付款金额', minWidth: 130, money: true }, { prop: 'receiptAmount', label: '付款金额', minWidth: 130, money: true },
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 }, { prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
+12 -2
View File
@@ -10,8 +10,18 @@ export const preSettlementTableColumns = [
{ label: '原币结算金额', prop: 'settlementAmount', minWidth: 140, money: true, precision: 2 }, { label: '原币结算金额', prop: 'settlementAmount', minWidth: 140, money: true, precision: 2 },
{ label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 150, money: true, precision: 2 }, { label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 150, money: true, precision: 2 },
{ label: '结算汇率', prop: 'exchangeRate', minWidth: 110, precision: 2 }, { label: '结算汇率', prop: 'exchangeRate', minWidth: 110, precision: 2 },
{ label: '申请预付金额', prop: 'advanceAppliedAmount', minWidth: 140, money: true }, {
{ label: '已付款金额', prop: 'advancePaidAmount', minWidth: 130, money: true }, label: '申请预付金额(审核中的)',
prop: 'advanceAppliedAmount',
minWidth: 190,
money: true,
},
{
label: '已付款金额(审核通过的)',
prop: 'advancePaidAmount',
minWidth: 200,
money: true,
},
{ label: '审核状态', prop: 'approvalStatusName', minWidth: 110, status: true }, { label: '审核状态', prop: 'approvalStatusName', minWidth: 110, status: true },
{ label: '当前节点', prop: 'currentNode', minWidth: 130 }, { label: '当前节点', prop: 'currentNode', minWidth: 130 },
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 130 }, { label: '当前处理人', prop: 'currentProcessor', minWidth: 130 },
+1 -1
View File
@@ -75,7 +75,7 @@
</section-card> </section-card>
<section-card title="附件信息"> <section-card title="附件信息">
<vehicle-attachment-table v-model="form.attachments" :readonly="readonly" /> <vehicle-attachment-table v-model="form.attachments" :readonly="readonly" :max-size="10" />
</section-card> </section-card>
<div class="bill-payment-form-page__actions"> <div class="bill-payment-form-page__actions">
+13
View File
@@ -15,6 +15,8 @@
@edit="openEdit" @edit="openEdit"
@delete="handleDelete" @delete="handleDelete"
@flow="openFlow" @flow="openFlow"
@approve="handleApprove"
@return="handleReturn"
@void="handleVoid" @void="handleVoid"
@page-change="handlePageChange" @page-change="handlePageChange"
@size-change="handleSizeChange" @size-change="handleSizeChange"
@@ -126,6 +128,17 @@ export default {
this.flowDialog.row = row; this.flowDialog.row = row;
this.flowDialog.visible = true; this.flowDialog.visible = true;
}, },
async handleApprove(row) {
await api.approve({ id: row.id });
this.$message.success('审批通过');
this.loadTable();
},
async handleReturn(row) {
const { value } = await this.$prompt('请输入驳回原因', '审批驳回');
await api.returnBill({ id: row.id, reason: value });
this.$message.success('已驳回');
this.loadTable();
},
async handleVoid(row) { async handleVoid(row) {
const { value } = await this.$prompt('请输入作废原因', '作废汇票付款'); const { value } = await this.$prompt('请输入作废原因', '作废汇票付款');
await api.voidBill({ id: row.id, reason: value }); await api.voidBill({ id: row.id, reason: value });
@@ -22,7 +22,7 @@
<span v-else>{{ displayValue(row[column.prop]) }}</span> <span v-else>{{ displayValue(row[column.prop]) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="220" fixed="right" align="center"> <el-table-column label="操作" width="320" fixed="right" align="center">
<template #default="{ row }"> <template #default="{ row }">
<div class="bill-payment-table__links"> <div class="bill-payment-table__links">
<el-link <el-link
@@ -55,6 +55,18 @@
@click="$emit('flow', row)" @click="$emit('flow', row)"
>流程</el-link >流程</el-link
> >
<el-link
v-if="row.approvalStatus === 'reviewing' && hasPermission('bill_payment_approve')"
type="primary"
@click="$emit('approve', row)"
>通过</el-link
>
<el-link
v-if="row.approvalStatus === 'reviewing' && hasPermission('bill_payment_approve')"
type="danger"
@click="$emit('return', row)"
>驳回</el-link
>
<el-link <el-link
v-if="row.approvalStatus === 'approved' && hasPermission('bill_payment_void')" v-if="row.approvalStatus === 'approved' && hasPermission('bill_payment_void')"
type="danger" type="danger"
@@ -90,7 +102,18 @@ export default {
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
page: { type: Object, required: true }, page: { type: Object, required: true },
}, },
emits: ['add', 'view', 'edit', 'delete', 'flow', 'void', 'page-change', 'size-change'], emits: [
'add',
'view',
'edit',
'delete',
'flow',
'approve',
'return',
'void',
'page-change',
'size-change',
],
data() { data() {
return { columns: billPaymentTableColumns }; return { columns: billPaymentTableColumns };
}, },
+77 -29
View File
@@ -188,7 +188,10 @@
</el-row> </el-row>
</section-card> </section-card>
<section-card title="开票内容"><template #extra><el-button v-if="!readonly" type="primary" @click="addSheet">添加</el-button></template> <section-card title="开票内容"
><template #extra
><el-button v-if="!readonly" type="primary" @click="addSheet">添加</el-button></template
>
<div v-for="(sheet, sheetIndex) in form.sheets" :key="sheet.localId" class="invoice-sheet"> <div v-for="(sheet, sheetIndex) in form.sheets" :key="sheet.localId" class="invoice-sheet">
<div class="invoice-sheet__header"> <div class="invoice-sheet__header">
<span>第{{ sheetIndex + 1 }}张</span> <span>第{{ sheetIndex + 1 }}张</span>
@@ -247,17 +250,6 @@
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="不含税单价" min-width="130">
<template #default="{ row }">
<el-input-number
v-model="row.unitPriceNoTax"
:disabled="readonly"
:min="0"
:precision="2"
:controls="false"
/>
</template>
</el-table-column>
<el-table-column label="含税金额" min-width="130"> <el-table-column label="含税金额" min-width="130">
<template #default="{ row }"> <template #default="{ row }">
<el-input-number <el-input-number
@@ -362,7 +354,11 @@
show-overflow-tooltip show-overflow-tooltip
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link v-if="column.link && row[column.prop]" type="primary"> <el-link
v-if="column.link && row[column.prop]"
type="primary"
@click.stop="handleDetailLink(row, column)"
>
{{ row[column.prop] }} {{ row[column.prop] }}
</el-link> </el-link>
<span <span
@@ -371,9 +367,13 @@
Number(row[column.prop]) === -1 Number(row[column.prop]) === -1
" "
></span> ></span>
<span v-else-if="column.feeItemKeys">{{ formatMoney(getFeeItemValue(row, column.feeItemKeys)) }}</span> <span v-else-if="column.feeItemKeys">{{
formatMoney(getFeeItemValue(row, column.feeItemKeys))
}}</span>
<span v-else-if="column.money">{{ formatMoney(row[column.prop]) }}</span> <span v-else-if="column.money">{{ formatMoney(row[column.prop]) }}</span>
<span v-else-if="column.prop === 'transportType'">{{ transportTypeLabel(row.transportType) }}</span> <span v-else-if="column.prop === 'transportType'">{{
transportTypeLabel(row.transportType)
}}</span>
<span v-else>{{ displayValue(row[column.prop]) }}</span> <span v-else>{{ displayValue(row[column.prop]) }}</span>
</template> </template>
</el-table-column> </el-table-column>
@@ -400,17 +400,15 @@
<div class="invoice-form-page__actions"> <div class="invoice-form-page__actions">
<el-button @click="goBack">取消</el-button> <el-button @click="goBack">取消</el-button>
<el-button v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button> <el-button v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button>
<el-button <el-button v-if="!readonly && canSave" type="primary" plain @click="saveDraft"
v-if="!readonly && canSave" >保存</el-button
type="primary" >
plain
@click="saveDraft"
>保存</el-button>
<el-button <el-button
v-if="!readonly && canSave && hasPermission('invoice_application_submit')" v-if="!readonly && canSave && hasPermission('invoice_application_submit')"
type="primary" type="primary"
@click="submitForm" @click="submitForm"
>提交</el-button> >提交</el-button
>
</div> </div>
</el-form> </el-form>
@@ -468,6 +466,8 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import * as api from '@/api/payment/invoiceApplication'; import * as api from '@/api/payment/invoiceApplication';
import { getAll as getInvoiceItems } from '@/api/base/invoice-item'; import { getAll as getInvoiceItems } from '@/api/base/invoice-item';
import { getList as getWaybillList } from '@/api/business/waybill-manage';
import { getList as getReceivablePayableDetailList } from '@/api/settlement/receivable-payable-detail';
import { getDictionary } from '@/api/system/dictbiz'; import { getDictionary } from '@/api/system/dictbiz';
import { invoiceApplicationDetailColumns } from '@/option/payment/invoiceApplication'; import { invoiceApplicationDetailColumns } from '@/option/payment/invoiceApplication';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue'; import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
@@ -662,7 +662,8 @@ export default {
if (this.settlementIds.length) { if (this.settlementIds.length) {
await Promise.all([this.loadReceiverInformation(), this.loadSettlementDetails(false)]); await Promise.all([this.loadReceiverInformation(), this.loadSettlementDetails(false)]);
} }
if (this.readonly) this.$nextTick(() => this.$refs.formRef?.clearValidate('departmentEmails')); if (this.readonly)
this.$nextTick(() => this.$refs.formRef?.clearValidate('departmentEmails'));
this.$nextTick(this.restoreDetailSelection); this.$nextTick(this.restoreDetailSelection);
}, },
async loadInvoiceItems() { async loadInvoiceItems() {
@@ -683,8 +684,7 @@ export default {
transportTypeLabel(value) { transportTypeLabel(value) {
if (!value) return '-'; if (!value) return '-';
return ( return (
this.transportTypeOptions.find(item => String(item.value) === String(value))?.label || this.transportTypeOptions.find(item => String(item.value) === String(value))?.label || value
value
); );
}, },
invoiceItemNames(categoryName) { invoiceItemNames(categoryName) {
@@ -840,7 +840,7 @@ export default {
...item, ...item,
formalSettlementId: item.id, formalSettlementId: item.id,
settlementId: item.id, settlementId: item.id,
allocatedInvoiceAmount: 0, allocatedInvoiceAmount: rows.length === 1 ? Number(item.availableInvoiceAmount || 0) : 0,
})); }));
this.form.projectName = first.projectName; this.form.projectName = first.projectName;
this.form.deptName = first.deptName; this.form.deptName = first.deptName;
@@ -906,9 +906,7 @@ export default {
const invoiceInfoEmails = [ const invoiceInfoEmails = [
...this.receiverInvoiceOptions.flatMap(item => this.parseEmails(item.email)), ...this.receiverInvoiceOptions.flatMap(item => this.parseEmails(item.email)),
]; ];
this.departmentEmailOptions = invoiceInfoEmails this.departmentEmailOptions = invoiceInfoEmails.filter(Boolean).reduce((emails, email) => {
.filter(Boolean)
.reduce((emails, email) => {
if (!emails.some(item => item.toLowerCase() === email.toLowerCase())) emails.push(email); if (!emails.some(item => item.toLowerCase() === email.toLowerCase())) emails.push(email);
return emails; return emails;
}, []); }, []);
@@ -962,6 +960,56 @@ export default {
if (this.readonly) return; if (this.readonly) return;
this.selectedDetailIds = rows.map(item => item.formalSettlementDetailId || item.id); this.selectedDetailIds = rows.map(item => item.formalSettlementDetailId || item.id);
}, },
handleDetailLink(row, column) {
if (column.prop === 'documentNo') {
this.openPayableDetail(row);
return;
}
if (column.prop === 'waybillNo') this.openWaybillDetail(row);
},
async openPayableDetail(row) {
let detailId = row.sourceDetailId || '';
if (!detailId && row.documentNo) {
try {
const data = this.unwrapData(
await getReceivablePayableDetailList(1, 1, {
documentNo: row.documentNo,
settlementType: 'payable',
})
);
detailId = (Array.isArray(data) ? data : data?.records || [])[0]?.id || '';
} catch {
detailId = '';
}
}
if (!detailId) {
this.$message.info('当前记录未找到对应的应付明细');
return;
}
this.$router.push({
path: '/settlement/payable-detail',
query: { detailId },
});
},
async openWaybillDetail(row) {
let waybillId = row.waybillId || '';
if (!waybillId && row.waybillNo) {
try {
const data = this.unwrapData(await getWaybillList(1, 1, { waybillNo: row.waybillNo }));
waybillId = (Array.isArray(data) ? data : data?.records || [])[0]?.id || '';
} catch {
waybillId = '';
}
}
if (!waybillId) {
this.$message.info('当前记录未找到对应的运单详情');
return;
}
this.$router.push({
path: '/business/waybill-manage',
query: { detailId: waybillId },
});
},
restoreDetailSelection() { restoreDetailSelection() {
if (this.readonly || !this.$refs.detailTable) return; if (this.readonly || !this.$refs.detailTable) return;
const selected = new Set(this.selectedDetailIds.map(String)); const selected = new Set(this.selectedDetailIds.map(String));
+127 -76
View File
@@ -163,6 +163,7 @@
v-loading="invoiceDialog.loading" v-loading="invoiceDialog.loading"
:data="invoiceDialog.rows" :data="invoiceDialog.rows"
border border
empty-text="暂无票据数据"
highlight-current-row highlight-current-row
@current-change="invoiceDialog.current = $event" @current-change="invoiceDialog.current = $event"
@row-dblclick="confirmInvoice" @row-dblclick="confirmInvoice"
@@ -188,6 +189,17 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="receipt-form-page__dialog-pagination">
<el-pagination
v-model:current-page="invoiceDialog.page.current"
v-model:page-size="invoiceDialog.page.size"
:total="invoiceDialog.page.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="refreshInvoicePoolPage"
@size-change="handleInvoicePoolSizeChange"
/>
</div>
<template #footer> <template #footer>
<el-button @click="invoiceDialog.visible = false">取消</el-button> <el-button @click="invoiceDialog.visible = false">取消</el-button>
<el-button type="primary" @click="confirmInvoice()">确定</el-button> <el-button type="primary" @click="confirmInvoice()">确定</el-button>
@@ -247,67 +259,12 @@
import { Search } from '@element-plus/icons-vue'; import { Search } from '@element-plus/icons-vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import * as api from '@/api/payment/invoiceReceipt'; import * as api from '@/api/payment/invoiceReceipt';
import { getList as getCustomerList } from '@/api/vehicle/customer-archive';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue'; import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
const invoicePoolMockTemplates = [ const mockInvoiceTypes = ['增值税专用发票', '增值税普通发票'];
{ const mockTaxRates = [3, 6, 9, 13];
id: 90000001, const mockBankNames = ['中国工商银行', '中国农业银行', '中国银行', '中国建设银行', '招商银行'];
invoiceNo: '25312000000000000101',
invoiceDate: '2026-08-25',
invoiceType: '增值税专用发票',
taxRate: 9,
invoiceAmount: 109000,
taxAmount: 9000,
receiverName: '华东供应链管理有限公司',
issuerName: '上海安捷运输有限公司',
bankName: '中国工商银行上海分行',
bankAccount: '1001000100000000019',
issuingBank: '中国工商银行上海分行营业部',
phone: '021-66880001',
customerEmails: 'finance@huadong.example.com',
departmentEmails: 'transport@huadong.example.com',
attachmentsJson: '[]',
kingdeeBillNo: 'KD-FP-20260825001',
},
{
id: 90000002,
invoiceNo: '25312000000000000102',
invoiceDate: '2026-08-26',
invoiceType: '增值税普通发票',
taxRate: 6,
invoiceAmount: 53000,
taxAmount: 3000,
receiverName: '华东供应链管理有限公司',
issuerName: '江苏联运物流有限公司',
bankName: '中国建设银行南京分行',
bankAccount: '3201000100000000026',
issuingBank: '中国建设银行南京城南支行',
phone: '025-66880002',
customerEmails: 'finance@huadong.example.com',
departmentEmails: 'logistics@huadong.example.com',
attachmentsJson: '[]',
kingdeeBillNo: 'KD-FP-20260826002',
},
{
id: 90000003,
invoiceNo: '25312000000000000103',
invoiceDate: '2026-08-27',
invoiceType: '增值税专用发票',
taxRate: 3,
invoiceAmount: 20600,
taxAmount: 600,
receiverName: '华东供应链管理有限公司',
issuerName: '浙江通达物流有限公司',
bankName: '招商银行杭州分行',
bankAccount: '5719000100000000033',
issuingBank: '招商银行杭州高新支行',
phone: '0571-66880003',
customerEmails: 'finance@huadong.example.com',
departmentEmails: 'settlement@huadong.example.com',
attachmentsJson: '[]',
kingdeeBillNo: 'KD-FP-20260827003',
},
];
const randomDigits = length => const randomDigits = length =>
Array.from({ length }, () => Math.floor(Math.random() * 10)).join(''); Array.from({ length }, () => Math.floor(Math.random() * 10)).join('');
@@ -319,28 +276,59 @@ const formatMockDate = date => {
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
}; };
const createInvoicePoolMockRows = () => const customerName = customer =>
invoicePoolMockTemplates.map((template, index) => { customer.fullName || customer.shortName || customer.customerCode || `客商${customer.id}`;
const customerEmail = (customer, index) => {
const prefix = String(customer.customerCode || customer.id || `customer${index + 1}`)
.replace(/[^a-zA-Z0-9_-]/g, '')
.toLowerCase();
return `finance@${prefix || `customer${index + 1}`}.example.com`;
};
const createInvoicePoolMockRows = (customers, counterpartyName, departmentEmail) => {
const rows = [];
const baseId = Date.now();
customers.forEach((customer, customerIndex) => {
const name = customerName(customer);
['issuer', 'receiver'].forEach((role, roleIndex) => {
const count = 3 + Math.floor(Math.random() * 5);
for (let index = 0; index < count; index += 1) {
const rowIndex = rows.length;
const invoiceDateValue = new Date(); const invoiceDateValue = new Date();
invoiceDateValue.setDate(invoiceDateValue.getDate() - Math.floor(Math.random() * 15)); invoiceDateValue.setDate(invoiceDateValue.getDate() - Math.floor(Math.random() * 90));
const invoiceDate = formatMockDate(invoiceDateValue); const invoiceDate = formatMockDate(invoiceDateValue);
const taxRate = mockTaxRates[(customerIndex + roleIndex + index) % mockTaxRates.length];
const invoiceAmount = Math.floor(10000 + Math.random() * 190000); const invoiceAmount = Math.floor(10000 + Math.random() * 190000);
const taxAmount = Number( const taxAmount = Number(
( ((invoiceAmount * Number(taxRate)) / (100 + Number(taxRate))).toFixed(2)
(invoiceAmount * Number(template.taxRate || 0)) /
(100 + Number(template.taxRate || 0))
).toFixed(2)
); );
return { const bankName = mockBankNames[(customerIndex + index) % mockBankNames.length];
...template, rows.push({
id: Date.now() + index * 100 + Math.floor(Math.random() * 100), id: baseId + rowIndex,
invoiceNo: `25${randomDigits(18)}`, invoiceNo: `25${randomDigits(18)}`,
invoiceDate, invoiceDate,
invoiceType: mockInvoiceTypes[(customerIndex + index) % mockInvoiceTypes.length],
taxRate,
invoiceAmount, invoiceAmount,
taxAmount, taxAmount,
kingdeeBillNo: `KD-FP-${invoiceDate.replaceAll('-', '')}${randomDigits(3)}`, receiverName: role === 'receiver' ? name : counterpartyName,
}; issuerName: role === 'issuer' ? name : counterpartyName,
bankName,
bankAccount: randomDigits(19),
issuingBank: `${bankName}营业部`,
phone: customer.contactPhone || '',
customerEmails: customerEmail(customer, customerIndex),
departmentEmails: departmentEmail || '',
attachmentsJson: '[]',
kingdeeBillNo: `KD-FP-${invoiceDate.replaceAll('-', '')}${randomDigits(5)}`,
kingdeeStatus: 'unsynced',
}); });
}
});
});
return rows;
};
const emptyForm = () => ({ const emptyForm = () => ({
id: null, id: null,
@@ -380,9 +368,18 @@ export default {
Search, Search,
form: emptyForm(), form: emptyForm(),
invoicePoolMockRows: [], invoicePoolMockRows: [],
invoicePoolMockLoaded: false,
customerEmailOptions: [], customerEmailOptions: [],
departmentEmailOptions: [], departmentEmailOptions: [],
invoiceDialog: { visible: false, loading: false, keyword: '', rows: [], current: null }, invoiceDialog: {
visible: false,
loading: false,
keyword: '',
sourceRows: [],
rows: [],
current: null,
page: { current: 1, size: 10, total: 0 },
},
settlementDialog: { settlementDialog: {
visible: false, visible: false,
loading: false, loading: false,
@@ -447,7 +444,6 @@ export default {
.filter(Boolean); .filter(Boolean);
}, },
async initialize() { async initialize() {
this.invoicePoolMockRows = createInvoicePoolMockRows();
const userInfo = this.$store.getters.userInfo || {}; const userInfo = this.$store.getters.userInfo || {};
const userEmail = userInfo.email || ''; const userEmail = userInfo.email || '';
this.departmentEmailOptions = userEmail ? [userEmail] : []; this.departmentEmailOptions = userEmail ? [userEmail] : [];
@@ -499,22 +495,72 @@ export default {
async openInvoiceDialog() { async openInvoiceDialog() {
this.invoiceDialog.visible = true; this.invoiceDialog.visible = true;
this.invoiceDialog.keyword = this.form.invoiceNo || ''; this.invoiceDialog.keyword = this.form.invoiceNo || '';
if (!this.recordId) this.invoicePoolMockRows = createInvoicePoolMockRows();
await this.loadInvoicePool(); await this.loadInvoicePool();
}, },
async loadInvoicePool() { async loadInvoicePool() {
this.invoiceDialog.loading = true; this.invoiceDialog.loading = true;
this.invoiceDialog.page.current = 1;
this.invoiceDialog.current = null;
try { try {
if (!this.recordId) { if (!this.recordId) {
this.invoiceDialog.rows = this.filterInvoicePoolMockRows(this.invoiceDialog.keyword); if (!this.invoicePoolMockLoaded) await this.loadInvoicePoolMockRows();
this.invoiceDialog.sourceRows = this.filterInvoicePoolMockRows(
this.invoiceDialog.keyword
);
this.refreshInvoicePoolPage();
return; return;
} }
const data = this.unwrapData(await api.getInvoicePool(this.invoiceDialog.keyword)); const data = this.unwrapData(await api.getInvoicePool(this.invoiceDialog.keyword));
this.invoiceDialog.rows = Array.isArray(data) ? data : data?.records || []; this.invoiceDialog.sourceRows = Array.isArray(data) ? data : data?.records || [];
this.refreshInvoicePoolPage();
} finally { } finally {
this.invoiceDialog.loading = false; this.invoiceDialog.loading = false;
} }
}, },
async loadInvoicePoolMockRows() {
const pageSize = 500;
const firstData = this.unwrapData(await getCustomerList(1, pageSize, {}));
const firstRows = Array.isArray(firstData) ? firstData : firstData?.records || [];
const total = Number(firstData?.total || firstRows.length);
const pageCount = Math.ceil(total / pageSize);
const remainingPages = await Promise.all(
Array.from({ length: Math.max(pageCount - 1, 0) }, (_, index) =>
getCustomerList(index + 2, pageSize, {})
)
);
const customers = [
...firstRows,
...remainingPages.flatMap(response => {
const data = this.unwrapData(response);
return Array.isArray(data) ? data : data?.records || [];
}),
].filter(
(customer, index, rows) =>
rows.findIndex(item => String(item.id) === String(customer.id)) === index
);
const userInfo = this.$store.getters.userInfo || {};
const counterpartyName = userInfo.deptName || userInfo.dept_name || '本企业';
this.invoicePoolMockRows = createInvoicePoolMockRows(
customers,
counterpartyName,
userInfo.email || ''
);
this.invoicePoolMockLoaded = true;
},
refreshInvoicePoolPage() {
const page = this.invoiceDialog.page;
const total = this.invoiceDialog.sourceRows.length;
const maxPage = Math.max(Math.ceil(total / page.size), 1);
if (page.current > maxPage) page.current = maxPage;
const start = (page.current - 1) * page.size;
page.total = total;
this.invoiceDialog.current = null;
this.invoiceDialog.rows = this.invoiceDialog.sourceRows.slice(start, start + page.size);
},
handleInvoicePoolSizeChange() {
this.invoiceDialog.page.current = 1;
this.refreshInvoicePoolPage();
},
filterInvoicePoolMockRows(keyword) { filterInvoicePoolMockRows(keyword) {
const normalizedKeyword = String(keyword || '') const normalizedKeyword = String(keyword || '')
.trim() .trim()
@@ -781,6 +827,11 @@ export default {
.receipt-form-page__dialog-search .el-input { .receipt-form-page__dialog-search .el-input {
width: 360px; width: 360px;
} }
.receipt-form-page__dialog-pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
.receipt-form-page :deep(.el-table) { .receipt-form-page :deep(.el-table) {
--el-table-border-color: #eff1f7; --el-table-border-color: #eff1f7;
} }
+134 -31
View File
@@ -238,9 +238,19 @@
<el-table-column label="匹配金额(含税)" min-width="150"> <el-table-column label="匹配金额(含税)" min-width="150">
<template #default="{ row }">{{ formatMoney(row.matchedAmount) }}</template> <template #default="{ row }">{{ formatMoney(row.matchedAmount) }}</template>
</el-table-column> </el-table-column>
<el-table-column v-if="!readonly" label="操作" width="100"> <el-table-column label="操作" width="220" fixed="right" align="center">
<template #default="{ $index }"> <template #default="{ row, $index }">
<el-link type="danger" @click="form.invoices.splice($index, 1)">删除</el-link> <div class="payment-form-page__invoice-actions">
<el-link type="primary" @click="viewInvoiceAttachment(row)">查看</el-link>
<el-link type="primary" @click="downloadInvoiceAttachment(row)">下载</el-link>
<el-link
v-if="!readonly"
type="danger"
@click="form.invoices.splice($index, 1)"
>
删除
</el-link>
</div>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -333,7 +343,7 @@
> >
<div class="payment-form-page__attachment-upload"> <div class="payment-form-page__attachment-upload">
<vehicle-attachment-upload <vehicle-attachment-upload
v-model="form.attachments" :model-value="form.attachments"
:readonly="readonly" :readonly="readonly"
:multiple="true" :multiple="true"
:limit="20" :limit="20"
@@ -341,7 +351,7 @@
:file-types="attachmentFileTypes" :file-types="attachmentFileTypes"
:show-file-list="false" :show-file-list="false"
button-text="上传附件" button-text="上传附件"
@change="normalizeAttachments" @update:model-value="normalizeAttachments"
@success="handleManualAttachmentUpload" @success="handleManualAttachmentUpload"
/> />
</div> </div>
@@ -598,7 +608,7 @@ const emptyForm = () => ({
settlementAmount: 0, settlementAmount: 0,
payableAmount: 0, payableAmount: 0,
billType: '', billType: '',
paymentRatio: 50, paymentRatio: null,
appliedAmount: 0, appliedAmount: 0,
paymentMethod: 'bank_transfer', paymentMethod: 'bank_transfer',
billLedgerId: null, billLedgerId: null,
@@ -661,6 +671,8 @@ export default {
receiptAccountLoading: false, receiptAccountLoading: false,
firstContractPayment: false, firstContractPayment: false,
contractSignatureFileAvailable: false, contractSignatureFileAvailable: false,
contractPaymentRatioLimit: null,
contractPaymentRatioExceeded: false,
payeeCustomerLevel: '', payeeCustomerLevel: '',
attachmentRuleLoading: false, attachmentRuleLoading: false,
attachmentImagePreviewVisible: false, attachmentImagePreviewVisible: false,
@@ -794,6 +806,7 @@ export default {
} }
}, },
'form.paymentRatio'(value) { 'form.paymentRatio'(value) {
this.checkContractPaymentRatio(value);
if (this.amountSyncing || !this.paymentAmountBase) return; if (this.amountSyncing || !this.paymentAmountBase) return;
this.amountSyncing = true; this.amountSyncing = true;
this.form.appliedAmount = Number( this.form.appliedAmount = Number(
@@ -1013,7 +1026,8 @@ export default {
); );
}, },
isValidReferenceId(id) { isValidReferenceId(id) {
return id !== null && id !== undefined && String(id).trim() !== '-1'; const value = String(id ?? '').trim();
return value !== '' && value !== '-1' && value !== '0';
}, },
async loadTransferredPreSettlements() { async loadTransferredPreSettlements() {
const fallbackRows = this.transferPayload?.sourcePreSettlements || []; const fallbackRows = this.transferPayload?.sourcePreSettlements || [];
@@ -1246,6 +1260,44 @@ export default {
return []; return [];
} }
}, },
invoiceAttachment(row = {}) {
const value = row.attachmentJson;
if (!value) return {};
if (typeof value === 'object') return Array.isArray(value) ? value[0] || {} : value;
try {
const parsed = JSON.parse(value);
return Array.isArray(parsed) ? parsed[0] || {} : parsed || {};
} catch {
return {};
}
},
invoiceAttachmentUrl(row) {
return this.attachmentFileUrl(this.invoiceAttachment(row));
},
invoiceAttachmentName(row) {
return (
this.attachmentFileName(this.invoiceAttachment(row)) || `${row.invoiceNo || '发票'}.pdf`
);
},
viewInvoiceAttachment(row) {
const attachment = this.invoiceAttachment(row);
if (!this.attachmentFileUrl(attachment)) {
this.$message.warning('当前发票暂无可查看附件');
return;
}
this.previewAttachment(
{ ...attachment, name: this.invoiceAttachmentName(row) },
[attachment]
);
},
downloadInvoiceAttachment(row) {
const url = this.invoiceAttachmentUrl(row);
if (!url) {
this.$message.warning('当前发票暂无可下载附件');
return;
}
downloadFileByUrl(url, this.invoiceAttachmentName(row));
},
attachmentFileName(file) { attachmentFileName(file) {
return String(file?.originalName || file?.name || file?.fileName || '').trim(); return String(file?.originalName || file?.name || file?.fileName || '').trim();
}, },
@@ -1282,14 +1334,14 @@ export default {
this.attachmentFileExtension(file) === 'pdf' this.attachmentFileExtension(file) === 'pdf'
); );
}, },
previewAttachment(file) { previewAttachment(file, files = this.form.attachments) {
const url = this.attachmentFileUrl(file); const url = this.attachmentFileUrl(file);
if (!url) { if (!url) {
this.$message.warning('附件地址为空,无法预览'); this.$message.warning('附件地址为空,无法预览');
return; return;
} }
if (this.isAttachmentImage(file)) { if (this.isAttachmentImage(file)) {
this.attachmentImagePreviewUrls = (this.form.attachments || []) this.attachmentImagePreviewUrls = (files || [])
.filter(item => this.isAttachmentImage(item) && this.attachmentFileUrl(item)) .filter(item => this.isAttachmentImage(item) && this.attachmentFileUrl(item))
.map(item => this.attachmentFileUrl(item)); .map(item => this.attachmentFileUrl(item));
this.attachmentImagePreviewIndex = Math.max( this.attachmentImagePreviewIndex = Math.max(
@@ -1384,22 +1436,29 @@ export default {
if (imported.length) this.form.attachments = [...this.form.attachments, ...imported]; if (imported.length) this.form.attachments = [...this.form.attachments, ...imported];
}, },
async loadCurrentSettlementDetails() { async loadCurrentSettlementDetails() {
if (this.form.paymentType === 'project_advance') return []; if (
const requests = []; this.form.paymentType === 'progress_advance' &&
if (this.isValidReferenceId(this.form.preSettlementId)) { this.isValidReferenceId(this.form.preSettlementId)
requests.push(preApi.getDetail(this.form.preSettlementId)); ) {
const response = await preApi.getDetail(this.form.preSettlementId);
const detail = this.unwrapData(response);
return detail?.id ? [detail] : [];
} }
if (this.isValidReferenceId(this.form.settlementId)) { if (
requests.push(formalApi.getDetail(this.form.settlementId)); this.form.paymentType === 'settlement_payment' &&
this.isValidReferenceId(this.form.settlementId)
) {
const response = await formalApi.getDetail(this.form.settlementId);
const detail = this.unwrapData(response);
return detail?.id ? [detail] : [];
} }
if (!requests.length) return []; return [];
const responses = await Promise.all(requests);
return responses.map(response => this.unwrapData(response)).filter(item => item?.id);
}, },
async loadAttachmentRuleData(settlementRows = []) { async loadAttachmentRuleData(settlementRows = []) {
this.attachmentRuleLoading = true; this.attachmentRuleLoading = true;
this.firstContractPayment = false; this.firstContractPayment = false;
this.contractSignatureFileAvailable = false; this.contractSignatureFileAvailable = false;
this.resetContractPaymentRatioLimit();
try { try {
const settlementMaterials = [ const settlementMaterials = [
ATTACHMENT_MATERIALS.weighingSlip, ATTACHMENT_MATERIALS.weighingSlip,
@@ -1417,6 +1476,7 @@ export default {
const contractResponse = await getContractDetail(this.form.contractId); const contractResponse = await getContractDetail(this.form.contractId);
const contract = this.unwrapData(contractResponse) || {}; const contract = this.unwrapData(contractResponse) || {};
if (this.form.paymentType === 'project_advance') { if (this.form.paymentType === 'project_advance') {
this.applyContractPaymentRatioLimit(contract);
const contractFiles = this.parse(contract.contractFileJson); const contractFiles = this.parse(contract.contractFileJson);
this.contractSignatureFileAvailable = contractFiles.some(file => this.contractSignatureFileAvailable = contractFiles.some(file =>
Boolean(this.attachmentFileUrl(file)) Boolean(this.attachmentFileUrl(file))
@@ -1453,6 +1513,41 @@ export default {
this.attachmentRuleLoading = false; this.attachmentRuleLoading = false;
} }
}, },
resetContractPaymentRatioLimit() {
this.contractPaymentRatioLimit = null;
this.contractPaymentRatioExceeded = false;
},
applyContractPaymentRatioLimit(contract = {}) {
const [firstRatio] = this.parse(contract.paymentRatioJson);
const ratioLimitValue = firstRatio?.ratioLimit;
const ratioLimit = Number(ratioLimitValue);
this.contractPaymentRatioLimit =
ratioLimitValue === null ||
ratioLimitValue === undefined ||
String(ratioLimitValue).trim() === '' ||
!Number.isFinite(ratioLimit)
? null
: ratioLimit;
this.checkContractPaymentRatio(this.form.paymentRatio);
},
checkContractPaymentRatio(value) {
const paymentRatio = Number(value);
const hasPaymentRatio =
value !== null &&
value !== undefined &&
String(value).trim() !== '' &&
Number.isFinite(paymentRatio);
const exceeded =
this.form.paymentType === 'project_advance' &&
Boolean(this.form.contractId) &&
this.contractPaymentRatioLimit !== null &&
hasPaymentRatio &&
paymentRatio > this.contractPaymentRatioLimit;
if (exceeded && !this.contractPaymentRatioExceeded) {
this.$message.warning('已超合同配置比例');
}
this.contractPaymentRatioExceeded = exceeded;
},
validateRequiredAttachments() { validateRequiredAttachments() {
if (!this.missingAttachmentMaterials.length) return true; if (!this.missingAttachmentMaterials.length) return true;
this.$message.warning( this.$message.warning(
@@ -1949,20 +2044,22 @@ export default {
this.referenceVisible = false; this.referenceVisible = false;
}, },
normalizeAttachments(files) { normalizeAttachments(files) {
this.form.attachments = (files || []).map(file => ({ const existingAttachments = this.form.attachments || [];
this.form.attachments = (files || []).map(file => {
const fileUrl = this.attachmentFileUrl(file);
const existingFile = existingAttachments.find(item => {
const sameUid = file.uid && item.uid && String(file.uid) === String(item.uid);
const sameUrl = fileUrl && this.attachmentFileUrl(item) === fileUrl;
return sameUid || sameUrl;
});
return {
...existingFile,
...file, ...file,
attachmentType: (() => { attachmentType:
const matchedType = this.resolveAttachmentTypeByFileName(file); existingFile?.attachmentType || this.resolveAttachmentTypeByFileName(file),
const existingType = [ description: file.description || existingFile?.description || '',
...Object.values(MATERIAL_TYPE_MAP), };
'other', });
].includes(file.attachmentType)
? file.attachmentType
: 'other';
return matchedType !== 'other' ? matchedType : existingType;
})(),
description: file.description || '',
}));
}, },
handleManualAttachmentUpload(uploadedFile) { handleManualAttachmentUpload(uploadedFile) {
const uploadedUrl = this.attachmentFileUrl(uploadedFile); const uploadedUrl = this.attachmentFileUrl(uploadedFile);
@@ -2206,6 +2303,12 @@ export default {
.payment-form-page__attachment-download { .payment-form-page__attachment-download {
margin-left: auto; margin-left: auto;
} }
.payment-form-page__invoice-actions {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
}
.payment-form-page__attachment-file-name-cell { .payment-form-page__attachment-file-name-cell {
display: block; display: block;
width: 100%; width: 100%;
+3
View File
@@ -371,6 +371,9 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.receipt-claim-form-page__form {
padding-bottom: 72px;
}
.receipt-claim-form-page__form :deep(.el-select), .receipt-claim-form-page__form :deep(.el-select),
.receipt-claim-form-page__form :deep(.el-input-number) { .receipt-claim-form-page__form :deep(.el-input-number) {
width: 100%; width: 100%;
+98 -4
View File
@@ -71,10 +71,9 @@
show-overflow-tooltip show-overflow-tooltip
> >
<template #default="{ row }"> <template #default="{ row }">
<el-link v-if="column.link && canClaim(row)" type="primary" @click="openClaim(row)"> <el-link v-if="column.link" type="primary" @click="openDetail(row)">
{{ displayValue(row[column.prop]) }} {{ displayValue(row[column.prop]) }}
</el-link> </el-link>
<span v-else-if="column.link">{{ displayValue(row[column.prop]) }}</span>
<el-tag <el-tag
v-else-if="column.status" v-else-if="column.status"
:type="statusType(row.claimStatus)" :type="statusType(row.claimStatus)"
@@ -105,6 +104,74 @@
/> />
</div> </div>
</section> </section>
<el-dialog
v-model="detailDialog.visible"
title="收款流水详情"
width="960px"
append-to-body
destroy-on-close
>
<div v-loading="detailDialog.loading">
<el-descriptions :column="3" border>
<el-descriptions-item label="认领通知单">
{{ displayValue(detailDialog.data.receiptNoticeNo) }}
</el-descriptions-item>
<el-descriptions-item label="付款人">
{{ displayValue(detailDialog.data.payerName) }}
</el-descriptions-item>
<el-descriptions-item label="付款金额">
{{ formatMoney(detailDialog.data.receiptAmount) }}
</el-descriptions-item>
<el-descriptions-item label="交易时间">
{{ displayValue(detailDialog.data.transactionTime) }}
</el-descriptions-item>
<el-descriptions-item label="对方户名">
{{ displayValue(detailDialog.data.counterpartyName) }}
</el-descriptions-item>
<el-descriptions-item label="对方开户行">
{{ displayValue(detailDialog.data.counterpartyBank) }}
</el-descriptions-item>
<el-descriptions-item label="对方账号">
{{ displayValue(detailDialog.data.counterpartyAccount) }}
</el-descriptions-item>
<el-descriptions-item label="明细流水号">
{{ displayValue(detailDialog.data.detailSerialNo) }}
</el-descriptions-item>
<el-descriptions-item label="认领状态">
<el-tag :type="statusType(detailDialog.data.claimStatus)">
{{ displayValue(detailDialog.data.claimStatusName) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="已认领金额">
{{ formatMoney(detailDialog.data.claimedAmount) }}
</el-descriptions-item>
<el-descriptions-item label="剩余可认领金额">
{{ formatMoney(detailDialog.data.remainingAmount) }}
</el-descriptions-item>
<el-descriptions-item label="摘要">
{{ displayValue(detailDialog.data.summary) }}
</el-descriptions-item>
</el-descriptions>
<div class="dialog-section-title receipt-flow-page__detail-title">认领记录</div>
<el-table :data="detailDialog.claimRecords" border empty-text="暂无认领记录">
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column prop="createTime" label="认领时间" min-width="170" align="center" />
<el-table-column label="认领金额" min-width="130" align="right">
<template #default="{ row }">{{ formatMoney(row.operationAmount) }}</template>
</el-table-column>
<el-table-column prop="operatorName" label="认领人" min-width="120" align="center" />
<el-table-column label="状态变化" min-width="170" align="center">
<template #default="{ row }">{{ claimStatusChange(row) }}</template>
</el-table-column>
<el-table-column prop="content" label="认领说明" min-width="220" />
</el-table>
</div>
<template #footer>
<el-button @click="detailDialog.visible = false">关闭</el-button>
</template>
</el-dialog>
</basic-container> </basic-container>
</template> </template>
@@ -150,8 +217,10 @@ const formatMockDateTime = date => {
)}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; )}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
}; };
const createReceiptFlowMockRows = () => const createReceiptFlowMockRows = () => {
receiptFlowMockTemplates.map((template, index) => { const count = 20 + Math.floor(Math.random() * 31);
return Array.from({ length: count }, (_, index) => {
const template = receiptFlowMockTemplates[index % receiptFlowMockTemplates.length];
const transactionDate = new Date(); const transactionDate = new Date();
transactionDate.setDate(transactionDate.getDate() - Math.floor(Math.random() * 7)); transactionDate.setDate(transactionDate.getDate() - Math.floor(Math.random() * 7));
transactionDate.setHours(8 + Math.floor(Math.random() * 10), Math.floor(Math.random() * 60), 0); transactionDate.setHours(8 + Math.floor(Math.random() * 10), Math.floor(Math.random() * 60), 0);
@@ -167,6 +236,7 @@ const createReceiptFlowMockRows = () =>
sourceUpdatedTime: transactionTime, sourceUpdatedTime: transactionTime,
}; };
}); });
};
const emptyQuery = () => ({ const emptyQuery = () => ({
receiptNoticeNo: '', receiptNoticeNo: '',
@@ -190,6 +260,7 @@ export default {
syncing: false, syncing: false,
searchExpanded: false, searchExpanded: false,
page: { current: 1, size: 10, total: 0 }, page: { current: 1, size: 10, total: 0 },
detailDialog: { visible: false, loading: false, data: {}, claimRecords: [] },
}; };
}, },
computed: { computed: {
@@ -250,6 +321,21 @@ export default {
this.syncing = false; this.syncing = false;
} }
}, },
async openDetail(row) {
this.detailDialog = {
visible: true,
loading: true,
data: { ...row },
claimRecords: [],
};
try {
const data = this.unwrapData(await api.getDetail(row.id));
this.detailDialog.data = data || {};
this.detailDialog.claimRecords = data?.claimRecords || [];
} finally {
this.detailDialog.loading = false;
}
},
openClaim(row) { openClaim(row) {
this.$router.push({ this.$router.push({
path: '/payment/receipt-flow/form', path: '/payment/receipt-flow/form',
@@ -265,6 +351,11 @@ export default {
statusType(status) { statusType(status) {
return { claimed: 'success', partial: 'warning', unclaimed: 'info' }[status] || ''; return { claimed: 'success', partial: 'warning', unclaimed: 'info' }[status] || '';
}, },
claimStatusChange(row) {
const label = status =>
({ claimed: '认领完成', partial: '部分认领', unclaimed: '未认领' }[status] || '-');
return `${label(row.fromStatus)}${label(row.toStatus)}`;
},
displayValue(value) { displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value; return value === null || value === undefined || value === '' ? '-' : value;
}, },
@@ -314,6 +405,9 @@ export default {
justify-content: flex-end; justify-content: flex-end;
padding: 16px 0; padding: 16px 0;
} }
.receipt-flow-page__detail-title {
margin: 20px 0 12px;
}
.receipt-flow-page :deep(.el-table) { .receipt-flow-page :deep(.el-table) {
--el-table-border-color: #eff1f7; --el-table-border-color: #eff1f7;
} }
@@ -34,7 +34,9 @@
<div class="settlement-detail-page__toolbar-left"> <div class="settlement-detail-page__toolbar-left">
<el-button type="primary" @click="openGenerateDialog">生成费用</el-button> <el-button type="primary" @click="openGenerateDialog">生成费用</el-button>
<el-button type="primary" plain @click="openUpdateFeeDialog">更新费用</el-button> <el-button type="primary" plain @click="openUpdateFeeDialog">更新费用</el-button>
<el-button type="primary" plain @click="openTransferDialog">批量转结算</el-button> <el-button v-if="isPayable" type="primary" plain @click="openTransferDialog">
批量转结算
</el-button>
<el-button type="primary" plain @click="handleExport">导出</el-button> <el-button type="primary" plain @click="handleExport">导出</el-button>
</div> </div>
<div class="settlement-detail-page__toolbar-right"> <div class="settlement-detail-page__toolbar-right">
@@ -849,11 +851,17 @@ export default {
return this.cargoTypeOptions.filter(item => item.children?.length); return this.cargoTypeOptions.filter(item => item.children?.length);
}, },
}, },
mounted() { watch: {
'$route.fullPath'() {
this.openRouteDetail();
},
},
async mounted() {
this.loadTransportTypeOptions(); this.loadTransportTypeOptions();
this.loadCargoTypeOptions(); this.loadCargoTypeOptions();
this.loadPriceUnitOptions(); this.loadPriceUnitOptions();
this.loadTable(); await this.loadTable();
await this.openRouteDetail();
}, },
beforeUnmount() { beforeUnmount() {
this.clearAdjustCalculations(); this.clearAdjustCalculations();
@@ -1191,6 +1199,29 @@ export default {
} }
this.$router.push({ path, query: { detailNo } }); this.$router.push({ path, query: { detailNo } });
}, },
async openRouteDetail(detailId = this.$route.query.detailId) {
if (
!detailId ||
this.settlementType !== 'payable' ||
this.$route.path !== '/settlement/payable-detail'
) {
return;
}
let row = this.rows.find(item => String(item.id) === String(detailId));
if (!row) {
const res = await api.getList(1, 1, {
ids: detailId,
settlementType: this.settlementType,
});
const data = this.unwrapPage(res);
if (data.records?.[0]) row = this.decorateRow(data.records[0]);
}
if (!row) {
this.$message.info('当前记录未找到对应的应付明细');
return;
}
await this.openDetailDialog(row);
},
openWaybillDetail(row) { openWaybillDetail(row) {
if (!row.waybillId) { if (!row.waybillId) {
this.$message.info('当前记录未关联运单详情'); this.$message.info('当前记录未关联运单详情');