✨ 业务数量单位改走计量单位,并放开运输计划日期必填
发货模板、运输计划、运单与总单调度从计量单位取 unitName;修复调度提交顶层单位为空,并取消计划开始/结束日期必填。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,9 @@ const dimensionOptions = [
|
|||||||
{ label: '重量', value: '重量' },
|
{ label: '重量', value: '重量' },
|
||||||
{ label: '体积', value: '体积' },
|
{ label: '体积', value: '体积' },
|
||||||
{ label: '数量', value: '数量' },
|
{ label: '数量', value: '数量' },
|
||||||
|
{ label: '整车', value: '整车' },
|
||||||
|
{ label: '里程', value: '里程' },
|
||||||
|
{ label: '吨·公里', value: '吨·公里' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
|
|||||||
@@ -400,7 +400,6 @@ export const option = {
|
|||||||
span: 6,
|
span: 6,
|
||||||
order: 350,
|
order: 350,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
rules: [{ required: true, message: '请选择计划开始日期', trigger: 'change' }],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '计划结束日期',
|
label: '计划结束日期',
|
||||||
@@ -411,7 +410,6 @@ export const option = {
|
|||||||
span: 6,
|
span: 6,
|
||||||
order: 340,
|
order: 340,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
rules: [{ required: true, message: '请选择计划结束日期', trigger: 'change' }],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '数据来源',
|
label: '数据来源',
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { getList as getMeasurementUnitList } from '@/api/base/measurement-unit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载启用状态的计量单位选项,展示/取值均为「计量单位」字段(unitName)。
|
||||||
|
* @returns {Promise<Array<{ label: string, value: string, dimension: string, id: string|number }>>}
|
||||||
|
*/
|
||||||
|
export const loadMeasurementUnitOptions = () => {
|
||||||
|
return getMeasurementUnitList(1, 9999, { status: 1 }).then(res => {
|
||||||
|
const data = res?.data?.data || res?.data || {};
|
||||||
|
const records = Array.isArray(data) ? data : data.records || [];
|
||||||
|
const names = new Set();
|
||||||
|
return records
|
||||||
|
.filter(item => item.status === undefined || item.status === null || Number(item.status) === 1)
|
||||||
|
.map(item => {
|
||||||
|
const name = String(item.unitName || '').trim();
|
||||||
|
if (!name || names.has(name)) return null;
|
||||||
|
names.add(name);
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
label: name,
|
||||||
|
value: name,
|
||||||
|
dimension: String(item.dimension || '').trim(),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -386,12 +386,15 @@ const BILLING_ELEMENT_DIMENSION_MAP = {
|
|||||||
按重量: '重量',
|
按重量: '重量',
|
||||||
按体积: '体积',
|
按体积: '体积',
|
||||||
按数量: '数量',
|
按数量: '数量',
|
||||||
|
按里程: '里程',
|
||||||
|
'按吨·公里': '吨·公里',
|
||||||
|
'固定金额(整单一口价)': '整车',
|
||||||
};
|
};
|
||||||
const BILLING_UNIT_SELECTABLE_ELEMENTS = Object.keys(BILLING_ELEMENT_DIMENSION_MAP);
|
const BILLING_UNIT_SELECTABLE_ELEMENTS = Object.keys(BILLING_ELEMENT_DIMENSION_MAP);
|
||||||
/** 固定计费单位(不可编辑) */
|
/** 对应维度下无计量单位时的默认计费单位 */
|
||||||
const FIXED_BILLING_UNIT_MAP = {
|
const DEFAULT_BILLING_UNIT_MAP = {
|
||||||
按里程: '公里',
|
按里程: '公里',
|
||||||
'按吨·公里': '吨公里',
|
'按吨·公里': '吨·公里',
|
||||||
'固定金额(整单一口价)': '单',
|
'固定金额(整单一口价)': '单',
|
||||||
};
|
};
|
||||||
const defaultRule = () => ({
|
const defaultRule = () => ({
|
||||||
@@ -652,58 +655,61 @@ export default {
|
|||||||
}),
|
}),
|
||||||
]).finally(() => {
|
]).finally(() => {
|
||||||
this.unitLoading = false;
|
this.unitLoading = false;
|
||||||
|
(this.draft.rules || []).forEach(row => this.syncBillingUnit(row));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
measurementDimension(billingElement) {
|
measurementDimension(billingElement) {
|
||||||
return BILLING_ELEMENT_DIMENSION_MAP[billingElement] || '';
|
return BILLING_ELEMENT_DIMENSION_MAP[billingElement] || '';
|
||||||
},
|
},
|
||||||
fixedBillingUnit(billingElement) {
|
defaultBillingUnit(billingElement) {
|
||||||
return FIXED_BILLING_UNIT_MAP[String(billingElement || '').trim()] || '';
|
return DEFAULT_BILLING_UNIT_MAP[String(billingElement || '').trim()] || '';
|
||||||
},
|
},
|
||||||
canSelectBillingUnit(row) {
|
canSelectBillingUnit(row) {
|
||||||
return BILLING_UNIT_SELECTABLE_ELEMENTS.includes(String(row?.billingElement || '').trim());
|
return BILLING_UNIT_SELECTABLE_ELEMENTS.includes(String(row?.billingElement || '').trim());
|
||||||
},
|
},
|
||||||
billingUnitPlaceholder(row) {
|
billingUnitPlaceholder(row) {
|
||||||
if (!row?.billingElement) return '请先选择计费要素';
|
if (!row?.billingElement) return '请先选择计费要素';
|
||||||
if (this.fixedBillingUnit(row.billingElement)) return this.fixedBillingUnit(row.billingElement);
|
|
||||||
if (!this.canSelectBillingUnit(row)) return '当前计费要素无需选择';
|
if (!this.canSelectBillingUnit(row)) return '当前计费要素无需选择';
|
||||||
return '请选择';
|
return '请选择';
|
||||||
},
|
},
|
||||||
unitOptionsFor(row) {
|
unitOptionsFor(row) {
|
||||||
const fixedUnit = this.fixedBillingUnit(row?.billingElement);
|
|
||||||
if (fixedUnit) {
|
|
||||||
return [{ id: fixedUnit, label: fixedUnit, value: fixedUnit }];
|
|
||||||
}
|
|
||||||
if (!this.canSelectBillingUnit(row)) {
|
if (!this.canSelectBillingUnit(row)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const dimension = this.measurementDimension(row?.billingElement);
|
const dimension = this.measurementDimension(row?.billingElement);
|
||||||
if (dimension) {
|
const defaultUnit = this.defaultBillingUnit(row?.billingElement);
|
||||||
return this.measurementUnits
|
const options = dimension
|
||||||
.filter(item => String(item.dimension || '').trim() === dimension)
|
? this.measurementUnits
|
||||||
.map(item => ({
|
.filter(item => String(item.dimension || '').trim() === dimension)
|
||||||
id: item.id,
|
.map(item => ({
|
||||||
label: item.unitName,
|
id: item.id,
|
||||||
value: item.unitName,
|
label: item.unitName,
|
||||||
}))
|
value: item.unitName,
|
||||||
.filter(item => item.value);
|
}))
|
||||||
|
.filter(item => item.value)
|
||||||
|
: [];
|
||||||
|
// 对应维度未配置计量单位时,下拉仅展示默认值
|
||||||
|
if (!options.length && defaultUnit) {
|
||||||
|
return [{ id: `default-${defaultUnit}`, label: defaultUnit, value: defaultUnit }];
|
||||||
}
|
}
|
||||||
return [];
|
return options;
|
||||||
},
|
},
|
||||||
syncBillingUnit(row) {
|
syncBillingUnit(row) {
|
||||||
const fixedUnit = this.fixedBillingUnit(row?.billingElement);
|
|
||||||
if (fixedUnit) {
|
|
||||||
row.billingUnit = fixedUnit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.canSelectBillingUnit(row)) {
|
if (!this.canSelectBillingUnit(row)) {
|
||||||
row.billingUnit = '';
|
row.billingUnit = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const options = this.unitOptionsFor(row);
|
const options = this.unitOptionsFor(row);
|
||||||
if (!options.some(item => String(item.value) === String(row.billingUnit || ''))) {
|
const defaultUnit = this.defaultBillingUnit(row?.billingElement);
|
||||||
row.billingUnit = '';
|
const current = String(row.billingUnit || '').trim();
|
||||||
|
if (options.some(item => String(item.value) === current)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (defaultUnit && options.some(item => String(item.value) === defaultUnit)) {
|
||||||
|
row.billingUnit = defaultUnit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row.billingUnit = options[0]?.value || defaultUnit || '';
|
||||||
},
|
},
|
||||||
feeTypeKey(row) {
|
feeTypeKey(row) {
|
||||||
const option = this.feeCategories.find(
|
const option = this.feeCategories.find(
|
||||||
|
|||||||
@@ -5244,6 +5244,7 @@ import { formatUpdateUserName } from '@/utils/audit';
|
|||||||
import { getToken, isAdministrator } from '@/utils/auth';
|
import { getToken, isAdministrator } from '@/utils/auth';
|
||||||
import { openImportDialog } from '@/utils/import-excel';
|
import { openImportDialog } from '@/utils/import-excel';
|
||||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||||
|
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
import { applyTableMenuWidth } from '@/utils/table-menu';
|
||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
import { isMobile } from '@/utils/validate';
|
import { isMobile } from '@/utils/validate';
|
||||||
@@ -5822,7 +5823,7 @@ export default {
|
|||||||
billCycleTypeOptions: ['固定截单日', '自然月', '自定义多周期'],
|
billCycleTypeOptions: ['固定截单日', '自然月', '自定义多周期'],
|
||||||
reconciliationModeOptions: ['明细逐行核对', '按账单汇总核对', '跳过自动核对'],
|
reconciliationModeOptions: ['明细逐行核对', '按账单汇总核对', '跳过自动核对'],
|
||||||
packageOptions,
|
packageOptions,
|
||||||
quantityUnitOptions: ['吨', '千克', '立方米', '件', '车', '箱', '托盘'],
|
quantityUnitOptions: [],
|
||||||
attachmentFileTypes: [
|
attachmentFileTypes: [
|
||||||
'pdf',
|
'pdf',
|
||||||
'bmp',
|
'bmp',
|
||||||
@@ -5865,7 +5866,6 @@ export default {
|
|||||||
this.ensureBillingUnitOptions();
|
this.ensureBillingUnitOptions();
|
||||||
}
|
}
|
||||||
if (this.config.enableTaskInfoForm) {
|
if (this.config.enableTaskInfoForm) {
|
||||||
this.loadTaskQuantityUnitOptions();
|
|
||||||
this.loadTaskFeeUnitOptions();
|
this.loadTaskFeeUnitOptions();
|
||||||
this.ensureBillingCargoTypeOptions();
|
this.ensureBillingCargoTypeOptions();
|
||||||
}
|
}
|
||||||
@@ -5886,6 +5886,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.consumeTemplateCreatePayload();
|
this.consumeTemplateCreatePayload();
|
||||||
}
|
}
|
||||||
|
this.loadTaskQuantityUnitOptions();
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission', 'userInfo']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
@@ -7789,8 +7790,6 @@ export default {
|
|||||||
['contractName', '客户合同'],
|
['contractName', '客户合同'],
|
||||||
['planName', '计划名称'],
|
['planName', '计划名称'],
|
||||||
['transportType', '运输方式'],
|
['transportType', '运输方式'],
|
||||||
['planStartDate', '计划开始日期'],
|
|
||||||
['planEndDate', '计划结束日期'],
|
|
||||||
['departureAddress', '发货地址'],
|
['departureAddress', '发货地址'],
|
||||||
['arrivalAddress', '收货地址'],
|
['arrivalAddress', '收货地址'],
|
||||||
];
|
];
|
||||||
@@ -9270,9 +9269,10 @@ export default {
|
|||||||
return Promise.resolve(this.taskQuantityUnitOptions);
|
return Promise.resolve(this.taskQuantityUnitOptions);
|
||||||
}
|
}
|
||||||
this.taskQuantityUnitLoading = true;
|
this.taskQuantityUnitLoading = true;
|
||||||
return getDictionary({ code: 'quantity_unit' })
|
return loadMeasurementUnitOptions()
|
||||||
.then(res => {
|
.then(options => {
|
||||||
this.taskQuantityUnitOptions = this.normalizeDictOptions(res.data.data || []);
|
this.taskQuantityUnitOptions = options;
|
||||||
|
this.quantityUnitOptions = options.map(item => item.value);
|
||||||
return this.taskQuantityUnitOptions;
|
return this.taskQuantityUnitOptions;
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|||||||
@@ -317,6 +317,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import * as api from '@/api/business/master-order';
|
import * as api from '@/api/business/master-order';
|
||||||
import { fetchDriversByCarrierOrganizations } from '@/utils/carrier-org-resource';
|
import { fetchDriversByCarrierOrganizations } from '@/utils/carrier-org-resource';
|
||||||
|
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||||
import { isMobile } from '@/utils/validate';
|
import { isMobile } from '@/utils/validate';
|
||||||
|
|
||||||
const unwrapRecords = res => {
|
const unwrapRecords = res => {
|
||||||
@@ -347,7 +348,8 @@ export default {
|
|||||||
carrierLoading: false,
|
carrierLoading: false,
|
||||||
driverLoading: false,
|
driverLoading: false,
|
||||||
escortLoading: false,
|
escortLoading: false,
|
||||||
quantityUnitOptions: ['吨', '千克', '立方米', '件', '车', '箱', '托盘'],
|
quantityUnitOptions: [],
|
||||||
|
quantityUnitLoading: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -389,10 +391,24 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
await this.loadQuantityUnitOptions();
|
||||||
await Promise.all([this.load(), this.loadCarrierOptions()]);
|
await Promise.all([this.load(), this.loadCarrierOptions()]);
|
||||||
this.applySelfOperatedCarrierDefaults();
|
this.applySelfOperatedCarrierDefaults();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
loadQuantityUnitOptions() {
|
||||||
|
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
||||||
|
this.quantityUnitLoading = true;
|
||||||
|
this.quantityUnitLoadPromise = loadMeasurementUnitOptions()
|
||||||
|
.then(options => {
|
||||||
|
this.quantityUnitOptions = options.map(item => item.value);
|
||||||
|
return this.quantityUnitOptions;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.quantityUnitLoading = false;
|
||||||
|
});
|
||||||
|
return this.quantityUnitLoadPromise;
|
||||||
|
},
|
||||||
async load() {
|
async load() {
|
||||||
if (!this.id) return;
|
if (!this.id) return;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|||||||
@@ -597,10 +597,10 @@ import { fallbackPlugin, imagePlugin, officePlugin, pdfPlugin, textPlugin } from
|
|||||||
import '@open-file-viewer/core/style.css';
|
import '@open-file-viewer/core/style.css';
|
||||||
import pdfWorkerSrc from 'pdfjs-dist/build/pdf.worker.mjs?url';
|
import pdfWorkerSrc from 'pdfjs-dist/build/pdf.worker.mjs?url';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||||
|
|
||||||
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
||||||
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||||
const quantityUnitOptions = ['吨', '件', '方'];
|
|
||||||
const attachmentViewerPlugins = [
|
const attachmentViewerPlugins = [
|
||||||
imagePlugin(),
|
imagePlugin(),
|
||||||
pdfPlugin({ workerSrc: pdfWorkerSrc, useFetchData: true }),
|
pdfPlugin({ workerSrc: pdfWorkerSrc, useFetchData: true }),
|
||||||
@@ -703,10 +703,11 @@ export default {
|
|||||||
'zip',
|
'zip',
|
||||||
],
|
],
|
||||||
transports: ['公路运输', '铁路运输', '水路运输', '航空运输'],
|
transports: ['公路运输', '铁路运输', '水路运输', '航空运输'],
|
||||||
quantityUnitOptions,
|
quantityUnitOptions: [],
|
||||||
|
quantityUnitLoading: false,
|
||||||
form: {
|
form: {
|
||||||
routes: [{ segmentNo: '段1', transportType: '' }],
|
routes: [{ segmentNo: '段1', transportType: '' }],
|
||||||
goods: [{ quantityUnit: quantityUnitOptions[0] }],
|
goods: [{ quantityUnit: '吨' }],
|
||||||
attachmentsJson: '[]',
|
attachmentsJson: '[]',
|
||||||
transportOrganizationType: '多式联运',
|
transportOrganizationType: '多式联运',
|
||||||
},
|
},
|
||||||
@@ -773,6 +774,7 @@ export default {
|
|||||||
async mounted() {
|
async mounted() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
|
await this.loadQuantityUnitOptions();
|
||||||
await Promise.all([this.loadProjects(), this.loadCargoTypeOptions(), this.loadRegionOptions()]);
|
await Promise.all([this.loadProjects(), this.loadCargoTypeOptions(), this.loadRegionOptions()]);
|
||||||
if (this.id) {
|
if (this.id) {
|
||||||
await this.loadDetail(this.id);
|
await this.loadDetail(this.id);
|
||||||
@@ -782,6 +784,22 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
defaultQuantityUnit() {
|
||||||
|
return this.quantityUnitOptions[0] || '吨';
|
||||||
|
},
|
||||||
|
loadQuantityUnitOptions() {
|
||||||
|
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
||||||
|
this.quantityUnitLoading = true;
|
||||||
|
this.quantityUnitLoadPromise = loadMeasurementUnitOptions()
|
||||||
|
.then(options => {
|
||||||
|
this.quantityUnitOptions = options.map(item => item.value);
|
||||||
|
return this.quantityUnitOptions;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.quantityUnitLoading = false;
|
||||||
|
});
|
||||||
|
return this.quantityUnitLoadPromise;
|
||||||
|
},
|
||||||
responseData(response) {
|
responseData(response) {
|
||||||
return response?.data?.data || response?.data || response || {};
|
return response?.data?.data || response?.data || response || {};
|
||||||
},
|
},
|
||||||
@@ -958,7 +976,7 @@ export default {
|
|||||||
finalTransportType: hasFinalSegment
|
finalTransportType: hasFinalSegment
|
||||||
? finalSegment.transportType
|
? finalSegment.transportType
|
||||||
: detail.finalTransportType || '',
|
: detail.finalTransportType || '',
|
||||||
goods: detail.goods || [{ quantityUnit: quantityUnitOptions[0] }],
|
goods: detail.goods || [{ quantityUnit: this.defaultQuantityUnit() }],
|
||||||
attachmentsJson: detail.attachmentsJson || '[]',
|
attachmentsJson: detail.attachmentsJson || '[]',
|
||||||
transportOrganizationType: '多式联运',
|
transportOrganizationType: '多式联运',
|
||||||
};
|
};
|
||||||
@@ -1659,7 +1677,7 @@ export default {
|
|||||||
'',
|
'',
|
||||||
cargoTypePath,
|
cargoTypePath,
|
||||||
quantity: row.quantity || '',
|
quantity: row.quantity || '',
|
||||||
quantityUnit: row.quantityUnit || quantityUnitOptions[0],
|
quantityUnit: row.quantityUnit || this.defaultQuantityUnit(),
|
||||||
packageType: row.packageType || row.package || '',
|
packageType: row.packageType || row.package || '',
|
||||||
brand: row.brand || '',
|
brand: row.brand || '',
|
||||||
specification: row.specification || row.spec || '',
|
specification: row.specification || row.spec || '',
|
||||||
@@ -1785,7 +1803,7 @@ export default {
|
|||||||
},
|
},
|
||||||
addGoods(index) {
|
addGoods(index) {
|
||||||
this.form.goods.splice(index + 1, 0, {
|
this.form.goods.splice(index + 1, 0, {
|
||||||
quantityUnit: quantityUnitOptions[0],
|
quantityUnit: this.defaultQuantityUnit(),
|
||||||
materialCode: '',
|
materialCode: '',
|
||||||
deviceCode: '',
|
deviceCode: '',
|
||||||
remark: '',
|
remark: '',
|
||||||
|
|||||||
@@ -1098,6 +1098,7 @@ import {
|
|||||||
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
||||||
import { getDictionary } from '@/api/system/dictbiz';
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import { packageOptions } from '@/option/business/common';
|
import { packageOptions } from '@/option/business/common';
|
||||||
|
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
import { isMobile } from '@/utils/validate';
|
import { isMobile } from '@/utils/validate';
|
||||||
@@ -1278,7 +1279,8 @@ export default {
|
|||||||
cargoTypeRequest: null,
|
cargoTypeRequest: null,
|
||||||
transportCargoRows: [],
|
transportCargoRows: [],
|
||||||
packageOptions,
|
packageOptions,
|
||||||
quantityUnitOptions: ['吨', '千克', '立方米', '立方', '公里', '单', '件', '车', '箱', '托盘'],
|
quantityUnitOptions: [],
|
||||||
|
quantityUnitLoading: false,
|
||||||
feeUnitOptions: [],
|
feeUnitOptions: [],
|
||||||
currencyOptions: [],
|
currencyOptions: [],
|
||||||
currencyLoading: false,
|
currencyLoading: false,
|
||||||
@@ -1525,11 +1527,25 @@ export default {
|
|||||||
created() {
|
created() {
|
||||||
this.loadProjectOptions();
|
this.loadProjectOptions();
|
||||||
this.ensureCargoTypeOptions();
|
this.ensureCargoTypeOptions();
|
||||||
|
this.loadQuantityUnitOptions();
|
||||||
this.loadFeeUnitOptions();
|
this.loadFeeUnitOptions();
|
||||||
this.loadCurrencyOptions();
|
this.loadCurrencyOptions();
|
||||||
if (this.isStandaloneFormPage) this.$nextTick(() => this.initStandaloneFormPage());
|
if (this.isStandaloneFormPage) this.$nextTick(() => this.initStandaloneFormPage());
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
loadQuantityUnitOptions() {
|
||||||
|
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
||||||
|
this.quantityUnitLoading = true;
|
||||||
|
this.quantityUnitLoadPromise = loadMeasurementUnitOptions()
|
||||||
|
.then(options => {
|
||||||
|
this.quantityUnitOptions = options.map(item => item.value);
|
||||||
|
return this.quantityUnitOptions;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.quantityUnitLoading = false;
|
||||||
|
});
|
||||||
|
return this.quantityUnitLoadPromise;
|
||||||
|
},
|
||||||
buildOption(option) {
|
buildOption(option) {
|
||||||
const next = { ...option, column: (option.column || []).map(column => ({ ...column })) };
|
const next = { ...option, column: (option.column || []).map(column => ({ ...column })) };
|
||||||
const tableOrder = this.config.tableColumnOrder || [];
|
const tableOrder = this.config.tableColumnOrder || [];
|
||||||
|
|||||||
@@ -2742,6 +2742,7 @@ import { packageOptions } from '@/option/business/common';
|
|||||||
import { formatUpdateUserName } from '@/utils/audit';
|
import { formatUpdateUserName } from '@/utils/audit';
|
||||||
import { getToken, isAdministrator } from '@/utils/auth';
|
import { getToken, isAdministrator } from '@/utils/auth';
|
||||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||||
|
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
import { applyTableMenuWidth } from '@/utils/table-menu';
|
||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
import { isMobile } from '@/utils/validate';
|
import { isMobile } from '@/utils/validate';
|
||||||
@@ -3206,7 +3207,7 @@ export default {
|
|||||||
billingCargoTypeLoading: false,
|
billingCargoTypeLoading: false,
|
||||||
billingCargoTypeRequest: null,
|
billingCargoTypeRequest: null,
|
||||||
packageOptions,
|
packageOptions,
|
||||||
quantityUnitOptions: ['吨', '千克', '立方米', '件', '车', '箱', '托盘'],
|
quantityUnitOptions: [],
|
||||||
attachmentFileTypes: [
|
attachmentFileTypes: [
|
||||||
'pdf',
|
'pdf',
|
||||||
'bmp',
|
'bmp',
|
||||||
@@ -3245,6 +3246,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.consumeTemplateCreatePayload();
|
this.consumeTemplateCreatePayload();
|
||||||
}
|
}
|
||||||
|
this.loadTaskQuantityUnitOptions();
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission', 'userInfo']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
@@ -4307,8 +4309,6 @@ export default {
|
|||||||
['contractName', '客户合同'],
|
['contractName', '客户合同'],
|
||||||
['planName', '计划名称'],
|
['planName', '计划名称'],
|
||||||
['transportType', '运输方式'],
|
['transportType', '运输方式'],
|
||||||
['planStartDate', '计划开始日期'],
|
|
||||||
['planEndDate', '计划结束日期'],
|
|
||||||
['departureAddress', '发货地址'],
|
['departureAddress', '发货地址'],
|
||||||
['arrivalAddress', '收货地址'],
|
['arrivalAddress', '收货地址'],
|
||||||
];
|
];
|
||||||
@@ -5076,15 +5076,40 @@ export default {
|
|||||||
return Promise.resolve(this.taskQuantityUnitOptions);
|
return Promise.resolve(this.taskQuantityUnitOptions);
|
||||||
}
|
}
|
||||||
this.taskQuantityUnitLoading = true;
|
this.taskQuantityUnitLoading = true;
|
||||||
return getDictionary({ code: 'quantity_unit' })
|
return loadMeasurementUnitOptions()
|
||||||
.then(res => {
|
.then(options => {
|
||||||
this.taskQuantityUnitOptions = this.normalizeDictOptions(res.data.data || []);
|
this.taskQuantityUnitOptions = options;
|
||||||
|
this.quantityUnitOptions = options.map(item => item.value);
|
||||||
|
this.ensureQuantityUnitOptions([
|
||||||
|
this.dispatchItemForm?.quantityUnit,
|
||||||
|
...(this.dispatchItemCargoRows || []).map(row => row.quantityUnit),
|
||||||
|
...(this.transportCargoRows || []).map(row => row.quantityUnit),
|
||||||
|
]);
|
||||||
return this.taskQuantityUnitOptions;
|
return this.taskQuantityUnitOptions;
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.taskQuantityUnitLoading = false;
|
this.taskQuantityUnitLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
ensureQuantityUnitOptions(units = []) {
|
||||||
|
const pending = [...new Set(
|
||||||
|
(Array.isArray(units) ? units : [units])
|
||||||
|
.map(item => String(item || '').trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
)];
|
||||||
|
if (!pending.length) return;
|
||||||
|
pending.forEach(unit => {
|
||||||
|
if (!this.quantityUnitOptions.includes(unit)) {
|
||||||
|
this.quantityUnitOptions = [...this.quantityUnitOptions, unit];
|
||||||
|
}
|
||||||
|
if (!this.taskQuantityUnitOptions.some(item => item.value === unit)) {
|
||||||
|
this.taskQuantityUnitOptions = [
|
||||||
|
...this.taskQuantityUnitOptions,
|
||||||
|
{ label: unit, value: unit },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
loadTaskFeeUnitOptions() {
|
loadTaskFeeUnitOptions() {
|
||||||
if (this.taskFeeUnitOptions.length || this.taskFeeUnitLoading) {
|
if (this.taskFeeUnitOptions.length || this.taskFeeUnitLoading) {
|
||||||
return Promise.resolve(this.taskFeeUnitOptions);
|
return Promise.resolve(this.taskFeeUnitOptions);
|
||||||
@@ -5146,6 +5171,9 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
normalizeTransportCargoRow(row = {}) {
|
normalizeTransportCargoRow(row = {}) {
|
||||||
|
const quantityUnit = String(
|
||||||
|
row.quantityUnit || row.goodsQuantityUnit || row.unit || ''
|
||||||
|
).trim();
|
||||||
const cargo = {
|
const cargo = {
|
||||||
...defaultTransportCargo(),
|
...defaultTransportCargo(),
|
||||||
...row,
|
...row,
|
||||||
@@ -5162,10 +5190,14 @@ export default {
|
|||||||
packageType: row.packageType || row.package || '',
|
packageType: row.packageType || row.package || '',
|
||||||
specification: row.specification || row.spec || '',
|
specification: row.specification || row.spec || '',
|
||||||
freightAmount: row.freightAmount ?? row.amount ?? row.totalAmount ?? '',
|
freightAmount: row.freightAmount ?? row.amount ?? row.totalAmount ?? '',
|
||||||
|
quantityUnit,
|
||||||
};
|
};
|
||||||
['quantity', 'mileage', 'unitPrice', 'freightAmount'].forEach(prop => {
|
['quantity', 'mileage', 'unitPrice', 'freightAmount'].forEach(prop => {
|
||||||
if (Number(cargo[prop]) === -1) cargo[prop] = '';
|
if (Number(cargo[prop]) === -1) cargo[prop] = '';
|
||||||
});
|
});
|
||||||
|
if (quantityUnit) {
|
||||||
|
this.ensureQuantityUnitOptions(quantityUnit);
|
||||||
|
}
|
||||||
return cargo;
|
return cargo;
|
||||||
},
|
},
|
||||||
hasMultipleConfiguredGoods(source = {}, rows = []) {
|
hasMultipleConfiguredGoods(source = {}, rows = []) {
|
||||||
@@ -7594,6 +7626,9 @@ export default {
|
|||||||
...baseRow,
|
...baseRow,
|
||||||
...(index >= 0 ? row : {}),
|
...(index >= 0 ? row : {}),
|
||||||
};
|
};
|
||||||
|
this.dispatchItemForm.quantityUnit =
|
||||||
|
this.dispatchItemForm.quantityUnit || defaultUnit || TRANSPORT_PLAN_QUANTITY_UNIT;
|
||||||
|
this.ensureQuantityUnitOptions(this.dispatchItemForm.quantityUnit);
|
||||||
this.dispatchItemForm.otherFeeTotal = this.normalizeDispatchFeeValue(
|
this.dispatchItemForm.otherFeeTotal = this.normalizeDispatchFeeValue(
|
||||||
this.dispatchItemForm.otherFeeTotal
|
this.dispatchItemForm.otherFeeTotal
|
||||||
);
|
);
|
||||||
@@ -7603,7 +7638,11 @@ export default {
|
|||||||
});
|
});
|
||||||
const goodsRows = this.parseJsonArray(this.dispatchItemForm.goodsJson);
|
const goodsRows = this.parseJsonArray(this.dispatchItemForm.goodsJson);
|
||||||
this.dispatchItemCargoRows = (goodsRows.length ? goodsRows : [this.dispatchItemForm]).map(
|
this.dispatchItemCargoRows = (goodsRows.length ? goodsRows : [this.dispatchItemForm]).map(
|
||||||
item => this.normalizeTransportCargoRow(item)
|
item =>
|
||||||
|
this.normalizeTransportCargoRow({
|
||||||
|
...item,
|
||||||
|
quantityUnit: item.quantityUnit || this.dispatchItemForm.quantityUnit || defaultUnit,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
const hasMultiplePlanGoods = this.dispatchPlanGoodsRows.length > 1;
|
const hasMultiplePlanGoods = this.dispatchPlanGoodsRows.length > 1;
|
||||||
const shouldAutoFillFullGoods =
|
const shouldAutoFillFullGoods =
|
||||||
@@ -7613,11 +7652,18 @@ export default {
|
|||||||
const unscheduledGoodsRows = this.getDispatchUnscheduledGoodsRows();
|
const unscheduledGoodsRows = this.getDispatchUnscheduledGoodsRows();
|
||||||
this.dispatchItemForm.taskEntryMode = 'full';
|
this.dispatchItemForm.taskEntryMode = 'full';
|
||||||
this.dispatchItemForm.quantity = '';
|
this.dispatchItemForm.quantity = '';
|
||||||
this.dispatchItemCargoRows = unscheduledGoodsRows.length
|
this.dispatchItemCargoRows = (
|
||||||
? unscheduledGoodsRows
|
unscheduledGoodsRows.length
|
||||||
: this.dispatchPlanGoodsRows.map(goods =>
|
? unscheduledGoodsRows
|
||||||
this.normalizeTransportCargoRow({ ...goods, quantity: '' })
|
: this.dispatchPlanGoodsRows.map(goods =>
|
||||||
);
|
this.normalizeTransportCargoRow({ ...goods, quantity: '' })
|
||||||
|
)
|
||||||
|
).map(goods =>
|
||||||
|
this.normalizeTransportCargoRow({
|
||||||
|
...goods,
|
||||||
|
quantityUnit: goods.quantityUnit || defaultUnit || TRANSPORT_PLAN_QUANTITY_UNIT,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!this.dispatchItemCargoRows.length) {
|
if (!this.dispatchItemCargoRows.length) {
|
||||||
this.dispatchItemCargoRows = [this.normalizeTransportCargoRow()];
|
this.dispatchItemCargoRows = [this.normalizeTransportCargoRow()];
|
||||||
@@ -8309,7 +8355,10 @@ export default {
|
|||||||
this.dispatchItemForm.cargoName ||
|
this.dispatchItemForm.cargoName ||
|
||||||
'',
|
'',
|
||||||
quantity: quantityText,
|
quantity: quantityText,
|
||||||
quantityUnit: firstGoods.quantityUnit || this.dispatchItemForm.quantityUnit || '',
|
quantityUnit:
|
||||||
|
firstGoods.quantityUnit ||
|
||||||
|
this.dispatchItemForm.quantityUnit ||
|
||||||
|
TRANSPORT_PLAN_QUANTITY_UNIT,
|
||||||
unitPrice: firstGoods.unitPrice || '',
|
unitPrice: firstGoods.unitPrice || '',
|
||||||
priceUnit: firstGoods.priceUnit || '',
|
priceUnit: firstGoods.priceUnit || '',
|
||||||
freightTotal: this.dispatchItemFreightTotal,
|
freightTotal: this.dispatchItemFreightTotal,
|
||||||
@@ -8324,7 +8373,7 @@ export default {
|
|||||||
unitPrice: cargo.unitPrice || '',
|
unitPrice: cargo.unitPrice || '',
|
||||||
priceUnit: cargo.priceUnit || '',
|
priceUnit: cargo.priceUnit || '',
|
||||||
quantity: cargo.quantity || '',
|
quantity: cargo.quantity || '',
|
||||||
quantityUnit: cargo.quantityUnit || '',
|
quantityUnit: cargo.quantityUnit || firstGoods.quantityUnit || TRANSPORT_PLAN_QUANTITY_UNIT,
|
||||||
freightAmount: this.dispatchCargoFreightAmount(cargo),
|
freightAmount: this.dispatchCargoFreightAmount(cargo),
|
||||||
})),
|
})),
|
||||||
}),
|
}),
|
||||||
@@ -8413,26 +8462,40 @@ export default {
|
|||||||
return {
|
return {
|
||||||
id: this.dispatchRow.id,
|
id: this.dispatchRow.id,
|
||||||
mode,
|
mode,
|
||||||
waybills: rows.map(row => ({
|
waybills: rows.map(row => {
|
||||||
...row,
|
const quantityUnit = this.getDispatchQuantityUnit(row);
|
||||||
taskEntryMode: row.taskEntryMode || 'simple',
|
let goodsJson = row.goodsJson;
|
||||||
taskRemark: row.remark || '',
|
const goodsRows = this.parseJsonArray(goodsJson);
|
||||||
estimatedStartTime: this.formatDispatchDate(row.estimatedStartTime),
|
if (goodsRows.length) {
|
||||||
estimatedEndTime: this.formatDispatchDate(row.estimatedEndTime),
|
goodsJson = JSON.stringify(
|
||||||
goodsJson:
|
goodsRows.map(goods => ({
|
||||||
row.goodsJson ||
|
...goods,
|
||||||
JSON.stringify([
|
quantityUnit: goods.quantityUnit || quantityUnit,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
goodsJson = JSON.stringify([
|
||||||
{
|
{
|
||||||
cargoName: row.cargoName,
|
cargoName: row.cargoName,
|
||||||
cargoType: row.cargoType,
|
cargoType: row.cargoType,
|
||||||
quantity: row.quantity,
|
quantity: row.quantity,
|
||||||
quantityUnit: row.quantityUnit,
|
quantityUnit,
|
||||||
specification: row.specification,
|
specification: row.specification,
|
||||||
model: row.model,
|
model: row.model,
|
||||||
packageType: row.packageType,
|
packageType: row.packageType,
|
||||||
},
|
},
|
||||||
]),
|
]);
|
||||||
})),
|
}
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
quantityUnit,
|
||||||
|
taskEntryMode: row.taskEntryMode || 'simple',
|
||||||
|
taskRemark: row.remark || '',
|
||||||
|
estimatedStartTime: this.formatDispatchDate(row.estimatedStartTime),
|
||||||
|
estimatedEndTime: this.formatDispatchDate(row.estimatedEndTime),
|
||||||
|
goodsJson,
|
||||||
|
};
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
formatDispatchDate(value) {
|
formatDispatchDate(value) {
|
||||||
|
|||||||
@@ -3100,6 +3100,7 @@ import { formatUpdateUserName } from '@/utils/audit';
|
|||||||
import { getToken, isAdministrator } from '@/utils/auth';
|
import { getToken, isAdministrator } from '@/utils/auth';
|
||||||
import { openImportDialog } from '@/utils/import-excel';
|
import { openImportDialog } from '@/utils/import-excel';
|
||||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||||
|
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
import { applyTableMenuWidth } from '@/utils/table-menu';
|
||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
import { isMobile } from '@/utils/validate';
|
import { isMobile } from '@/utils/validate';
|
||||||
@@ -3556,7 +3557,7 @@ export default {
|
|||||||
cargoTypeLoading: false,
|
cargoTypeLoading: false,
|
||||||
cargoTypeRequest: null,
|
cargoTypeRequest: null,
|
||||||
packageOptions,
|
packageOptions,
|
||||||
quantityUnitOptions: ['吨', '千克', '立方米', '件', '车', '箱', '托盘'],
|
quantityUnitOptions: [],
|
||||||
attachmentFileTypes: [
|
attachmentFileTypes: [
|
||||||
'pdf',
|
'pdf',
|
||||||
'bmp',
|
'bmp',
|
||||||
@@ -3613,7 +3614,6 @@ export default {
|
|||||||
this.loadProjectOptions();
|
this.loadProjectOptions();
|
||||||
}
|
}
|
||||||
if (this.config.enableTaskInfoForm) {
|
if (this.config.enableTaskInfoForm) {
|
||||||
this.loadTaskQuantityUnitOptions();
|
|
||||||
this.loadTaskFeeUnitOptions();
|
this.loadTaskFeeUnitOptions();
|
||||||
this.ensureCargoTypeOptions();
|
this.ensureCargoTypeOptions();
|
||||||
}
|
}
|
||||||
@@ -3628,6 +3628,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.consumeTemplateCreatePayload();
|
this.consumeTemplateCreatePayload();
|
||||||
}
|
}
|
||||||
|
this.loadTaskQuantityUnitOptions();
|
||||||
},
|
},
|
||||||
// 标签切走(实例被 keep-alive 缓存)或销毁时,收起本页所有 append-to-body 的弹窗。
|
// 标签切走(实例被 keep-alive 缓存)或销毁时,收起本页所有 append-to-body 的弹窗。
|
||||||
// 否则 Teleport 出去的弹窗 DOM 会一直留在 body 上,盖住后续打开的页面。
|
// 否则 Teleport 出去的弹窗 DOM 会一直留在 body 上,盖住后续打开的页面。
|
||||||
@@ -6983,9 +6984,10 @@ export default {
|
|||||||
return Promise.resolve(this.taskQuantityUnitOptions);
|
return Promise.resolve(this.taskQuantityUnitOptions);
|
||||||
}
|
}
|
||||||
this.taskQuantityUnitLoading = true;
|
this.taskQuantityUnitLoading = true;
|
||||||
return getDictionary({ code: 'quantity_unit' })
|
return loadMeasurementUnitOptions()
|
||||||
.then(res => {
|
.then(options => {
|
||||||
this.taskQuantityUnitOptions = this.normalizeDictOptions(res.data.data || []);
|
this.taskQuantityUnitOptions = options;
|
||||||
|
this.quantityUnitOptions = options.map(item => item.value);
|
||||||
return this.taskQuantityUnitOptions;
|
return this.taskQuantityUnitOptions;
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|||||||
@@ -846,15 +846,15 @@
|
|||||||
v-model="userQuery.realName"
|
v-model="userQuery.realName"
|
||||||
placeholder="用户姓名"
|
placeholder="用户姓名"
|
||||||
clearable
|
clearable
|
||||||
@keyup.enter="loadUsers"
|
@keyup.enter="searchUsers"
|
||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="userQuery.phone"
|
v-model="userQuery.phone"
|
||||||
placeholder="手机号"
|
placeholder="手机号"
|
||||||
clearable
|
clearable
|
||||||
@keyup.enter="loadUsers"
|
@keyup.enter="searchUsers"
|
||||||
/>
|
/>
|
||||||
<el-button type="primary" @click="loadUsers">查询</el-button>
|
<el-button type="primary" @click="searchUsers">查询</el-button>
|
||||||
<el-button @click="resetUserQuery">重置</el-button>
|
<el-button @click="resetUserQuery">重置</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="userData" border v-loading="userLoading" @row-dblclick="selectUser">
|
<el-table :data="userData" border v-loading="userLoading" @row-dblclick="selectUser">
|
||||||
@@ -2756,11 +2756,20 @@ export default {
|
|||||||
if (this.dialogReadonly) return;
|
if (this.dialogReadonly) return;
|
||||||
this.userPickType = type;
|
this.userPickType = type;
|
||||||
this.userBox = true;
|
this.userBox = true;
|
||||||
|
this.userPage.currentPage = 1;
|
||||||
|
this.loadUsers();
|
||||||
|
},
|
||||||
|
searchUsers() {
|
||||||
|
this.userPage.currentPage = 1;
|
||||||
this.loadUsers();
|
this.loadUsers();
|
||||||
},
|
},
|
||||||
loadUsers() {
|
loadUsers() {
|
||||||
this.userLoading = true;
|
this.userLoading = true;
|
||||||
getUserList(this.userPage.currentPage, this.userPage.pageSize, this.userQuery)
|
const params = {
|
||||||
|
realName: String(this.userQuery.realName || '').trim(),
|
||||||
|
phone: String(this.userQuery.phone || '').trim(),
|
||||||
|
};
|
||||||
|
getUserList(this.userPage.currentPage, this.userPage.pageSize, params)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const result = res.data.data || {};
|
const result = res.data.data || {};
|
||||||
this.userData = result.records || [];
|
this.userData = result.records || [];
|
||||||
|
|||||||
@@ -585,6 +585,10 @@ export default {
|
|||||||
this.$message.warning(`第${index + 1}条调度明细缺少车牌号`);
|
this.$message.warning(`第${index + 1}条调度明细缺少车牌号`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.resolveDispatchQuantityUnit(row)) {
|
||||||
|
this.$message.warning(`第${index + 1}条调度明细缺少数量单位`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$confirm(
|
this.$confirm(
|
||||||
@@ -600,32 +604,57 @@ export default {
|
|||||||
this.submitDispatch();
|
this.submitDispatch();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
resolveDispatchQuantityUnit(row = {}) {
|
||||||
|
const topUnit = String(row.quantityUnit || '').trim();
|
||||||
|
if (topUnit) return topUnit;
|
||||||
|
const goodsList = this.parseGoodsList(row.goodsJson);
|
||||||
|
for (const goods of goodsList) {
|
||||||
|
const unit = String(
|
||||||
|
goods?.quantityUnit || goods?.goodsQuantityUnit || goods?.unit || ''
|
||||||
|
).trim();
|
||||||
|
if (unit) return unit;
|
||||||
|
}
|
||||||
|
return TRANSPORT_PLAN_QUANTITY_UNIT;
|
||||||
|
},
|
||||||
|
enrichDispatchGoodsJson(row = {}, quantityUnit) {
|
||||||
|
const goodsList = this.parseGoodsList(row.goodsJson);
|
||||||
|
if (goodsList.length) {
|
||||||
|
const nextGoods = goodsList.map(goods => ({
|
||||||
|
...goods,
|
||||||
|
quantityUnit: String(goods.quantityUnit || quantityUnit || '').trim() || quantityUnit,
|
||||||
|
}));
|
||||||
|
return JSON.stringify(nextGoods);
|
||||||
|
}
|
||||||
|
return JSON.stringify([
|
||||||
|
{
|
||||||
|
cargoName: row.cargoName,
|
||||||
|
cargoType: row.cargoType,
|
||||||
|
quantity: row.quantity,
|
||||||
|
quantityUnit,
|
||||||
|
specification: row.specification,
|
||||||
|
model: row.model,
|
||||||
|
packageType: row.packageType,
|
||||||
|
brand: row.brand,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
},
|
||||||
submitDispatch() {
|
submitDispatch() {
|
||||||
this.saving = true;
|
this.saving = true;
|
||||||
const payload = {
|
const payload = {
|
||||||
id: this.planId,
|
id: this.planId,
|
||||||
mode: 'submit',
|
mode: 'submit',
|
||||||
waybills: this.dispatchList.map(row => ({
|
waybills: this.dispatchList.map(row => {
|
||||||
...row,
|
const quantityUnit = this.resolveDispatchQuantityUnit(row);
|
||||||
taskEntryMode: row.taskEntryMode || 'simple',
|
return {
|
||||||
taskRemark: row.remark || '',
|
...row,
|
||||||
estimatedStartTime: row.estimatedStartTime || this.planData.planStartDate || '',
|
quantityUnit,
|
||||||
estimatedEndTime: row.estimatedEndTime || this.planData.planEndDate || '',
|
taskEntryMode: row.taskEntryMode || 'simple',
|
||||||
goodsJson:
|
taskRemark: row.remark || '',
|
||||||
row.goodsJson ||
|
estimatedStartTime: row.estimatedStartTime || this.planData.planStartDate || '',
|
||||||
JSON.stringify([
|
estimatedEndTime: row.estimatedEndTime || this.planData.planEndDate || '',
|
||||||
{
|
goodsJson: this.enrichDispatchGoodsJson(row, quantityUnit),
|
||||||
cargoName: row.cargoName,
|
};
|
||||||
cargoType: row.cargoType,
|
}),
|
||||||
quantity: row.quantity,
|
|
||||||
quantityUnit: row.quantityUnit,
|
|
||||||
specification: row.specification,
|
|
||||||
model: row.model,
|
|
||||||
packageType: row.packageType,
|
|
||||||
brand: row.brand,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
})),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatch(payload)
|
dispatch(payload)
|
||||||
@@ -639,7 +668,7 @@ export default {
|
|||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error('调度失败:', err);
|
console.error('调度失败:', err);
|
||||||
this.$message.error('调度失败');
|
this.$message.error(err?.response?.data?.msg || err?.message || '调度失败');
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.saving = false;
|
this.saving = false;
|
||||||
|
|||||||
+35
-38
@@ -189,6 +189,20 @@ import func from '@/utils/func';
|
|||||||
|
|
||||||
const escapeRegExp = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
const escapeRegExp = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
const ORGANIZATION_TYPE_DICT_CODE = 'organization_type';
|
const ORGANIZATION_TYPE_DICT_CODE = 'organization_type';
|
||||||
|
/**
|
||||||
|
* 组织类型名称 → 字典数字键(兼容 dictKey 配成中文的情况)
|
||||||
|
*/
|
||||||
|
const ORGANIZATION_TYPE_CODE_BY_LABEL = {
|
||||||
|
集团: 1,
|
||||||
|
一级集团: 1,
|
||||||
|
事业部: 2,
|
||||||
|
二级事业部: 2,
|
||||||
|
部门: 3,
|
||||||
|
分公司: 4,
|
||||||
|
三级分公司: 4,
|
||||||
|
物流园区: 5,
|
||||||
|
承运商: 6,
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@@ -755,7 +769,7 @@ export default {
|
|||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
this.resetDeptCategoryOptions();
|
this.resetDeptCategoryOptions();
|
||||||
if (list.length && !this.organizationTypeOptions.length) {
|
if (list.length && !this.organizationTypeOptions.length) {
|
||||||
this.$message.warning('组织类型字典 dictKey 须为数字 1~6,当前无法解析,请检查业务字典配置');
|
this.$message.warning('组织类型字典无法解析,请检查业务字典 organization_type 的字典键配置');
|
||||||
}
|
}
|
||||||
// 字典异步返回后触发表格组织类型标签重绘
|
// 字典异步返回后触发表格组织类型标签重绘
|
||||||
if (Array.isArray(this.data) && this.data.length) {
|
if (Array.isArray(this.data) && this.data.length) {
|
||||||
@@ -765,29 +779,31 @@ export default {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 业务字典项转下拉选项。后端 deptCategory 为 Integer,value 必须始终为数字。
|
* 业务字典项转下拉选项。后端 deptCategory 为 Integer,value 必须始终为数字。
|
||||||
* dictKey 为纯数字时直接使用;若配成中文则回退用 sort(1~6)作为层级码。
|
* 优先用数字 dictKey;若 dictKey 配成中文,则按名称映射已知编码。
|
||||||
*/
|
*/
|
||||||
normalizeOrganizationTypeOption(item) {
|
normalizeOrganizationTypeOption(item) {
|
||||||
const label = item?.dictValue ?? item?.label;
|
const label = item?.dictValue ?? item?.label;
|
||||||
if (label === undefined || label === null || String(label).trim() === '') {
|
if (label === undefined || label === null || String(label).trim() === '') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const labelText = String(label).trim();
|
||||||
const rawKey = item?.dictKey ?? item?.value;
|
const rawKey = item?.dictKey ?? item?.value;
|
||||||
const keyText = rawKey === undefined || rawKey === null ? '' : String(rawKey).trim();
|
const keyText = rawKey === undefined || rawKey === null ? '' : String(rawKey).trim();
|
||||||
const keyNumber = Number(keyText);
|
const keyNumber = Number(keyText);
|
||||||
const isPureNumber = keyText !== '' && !Number.isNaN(keyNumber) && String(keyNumber) === keyText;
|
const isPureNumber = keyText !== '' && !Number.isNaN(keyNumber) && String(keyNumber) === keyText;
|
||||||
if (isPureNumber) {
|
if (isPureNumber) {
|
||||||
return {
|
return {
|
||||||
label: String(label),
|
label: labelText,
|
||||||
value: keyNumber,
|
value: keyNumber,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// 兼容 dictKey 误配成中文:用排序号作为 1~6 层级码,保证下拉有数据且可提交 Integer
|
// dictKey / 名称 配成中文时,按标准名称映射到数字键
|
||||||
const sortNumber = Number(item?.sort);
|
const codeByLabel =
|
||||||
if (!Number.isNaN(sortNumber) && sortNumber >= 1 && sortNumber <= 6) {
|
ORGANIZATION_TYPE_CODE_BY_LABEL[labelText] ?? ORGANIZATION_TYPE_CODE_BY_LABEL[keyText];
|
||||||
|
if (codeByLabel) {
|
||||||
return {
|
return {
|
||||||
label: String(label),
|
label: labelText,
|
||||||
value: sortNumber,
|
value: codeByLabel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -813,18 +829,25 @@ export default {
|
|||||||
this.$message.warning('请选择组织类型');
|
this.$message.warning('请选择组织类型');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (typeof value === 'number' && !Number.isNaN(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const asNumber = Number(value);
|
const asNumber = Number(value);
|
||||||
if (!Number.isNaN(asNumber) && String(asNumber) === String(value).trim()) {
|
if (!Number.isNaN(asNumber) && String(asNumber) === String(value).trim()) {
|
||||||
return asNumber;
|
return asNumber;
|
||||||
}
|
}
|
||||||
// 容错:表单里残留了中文标签时,按字典项 label 反查数字编码
|
// 容错:表单里残留了中文标签时,按字典项 label / 标准名称反查数字编码
|
||||||
const matched = this.organizationTypeOptions.find(
|
const matched = this.organizationTypeOptions.find(
|
||||||
item => String(item.label) === String(value) || this.isSameDeptCategory(item.value, value)
|
item => String(item.label) === String(value) || this.isSameDeptCategory(item.value, value)
|
||||||
);
|
);
|
||||||
if (matched && typeof matched.value === 'number' && !Number.isNaN(matched.value)) {
|
if (matched && typeof matched.value === 'number' && !Number.isNaN(matched.value)) {
|
||||||
return matched.value;
|
return matched.value;
|
||||||
}
|
}
|
||||||
this.$message.warning('组织类型无效,请重新选择(字典键须为数字 1~6)');
|
const codeByLabel = ORGANIZATION_TYPE_CODE_BY_LABEL[String(value).trim()];
|
||||||
|
if (codeByLabel) {
|
||||||
|
return codeByLabel;
|
||||||
|
}
|
||||||
|
this.$message.warning('组织类型无效,请重新选择');
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
resetDeptCategoryOptions() {
|
resetDeptCategoryOptions() {
|
||||||
@@ -860,35 +883,9 @@ export default {
|
|||||||
const text = matched?.label || value;
|
const text = matched?.label || value;
|
||||||
return String(text).includes('承运商');
|
return String(text).includes('承运商');
|
||||||
},
|
},
|
||||||
filterOrganizationTypeOptions(values) {
|
|
||||||
const valueSet = new Set(values.map(item => String(item)));
|
|
||||||
const filtered = this.organizationTypeOptions.filter(item => valueSet.has(String(item.value)));
|
|
||||||
// 字典 key 非数字时无法按历史层级码过滤,回退展示全部,避免下拉无选项
|
|
||||||
return filtered.length ? filtered : [...this.organizationTypeOptions];
|
|
||||||
},
|
|
||||||
updateDeptCategoryOptions() {
|
updateDeptCategoryOptions() {
|
||||||
const categoryColumn = this.findColumn(this.option.column, 'deptCategory');
|
// 组织层级仅由 parentId 决定,组织类型不再按上级过滤,始终展示全部字典项
|
||||||
const parent = this.parentDept;
|
this.resetDeptCategoryOptions();
|
||||||
if (!parent || !categoryColumn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let dicData = [];
|
|
||||||
if (this.isRootDept(parent)) {
|
|
||||||
dicData =
|
|
||||||
parent.deptName === '外部组织'
|
|
||||||
? this.filterOrganizationTypeOptions([6])
|
|
||||||
: this.filterOrganizationTypeOptions([1]);
|
|
||||||
} else if (Number(parent.deptCategory) === 1) {
|
|
||||||
dicData = this.filterOrganizationTypeOptions([2, 3]);
|
|
||||||
} else if ([2, 3].includes(Number(parent.deptCategory))) {
|
|
||||||
dicData = this.filterOrganizationTypeOptions([4, 5, 6]);
|
|
||||||
} else {
|
|
||||||
dicData = [...this.organizationTypeOptions];
|
|
||||||
}
|
|
||||||
categoryColumn.dicData = dicData;
|
|
||||||
if (!dicData.some(item => this.isSameDeptCategory(item.value, this.form.deptCategory))) {
|
|
||||||
this.form.deptCategory = dicData[0]?.value;
|
|
||||||
}
|
|
||||||
if (this.isCarrierDeptCategory(this.form.deptCategory)) {
|
if (this.isCarrierDeptCategory(this.form.deptCategory)) {
|
||||||
this.openCarrierDialog();
|
this.openCarrierDialog();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user