返回保存保存 ({
id: null,
@@ -356,6 +418,7 @@ const emptyForm = () => ({
paymentType: 'project_advance',
settlementId: null,
preSettlementId: null,
+ preSettlementIds: [],
projectId: null,
projectName: '',
deptId: null,
@@ -389,6 +452,8 @@ export default {
return {
form: emptyForm(),
amountSyncing: false,
+ transferPayload: null,
+ referenceRows: [],
paymentRecords: [],
referenceVisible: false,
referenceTab: 'formal',
@@ -397,6 +462,11 @@ export default {
contractRows: [],
billOptions: [],
billLoading: false,
+ receiptAccountOptions: [],
+ receiptAccountLoading: false,
+ firstContractPayment: false,
+ payeeCustomerLevel: '',
+ attachmentRuleLoading: false,
paymentTypeOptions: api.paymentTypeOptions,
paymentMethodOptions: api.paymentMethodOptions,
attachmentFileTypes: [
@@ -420,6 +490,7 @@ export default {
paymentType: [{ required: true, message: '请选择付款类型' }],
referenceId: [{ validator: this.validateReference, trigger: 'change' }],
paymentMethod: [{ required: true, message: '请选择付款方式' }],
+ receiptAccountId: [{ required: true, message: '请选择收款账号', trigger: 'change' }],
billLedgerId: [{ validator: this.validateBillLedger, trigger: 'change' }],
appliedAmount: [{ validator: this.validateAppliedAmount, trigger: 'change' }],
},
@@ -441,9 +512,26 @@ export default {
return ['bank_draft', 'commercial_draft'].includes(this.form.paymentMethod);
},
referenceLabel() {
+ if (this.referenceRows.length) {
+ return this.referenceRows
+ .map(item => item.settlementNo)
+ .filter(Boolean)
+ .join('、');
+ }
return this.form.settlementNo || this.form.preSettlementNo || '';
},
settlementRows() {
+ if (this.referenceRows.length) {
+ return this.referenceRows.map(item => ({
+ ...item,
+ paymentRatio: this.form.paymentRatio,
+ appliedAmount: Number(
+ ((Number(item.payableAmount || 0) * Number(this.form.paymentRatio || 0)) / 100).toFixed(
+ 2
+ )
+ ),
+ }));
+ }
if (!this.referenceLabel) return [];
return [
{
@@ -455,8 +543,32 @@ export default {
},
];
},
+ highRiskPayee() {
+ const level = String(this.payeeCustomerLevel || '')
+ .trim()
+ .toUpperCase();
+ return ['D', 'D级', 'E', 'E级', 'F', 'F级'].includes(level) || level.includes('高风险');
+ },
+ requiredAttachmentMaterials() {
+ const materials = [ATTACHMENT_MATERIALS.weighingSlip, ATTACHMENT_MATERIALS.settlement];
+ if (this.form.paymentType === 'project_advance') {
+ materials.splice(1, 0, ATTACHMENT_MATERIALS.entrustOrder);
+ }
+ if (this.firstContractPayment) materials.push(ATTACHMENT_MATERIALS.contract);
+ if (this.highRiskPayee) materials.push(ATTACHMENT_MATERIALS.specialApproval);
+ return materials;
+ },
+ missingAttachmentMaterials() {
+ return this.requiredAttachmentMaterials.filter(item => !this.hasAttachmentMaterial(item));
+ },
},
watch: {
+ '$route.query.transferToken': async function (token, oldToken) {
+ if (!this.recordId && token && token !== oldToken) {
+ this.transferPayload = readSettlementTransfer(token);
+ await this.initialize();
+ }
+ },
'form.paymentRatio'(value) {
if (this.amountSyncing || !Number(this.form.payableAmount)) return;
this.amountSyncing = true;
@@ -479,6 +591,7 @@ export default {
},
},
created() {
+ this.transferPayload = readSettlementTransfer(this.$route.query.transferToken);
this.initialize();
},
methods: {
@@ -486,7 +599,11 @@ export default {
return this.permission?.[code] !== false;
},
validateReference(rule, value, callback) {
- if (this.form.paymentType === 'progress_advance' && !this.form.preSettlementId) {
+ if (
+ this.form.paymentType === 'progress_advance' &&
+ !this.form.preSettlementId &&
+ !this.form.preSettlementIds?.length
+ ) {
callback(new Error('请选择预结算单'));
return;
}
@@ -556,17 +673,133 @@ export default {
this.form = {
...emptyForm(),
...data,
+ preSettlementIds: data.preSettlementIds?.length
+ ? data.preSettlementIds
+ : data.preSettlementId
+ ? [data.preSettlementId]
+ : [],
attachments: this.parse(data.attachmentsJson),
invoices: data.invoices || [],
};
+ const referenceRow = this.createReferenceRow(data);
+ this.referenceRows = referenceRow.settlementNo ? [referenceRow] : [];
this.paymentRecords = data.paymentRecords || [];
+ await this.loadReceiptAccountOptions(false);
+ await this.loadAttachmentRuleData(await this.loadCurrentSettlementDetails());
if (this.billPayment) await this.loadBillOptions('', data.billLedgerId);
} else {
+ this.form = emptyForm();
+ this.referenceRows = [];
this.form.applyDate = this.$dayjs().format('YYYY-MM-DD');
this.form.applicantName =
this.$store.getters.userInfo?.realName || this.$store.getters.userInfo?.userName || '';
+ await this.loadTransferredPreSettlements();
}
},
+ getTransferredPreSettlementIds() {
+ const payloadIds = (this.transferPayload?.sourcePreSettlements || []).map(
+ item => item.preSettlementId || item.id
+ );
+ const queryIds = String(this.$route.query.preSettlementIds || '')
+ .split(',')
+ .map(item => item.trim())
+ .filter(Boolean);
+ return [...new Set([...payloadIds, ...queryIds].map(String))];
+ },
+ async loadTransferredPreSettlements() {
+ const fallbackRows = this.transferPayload?.sourcePreSettlements || [];
+ const ids = this.getTransferredPreSettlementIds();
+ if (!ids.length) {
+ this.applyTransferredPreSettlements(fallbackRows);
+ await Promise.all([
+ this.loadReceiptAccountOptions(),
+ this.loadAttachmentRuleData(fallbackRows),
+ ]);
+ return;
+ }
+ try {
+ const responses = await Promise.all(ids.map(id => preApi.getDetail(id)));
+ const rows = responses.map(response => this.unwrapData(response)).filter(item => item?.id);
+ const sourceRows = rows.length ? rows : fallbackRows;
+ this.applyTransferredPreSettlements(sourceRows);
+ await Promise.all([
+ this.loadReceiptAccountOptions(),
+ this.loadAttachmentRuleData(sourceRows),
+ ]);
+ } catch (error) {
+ if (fallbackRows.length) {
+ this.applyTransferredPreSettlements(fallbackRows);
+ await Promise.all([
+ this.loadReceiptAccountOptions(),
+ this.loadAttachmentRuleData(fallbackRows),
+ ]);
+ return;
+ }
+ this.$message.error('预结算信息加载失败,请返回后重新发起预付申请');
+ throw error;
+ }
+ },
+ createReferenceRow(row) {
+ const settlementAmount = Number(row.settlementAmount || 0);
+ const appliedAmount = Number(row.advanceAppliedAmount || row.appliedPaymentAmount || 0);
+ return {
+ id: row.preSettlementId || row.settlementId || row.id,
+ settlementNo: row.preSettlementNo || row.formalSettlementNo || row.settlementNo || '',
+ settlementAmount,
+ payableAmount:
+ row.payableAmount === undefined || row.payableAmount === null
+ ? Math.max(0, settlementAmount - appliedAmount)
+ : Number(row.payableAmount || 0),
+ };
+ },
+ applyTransferredPreSettlements(rows = []) {
+ if (!rows.length) return;
+ const contractIds = new Set(rows.map(item => String(item.contractId || '')));
+ if (contractIds.size > 1 || contractIds.has('')) {
+ this.$message.warning('所选预结算单合同信息不一致,请返回后重新选择');
+ return;
+ }
+ const first = rows[0];
+ this.referenceRows = rows.map(item => this.createReferenceRow(item));
+ const settlementAmount = this.referenceRows.reduce(
+ (total, item) => total + Number(item.settlementAmount || 0),
+ 0
+ );
+ const payableAmount = this.referenceRows.reduce(
+ (total, item) => total + Number(item.payableAmount || 0),
+ 0
+ );
+ const paymentRatio = Number(this.form.paymentRatio || 0);
+ this.amountSyncing = true;
+ Object.assign(this.form, {
+ paymentType: 'progress_advance',
+ settlementId: null,
+ settlementNo: '',
+ preSettlementId: first.preSettlementId || first.id,
+ preSettlementIds: rows.map(item => item.preSettlementId || item.id),
+ preSettlementNo: this.referenceRows
+ .map(item => item.settlementNo)
+ .filter(Boolean)
+ .join('、'),
+ projectId: first.projectId,
+ projectName: first.projectName,
+ deptId: first.deptId,
+ deptName: first.deptName,
+ contractId: first.contractId,
+ contractNo: first.contractNo,
+ contractName: first.contractName,
+ payerName: first.payerName,
+ payeeName: first.payeeName,
+ settlementAmount: Number(settlementAmount.toFixed(2)),
+ payableAmount: Number(payableAmount.toFixed(2)),
+ billType: '预结算单',
+ appliedAmount: Number(((payableAmount * paymentRatio) / 100).toFixed(2)),
+ });
+ this.$nextTick(() => {
+ this.amountSyncing = false;
+ this.$refs.formRef?.clearValidate();
+ });
+ },
parse(value) {
if (!value) return [];
if (Array.isArray(value)) return value;
@@ -576,11 +809,218 @@ export default {
return [];
}
},
+ attachmentFileName(file) {
+ return String(file?.originalName || file?.name || file?.fileName || '').trim();
+ },
+ attachmentFileUrl(file) {
+ return file?.url || file?.link || file?.src || file?.domain || '';
+ },
+ attachmentMatchesMaterial(file, material) {
+ const fileName = this.attachmentFileName(file).toLocaleLowerCase();
+ return (
+ Boolean(this.attachmentFileUrl(file)) &&
+ material.keywords.some(keyword => fileName.includes(keyword.toLocaleLowerCase()))
+ );
+ },
+ hasAttachmentMaterial(material) {
+ return (this.form.attachments || []).some(file =>
+ this.attachmentMatchesMaterial(file, material)
+ );
+ },
+ resolveAttachmentMaterial(file, materials = Object.values(ATTACHMENT_MATERIALS)) {
+ return [...materials]
+ .sort(
+ (a, b) =>
+ Math.max(...b.keywords.map(String.length)) - Math.max(...a.keywords.map(String.length))
+ )
+ .find(material => this.attachmentMatchesMaterial(file, material));
+ },
+ mergeAutomaticAttachments(files, materials, sourceName) {
+ const existingUrls = new Set(
+ (this.form.attachments || []).map(file => this.attachmentFileUrl(file)).filter(Boolean)
+ );
+ const imported = (files || [])
+ .map(file => ({ file, material: this.resolveAttachmentMaterial(file, materials) }))
+ .filter(item => item.material && !existingUrls.has(this.attachmentFileUrl(item.file)))
+ .map(({ file, material }) => {
+ existingUrls.add(this.attachmentFileUrl(file));
+ return {
+ ...file,
+ originalName: this.attachmentFileName(file),
+ name: this.attachmentFileName(file),
+ url: this.attachmentFileUrl(file),
+ link: file.link || this.attachmentFileUrl(file),
+ attachmentType: MATERIAL_TYPE_MAP[material.key],
+ description: file.description || `自动取自${sourceName}`,
+ sourceImported: true,
+ };
+ });
+ if (imported.length) this.form.attachments = [...this.form.attachments, ...imported];
+ },
+ async loadCurrentSettlementDetails() {
+ const requests = [];
+ if (this.form.preSettlementId) requests.push(preApi.getDetail(this.form.preSettlementId));
+ if (this.form.settlementId) requests.push(formalApi.getDetail(this.form.settlementId));
+ if (!requests.length) return [];
+ const responses = await Promise.all(requests);
+ return responses.map(response => this.unwrapData(response)).filter(item => item?.id);
+ },
+ async loadAttachmentRuleData(settlementRows = []) {
+ this.attachmentRuleLoading = true;
+ this.firstContractPayment = false;
+ try {
+ const settlementMaterials = [
+ ATTACHMENT_MATERIALS.weighingSlip,
+ ATTACHMENT_MATERIALS.entrustOrder,
+ ATTACHMENT_MATERIALS.settlement,
+ ];
+ const settlementFiles = (settlementRows || []).flatMap(row =>
+ this.parse(row.attachmentsJson)
+ );
+ this.mergeAutomaticAttachments(settlementFiles, settlementMaterials, '结算单');
+ if (!this.form.contractId) {
+ this.firstContractPayment = false;
+ return;
+ }
+ const [contractResponse, paymentResponse] = await Promise.all([
+ getContractDetail(this.form.contractId),
+ api.getList(1, 9999, { contractId: this.form.contractId }),
+ ]);
+ const contract = this.unwrapData(contractResponse) || {};
+ const payments = this.unwrapData(paymentResponse)?.records || [];
+ this.firstContractPayment = !payments.some(
+ item =>
+ String(item.contractId || '') === String(this.form.contractId) &&
+ String(item.id || '') !== String(this.form.id || '') &&
+ item.approvalStatus !== 'voided'
+ );
+ if (this.firstContractPayment) {
+ this.mergeAutomaticAttachments(
+ this.parse(contract.contractFileJson),
+ [ATTACHMENT_MATERIALS.contract],
+ '合同'
+ );
+ }
+ } catch (error) {
+ this.$message.warning('附件清单来源材料加载失败,请核对后手工补充');
+ } finally {
+ this.attachmentRuleLoading = false;
+ }
+ },
+ validateRequiredAttachments() {
+ if (!this.missingAttachmentMaterials.length) return true;
+ this.$message.warning(
+ `请先上传付款申请所需材料:${this.missingAttachmentMaterials
+ .map(item => item.label)
+ .join('、')}`
+ );
+ return false;
+ },
handleTypeChange() {
if (this.form.paymentType === 'project_advance') {
this.form.settlementId = null;
this.form.preSettlementId = null;
+ this.form.preSettlementIds = [];
+ this.form.settlementNo = '';
+ this.form.preSettlementNo = '';
+ this.referenceRows = [];
}
+ this.loadAttachmentRuleData([]);
+ },
+ clearReceiptAccount() {
+ Object.assign(this.form, {
+ receiptAccountId: null,
+ receiptAccountName: '',
+ bankName: '',
+ bankAccount: '',
+ });
+ },
+ customerRecords(response) {
+ return this.unwrapData(response)?.records || [];
+ },
+ async loadReceiptAccountOptions(autoSelectDefault = true) {
+ const payeeName = String(this.form.payeeName || '').trim();
+ const preserveCurrentValue = autoSelectDefault === false;
+ this.receiptAccountOptions = [];
+ this.payeeCustomerLevel = '';
+ if (!payeeName) {
+ if (!preserveCurrentValue) this.clearReceiptAccount();
+ return;
+ }
+ this.receiptAccountLoading = true;
+ try {
+ const [fullNameResponse, shortNameResponse] = await Promise.all([
+ getCustomerArchiveList(1, 20, {
+ fullName: payeeName,
+ approvalStatus: 'approved',
+ status: 1,
+ }),
+ getCustomerArchiveList(1, 20, {
+ shortName: payeeName,
+ approvalStatus: 'approved',
+ status: 1,
+ }),
+ ]);
+ const customers = [
+ ...this.customerRecords(fullNameResponse),
+ ...this.customerRecords(shortNameResponse),
+ ];
+ const customer = customers.find(
+ item => item.fullName === payeeName || item.shortName === payeeName
+ );
+ if (!customer?.id) {
+ if (!preserveCurrentValue) this.clearReceiptAccount();
+ return;
+ }
+ const detail = this.unwrapData(await getCustomerArchiveDetail(customer.id));
+ this.payeeCustomerLevel = detail.customerLevel || '';
+ this.receiptAccountOptions = (detail.receiptAccounts || []).map(item => ({
+ ...item,
+ id: String(item.id),
+ }));
+ const selected = this.receiptAccountOptions.find(
+ item => String(item.id) === String(this.form.receiptAccountId || '')
+ );
+ if (selected) {
+ this.applyReceiptAccount(selected);
+ return;
+ }
+ if (preserveCurrentValue) return;
+ this.clearReceiptAccount();
+ if (autoSelectDefault && !this.readonly) {
+ const defaultAccount =
+ this.receiptAccountOptions.find(item => Number(item.isDefault) === 1) ||
+ (this.receiptAccountOptions.length === 1 ? this.receiptAccountOptions[0] : null);
+ if (defaultAccount) this.applyReceiptAccount(defaultAccount);
+ }
+ } catch (error) {
+ if (!preserveCurrentValue) this.clearReceiptAccount();
+ this.$message.warning('收款方的客商收款信息加载失败,请稍后重试');
+ } finally {
+ this.receiptAccountLoading = false;
+ }
+ },
+ receiptAccountLabel(item) {
+ return [item.accountName || item.accountHolderName, item.bankName, item.bankAccount]
+ .filter(Boolean)
+ .join('|');
+ },
+ applyReceiptAccount(account) {
+ Object.assign(this.form, {
+ receiptAccountId: account.id,
+ receiptAccountName: account.accountName || account.accountHolderName || '',
+ bankName: account.bankName || '',
+ bankAccount: account.bankAccount || '',
+ });
+ this.$nextTick(() => this.$refs.formRef?.validateField('receiptAccountId').catch(() => {}));
+ },
+ handleReceiptAccountChange(id) {
+ const account = this.receiptAccountOptions.find(item => String(item.id) === String(id || ''));
+ if (account) {
+ this.applyReceiptAccount(account);
+ return;
+ }
+ this.clearReceiptAccount();
},
async handlePaymentMethodChange() {
if (!this.billPayment) {
@@ -624,7 +1064,10 @@ export default {
await this.loadReferences();
this.referenceVisible = true;
},
- selectContract(row) {
+ async selectContract(row) {
+ this.referenceRows = [];
+ this.clearReceiptAccount();
+ const settlementType = row.settlementType || 'payable';
Object.assign(this.form, {
projectId: row.projectId,
projectName: row.projectName,
@@ -633,21 +1076,31 @@ export default {
contractId: row.id,
contractNo: row.contractNo,
contractName: row.contractName,
- payerName: row.payerName,
- payeeName: row.payeeName,
+ payerName:
+ row.payerName || (settlementType === 'receivable' ? row.partyB : row.partyA) || '',
+ payeeName:
+ row.payeeName || (settlementType === 'receivable' ? row.partyA : row.partyB) || '',
billType: '项目预付',
});
this.referenceVisible = false;
+ await Promise.all([this.loadReceiptAccountOptions(), this.loadAttachmentRuleData([])]);
if (this.billPayment) this.loadBillOptions();
},
- selectFormal(row) {
+ async selectFormal(row) {
+ this.referenceRows = [this.createReferenceRow(row)];
+ this.clearReceiptAccount();
Object.assign(this.form, {
settlementId: row.id,
preSettlementId: null,
+ preSettlementIds: [],
settlementNo: row.formalSettlementNo,
+ preSettlementNo: '',
+ projectId: row.projectId,
projectName: row.projectName,
deptId: row.deptId,
deptName: row.deptName,
+ contractId: row.contractId,
+ contractNo: row.contractNo,
contractName: row.contractName,
settlementAmount: row.settlementAmount,
payableAmount: Math.max(
@@ -655,19 +1108,32 @@ export default {
Number(row.settlementAmount || 0) - Number(row.appliedPaymentAmount || 0)
),
billType: '正式结算单',
+ payerName: row.payerName,
payeeName: row.payeeName,
});
this.referenceVisible = false;
+ const detail = this.unwrapData(await formalApi.getDetail(row.id));
+ await Promise.all([
+ this.loadReceiptAccountOptions(),
+ this.loadAttachmentRuleData(detail?.id ? [detail] : []),
+ ]);
if (this.billPayment) this.loadBillOptions();
},
- selectPre(row) {
+ async selectPre(row) {
+ this.referenceRows = [this.createReferenceRow(row)];
+ this.clearReceiptAccount();
Object.assign(this.form, {
preSettlementId: row.id,
+ preSettlementIds: [row.id],
settlementId: null,
preSettlementNo: row.preSettlementNo,
+ settlementNo: '',
+ projectId: row.projectId,
projectName: row.projectName,
deptId: row.deptId,
deptName: row.deptName,
+ contractId: row.contractId,
+ contractNo: row.contractNo,
contractName: row.contractName,
settlementAmount: row.settlementAmount,
payableAmount: Math.max(
@@ -675,9 +1141,15 @@ export default {
Number(row.settlementAmount || 0) - Number(row.advanceAppliedAmount || 0)
),
billType: '预结算单',
+ payerName: row.payerName,
payeeName: row.payeeName,
});
this.referenceVisible = false;
+ const detail = this.unwrapData(await preApi.getDetail(row.id));
+ await Promise.all([
+ this.loadReceiptAccountOptions(),
+ this.loadAttachmentRuleData(detail?.id ? [detail] : []),
+ ]);
if (this.billPayment) this.loadBillOptions();
},
addInvoice() {
@@ -698,7 +1170,10 @@ export default {
const time = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
this.form.attachments = (files || []).map(file => ({
...file,
- attachmentType: file.attachmentType || 'other',
+ attachmentType:
+ file.attachmentType ||
+ MATERIAL_TYPE_MAP[this.resolveAttachmentMaterial(file)?.key] ||
+ 'other',
description: file.description || '',
uploadUserName: file.uploadUserName || userName,
uploadTime: file.uploadTime || time,
@@ -710,6 +1185,7 @@ export default {
paymentType,
settlementId,
preSettlementId,
+ preSettlementIds,
projectId,
projectName,
deptId,
@@ -740,6 +1216,7 @@ export default {
paymentType,
settlementId,
preSettlementId,
+ preSettlementIds,
projectId,
projectName,
deptId,
@@ -766,12 +1243,13 @@ export default {
invoices,
};
},
- async saveDraft() {
+ async saveDraft(validateMaterials = false) {
await this.$refs.formRef.validate();
if (this.form.paymentType === 'project_advance' && !this.form.projectId) {
this.$message.warning('请选择所属项目');
return false;
}
+ if (validateMaterials && !this.validateRequiredAttachments()) return false;
try {
this.validateInvoices();
} catch (error) {
@@ -784,13 +1262,14 @@ export default {
return true;
},
async submitForm() {
- const saved = await this.saveDraft();
+ const saved = await this.saveDraft(true);
if (!saved) return;
await api.submit({ id: this.form.id });
this.$message.success('提交成功');
this.goBack();
},
goBack() {
+ removeSettlementTransfer(this.$route.query.transferToken);
this.$router.push('/payment/payment-application');
},
formatMoney(value) {
@@ -818,6 +1297,23 @@ export default {
justify-content: flex-start;
margin-top: 12px;
}
+.payment-form-page__missing-text {
+ margin-left: 12px;
+ color: var(--el-color-danger);
+ font-size: 13px;
+ font-weight: 400;
+}
+.payment-form-page__attachment-checklist {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 12px;
+}
+.payment-form-page__attachment-checklist-label {
+ color: var(--el-text-color-regular);
+ font-weight: 600;
+}
.payment-form-page__attachment-upload .vehicle-attachment-upload {
width: auto;
}
diff --git a/src/views/settlement/components/pre-settlement-editor.vue b/src/views/settlement/components/pre-settlement-editor.vue
index 7876f6f..5e224c6 100644
--- a/src/views/settlement/components/pre-settlement-editor.vue
+++ b/src/views/settlement/components/pre-settlement-editor.vue
@@ -1056,6 +1056,7 @@ export default {
id: row.id || undefined,
feeType: row.feeType || '',
feeItem: row.feeItem,
+ originalAmount: Number(row.originalAmount || 0),
adjustAmount: Number(row.adjustAmount || 0),
remark: row.remark,
manualFlag: row.manualFlag || 0,
diff --git a/src/views/settlement/components/settlement-adjustment-editor.vue b/src/views/settlement/components/settlement-adjustment-editor.vue
index 81e559d..10af845 100644
--- a/src/views/settlement/components/settlement-adjustment-editor.vue
+++ b/src/views/settlement/components/settlement-adjustment-editor.vue
@@ -141,7 +141,17 @@
-
+
+
+ 批量下载
+
+
+
+
@@ -264,6 +274,7 @@ export default {
fields: settlementAdjustmentFormFields,
details: [],
attachments: [],
+ selectedAttachments: [],
attachmentFileTypes: [
'pdf',
'bmp',
@@ -320,6 +331,7 @@ export default {
this.form = createSettlementAdjustmentForm();
this.details = [];
this.attachments = [];
+ this.selectedAttachments = [];
this.candidates = [];
this.feeRows = [];
if (!this.recordId) {
@@ -347,6 +359,22 @@ export default {
this.candidates = data?.data || data || [];
},
async handleFormalChange(id) {
+ if (!id) {
+ Object.assign(this.form, {
+ formalSettlementId: null,
+ formalSettlementNo: '',
+ settlementType: '',
+ projectName: '',
+ deptName: '',
+ customerName: '',
+ contractNo: '',
+ contractName: '',
+ originalSettlementAmount: 0,
+ });
+ this.details = [];
+ this.recalculate();
+ return;
+ }
const item = this.candidates.find(row => String(row.id) === String(id));
if (!item) return;
const { id: formalSettlementId, ...formalSettlement } = item;
@@ -358,6 +386,21 @@ export default {
});
this.details = [];
this.recalculate();
+ this.loading = true;
+ try {
+ const { data } = await api.getFormalDetails(formalSettlementId);
+ if (String(this.form.formalSettlementId) !== String(formalSettlementId)) return;
+ this.details = (data?.data || data || []).map(fee => ({
+ ...fee,
+ originalAmountTax: Number(fee.originalAmountTax || 0),
+ adjustmentAmountTax: 0,
+ adjustmentAmountNoTax: null,
+ remark: '',
+ }));
+ this.recalculate();
+ } finally {
+ this.loading = false;
+ }
},
async openFeeDialog() {
const { data } = await api.getFormalDetails(this.form.formalSettlementId);
@@ -432,6 +475,7 @@ export default {
uploadUserName: file.uploadUserName || uploadUserName,
uploadTime: file.uploadTime || uploadTime,
}));
+ this.selectedAttachments = [];
},
parseAttachments(value) {
if (!value) return [];
@@ -467,8 +511,22 @@ export default {
}
downloadFileByUrl(url, this.attachmentName(file));
},
+ batchDownloadAttachments() {
+ const files = this.selectedAttachments.length ? this.selectedAttachments : this.attachments;
+ const downloadableFiles = files.filter(file => this.attachmentUrl(file));
+ if (!downloadableFiles.length) {
+ this.$message.warning(
+ this.selectedAttachments.length ? '所选附件暂无可下载地址' : '暂无可下载附件'
+ );
+ return;
+ }
+ downloadableFiles.forEach((file, index) => {
+ window.setTimeout(() => this.downloadAttachment(file), index * 200);
+ });
+ },
removeAttachment(index) {
- this.attachments.splice(index, 1);
+ const [removed] = this.attachments.splice(index, 1);
+ this.selectedAttachments = this.selectedAttachments.filter(file => file !== removed);
},
},
};
@@ -484,6 +542,11 @@ export default {
padding: 12px 0;
text-align: right;
}
+.settlement-adjustment-editor__attachment-actions {
+ display: flex;
+ justify-content: flex-end;
+ margin-bottom: 12px;
+}
.settlement-adjustment-editor__attachment-upload {
padding-top: 12px;
}
diff --git a/src/views/settlement/pre-settlement.vue b/src/views/settlement/pre-settlement.vue
index 605c636..98518d5 100644
--- a/src/views/settlement/pre-settlement.vue
+++ b/src/views/settlement/pre-settlement.vue
@@ -53,8 +53,8 @@
v-if="hasPermission('pre_settlement_advance')"
type="primary"
plain
- disabled
- @click="openAdvanceDialog"
+ :disabled="!selection.length"
+ @click="handleAdvanceApplication"
>
预付申请
@@ -215,52 +215,6 @@
@success="loadTable"
/>
-
-
-
- {{ advanceDialog.row.preSettlementNo || '-' }}
-
-
-
- {{ formatMoney(advanceDialog.row.settlementAmount, advanceDialog.row.currency) }}
-
-
-
-
- {{ formatMoney(advanceDialog.row.advanceAppliedAmount, advanceDialog.row.currency) }}
-
-
-
-
-
-
-
-
-
-
- 取消
-
- 提交
-
-
-
-
{
- if (!value || Number(value) <= 0) {
- callback(new Error('申请预付金额必须大于0'));
- return;
- }
- if (Number(value) > this.advanceAvailableAmount) {
- callback(new Error('申请预付金额不能超过剩余可申请金额'));
- return;
- }
- callback();
- },
- trigger: ['blur', 'change'],
- },
- ],
- },
printDialog: {
visible: false,
loading: false,
@@ -422,13 +347,6 @@ export default {
visibleSearchFields() {
return this.searchExpanded ? this.searchFields : this.searchFields.slice(0, 4);
},
- advanceAvailableAmount() {
- return Math.max(
- Number(this.advanceDialog.row.settlementAmount || 0) -
- Number(this.advanceDialog.row.advanceAppliedAmount || 0),
- 0
- );
- },
},
watch: {
'$route.query.detailNo'(detailNo) {
@@ -525,37 +443,49 @@ export default {
}
return this.selection[0];
},
- openAdvanceDialog() {
- const row = this.selectedOne('预付申请');
- if (!row) return;
+ handleAdvanceApplication() {
+ if (!this.selection.length) {
+ this.$message.warning('请选择需要发起预付申请的预结算单');
+ return;
+ }
+ if (this.selection.some(row => !row.contractId)) {
+ this.$message.warning('所选预结算单缺少合同ID,无法发起预付申请');
+ return;
+ }
+ const contractIds = new Set(this.selection.map(row => String(row.contractId)));
+ if (contractIds.size > 1) {
+ this.$message.warning('预付申请只能选择同一合同下的预结算单');
+ return;
+ }
if (
- row.approvalStatus !== 'approved' ||
- row.settlementType !== 'payable' ||
- row.formalSettlementNo
+ this.selection.some(
+ row =>
+ row.approvalStatus !== 'approved' ||
+ row.settlementType !== 'payable' ||
+ row.formalSettlementNo
+ )
) {
this.$message.warning('仅审批通过、未转正式结算的应付预结算单可发起预付');
return;
}
- this.advanceDialog.row = row;
- this.advanceDialog.visible = true;
- this.advanceForm = { appliedAmount: null, kingdeeAdvanceNo: '' };
- this.$nextTick(() => this.$refs.advanceFormRef?.clearValidate());
- },
- async submitAdvance() {
- await this.$refs.advanceFormRef?.validate();
- this.advanceDialog.submitting = true;
- try {
- await applyAdvance({
- preSettlementId: this.advanceDialog.row.id,
- appliedAmount: this.advanceForm.appliedAmount,
- kingdeeAdvanceNo: this.advanceForm.kingdeeAdvanceNo,
- });
- this.$message.success('预付申请提交成功');
- this.advanceDialog.visible = false;
- this.loadTable();
- } finally {
- this.advanceDialog.submitting = false;
- }
+ const sourcePreSettlements = this.selection.map(row => ({
+ ...row,
+ preSettlementId: row.preSettlementId || row.id,
+ }));
+ const transferToken = createSettlementTransfer({
+ sourcePreSettlements,
+ });
+ this.$router.push({
+ path: '/payment/payment-application/form',
+ query: {
+ mode: 'add',
+ transferToken,
+ preSettlementIds: sourcePreSettlements
+ .map(row => row.preSettlementId)
+ .filter(Boolean)
+ .join(','),
+ },
+ });
},
handleFormalSettlement() {
if (!this.selection.length) {
diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue
index 8adc03d..c807799 100644
--- a/src/views/vehicle/customer-archive.vue
+++ b/src/views/vehicle/customer-archive.vue
@@ -170,7 +170,7 @@
:disabled="readonly"
class="archive-form dialog-form-label-fixed"
>
-
+