Merge remote-tracking branch 'websoft/dev'
This commit is contained in:
@@ -66,7 +66,7 @@
|
|||||||
## 表单 / 自检 / 导出
|
## 表单 / 自检 / 导出
|
||||||
- placeholder 只写 `请输入`/`请选择`;例外:`请输入或选择车辆`、日期区间 `起`/`止`、示例值。校验 message 须带字段名。
|
- placeholder 只写 `请输入`/`请选择`;例外:`请输入或选择车辆`、日期区间 `起`/`止`、示例值。校验 message 须带字段名。
|
||||||
- `business-crud-page.vue`:option 经 `cloneOption` 克隆,独立表单页走 `PageAvueForm`。
|
- `business-crud-page.vue`:option 经 `cloneOption` 克隆,独立表单页走 `PageAvueForm`。
|
||||||
- 自检:`curl "localhost:2889/src/xxx.vue"` 与 `"...?vue&type=style&index=0&scoped=true&lang.scss"`(200 / 500)。`vite build` 在 `facelogin.vue` 被沙箱中断,不能作唯一校验。dev `VITE_APP_API=/api` 代理 `172.16.203.228:8000`。
|
- 自检:`curl "localhost:2888/src/xxx.vue"` 与 `"...?vue&type=style&index=0&scoped=true&lang.scss"`(200 / 500)。`vite build` 在 `facelogin.vue` 被沙箱中断,不能作唯一校验。dev `VITE_APP_API=/api` 代理 `172.16.203.228:8000`。
|
||||||
- 导出:前端 `exportColumns` 后端未用,以 `XxxExportExcel.java` 为准;BladeX `BeanUtil` 类型不兼容静默跳过(`Date` → `LocalDateTime` 丢值,用 `DateUtil.fromDate`)。
|
- 导出:前端 `exportColumns` 后端未用,以 `XxxExportExcel.java` 为准;BladeX `BeanUtil` 类型不兼容静默跳过(`Date` → `LocalDateTime` 丢值,用 `DateUtil.fromDate`)。
|
||||||
|
|
||||||
## Element Plus 图标两种用法的机制差异(易误判)
|
## Element Plus 图标两种用法的机制差异(易误判)
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ export const getContractList = (current, size, params) =>
|
|||||||
|
|
||||||
export const getFeeOptions = () => request({ url: `${baseUrl}/fee-options`, method: 'get' });
|
export const getFeeOptions = () => request({ url: `${baseUrl}/fee-options`, method: 'get' });
|
||||||
|
|
||||||
|
export const getNextNo = () => request({ url: `${baseUrl}/next-no`, method: 'get' });
|
||||||
|
|
||||||
export const getCandidateDetails = (current, size, params) =>
|
export const getCandidateDetails = (current, size, params) =>
|
||||||
request({
|
request({
|
||||||
url: `${baseUrl}/candidate-details`,
|
url: `${baseUrl}/candidate-details`,
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ export const sourceColumns = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const detailColumns = [
|
export const detailColumns = [
|
||||||
{ label: '单据号', prop: 'documentNo', minWidth: 180 },
|
{ label: '单据号', prop: 'documentNo', minWidth: 180, link: true },
|
||||||
{ label: '运单号', prop: 'waybillNo', minWidth: 160 },
|
{ label: '运单号', prop: 'waybillNo', minWidth: 160, link: true },
|
||||||
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
||||||
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
||||||
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export const settlementSummaryColumns = [
|
|||||||
|
|
||||||
export const settlementDetailColumns = [
|
export const settlementDetailColumns = [
|
||||||
{ label: '单据号', prop: 'documentNo', minWidth: 180, link: true },
|
{ label: '单据号', prop: 'documentNo', minWidth: 180, link: true },
|
||||||
{ label: '运单号', prop: 'waybillNo', minWidth: 160 },
|
{ label: '运单号', prop: 'waybillNo', minWidth: 160, link: true },
|
||||||
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
{ label: '车号', prop: 'vehicleNo', minWidth: 130 },
|
||||||
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
{ label: '发货地址', prop: 'departureAddress', minWidth: 180 },
|
||||||
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
{ label: '到货地址', prop: 'arrivalAddress', minWidth: 180 },
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { getList as getReceivablePayableDetailList } from '@/api/settlement/receivable-payable-detail';
|
||||||
|
import { getList as getWaybillList } from '@/api/business/waybill-manage';
|
||||||
|
|
||||||
|
// 结算明细的「单据号」是应收应付明细单据号(应收 YS…/应付 YF…),按结算类型落到对应菜单页
|
||||||
|
const SETTLEMENT_DETAIL_PATHS = {
|
||||||
|
receivable: '/settlement/receivable-detail',
|
||||||
|
payable: '/settlement/payable-detail',
|
||||||
|
};
|
||||||
|
|
||||||
|
const unwrapPage = response => {
|
||||||
|
const body = response?.data || response || {};
|
||||||
|
return body?.data || body;
|
||||||
|
};
|
||||||
|
|
||||||
|
const firstRecordId = data => (Array.isArray(data) ? data : data?.records || [])[0]?.id || '';
|
||||||
|
|
||||||
|
export const settlementDetailPath = settlementType =>
|
||||||
|
SETTLEMENT_DETAIL_PATHS[settlementType] || SETTLEMENT_DETAIL_PATHS.payable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算明细行「单据号」对应的应收应付明细ID:已落库的明细自带 sourceDetailId,未落库的行按单据号回查。
|
||||||
|
*/
|
||||||
|
export const resolveReceivablePayableDetailId = async (row = {}, settlementType) => {
|
||||||
|
if (row.sourceDetailId) return row.sourceDetailId;
|
||||||
|
if (!row.documentNo) return '';
|
||||||
|
try {
|
||||||
|
const data = unwrapPage(
|
||||||
|
await getReceivablePayableDetailList(1, 1, {
|
||||||
|
documentNo: row.documentNo,
|
||||||
|
settlementType,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return firstRecordId(data);
|
||||||
|
} catch (error) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算明细行「运单号」对应的运单ID:总单来源的明细没有 waybillId(运单号列存的是总单号),按运单号回查。
|
||||||
|
*/
|
||||||
|
export const resolveWaybillId = async (row = {}) => {
|
||||||
|
if (row.waybillId) return row.waybillId;
|
||||||
|
if (!row.waybillNo) return '';
|
||||||
|
try {
|
||||||
|
const data = unwrapPage(await getWaybillList(1, 1, { waybillNo: row.waybillNo }));
|
||||||
|
return firstRecordId(data);
|
||||||
|
} catch (error) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
<p>{{ timeRange(row) }}</p>
|
<p>{{ timeRange(row) }}</p>
|
||||||
<p>{{ goodsSummary(row) }}</p>
|
<p>{{ goodsSummary(row) }}</p>
|
||||||
<p>创建人:{{ row.createUserName || '-' }}</p>
|
<p>创建人:{{ row.createUserName || '-' }}</p>
|
||||||
<p>创建时间:{{ row.createTime || '-' }}</p>
|
<p>创建时间:{{ formatDate(row.createTime) }}</p>
|
||||||
</section>
|
</section>
|
||||||
<section class="route-progress">
|
<section class="route-progress">
|
||||||
<div class="route-track">
|
<div class="route-track">
|
||||||
@@ -155,6 +155,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as api from '@/api/business/master-order';
|
import * as api from '@/api/business/master-order';
|
||||||
|
import { splitRegionTokens } from '@/utils/region-address';
|
||||||
import TableHeaderTools from '@/components/table-header-tools/main.vue';
|
import TableHeaderTools from '@/components/table-header-tools/main.vue';
|
||||||
import MasterOrderEditor from './components/master-order-editor.vue';
|
import MasterOrderEditor from './components/master-order-editor.vue';
|
||||||
import MasterOrderDispatch from './components/master-order-dispatch.vue';
|
import MasterOrderDispatch from './components/master-order-dispatch.vue';
|
||||||
@@ -332,6 +333,10 @@ export default {
|
|||||||
? `${String(row.planStartTime).slice(0, 10)} - ${String(row.planEndTime).slice(0, 10)}`
|
? `${String(row.planStartTime).slice(0, 10)} - ${String(row.planEndTime).slice(0, 10)}`
|
||||||
: '-';
|
: '-';
|
||||||
},
|
},
|
||||||
|
// 创建时间只展示日期。
|
||||||
|
formatDate(value) {
|
||||||
|
return value ? String(value).slice(0, 10) : '-';
|
||||||
|
},
|
||||||
goodsSummary(row) {
|
goodsSummary(row) {
|
||||||
const item = (row.goods || [])[0] || {};
|
const item = (row.goods || [])[0] || {};
|
||||||
if (!item.cargoName && !item.cargoType) return '-';
|
if (!item.cargoName && !item.cargoType) return '-';
|
||||||
@@ -391,6 +396,26 @@ export default {
|
|||||||
}`;
|
}`;
|
||||||
return `${city} ${district}`;
|
return `${city} ${district}`;
|
||||||
},
|
},
|
||||||
|
// 悬停气泡里的地址:起讫点若只保存了名称或详细地址的一半,气泡就会显示成
|
||||||
|
// “柳南区”“安徽”这类残缺地址,故把两个字段互为补充后展示。
|
||||||
|
completeAddress(name, address) {
|
||||||
|
const rawName = String(name || '').trim();
|
||||||
|
const rawAddress = String(address || '').trim();
|
||||||
|
if (!rawName) return rawAddress;
|
||||||
|
if (!rawAddress) return rawName;
|
||||||
|
// 详细地址已含省市,本身就是完整地址,不再拼接名称,避免重复卡片上已有的站点名。
|
||||||
|
if (/(?:省|自治区|特别行政区|市)/.test(rawAddress)) return rawAddress;
|
||||||
|
const normalizedName = rawName.replace(/\s+/g, '');
|
||||||
|
const normalizedAddress = rawAddress.replace(/\s+/g, '');
|
||||||
|
if (normalizedAddress.includes(normalizedName)) return rawAddress;
|
||||||
|
if (normalizedName.includes(normalizedAddress)) return rawName;
|
||||||
|
// “珠海1号港口”与“珠海港口1号”这类同字异序写法只保留一个。
|
||||||
|
if ([...normalizedName].sort().join('') === [...normalizedAddress].sort().join('')) {
|
||||||
|
return normalizedName.length >= normalizedAddress.length ? rawName : rawAddress;
|
||||||
|
}
|
||||||
|
// 区域在前、详细地址在后。
|
||||||
|
return splitRegionTokens(rawName) ? `${rawName}${rawAddress}` : `${rawAddress}${rawName}`;
|
||||||
|
},
|
||||||
routeNodeName(value, address, transportType, region = {}) {
|
routeNodeName(value, address, transportType, region = {}) {
|
||||||
const text = String(value || '').trim();
|
const text = String(value || '').trim();
|
||||||
if (!text) return '-';
|
if (!text) return '-';
|
||||||
@@ -457,15 +482,12 @@ export default {
|
|||||||
if (this.isStationLikeName(rawAddress) && !this.isStationLikeName(rawName)) {
|
if (this.isStationLikeName(rawAddress) && !this.isStationLikeName(rawName)) {
|
||||||
return {
|
return {
|
||||||
name: rawAddress,
|
name: rawAddress,
|
||||||
address: rawName || regionText || rawAddress,
|
address: this.completeAddress(rawName, rawAddress) || regionText || rawAddress,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const displayName = rawName || rawAddress || '-';
|
const displayName = rawName || rawAddress || '-';
|
||||||
const tipAddress =
|
const tipAddress =
|
||||||
(rawAddress && rawAddress !== displayName ? rawAddress : '') ||
|
this.completeAddress(rawName, rawAddress) || regionText || rawAddress || displayName;
|
||||||
regionText ||
|
|
||||||
rawAddress ||
|
|
||||||
displayName;
|
|
||||||
return { name: displayName, address: tipAddress };
|
return { name: displayName, address: tipAddress };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -475,7 +497,7 @@ export default {
|
|||||||
siteCode,
|
siteCode,
|
||||||
nextTransportType,
|
nextTransportType,
|
||||||
}),
|
}),
|
||||||
address: rawAddress || rawName || regionText || '-',
|
address: this.completeAddress(rawName, rawAddress) || regionText || '-',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
routeNodes(row = {}) {
|
routeNodes(row = {}) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
label-width="auto"
|
label-width="auto"
|
||||||
>
|
>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col v-for="field in fields" :key="field.prop" :span="6">
|
<el-col v-for="field in visibleFields" :key="field.prop" :span="6">
|
||||||
<el-form-item :label="field.label" :prop="field.prop">
|
<el-form-item :label="field.label" :prop="field.prop">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-if="field.type === 'date' && editable"
|
v-if="field.type === 'date' && editable"
|
||||||
@@ -64,6 +64,12 @@
|
|||||||
:precision="2"
|
:precision="2"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
/>
|
/>
|
||||||
|
<span
|
||||||
|
v-else-if="field.prop === 'formalSettlementNo'"
|
||||||
|
:class="{ 'form-readonly--code': form.formalSettlementNo }"
|
||||||
|
>
|
||||||
|
{{ form.formalSettlementNo || (form.id ? '-' : '系统自动生成') }}
|
||||||
|
</span>
|
||||||
<span v-else-if="field.money">{{ formatMoney(form[field.prop]) }}</span>
|
<span v-else-if="field.money">{{ formatMoney(form[field.prop]) }}</span>
|
||||||
<span v-else-if="field.type === 'contract'">{{
|
<span v-else-if="field.type === 'contract'">{{
|
||||||
displayValue(form.contractName)
|
displayValue(form.contractName)
|
||||||
@@ -253,7 +259,14 @@
|
|||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
>
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span v-if="column.money">{{ formatMoney(row[column.prop]) }}</span>
|
<el-link
|
||||||
|
v-if="column.link && row[column.prop] && !publicMode"
|
||||||
|
type="primary"
|
||||||
|
@click.stop="handleDetailLink(row, column)"
|
||||||
|
>
|
||||||
|
{{ row[column.prop] }}
|
||||||
|
</el-link>
|
||||||
|
<span v-else-if="column.money">{{ formatMoney(row[column.prop]) }}</span>
|
||||||
<span v-else-if="column.prop === 'transportQuantity'">
|
<span v-else-if="column.prop === 'transportQuantity'">
|
||||||
{{ formatDetailTransportQuantity(row[column.prop]) }}
|
{{ formatDetailTransportQuantity(row[column.prop]) }}
|
||||||
</span>
|
</span>
|
||||||
@@ -997,6 +1010,11 @@ import {
|
|||||||
getDetailFees as getPreSettlementDetailFees,
|
getDetailFees as getPreSettlementDetailFees,
|
||||||
} from '@/api/settlement/preSettlement';
|
} from '@/api/settlement/preSettlement';
|
||||||
import { calculateAdjustedFee, getFeeDetail } from '@/api/settlement/receivable-payable-detail';
|
import { calculateAdjustedFee, getFeeDetail } from '@/api/settlement/receivable-payable-detail';
|
||||||
|
import {
|
||||||
|
resolveReceivablePayableDetailId,
|
||||||
|
resolveWaybillId,
|
||||||
|
settlementDetailPath,
|
||||||
|
} from '@/utils/settlement-detail-link';
|
||||||
import { getBfiExchangeRate } from '@/api/base/currency';
|
import { getBfiExchangeRate } from '@/api/base/currency';
|
||||||
import {
|
import {
|
||||||
createFormalSettlementForm,
|
createFormalSettlementForm,
|
||||||
@@ -1014,6 +1032,7 @@ import { h } from 'vue';
|
|||||||
import { InfoFilled } from '@element-plus/icons-vue';
|
import { InfoFilled } from '@element-plus/icons-vue';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { formatContractOptionLabel } from '@/utils/contract';
|
import { formatContractOptionLabel } from '@/utils/contract';
|
||||||
|
import { normalizeCurrencyCode } from '@/utils/currency';
|
||||||
import { downloadFileByUrl } from '@/utils/util';
|
import { downloadFileByUrl } from '@/utils/util';
|
||||||
import {
|
import {
|
||||||
downloadKingdeeInvoiceFile,
|
downloadKingdeeInvoiceFile,
|
||||||
@@ -1025,6 +1044,9 @@ import ProjectAdvanceWriteOff from './project-advance-write-off.vue';
|
|||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
import { isAdministrator } from '@/utils/auth';
|
import { isAdministrator } from '@/utils/auth';
|
||||||
|
|
||||||
|
// 结算币种为本位币(人民币)时汇率恒为1,汇率日期、结算汇率与按汇率换算的本位币合计都不展示
|
||||||
|
const LOCAL_CURRENCY_HIDDEN_FIELDS = ['exchangeRateDate', 'exchangeRate', 'localSettlementAmount'];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FormalSettlementEditor',
|
name: 'FormalSettlementEditor',
|
||||||
components: { InfoFilled, KingdeeInvoicePoolDialog, ProjectAdvanceWriteOff },
|
components: { InfoFilled, KingdeeInvoicePoolDialog, ProjectAdvanceWriteOff },
|
||||||
@@ -1195,6 +1217,14 @@ export default {
|
|||||||
title() {
|
title() {
|
||||||
return this.readonly ? '查看正式结算单' : this.recordId ? '编辑正式结算单' : '新增正式结算单';
|
return this.readonly ? '查看正式结算单' : this.recordId ? '编辑正式结算单' : '新增正式结算单';
|
||||||
},
|
},
|
||||||
|
// 币种为空按人民币处理,与后端预结算/正式结算对空币种的默认取值一致
|
||||||
|
isLocalCurrencySettlement() {
|
||||||
|
return normalizeCurrencyCode(this.form.currency) === 'RMB';
|
||||||
|
},
|
||||||
|
visibleFields() {
|
||||||
|
if (!this.isLocalCurrencySettlement) return this.fields;
|
||||||
|
return this.fields.filter(field => !LOCAL_CURRENCY_HIDDEN_FIELDS.includes(field.prop));
|
||||||
|
},
|
||||||
summaryTotal() {
|
summaryTotal() {
|
||||||
return this.summaryFees.reduce((total, row) => total + Number(row.settlementAmount || 0), 0);
|
return this.summaryFees.reduce((total, row) => total + Number(row.settlementAmount || 0), 0);
|
||||||
},
|
},
|
||||||
@@ -2051,6 +2081,21 @@ export default {
|
|||||||
this.appliedDetailQuery = { ...this.detailQuery };
|
this.appliedDetailQuery = { ...this.detailQuery };
|
||||||
this.detailPage.current = 1;
|
this.detailPage.current = 1;
|
||||||
},
|
},
|
||||||
|
// 结算明细的「单据号」跳到该应收应付单据在应收明细/应付明细页的详情,「运单号」跳到运单详情
|
||||||
|
async handleDetailLink(row, column) {
|
||||||
|
if (column.prop === 'documentNo') {
|
||||||
|
const settlementType = row.settlementType || this.form.settlementType || 'payable';
|
||||||
|
const detailId = await resolveReceivablePayableDetailId(row, settlementType);
|
||||||
|
if (!detailId) return this.$message.info('当前记录未找到对应的应收/应付明细');
|
||||||
|
this.$router.push({ path: settlementDetailPath(settlementType), query: { detailId } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (column.prop === 'waybillNo') {
|
||||||
|
const waybillId = await resolveWaybillId(row);
|
||||||
|
if (!waybillId) return this.$message.info('当前记录未找到对应的运单详情');
|
||||||
|
this.$router.push({ path: '/business/waybill-manage/detail', query: { id: waybillId } });
|
||||||
|
}
|
||||||
|
},
|
||||||
resetDetailQuery(apply = true) {
|
resetDetailQuery(apply = true) {
|
||||||
this.detailQuery = { documentNo: '', waybillNo: '', batchNo: '', cargoName: '' };
|
this.detailQuery = { documentNo: '', waybillNo: '', batchNo: '', cargoName: '' };
|
||||||
if (apply) this.handleDetailQuery();
|
if (apply) this.handleDetailQuery();
|
||||||
@@ -2891,6 +2936,9 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.form-readonly--code {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
.formal-editor--page {
|
.formal-editor--page {
|
||||||
padding-bottom: 72px;
|
padding-bottom: 72px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
class="pre-settlement-editor__form"
|
class="pre-settlement-editor__form"
|
||||||
>
|
>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col v-for="field in formFields" :key="field.prop" :span="field.span || 6">
|
<el-col v-for="field in visibleFormFields" :key="field.prop" :span="field.span || 6">
|
||||||
<el-form-item :label="field.label" :prop="field.prop">
|
<el-form-item :label="field.label" :prop="field.prop">
|
||||||
<el-input
|
<el-input
|
||||||
v-if="field.type === 'contract'"
|
v-if="field.type === 'contract'"
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
type="date"
|
type="date"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
||||||
:disabled="!editable || form.currency === 'RMB'"
|
:disabled="!editable"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@change="handleExchangeRateDateChange"
|
@change="handleExchangeRateDateChange"
|
||||||
/>
|
/>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
:min="0"
|
:min="0"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
:disabled="!editable || form.currency === 'RMB'"
|
:disabled="!editable"
|
||||||
@change="recalculateLocalAmount"
|
@change="recalculateLocalAmount"
|
||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
@@ -66,7 +66,11 @@
|
|||||||
<span v-else-if="field.prop === 'settlementType'" class="form-readonly">
|
<span v-else-if="field.prop === 'settlementType'" class="form-readonly">
|
||||||
{{ settlementTypeName }}
|
{{ settlementTypeName }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="field.prop === 'preSettlementNo'" class="form-readonly">
|
<span
|
||||||
|
v-else-if="field.prop === 'preSettlementNo'"
|
||||||
|
class="form-readonly"
|
||||||
|
:class="{ 'form-readonly--code': form.preSettlementNo }"
|
||||||
|
>
|
||||||
{{ form.preSettlementNo || (!form.id ? '系统自动生成' : '-') }}
|
{{ form.preSettlementNo || (!form.id ? '系统自动生成' : '-') }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="field.prop === 'createTime'" class="form-readonly">
|
<span v-else-if="field.prop === 'createTime'" class="form-readonly">
|
||||||
@@ -253,9 +257,9 @@
|
|||||||
>
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-link
|
<el-link
|
||||||
v-if="column.link && row[column.prop]"
|
v-if="column.link && row[column.prop] && !publicMode"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="openAdjustDialog(row, true)"
|
@click.stop="handleDetailLink(row, column)"
|
||||||
>
|
>
|
||||||
{{ row[column.prop] }}
|
{{ row[column.prop] }}
|
||||||
</el-link>
|
</el-link>
|
||||||
@@ -955,14 +959,21 @@ import {
|
|||||||
adjustDetail,
|
adjustDetail,
|
||||||
getCandidateDetails,
|
getCandidateDetails,
|
||||||
getContractList,
|
getContractList,
|
||||||
|
getContractOptions,
|
||||||
getDetail,
|
getDetail,
|
||||||
getDetailFees,
|
getDetailFees,
|
||||||
getFeeOptions,
|
getFeeOptions,
|
||||||
|
getNextNo,
|
||||||
removeDetail,
|
removeDetail,
|
||||||
save,
|
save,
|
||||||
submit,
|
submit,
|
||||||
} from '@/api/settlement/preSettlement';
|
} from '@/api/settlement/preSettlement';
|
||||||
import { calculateAdjustedFee, getFeeDetail } from '@/api/settlement/receivable-payable-detail';
|
import { calculateAdjustedFee, getFeeDetail } from '@/api/settlement/receivable-payable-detail';
|
||||||
|
import {
|
||||||
|
resolveReceivablePayableDetailId,
|
||||||
|
resolveWaybillId,
|
||||||
|
settlementDetailPath,
|
||||||
|
} from '@/utils/settlement-detail-link';
|
||||||
import { getBfiExchangeRate } from '@/api/base/currency';
|
import { getBfiExchangeRate } from '@/api/base/currency';
|
||||||
import { getDictionary } from '@/api/system/dictbiz';
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import {
|
import {
|
||||||
@@ -985,11 +996,15 @@ import {
|
|||||||
settlementSummaryColumns,
|
settlementSummaryColumns,
|
||||||
} from '@/option/settlement/preSettlementTable';
|
} from '@/option/settlement/preSettlementTable';
|
||||||
import { formatContractOptionLabel } from '@/utils/contract';
|
import { formatContractOptionLabel } from '@/utils/contract';
|
||||||
|
import { normalizeCurrencyCode } from '@/utils/currency';
|
||||||
import { downloadFileByUrl } from '@/utils/util';
|
import { downloadFileByUrl } from '@/utils/util';
|
||||||
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
import { isAdministrator } from '@/utils/auth';
|
import { isAdministrator } from '@/utils/auth';
|
||||||
|
|
||||||
|
// 结算币种为本位币(人民币)时汇率恒为1,汇率日期、结算汇率与按汇率换算的本位币合计都不展示
|
||||||
|
const LOCAL_CURRENCY_HIDDEN_FIELDS = ['exchangeRateDate', 'exchangeRate', 'localSettlementAmount'];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PreSettlementEditor',
|
name: 'PreSettlementEditor',
|
||||||
components: { InfoFilled, ChangeRecordDetailDialog, ProjectAdvanceWriteOff },
|
components: { InfoFilled, ChangeRecordDetailDialog, ProjectAdvanceWriteOff },
|
||||||
@@ -1200,6 +1215,14 @@ export default {
|
|||||||
settlementTypeName() {
|
settlementTypeName() {
|
||||||
return this.form.settlementType === 'receivable' ? '应收' : '应付';
|
return this.form.settlementType === 'receivable' ? '应收' : '应付';
|
||||||
},
|
},
|
||||||
|
// 币种为空按人民币处理,与后端 normalizeRate 的取默认值一致
|
||||||
|
isLocalCurrencySettlement() {
|
||||||
|
return normalizeCurrencyCode(this.form.currency) === 'RMB';
|
||||||
|
},
|
||||||
|
visibleFormFields() {
|
||||||
|
if (!this.isLocalCurrencySettlement) return this.formFields;
|
||||||
|
return this.formFields.filter(field => !LOCAL_CURRENCY_HIDDEN_FIELDS.includes(field.prop));
|
||||||
|
},
|
||||||
contractDialogCategory() {
|
contractDialogCategory() {
|
||||||
return '承运商合同';
|
return '承运商合同';
|
||||||
},
|
},
|
||||||
@@ -1295,6 +1318,11 @@ export default {
|
|||||||
},
|
},
|
||||||
async initialize() {
|
async initialize() {
|
||||||
this.resetEditor();
|
this.resetEditor();
|
||||||
|
// 新增页在保存前没有创建人/创建日期,先按当前登录用户与当前时间展示将要落库的值
|
||||||
|
if (!this.recordId) {
|
||||||
|
this.form.createUserName = this.userInfo?.realName || this.userInfo?.userName || '';
|
||||||
|
this.form.createTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
}
|
||||||
if (!this.publicMode) {
|
if (!this.publicMode) {
|
||||||
await this.loadFeeOptions();
|
await this.loadFeeOptions();
|
||||||
await this.loadFeeCategoryOptions();
|
await this.loadFeeCategoryOptions();
|
||||||
@@ -1305,15 +1333,36 @@ export default {
|
|||||||
else if (this.initialData) {
|
else if (this.initialData) {
|
||||||
await this.applyInitialData();
|
await this.applyInitialData();
|
||||||
this.form.exchangeRateDate = this.$dayjs().format('YYYY-MM-DD');
|
this.form.exchangeRateDate = this.$dayjs().format('YYYY-MM-DD');
|
||||||
|
await this.refreshPreSettlementNo();
|
||||||
await this.fetchBfiExchangeRate();
|
await this.fetchBfiExchangeRate();
|
||||||
|
} else if (!this.publicMode) {
|
||||||
|
await this.refreshPreSettlementNo();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async refreshPreSettlementNo() {
|
||||||
|
if (this.form.id) return;
|
||||||
|
const response = await getNextNo();
|
||||||
|
this.form.preSettlementNo = response.data?.data || '';
|
||||||
|
},
|
||||||
async applyInitialData() {
|
async applyInitialData() {
|
||||||
const rows = Array.isArray(this.initialData?.rows) ? this.initialData.rows : [];
|
const rows = Array.isArray(this.initialData?.rows) ? this.initialData.rows : [];
|
||||||
if (!rows.length) return;
|
if (!rows.length) return;
|
||||||
const first = rows[0];
|
const first = rows[0];
|
||||||
const settlementType = this.initialData.settlementType || first.settlementType || 'payable';
|
const settlementType = this.initialData.settlementType || first.settlementType || 'payable';
|
||||||
const contractId = first.contractId || '';
|
const contractId = first.contractId || '';
|
||||||
|
let contractPartyA = first.payerName || '';
|
||||||
|
let contractPartyB = first.payeeName || '';
|
||||||
|
if (contractId && (!contractPartyA || !contractPartyB)) {
|
||||||
|
try {
|
||||||
|
const { data } = await getContractOptions(first.contractNo || '');
|
||||||
|
const matched = (data?.data || []).find(item => String(item.id) === String(contractId));
|
||||||
|
contractPartyA = contractPartyA || matched?.partyA || '';
|
||||||
|
contractPartyB = contractPartyB || matched?.partyB || '';
|
||||||
|
} catch (error) {
|
||||||
|
contractPartyA = '';
|
||||||
|
contractPartyB = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!this.contractOptions.some(item => String(item.id) === String(contractId))) {
|
if (!this.contractOptions.some(item => String(item.id) === String(contractId))) {
|
||||||
this.contractOptions.push({
|
this.contractOptions.push({
|
||||||
id: contractId,
|
id: contractId,
|
||||||
@@ -1324,8 +1373,8 @@ export default {
|
|||||||
deptId: first.deptId,
|
deptId: first.deptId,
|
||||||
deptName: first.deptName,
|
deptName: first.deptName,
|
||||||
settlementType,
|
settlementType,
|
||||||
partyA: first.payerName,
|
partyA: contractPartyA,
|
||||||
partyB: first.payeeName,
|
partyB: contractPartyB,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.handleContractChange(contractId);
|
this.handleContractChange(contractId);
|
||||||
@@ -1337,8 +1386,8 @@ export default {
|
|||||||
projectName: first.projectName || this.form.projectName,
|
projectName: first.projectName || this.form.projectName,
|
||||||
deptId: first.deptId || this.form.deptId,
|
deptId: first.deptId || this.form.deptId,
|
||||||
deptName: first.deptName || this.form.deptName,
|
deptName: first.deptName || this.form.deptName,
|
||||||
payerName: first.payerName || this.form.payerName,
|
payerName: this.form.payerName || contractPartyA,
|
||||||
payeeName: first.payeeName || this.form.payeeName,
|
payeeName: this.form.payeeName || contractPartyB,
|
||||||
settlementType,
|
settlementType,
|
||||||
currency: first.currency || 'RMB',
|
currency: first.currency || 'RMB',
|
||||||
localCurrency: first.localCurrency || 'RMB',
|
localCurrency: first.localCurrency || 'RMB',
|
||||||
@@ -1610,8 +1659,9 @@ export default {
|
|||||||
this.form.deptId = contract.deptId;
|
this.form.deptId = contract.deptId;
|
||||||
this.form.deptName = contract.deptName;
|
this.form.deptName = contract.deptName;
|
||||||
this.form.settlementType = contract.settlementType || 'payable';
|
this.form.settlementType = contract.settlementType || 'payable';
|
||||||
this.form.payerName = contract.partyA;
|
// 部分候选合同只带 id/名称,缺甲方乙方;此时保留已带出的收付方,不要清成 undefined
|
||||||
this.form.payeeName = contract.partyB;
|
if (contract.partyA) this.form.payerName = contract.partyA;
|
||||||
|
if (contract.partyB) this.form.payeeName = contract.partyB;
|
||||||
this.form.currency = contract.settlementCurrency || 'RMB';
|
this.form.currency = contract.settlementCurrency || 'RMB';
|
||||||
this.summaryFees = [];
|
this.summaryFees = [];
|
||||||
this.projectAdvanceWriteOffs = [];
|
this.projectAdvanceWriteOffs = [];
|
||||||
@@ -2014,6 +2064,21 @@ export default {
|
|||||||
this.appliedDetailQuery = { ...this.detailQuery };
|
this.appliedDetailQuery = { ...this.detailQuery };
|
||||||
this.detailPage.current = 1;
|
this.detailPage.current = 1;
|
||||||
},
|
},
|
||||||
|
// 结算明细的「单据号」跳到该应收应付单据在应收明细/应付明细页的详情,「运单号」跳到运单详情
|
||||||
|
async handleDetailLink(row, column) {
|
||||||
|
if (column.prop === 'documentNo') {
|
||||||
|
const settlementType = row.settlementType || this.form.settlementType || 'payable';
|
||||||
|
const detailId = await resolveReceivablePayableDetailId(row, settlementType);
|
||||||
|
if (!detailId) return this.$message.info('当前记录未找到对应的应收/应付明细');
|
||||||
|
this.$router.push({ path: settlementDetailPath(settlementType), query: { detailId } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (column.prop === 'waybillNo') {
|
||||||
|
const waybillId = await resolveWaybillId(row);
|
||||||
|
if (!waybillId) return this.$message.info('当前记录未找到对应的运单详情');
|
||||||
|
this.$router.push({ path: '/business/waybill-manage/detail', query: { id: waybillId } });
|
||||||
|
}
|
||||||
|
},
|
||||||
resetDetailQuery() {
|
resetDetailQuery() {
|
||||||
this.detailQuery = {
|
this.detailQuery = {
|
||||||
documentNo: '',
|
documentNo: '',
|
||||||
@@ -3019,6 +3084,10 @@ export default {
|
|||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-readonly--code {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-section-title {
|
.dialog-section-title {
|
||||||
|
|||||||
@@ -520,7 +520,7 @@
|
|||||||
:index="transferIndexMethod"
|
:index="transferIndexMethod"
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="column in tableColumns.slice(0, 13)"
|
v-for="column in transferTableColumns"
|
||||||
:key="column.prop"
|
:key="column.prop"
|
||||||
:prop="column.prop"
|
:prop="column.prop"
|
||||||
:label="column.label"
|
:label="column.label"
|
||||||
@@ -1174,6 +1174,13 @@ export default {
|
|||||||
columns.splice(totalIndex, 0, ...dynamicColumns);
|
columns.splice(totalIndex, 0, ...dynamicColumns);
|
||||||
return columns;
|
return columns;
|
||||||
},
|
},
|
||||||
|
// 批量转结算弹窗只展示前 13 列。预结算单号、正式结算单号正是本操作要生成的单号,
|
||||||
|
// 候选行上必为空,故不占列
|
||||||
|
transferTableColumns() {
|
||||||
|
return this.tableColumns
|
||||||
|
.filter(column => !['preSettlementNo', 'formalSettlementNo'].includes(column.prop))
|
||||||
|
.slice(0, 13);
|
||||||
|
},
|
||||||
columnSettingOptions() {
|
columnSettingOptions() {
|
||||||
return this.displayTableColumns.map(column => ({
|
return this.displayTableColumns.map(column => ({
|
||||||
prop: column.prop,
|
prop: column.prop,
|
||||||
@@ -1712,11 +1719,12 @@ export default {
|
|||||||
this.$router.push({ path, query: { detailNo } });
|
this.$router.push({ path, query: { detailNo } });
|
||||||
},
|
},
|
||||||
async openRouteDetail(detailId = this.$route.query.detailId) {
|
async openRouteDetail(detailId = this.$route.query.detailId) {
|
||||||
if (
|
// 结算明细点「单据号」会带 detailId 跳到本页;只有当前停在应收/应付明细页时才自动展开详情
|
||||||
!detailId ||
|
const routePath =
|
||||||
this.settlementType !== 'payable' ||
|
this.settlementType === 'payable'
|
||||||
this.$route.path !== '/settlement/payable-detail'
|
? '/settlement/payable-detail'
|
||||||
) {
|
: '/settlement/receivable-detail';
|
||||||
|
if (!detailId || this.$route.path !== routePath) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let row = this.rows.find(item => String(item.id) === String(detailId));
|
let row = this.rows.find(item => String(item.id) === String(detailId));
|
||||||
@@ -1729,7 +1737,9 @@ export default {
|
|||||||
if (data.records?.[0]) row = this.decorateRow(data.records[0]);
|
if (data.records?.[0]) row = this.decorateRow(data.records[0]);
|
||||||
}
|
}
|
||||||
if (!row) {
|
if (!row) {
|
||||||
this.$message.info('当前记录未找到对应的应付明细');
|
this.$message.info(
|
||||||
|
`当前记录未找到对应的${this.settlementType === 'payable' ? '应付' : '应收'}明细`
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.openDetailDialog(row);
|
await this.openDetailDialog(row);
|
||||||
|
|||||||
@@ -371,9 +371,8 @@ export default {
|
|||||||
placeholder: '日期时间选择器',
|
placeholder: '日期时间选择器',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '里程/航程数(公里)',
|
label: '里程/航程数',
|
||||||
prop: 'mileage',
|
prop: 'mileage',
|
||||||
renderHeader: () => '里程/航程数',
|
|
||||||
type: 'input',
|
type: 'input',
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
slot: true,
|
slot: true,
|
||||||
@@ -391,6 +390,7 @@ export default {
|
|||||||
],
|
],
|
||||||
value: '公里',
|
value: '公里',
|
||||||
hide: true,
|
hide: true,
|
||||||
|
display: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
@@ -565,12 +565,10 @@ export default {
|
|||||||
const mileageUnit = vehicleType === '船舶' ? '海里' : '公里';
|
const mileageUnit = vehicleType === '船舶' ? '海里' : '公里';
|
||||||
const vehicleTypeColumn = this.findColumn(this.option.column, 'vehicleType');
|
const vehicleTypeColumn = this.findColumn(this.option.column, 'vehicleType');
|
||||||
const vehicleNoColumn = this.findColumn(this.option.column, 'vehicleNo');
|
const vehicleNoColumn = this.findColumn(this.option.column, 'vehicleNo');
|
||||||
const mileageColumn = this.findColumn(this.option.column, 'mileage');
|
|
||||||
const mileageUnitColumn = this.findColumn(this.option.column, 'mileageUnit');
|
const mileageUnitColumn = this.findColumn(this.option.column, 'mileageUnit');
|
||||||
vehicleNoColumn.placeholder =
|
vehicleNoColumn.placeholder =
|
||||||
vehicleType === '船舶' ? '请选择船号' : '请选择车牌号';
|
vehicleType === '船舶' ? '请选择船号' : '请选择车牌号';
|
||||||
vehicleTypeColumn.disabled = Boolean(this.form.id);
|
vehicleTypeColumn.disabled = Boolean(this.form.id);
|
||||||
mileageColumn.label = `里程/航程数(${mileageUnit})`;
|
|
||||||
mileageUnitColumn.value = mileageUnit;
|
mileageUnitColumn.value = mileageUnit;
|
||||||
this.form.mileageUnit = mileageUnit;
|
this.form.mileageUnit = mileageUnit;
|
||||||
if (!this.isDetailLoading && oldValue && vehicleType !== oldValue) {
|
if (!this.isDetailLoading && oldValue && vehicleType !== oldValue) {
|
||||||
|
|||||||
Reference in New Issue
Block a user