1、调整业务模块
This commit is contained in:
@@ -400,7 +400,7 @@
|
||||
<div class="formal-editor__links">
|
||||
<el-link type="primary" @click="viewInvoiceAttachment(row)">查看</el-link>
|
||||
<el-link type="primary" @click="downloadInvoiceAttachment(row)">下载</el-link>
|
||||
<el-link type="danger" @click="removeInvoice($index)">删除</el-link>
|
||||
<el-link v-if="editable" type="danger" @click="removeInvoice($index)">删除</el-link>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -456,6 +456,9 @@
|
||||
<el-table-column prop="paymentTypeName" label="付款类型" min-width="120" align="center">
|
||||
<template #default="{ row }">{{ displayValue(row.paymentTypeName) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="付款方式" min-width="140" align="center">
|
||||
<template #default="{ row }">{{ paymentMethodName(row.paymentMethod) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paymentNo" label="单据号" min-width="160" align="center" />
|
||||
<el-table-column prop="appliedAmount" label="申请付款金额" min-width="145" align="center">
|
||||
<template #default="{ row }">{{ formatMoney(row.appliedAmount) }}</template>
|
||||
@@ -1784,6 +1787,14 @@ export default {
|
||||
displayValue(value) {
|
||||
return value === null || value === undefined || value === '' ? '-' : value;
|
||||
},
|
||||
paymentMethodName(value) {
|
||||
const labels = {
|
||||
bank_transfer: '银行转账',
|
||||
bank_draft: '银行承兑汇票',
|
||||
commercial_draft: '商业承兑汇票',
|
||||
};
|
||||
return this.displayValue(labels[value] || value);
|
||||
},
|
||||
unwrapData(response) {
|
||||
const body = response?.data || response || {};
|
||||
return body?.data || body;
|
||||
|
||||
@@ -121,7 +121,9 @@
|
||||
/>
|
||||
</el-select>
|
||||
<el-input-number
|
||||
v-else-if="editable && column.prop === 'adjustAmount'"
|
||||
v-else-if="
|
||||
editable && column.prop === 'adjustAmount' && Number(row.manualFlag) === 1
|
||||
"
|
||||
v-model="row.adjustAmount"
|
||||
:class="{
|
||||
'pre-settlement-editor__negative-amount': Number(row.adjustAmount || 0) < 0,
|
||||
@@ -671,6 +673,20 @@
|
||||
<el-table-column type="index" label="序号" width="64" fixed="left" align="center" />
|
||||
<el-table-column prop="cargoName" label="货物名称" min-width="140" align="center" />
|
||||
<el-table-column prop="cargoType" label="货物类型" min-width="130" align="center" />
|
||||
<el-table-column label="计费规则" min-width="190" align="center">
|
||||
<template #default="{ row }">
|
||||
<div class="pre-settlement-editor__billing-rule-cell">
|
||||
<span>{{ displayValue(billingRuleName(row)) }}</span>
|
||||
<el-icon
|
||||
class="pre-settlement-editor__billing-rule-icon"
|
||||
title="查看计费规则详情"
|
||||
@click="openBillingRuleInfo(row)"
|
||||
>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="运输总量" min-width="150" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="adjustDialog.readonly">{{ formatQuantity(row) }}</span>
|
||||
@@ -705,18 +721,6 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="运费" min-width="140" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
v-model="row.freightAmount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:controls="false"
|
||||
:disabled="adjustDialog.readonly"
|
||||
@change="recalculateAdjustRow(row, 'freight')"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="feeItem in adjustFeeItemNames"
|
||||
:key="feeItem"
|
||||
@@ -774,10 +778,76 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="billingRuleDialog.visible"
|
||||
title="计费规则详情"
|
||||
width="720px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<template v-if="billingRuleDialog.rule">
|
||||
<div class="dialog-section-title">计费规则</div>
|
||||
<el-descriptions :column="2" border class="pre-settlement-editor__billing-rule-detail">
|
||||
<el-descriptions-item label="规则名称">
|
||||
{{ displayValue(billingRuleDialog.rule.name) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="费用类型">
|
||||
{{ displayValue(billingRuleDialog.rule.feeType) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="费用项">
|
||||
{{ displayValue(billingRuleDialog.rule.feeItem) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="计费要素">
|
||||
{{ displayValue(billingRuleDialog.rule.billingElement) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="计费类型">
|
||||
{{ displayValue(billingRuleDialog.rule.billingType) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="计费单位">
|
||||
{{ displayValue(billingRuleDialog.rule.billingUnit) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="单价">
|
||||
{{ displayValue(billingRuleDialog.rule.unitPrice) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最低计费量">
|
||||
{{ displayValue(billingRuleDialog.rule.minimumBillingWeight) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="计费区间">
|
||||
{{ billingRuleRanges(billingRuleDialog.rule) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">
|
||||
{{ displayValue(billingRuleDialog.rule.remark) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div class="dialog-section-title pre-settlement-editor__billing-rule-match-title">
|
||||
匹配条件
|
||||
</div>
|
||||
<el-descriptions :column="2" border class="pre-settlement-editor__billing-rule-detail">
|
||||
<el-descriptions-item label="起运地">
|
||||
{{ displayValue(billingRuleDialog.rule.matchCondition.origin) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="目的地">
|
||||
{{ displayValue(billingRuleDialog.rule.matchCondition.destination) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="运输方式">
|
||||
{{ displayValue(billingRuleDialog.rule.matchCondition.transportMode) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="货物类型">
|
||||
{{ displayValue(billingRuleDialog.rule.matchCondition.cargoType) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
<el-empty v-else description="暂无计费规则详情" />
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="billingRuleDialog.visible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { InfoFilled } from '@element-plus/icons-vue';
|
||||
import {
|
||||
adjustDetail,
|
||||
getCandidateDetails,
|
||||
@@ -814,6 +884,7 @@ import * as XLSX from 'xlsx';
|
||||
|
||||
export default {
|
||||
name: 'PreSettlementEditor',
|
||||
components: { InfoFilled },
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
@@ -835,6 +906,10 @@ export default {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
deferSave: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'success'],
|
||||
data() {
|
||||
@@ -936,6 +1011,10 @@ export default {
|
||||
reason: '',
|
||||
},
|
||||
adjustRows: [],
|
||||
billingRuleDialog: {
|
||||
visible: false,
|
||||
rule: null,
|
||||
},
|
||||
attachmentFileTypes: [
|
||||
'pdf',
|
||||
'bmp',
|
||||
@@ -1146,6 +1225,9 @@ export default {
|
||||
this.changeRecords = [];
|
||||
this.attachments = [];
|
||||
this.selectedAttachmentRows = [];
|
||||
this.adjustRows = [];
|
||||
this.billingRuleDialog.visible = false;
|
||||
this.billingRuleDialog.rule = null;
|
||||
this.contractOptions = [];
|
||||
this.contractDialog.visible = false;
|
||||
this.contractDialog.expanded = false;
|
||||
@@ -1421,6 +1503,7 @@ export default {
|
||||
this.summaryFees.splice(index, 1);
|
||||
},
|
||||
recalculateSummaryRow(row) {
|
||||
if (Number(row.manualFlag) !== 1) return;
|
||||
row.settlementAmount = Number(row.originalAmount || 0) + Number(row.adjustAmount || 0);
|
||||
},
|
||||
buildSummaryFeesFromDetails() {
|
||||
@@ -1548,6 +1631,13 @@ export default {
|
||||
}
|
||||
});
|
||||
this.candidateDialog.confirming = true;
|
||||
if (this.deferSave) {
|
||||
this.buildSummaryFeesFromDetails();
|
||||
this.candidateDialog.visible = false;
|
||||
this.candidateDialog.confirming = false;
|
||||
this.$message.success('结算明细添加成功,请点击保存提交');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { data } = await save(this.buildSavePayload());
|
||||
this.form.id = data?.data || this.form.id;
|
||||
@@ -1588,6 +1678,10 @@ export default {
|
||||
const isPersistedDetail =
|
||||
row.id && sourceDetailId && String(row.id) !== String(sourceDetailId);
|
||||
if (isPersistedDetail) return row;
|
||||
if (this.deferSave) {
|
||||
this.$message.warning('请先保存预结算单后再调整结算明细');
|
||||
return null;
|
||||
}
|
||||
|
||||
await this.$refs.formRef?.validate();
|
||||
this.loading = true;
|
||||
@@ -1621,11 +1715,97 @@ export default {
|
||||
this.adjustRows = (data?.data || []).map(item => ({
|
||||
...item,
|
||||
feeItems: this.parseFeeItems(item.feeItemsJson),
|
||||
billingRule: this.normalizeBillingRule(item),
|
||||
}));
|
||||
} finally {
|
||||
this.adjustDialog.loading = false;
|
||||
}
|
||||
},
|
||||
billingRuleName(row) {
|
||||
return this.normalizeBillingRule(row).name;
|
||||
},
|
||||
openBillingRuleInfo(row) {
|
||||
this.billingRuleDialog.rule = this.normalizeBillingRule(row);
|
||||
this.billingRuleDialog.visible = true;
|
||||
},
|
||||
normalizeBillingRule(row) {
|
||||
const source = row || {};
|
||||
const nested = [
|
||||
source.billingRule,
|
||||
source.billingRuleInfo,
|
||||
source.billingRuleJson,
|
||||
source.billingRulesJson,
|
||||
source.billingRules,
|
||||
source.billingPlanRule,
|
||||
source.feeRule,
|
||||
source.rule,
|
||||
].find(value => value !== undefined && value !== null && value !== '');
|
||||
const parsedNested = this.parseJsonValue(nested);
|
||||
const matchedRules = Array.isArray(parsedNested)
|
||||
? parsedNested.filter(item => item && typeof item === 'object')
|
||||
: [];
|
||||
let rule = this.parseObject(matchedRules[0] || parsedNested || nested);
|
||||
if (!Object.keys(rule).length && typeof nested === 'string') rule = { name: nested };
|
||||
const matchCondition = this.parseObject(
|
||||
source.matchCondition ?? source.billingMatchCondition ?? rule.matchCondition
|
||||
);
|
||||
const ruleNames = matchedRules
|
||||
.map(item => item.ruleName || item.name || item.billingRuleName || item.feeItem)
|
||||
.filter(Boolean);
|
||||
const name =
|
||||
source.billingRuleName ||
|
||||
source.feeRuleName ||
|
||||
source.ruleName ||
|
||||
source.billingPlanRuleName ||
|
||||
source.billingPlanName ||
|
||||
rule.name ||
|
||||
rule.ruleName ||
|
||||
rule.billingRuleName ||
|
||||
rule.planName ||
|
||||
rule.billingPlanName ||
|
||||
ruleNames.join('、') ||
|
||||
rule.feeItem ||
|
||||
'';
|
||||
return {
|
||||
...rule,
|
||||
name,
|
||||
feeType: source.billingFeeType || source.feeType || rule.feeType,
|
||||
feeItem: source.billingFeeItem || source.feeItem || rule.feeItem,
|
||||
billingElement:
|
||||
source.billingElement ||
|
||||
source.billingFactor ||
|
||||
rule.billingElement ||
|
||||
rule.billingFactor,
|
||||
billingType: source.billingType || rule.billingType,
|
||||
billingUnit: source.billingUnit || source.priceUnit || rule.billingUnit || rule.priceUnit,
|
||||
unitPrice: source.billingUnitPrice ?? source.unitPrice ?? rule.unitPrice,
|
||||
minimumBillingWeight:
|
||||
source.minimumBillingWeight ?? rule.minimumBillingWeight ?? rule.lowerLimit,
|
||||
remark: source.billingRuleRemark || source.ruleRemark || rule.remark,
|
||||
rules: matchedRules,
|
||||
matchCondition: {
|
||||
...matchCondition,
|
||||
origin: matchCondition.origin || matchCondition.originName,
|
||||
destination: matchCondition.destination || matchCondition.destinationName,
|
||||
transportMode: matchCondition.transportMode || matchCondition.transportType,
|
||||
cargoType: matchCondition.cargoType || matchCondition.cargoTypeName,
|
||||
},
|
||||
};
|
||||
},
|
||||
billingRuleRanges(rule) {
|
||||
const ranges = Array.isArray(rule?.limitRanges) ? rule.limitRanges : [];
|
||||
if (ranges.length) {
|
||||
return ranges
|
||||
.map(
|
||||
item => `${item.lowerLimit ?? '-'}~${item.upperLimit ?? '-'}:${item.unitPrice ?? '-'}`
|
||||
)
|
||||
.join(';');
|
||||
}
|
||||
if (rule?.lowerLimit !== undefined || rule?.upperLimit !== undefined) {
|
||||
return `${rule.lowerLimit ?? '-'}~${rule.upperLimit ?? '-'}`;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
recalculateAdjustRow(row, changedField) {
|
||||
if (changedField && changedField !== 'freight' && this.isFreightFeeItem(changedField)) {
|
||||
row.freightAmount = Number(row.feeItems[changedField] || 0);
|
||||
@@ -1797,6 +1977,25 @@ export default {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
parseObject(value) {
|
||||
if (!value) return {};
|
||||
if (typeof value === 'object' && !Array.isArray(value)) return { ...value };
|
||||
if (typeof value !== 'string') return {};
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
parseJsonValue(value) {
|
||||
if (typeof value !== 'string') return value;
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (error) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
formatMoney(value, currency = 'RMB') {
|
||||
if (value === undefined || value === null || value === '') return '-';
|
||||
const amount = Number(value);
|
||||
@@ -1983,6 +2182,28 @@ export default {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
&__billing-rule-cell {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&__billing-rule-icon {
|
||||
flex: 0 0 auto;
|
||||
color: var(--el-color-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__billing-rule-detail {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
&__billing-rule-match-title {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.form-readonly {
|
||||
min-height: 32px;
|
||||
line-height: 32px;
|
||||
|
||||
Reference in New Issue
Block a user