调整收付款问题
This commit is contained in:
@@ -51,9 +51,9 @@
|
||||
<vehicle-attachment-upload
|
||||
:model-value="rows"
|
||||
:file-types="attachmentFileTypes"
|
||||
:max-size="500"
|
||||
:max-size="maxSize"
|
||||
:show-tip="true"
|
||||
tip="支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip的文件格式,单个文件不超过500M"
|
||||
:tip="`支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip的文件格式,单个文件不超过${maxSize}MB`"
|
||||
:show-file-list="false"
|
||||
button-text="上传附件"
|
||||
@update:model-value="handleUploadChange"
|
||||
@@ -149,6 +149,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
data() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const receiptFlowTableColumns = [
|
||||
{ prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150 },
|
||||
{ prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150, link: true },
|
||||
{ prop: 'payerName', label: '付款人', minWidth: 130 },
|
||||
{ prop: 'receiptAmount', label: '付款金额', minWidth: 130, money: true },
|
||||
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
|
||||
|
||||
@@ -10,8 +10,18 @@ export const preSettlementTableColumns = [
|
||||
{ label: '原币结算金额', prop: 'settlementAmount', minWidth: 140, money: true, precision: 2 },
|
||||
{ label: '本位币结算金额', prop: 'localSettlementAmount', minWidth: 150, money: true, 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: 'currentNode', minWidth: 130 },
|
||||
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 130 },
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
</section-card>
|
||||
|
||||
<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>
|
||||
|
||||
<div class="bill-payment-form-page__actions">
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
@edit="openEdit"
|
||||
@delete="handleDelete"
|
||||
@flow="openFlow"
|
||||
@approve="handleApprove"
|
||||
@return="handleReturn"
|
||||
@void="handleVoid"
|
||||
@page-change="handlePageChange"
|
||||
@size-change="handleSizeChange"
|
||||
@@ -126,6 +128,17 @@ export default {
|
||||
this.flowDialog.row = row;
|
||||
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) {
|
||||
const { value } = await this.$prompt('请输入作废原因', '作废汇票付款');
|
||||
await api.voidBill({ id: row.id, reason: value });
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<span v-else>{{ displayValue(row[column.prop]) }}</span>
|
||||
</template>
|
||||
</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 }">
|
||||
<div class="bill-payment-table__links">
|
||||
<el-link
|
||||
@@ -55,6 +55,18 @@
|
||||
@click="$emit('flow', row)"
|
||||
>流程</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
|
||||
v-if="row.approvalStatus === 'approved' && hasPermission('bill_payment_void')"
|
||||
type="danger"
|
||||
@@ -90,7 +102,18 @@ export default {
|
||||
loading: { type: Boolean, default: false },
|
||||
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() {
|
||||
return { columns: billPaymentTableColumns };
|
||||
},
|
||||
|
||||
@@ -188,7 +188,10 @@
|
||||
</el-row>
|
||||
</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 class="invoice-sheet__header">
|
||||
<span>第{{ sheetIndex + 1 }}张</span>
|
||||
@@ -247,17 +250,6 @@
|
||||
/>
|
||||
</template>
|
||||
</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">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
@@ -362,7 +354,11 @@
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<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] }}
|
||||
</el-link>
|
||||
<span
|
||||
@@ -371,9 +367,13 @@
|
||||
Number(row[column.prop]) === -1
|
||||
"
|
||||
></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.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>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -400,17 +400,15 @@
|
||||
<div class="invoice-form-page__actions">
|
||||
<el-button @click="goBack">取消</el-button>
|
||||
<el-button v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button>
|
||||
<el-button
|
||||
v-if="!readonly && canSave"
|
||||
type="primary"
|
||||
plain
|
||||
@click="saveDraft"
|
||||
>保存</el-button>
|
||||
<el-button v-if="!readonly && canSave" type="primary" plain @click="saveDraft"
|
||||
>保存</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="!readonly && canSave && hasPermission('invoice_application_submit')"
|
||||
type="primary"
|
||||
@click="submitForm"
|
||||
>提交</el-button>
|
||||
>提交</el-button
|
||||
>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
@@ -468,6 +466,8 @@
|
||||
import { mapGetters } from 'vuex';
|
||||
import * as api from '@/api/payment/invoiceApplication';
|
||||
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 { invoiceApplicationDetailColumns } from '@/option/payment/invoiceApplication';
|
||||
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
|
||||
@@ -662,7 +662,8 @@ export default {
|
||||
if (this.settlementIds.length) {
|
||||
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);
|
||||
},
|
||||
async loadInvoiceItems() {
|
||||
@@ -683,8 +684,7 @@ export default {
|
||||
transportTypeLabel(value) {
|
||||
if (!value) return '-';
|
||||
return (
|
||||
this.transportTypeOptions.find(item => String(item.value) === String(value))?.label ||
|
||||
value
|
||||
this.transportTypeOptions.find(item => String(item.value) === String(value))?.label || value
|
||||
);
|
||||
},
|
||||
invoiceItemNames(categoryName) {
|
||||
@@ -840,7 +840,7 @@ export default {
|
||||
...item,
|
||||
formalSettlementId: item.id,
|
||||
settlementId: item.id,
|
||||
allocatedInvoiceAmount: 0,
|
||||
allocatedInvoiceAmount: rows.length === 1 ? Number(item.availableInvoiceAmount || 0) : 0,
|
||||
}));
|
||||
this.form.projectName = first.projectName;
|
||||
this.form.deptName = first.deptName;
|
||||
@@ -906,9 +906,7 @@ export default {
|
||||
const invoiceInfoEmails = [
|
||||
...this.receiverInvoiceOptions.flatMap(item => this.parseEmails(item.email)),
|
||||
];
|
||||
this.departmentEmailOptions = invoiceInfoEmails
|
||||
.filter(Boolean)
|
||||
.reduce((emails, email) => {
|
||||
this.departmentEmailOptions = invoiceInfoEmails.filter(Boolean).reduce((emails, email) => {
|
||||
if (!emails.some(item => item.toLowerCase() === email.toLowerCase())) emails.push(email);
|
||||
return emails;
|
||||
}, []);
|
||||
@@ -962,6 +960,56 @@ export default {
|
||||
if (this.readonly) return;
|
||||
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() {
|
||||
if (this.readonly || !this.$refs.detailTable) return;
|
||||
const selected = new Set(this.selectedDetailIds.map(String));
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
v-loading="invoiceDialog.loading"
|
||||
:data="invoiceDialog.rows"
|
||||
border
|
||||
empty-text="暂无票据数据"
|
||||
highlight-current-row
|
||||
@current-change="invoiceDialog.current = $event"
|
||||
@row-dblclick="confirmInvoice"
|
||||
@@ -188,6 +189,17 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</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>
|
||||
<el-button @click="invoiceDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmInvoice()">确定</el-button>
|
||||
@@ -247,67 +259,12 @@
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
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';
|
||||
|
||||
const invoicePoolMockTemplates = [
|
||||
{
|
||||
id: 90000001,
|
||||
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 mockInvoiceTypes = ['增值税专用发票', '增值税普通发票'];
|
||||
const mockTaxRates = [3, 6, 9, 13];
|
||||
const mockBankNames = ['中国工商银行', '中国农业银行', '中国银行', '中国建设银行', '招商银行'];
|
||||
|
||||
const randomDigits = length =>
|
||||
Array.from({ length }, () => Math.floor(Math.random() * 10)).join('');
|
||||
@@ -319,28 +276,59 @@ const formatMockDate = date => {
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
const createInvoicePoolMockRows = () =>
|
||||
invoicePoolMockTemplates.map((template, index) => {
|
||||
const customerName = customer =>
|
||||
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();
|
||||
invoiceDateValue.setDate(invoiceDateValue.getDate() - Math.floor(Math.random() * 15));
|
||||
invoiceDateValue.setDate(invoiceDateValue.getDate() - Math.floor(Math.random() * 90));
|
||||
const invoiceDate = formatMockDate(invoiceDateValue);
|
||||
const taxRate = mockTaxRates[(customerIndex + roleIndex + index) % mockTaxRates.length];
|
||||
const invoiceAmount = Math.floor(10000 + Math.random() * 190000);
|
||||
const taxAmount = Number(
|
||||
(
|
||||
(invoiceAmount * Number(template.taxRate || 0)) /
|
||||
(100 + Number(template.taxRate || 0))
|
||||
).toFixed(2)
|
||||
((invoiceAmount * Number(taxRate)) / (100 + Number(taxRate))).toFixed(2)
|
||||
);
|
||||
return {
|
||||
...template,
|
||||
id: Date.now() + index * 100 + Math.floor(Math.random() * 100),
|
||||
const bankName = mockBankNames[(customerIndex + index) % mockBankNames.length];
|
||||
rows.push({
|
||||
id: baseId + rowIndex,
|
||||
invoiceNo: `25${randomDigits(18)}`,
|
||||
invoiceDate,
|
||||
invoiceType: mockInvoiceTypes[(customerIndex + index) % mockInvoiceTypes.length],
|
||||
taxRate,
|
||||
invoiceAmount,
|
||||
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 = () => ({
|
||||
id: null,
|
||||
@@ -380,9 +368,18 @@ export default {
|
||||
Search,
|
||||
form: emptyForm(),
|
||||
invoicePoolMockRows: [],
|
||||
invoicePoolMockLoaded: false,
|
||||
customerEmailOptions: [],
|
||||
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: {
|
||||
visible: false,
|
||||
loading: false,
|
||||
@@ -447,7 +444,6 @@ export default {
|
||||
.filter(Boolean);
|
||||
},
|
||||
async initialize() {
|
||||
this.invoicePoolMockRows = createInvoicePoolMockRows();
|
||||
const userInfo = this.$store.getters.userInfo || {};
|
||||
const userEmail = userInfo.email || '';
|
||||
this.departmentEmailOptions = userEmail ? [userEmail] : [];
|
||||
@@ -499,22 +495,72 @@ export default {
|
||||
async openInvoiceDialog() {
|
||||
this.invoiceDialog.visible = true;
|
||||
this.invoiceDialog.keyword = this.form.invoiceNo || '';
|
||||
if (!this.recordId) this.invoicePoolMockRows = createInvoicePoolMockRows();
|
||||
await this.loadInvoicePool();
|
||||
},
|
||||
async loadInvoicePool() {
|
||||
this.invoiceDialog.loading = true;
|
||||
this.invoiceDialog.page.current = 1;
|
||||
this.invoiceDialog.current = null;
|
||||
try {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
const normalizedKeyword = String(keyword || '')
|
||||
.trim()
|
||||
@@ -781,6 +827,11 @@ export default {
|
||||
.receipt-form-page__dialog-search .el-input {
|
||||
width: 360px;
|
||||
}
|
||||
.receipt-form-page__dialog-pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.receipt-form-page :deep(.el-table) {
|
||||
--el-table-border-color: #eff1f7;
|
||||
}
|
||||
|
||||
@@ -238,9 +238,19 @@
|
||||
<el-table-column label="匹配金额(含税)" min-width="150">
|
||||
<template #default="{ row }">{{ formatMoney(row.matchedAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="!readonly" label="操作" width="100">
|
||||
<template #default="{ $index }">
|
||||
<el-link type="danger" @click="form.invoices.splice($index, 1)">删除</el-link>
|
||||
<el-table-column label="操作" width="220" fixed="right" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<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>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -333,7 +343,7 @@
|
||||
>
|
||||
<div class="payment-form-page__attachment-upload">
|
||||
<vehicle-attachment-upload
|
||||
v-model="form.attachments"
|
||||
:model-value="form.attachments"
|
||||
:readonly="readonly"
|
||||
:multiple="true"
|
||||
:limit="20"
|
||||
@@ -341,7 +351,7 @@
|
||||
:file-types="attachmentFileTypes"
|
||||
:show-file-list="false"
|
||||
button-text="上传附件"
|
||||
@change="normalizeAttachments"
|
||||
@update:model-value="normalizeAttachments"
|
||||
@success="handleManualAttachmentUpload"
|
||||
/>
|
||||
</div>
|
||||
@@ -598,7 +608,7 @@ const emptyForm = () => ({
|
||||
settlementAmount: 0,
|
||||
payableAmount: 0,
|
||||
billType: '',
|
||||
paymentRatio: 50,
|
||||
paymentRatio: null,
|
||||
appliedAmount: 0,
|
||||
paymentMethod: 'bank_transfer',
|
||||
billLedgerId: null,
|
||||
@@ -661,6 +671,8 @@ export default {
|
||||
receiptAccountLoading: false,
|
||||
firstContractPayment: false,
|
||||
contractSignatureFileAvailable: false,
|
||||
contractPaymentRatioLimit: null,
|
||||
contractPaymentRatioExceeded: false,
|
||||
payeeCustomerLevel: '',
|
||||
attachmentRuleLoading: false,
|
||||
attachmentImagePreviewVisible: false,
|
||||
@@ -794,6 +806,7 @@ export default {
|
||||
}
|
||||
},
|
||||
'form.paymentRatio'(value) {
|
||||
this.checkContractPaymentRatio(value);
|
||||
if (this.amountSyncing || !this.paymentAmountBase) return;
|
||||
this.amountSyncing = true;
|
||||
this.form.appliedAmount = Number(
|
||||
@@ -1013,7 +1026,8 @@ export default {
|
||||
);
|
||||
},
|
||||
isValidReferenceId(id) {
|
||||
return id !== null && id !== undefined && String(id).trim() !== '-1';
|
||||
const value = String(id ?? '').trim();
|
||||
return value !== '' && value !== '-1' && value !== '0';
|
||||
},
|
||||
async loadTransferredPreSettlements() {
|
||||
const fallbackRows = this.transferPayload?.sourcePreSettlements || [];
|
||||
@@ -1246,6 +1260,44 @@ export default {
|
||||
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) {
|
||||
return String(file?.originalName || file?.name || file?.fileName || '').trim();
|
||||
},
|
||||
@@ -1282,14 +1334,14 @@ export default {
|
||||
this.attachmentFileExtension(file) === 'pdf'
|
||||
);
|
||||
},
|
||||
previewAttachment(file) {
|
||||
previewAttachment(file, files = this.form.attachments) {
|
||||
const url = this.attachmentFileUrl(file);
|
||||
if (!url) {
|
||||
this.$message.warning('附件地址为空,无法预览');
|
||||
return;
|
||||
}
|
||||
if (this.isAttachmentImage(file)) {
|
||||
this.attachmentImagePreviewUrls = (this.form.attachments || [])
|
||||
this.attachmentImagePreviewUrls = (files || [])
|
||||
.filter(item => this.isAttachmentImage(item) && this.attachmentFileUrl(item))
|
||||
.map(item => this.attachmentFileUrl(item));
|
||||
this.attachmentImagePreviewIndex = Math.max(
|
||||
@@ -1384,22 +1436,29 @@ export default {
|
||||
if (imported.length) this.form.attachments = [...this.form.attachments, ...imported];
|
||||
},
|
||||
async loadCurrentSettlementDetails() {
|
||||
if (this.form.paymentType === 'project_advance') return [];
|
||||
const requests = [];
|
||||
if (this.isValidReferenceId(this.form.preSettlementId)) {
|
||||
requests.push(preApi.getDetail(this.form.preSettlementId));
|
||||
if (
|
||||
this.form.paymentType === 'progress_advance' &&
|
||||
this.isValidReferenceId(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)) {
|
||||
requests.push(formalApi.getDetail(this.form.settlementId));
|
||||
if (
|
||||
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 [];
|
||||
const responses = await Promise.all(requests);
|
||||
return responses.map(response => this.unwrapData(response)).filter(item => item?.id);
|
||||
return [];
|
||||
},
|
||||
async loadAttachmentRuleData(settlementRows = []) {
|
||||
this.attachmentRuleLoading = true;
|
||||
this.firstContractPayment = false;
|
||||
this.contractSignatureFileAvailable = false;
|
||||
this.resetContractPaymentRatioLimit();
|
||||
try {
|
||||
const settlementMaterials = [
|
||||
ATTACHMENT_MATERIALS.weighingSlip,
|
||||
@@ -1417,6 +1476,7 @@ export default {
|
||||
const contractResponse = await getContractDetail(this.form.contractId);
|
||||
const contract = this.unwrapData(contractResponse) || {};
|
||||
if (this.form.paymentType === 'project_advance') {
|
||||
this.applyContractPaymentRatioLimit(contract);
|
||||
const contractFiles = this.parse(contract.contractFileJson);
|
||||
this.contractSignatureFileAvailable = contractFiles.some(file =>
|
||||
Boolean(this.attachmentFileUrl(file))
|
||||
@@ -1453,6 +1513,41 @@ export default {
|
||||
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() {
|
||||
if (!this.missingAttachmentMaterials.length) return true;
|
||||
this.$message.warning(
|
||||
@@ -1949,20 +2044,22 @@ export default {
|
||||
this.referenceVisible = false;
|
||||
},
|
||||
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,
|
||||
attachmentType: (() => {
|
||||
const matchedType = this.resolveAttachmentTypeByFileName(file);
|
||||
const existingType = [
|
||||
...Object.values(MATERIAL_TYPE_MAP),
|
||||
'other',
|
||||
].includes(file.attachmentType)
|
||||
? file.attachmentType
|
||||
: 'other';
|
||||
return matchedType !== 'other' ? matchedType : existingType;
|
||||
})(),
|
||||
description: file.description || '',
|
||||
}));
|
||||
attachmentType:
|
||||
existingFile?.attachmentType || this.resolveAttachmentTypeByFileName(file),
|
||||
description: file.description || existingFile?.description || '',
|
||||
};
|
||||
});
|
||||
},
|
||||
handleManualAttachmentUpload(uploadedFile) {
|
||||
const uploadedUrl = this.attachmentFileUrl(uploadedFile);
|
||||
@@ -2206,6 +2303,12 @@ export default {
|
||||
.payment-form-page__attachment-download {
|
||||
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 {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
@@ -371,6 +371,9 @@ export default {
|
||||
</script>
|
||||
|
||||
<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-input-number) {
|
||||
width: 100%;
|
||||
|
||||
@@ -71,10 +71,9 @@
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<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]) }}
|
||||
</el-link>
|
||||
<span v-else-if="column.link">{{ displayValue(row[column.prop]) }}</span>
|
||||
<el-tag
|
||||
v-else-if="column.status"
|
||||
:type="statusType(row.claimStatus)"
|
||||
@@ -105,6 +104,74 @@
|
||||
/>
|
||||
</div>
|
||||
</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>
|
||||
</template>
|
||||
|
||||
@@ -150,8 +217,10 @@ const formatMockDateTime = date => {
|
||||
)}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
||||
};
|
||||
|
||||
const createReceiptFlowMockRows = () =>
|
||||
receiptFlowMockTemplates.map((template, index) => {
|
||||
const createReceiptFlowMockRows = () => {
|
||||
const count = 20 + Math.floor(Math.random() * 31);
|
||||
return Array.from({ length: count }, (_, index) => {
|
||||
const template = receiptFlowMockTemplates[index % receiptFlowMockTemplates.length];
|
||||
const transactionDate = new Date();
|
||||
transactionDate.setDate(transactionDate.getDate() - Math.floor(Math.random() * 7));
|
||||
transactionDate.setHours(8 + Math.floor(Math.random() * 10), Math.floor(Math.random() * 60), 0);
|
||||
@@ -167,6 +236,7 @@ const createReceiptFlowMockRows = () =>
|
||||
sourceUpdatedTime: transactionTime,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const emptyQuery = () => ({
|
||||
receiptNoticeNo: '',
|
||||
@@ -190,6 +260,7 @@ export default {
|
||||
syncing: false,
|
||||
searchExpanded: false,
|
||||
page: { current: 1, size: 10, total: 0 },
|
||||
detailDialog: { visible: false, loading: false, data: {}, claimRecords: [] },
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -250,6 +321,21 @@ export default {
|
||||
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) {
|
||||
this.$router.push({
|
||||
path: '/payment/receipt-flow/form',
|
||||
@@ -265,6 +351,11 @@ export default {
|
||||
statusType(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) {
|
||||
return value === null || value === undefined || value === '' ? '-' : value;
|
||||
},
|
||||
@@ -314,6 +405,9 @@ export default {
|
||||
justify-content: flex-end;
|
||||
padding: 16px 0;
|
||||
}
|
||||
.receipt-flow-page__detail-title {
|
||||
margin: 20px 0 12px;
|
||||
}
|
||||
.receipt-flow-page :deep(.el-table) {
|
||||
--el-table-border-color: #eff1f7;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
<div class="settlement-detail-page__toolbar-left">
|
||||
<el-button type="primary" @click="openGenerateDialog">生成费用</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>
|
||||
</div>
|
||||
<div class="settlement-detail-page__toolbar-right">
|
||||
@@ -849,11 +851,17 @@ export default {
|
||||
return this.cargoTypeOptions.filter(item => item.children?.length);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
watch: {
|
||||
'$route.fullPath'() {
|
||||
this.openRouteDetail();
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.loadTransportTypeOptions();
|
||||
this.loadCargoTypeOptions();
|
||||
this.loadPriceUnitOptions();
|
||||
this.loadTable();
|
||||
await this.loadTable();
|
||||
await this.openRouteDetail();
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.clearAdjustCalculations();
|
||||
@@ -1191,6 +1199,29 @@ export default {
|
||||
}
|
||||
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) {
|
||||
if (!row.waybillId) {
|
||||
this.$message.info('当前记录未关联运单详情');
|
||||
|
||||
Reference in New Issue
Block a user