6f0f1842cb
2、修复业务模块 3、拆分页面代码
636 lines
17 KiB
JavaScript
636 lines
17 KiB
JavaScript
import {
|
||
auditColumns,
|
||
createCrudOption,
|
||
phoneRule,
|
||
planStatusOptions,
|
||
selectRule,
|
||
textRule,
|
||
withSearchPlaceholders,
|
||
} from './common';
|
||
|
||
const transportPlanDataSourceOptions = [
|
||
{ label: '批量导入', value: '批量导入' },
|
||
{ label: '手工创建', value: '手工创建' },
|
||
{ label: '外部系统', value: '外部系统' },
|
||
];
|
||
|
||
const listDicFormatter = res => {
|
||
const data = res?.data || res;
|
||
if (Array.isArray(data)) return data;
|
||
if (Array.isArray(data?.records)) return data.records;
|
||
if (Array.isArray(data?.data)) return data.data;
|
||
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||
return [];
|
||
};
|
||
|
||
const parseGoodsRows = value => {
|
||
if (!value) return [];
|
||
if (Array.isArray(value)) return value;
|
||
if (typeof value === 'object') return [value];
|
||
try {
|
||
const data = JSON.parse(value);
|
||
return Array.isArray(data) ? data : [data];
|
||
} catch (error) {
|
||
return [];
|
||
}
|
||
};
|
||
|
||
const formatGoodsField = (row, propList) => {
|
||
const values = propList.map(prop => row[prop]).filter(Boolean);
|
||
if (values.length) return values.join('、');
|
||
return parseGoodsRows(row.goodsJson)
|
||
.map(item => propList.map(prop => item?.[prop]).find(Boolean))
|
||
.filter(Boolean)
|
||
.join('、');
|
||
};
|
||
|
||
const getGoodsQuantity = item => {
|
||
const value = item?.quantity ?? item?.cargoQuantity ?? item?.goodsQuantity ?? 0;
|
||
const number = Number(String(value).replace(/,/g, ''));
|
||
return Number.isFinite(number) ? number : 0;
|
||
};
|
||
|
||
const formatGoodsQuantity = value => {
|
||
const number = Math.round((value + Number.EPSILON) * 1000) / 1000;
|
||
return Number.isInteger(number) ? String(number) : String(number).replace(/\.?0+$/, '');
|
||
};
|
||
|
||
const getSecondCargoTypeName = item =>
|
||
item?.secondCargoTypeName ||
|
||
item?.secondCargoType ||
|
||
item?.cargoType ||
|
||
item?.goodsType ||
|
||
item?.type ||
|
||
item?.cargoTypeName ||
|
||
item?.firstCargoTypeName ||
|
||
'货物';
|
||
|
||
const formatGoodsInfo = row => {
|
||
const rows =
|
||
[row.goodsJson, row.goodsList, row.goodsRows, row.cargoList, row.cargoRows, row.goods]
|
||
.map(source => parseGoodsRows(source))
|
||
.filter(source => source.length)
|
||
.sort((left, right) => right.length - left.length)[0] || [];
|
||
if (!rows.length) return row.goodsInfo || '';
|
||
|
||
const groups = rows.reduce((result, item = {}) => {
|
||
const hasGoodsInfo = [
|
||
item.cargoName,
|
||
item.goodsName,
|
||
item.name,
|
||
item.cargoType,
|
||
item.secondCargoTypeName,
|
||
item.goodsType,
|
||
item.type,
|
||
item.quantity,
|
||
item.cargoQuantity,
|
||
item.goodsQuantity,
|
||
item.quantityUnit,
|
||
item.goodsQuantityUnit,
|
||
item.cargoUnit,
|
||
item.unit,
|
||
].some(Boolean);
|
||
if (!hasGoodsInfo) return result;
|
||
|
||
const unit = String(
|
||
item.quantityUnit ||
|
||
item.goodsQuantityUnit ||
|
||
item.cargoUnit ||
|
||
item.unit ||
|
||
row.quantityUnit ||
|
||
row.goodsQuantityUnit ||
|
||
row.cargoUnit ||
|
||
row.unit ||
|
||
''
|
||
).trim();
|
||
if (!result[unit]) {
|
||
result[unit] = {
|
||
typeName: getSecondCargoTypeName(item),
|
||
count: 0,
|
||
quantity: 0,
|
||
};
|
||
}
|
||
result[unit].count += 1;
|
||
result[unit].quantity += getGoodsQuantity(item);
|
||
return result;
|
||
}, {});
|
||
|
||
const text = Object.entries(groups)
|
||
.map(([unit, group]) => {
|
||
const quantity = formatGoodsQuantity(group.quantity);
|
||
return `${group.typeName}等${group.count}种货物 | ${quantity}${unit ? ` ${unit}` : ''}`;
|
||
})
|
||
.join('; ');
|
||
|
||
return text || row.goodsInfo || '';
|
||
};
|
||
|
||
const parseDispatchRows = row => {
|
||
const sources = [
|
||
row.dispatchRows,
|
||
row.dispatchList,
|
||
row.dispatchRecords,
|
||
row.waybillList,
|
||
row.waybillRows,
|
||
];
|
||
for (const source of sources) {
|
||
const rows = parseGoodsRows(source);
|
||
if (rows.length) return rows;
|
||
}
|
||
return [];
|
||
};
|
||
|
||
const formatDispatchQuantity = value => {
|
||
const number = Number(value || 0);
|
||
if (!Number.isFinite(number)) return '0';
|
||
const fixed = Math.round((number + Number.EPSILON) * 1000) / 1000;
|
||
return Number.isInteger(fixed) ? String(fixed) : String(fixed).replace(/\.?0+$/, '');
|
||
};
|
||
|
||
const formatDispatchProgress = row => {
|
||
const goodsRows = parseGoodsRows(row.goodsJson);
|
||
const totalRows = goodsRows.length ? goodsRows : [row];
|
||
const dispatchRows = parseDispatchRows(row);
|
||
const summary = new Map();
|
||
const add = (item, field) => {
|
||
const unit = item.quantityUnit || item.goodsQuantityUnit || item.unit || '吨';
|
||
const quantity = Number(item.quantity || item.cargoQuantity || item.goodsQuantity || 0);
|
||
if (!summary.has(unit)) summary.set(unit, { total: 0, assigned: 0 });
|
||
if (Number.isFinite(quantity)) summary.get(unit)[field] += quantity;
|
||
};
|
||
totalRows.forEach(item => add(item, 'total'));
|
||
dispatchRows.forEach(item => add(item, 'assigned'));
|
||
|
||
if (!dispatchRows.length) {
|
||
const assigned = Number(row.dispatchedQuantity || row.dispatchQuantity || 0);
|
||
if (Number.isFinite(assigned)) {
|
||
const unit = row.quantityUnit || row.goodsQuantityUnit || row.unit || '吨';
|
||
if (!summary.has(unit)) summary.set(unit, { total: 0, assigned: 0 });
|
||
summary.get(unit).assigned = assigned;
|
||
}
|
||
}
|
||
const lines = Array.from(summary.entries()).map(
|
||
([unit, item]) =>
|
||
`${formatDispatchQuantity(item.assigned)}/${formatDispatchQuantity(item.total)}${unit}`
|
||
);
|
||
return lines.length
|
||
? lines.join('\n')
|
||
: row.dispatchProgressName || row.dispatchProgress || row.progress || '';
|
||
};
|
||
|
||
const auditColumn = prop => ({ ...auditColumns.find(item => item.prop === prop) });
|
||
|
||
export const config = {
|
||
title: '运输计划',
|
||
permission: 'transport_plan',
|
||
exportUrl: '/blade-transport/transport-plan/export-transport-plan',
|
||
exportName: '运输计划',
|
||
enableProjectSelect: true,
|
||
projectQueryParams: {
|
||
approvalStatuses: 'approved,change_approved',
|
||
},
|
||
contractQueryParams: {
|
||
contractCategory: '客户合同',
|
||
},
|
||
templateCreateTarget: 'transport-plan',
|
||
enableAttachmentTable: true,
|
||
enableTransportPlanForm: true,
|
||
enableTransportPlanCreateActions: true,
|
||
enableTransportPlanImport: true,
|
||
fixedTransportAddressType: true,
|
||
transportPlanImportTitle: '导入运输计划',
|
||
transportPlanTemplateUrl: '/blade-transport/transport-plan/export-template',
|
||
attachmentTitle: '附件',
|
||
searchRangeMap: {
|
||
planStartDateRange: ['planStartDateStart', 'planStartDateEnd'],
|
||
planEndDateRange: ['planEndDateStart', 'planEndDateEnd'],
|
||
},
|
||
actions: ['copy', 'complete'],
|
||
statusProp: 'businessStatus',
|
||
statusTextProp: 'businessStatusName',
|
||
deleteStatus: ['draft', 'waiting_dispatch'],
|
||
editStatus: ['draft', 'waiting_dispatch'],
|
||
detailButton: true,
|
||
detailSections: [
|
||
{
|
||
title: '基本信息',
|
||
fields: [
|
||
['planNo', '计划单号'],
|
||
['planName', '计划名称'],
|
||
['projectName', '项目名称'],
|
||
['customerName', '客户名称'],
|
||
['transportType', '运输方式'],
|
||
['businessStatus', '调度状态'],
|
||
['planStartDate', '计划开始日期'],
|
||
['planEndDate', '计划结束日期'],
|
||
['dataSource', '数据来源'],
|
||
],
|
||
},
|
||
{
|
||
title: '收发货信息',
|
||
fields: [
|
||
['departureName', '发货地'],
|
||
['departureContact', '发货联系人'],
|
||
['departureAddress', '发货地址'],
|
||
['departurePhone', '发货联系方式'],
|
||
['arrivalName', '收货地'],
|
||
['arrivalContact', '收货联系人'],
|
||
['arrivalAddress', '到货地址'],
|
||
['arrivalPhone', '收货联系方式'],
|
||
],
|
||
},
|
||
{
|
||
title: '其它信息',
|
||
fields: [
|
||
['remark', '备注'],
|
||
['updateUserName', '更新人'],
|
||
['updateTime', '更新时间'],
|
||
['createTime', '创建时间'],
|
||
],
|
||
},
|
||
],
|
||
operations: [
|
||
{
|
||
action: 'dispatch',
|
||
label: '调度',
|
||
statusProp: 'businessStatus',
|
||
status: ['waiting_dispatch', 'dispatching'],
|
||
permission: 'transport_plan_edit',
|
||
confirm: '确定调度该运输计划?',
|
||
},
|
||
],
|
||
};
|
||
|
||
export const option = {
|
||
...createCrudOption(
|
||
withSearchPlaceholders([
|
||
{
|
||
label: '',
|
||
prop: 'basicInfoTitle',
|
||
formslot: true,
|
||
span: 24,
|
||
order: 400,
|
||
hide: true,
|
||
labelWidth: 0,
|
||
},
|
||
{
|
||
label: '计划单号',
|
||
prop: 'planNo',
|
||
search: true,
|
||
searchOrder: 13,
|
||
span: 6,
|
||
order: 370,
|
||
minWidth: 150,
|
||
disabled: true,
|
||
placeholder: '系统自动生成',
|
||
},
|
||
{
|
||
label: '计划名称',
|
||
prop: 'planName',
|
||
search: true,
|
||
searchOrder: 12,
|
||
span: 6,
|
||
order: 380,
|
||
minWidth: 150,
|
||
rules: textRule('计划名称', 50, true),
|
||
},
|
||
{
|
||
label: '运输方式',
|
||
prop: 'transportType',
|
||
type: 'select',
|
||
search: true,
|
||
searchOrder: 10,
|
||
span: 6,
|
||
order: 360,
|
||
dicUrl: '/blade-system/dict-biz/dictionary?code=transport_type',
|
||
props: {
|
||
label: 'dictValue',
|
||
value: 'dictKey',
|
||
},
|
||
minWidth: 130,
|
||
rules: selectRule('运输类型'),
|
||
},
|
||
{
|
||
label: '货物信息',
|
||
prop: 'goodsInfo',
|
||
formatter: row => formatGoodsInfo(row),
|
||
minWidth: 320,
|
||
overHidden: false,
|
||
showOverflowTooltip: false,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
viewDisplay: false,
|
||
},
|
||
{
|
||
label: '调度进度',
|
||
prop: 'dispatchProgress',
|
||
formatter: row => formatDispatchProgress(row),
|
||
minWidth: 120,
|
||
overHidden: false,
|
||
showOverflowTooltip: false,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
viewDisplay: false,
|
||
},
|
||
{
|
||
label: '发货地址',
|
||
prop: 'departureAddress',
|
||
formslot: true,
|
||
search: true,
|
||
searchOrder: 7,
|
||
span: 24,
|
||
order: 310,
|
||
minWidth: 220,
|
||
rules: textRule('发货地址', 255, true),
|
||
},
|
||
{
|
||
label: '到货地址',
|
||
prop: 'arrivalAddress',
|
||
formslot: true,
|
||
search: true,
|
||
searchOrder: 6,
|
||
span: 24,
|
||
order: 300,
|
||
minWidth: 220,
|
||
rules: textRule('收货地址', 255, true),
|
||
},
|
||
{
|
||
label: '项目名称',
|
||
prop: 'projectName',
|
||
formslot: true,
|
||
search: true,
|
||
searchOrder: 11,
|
||
searchType: 'select',
|
||
span: 6,
|
||
order: 400,
|
||
dicUrl: '/blade-transport/project-apply/list?current=1&size=9999',
|
||
dicFormatter: listDicFormatter,
|
||
props: {
|
||
label: 'projectName',
|
||
value: 'projectName',
|
||
},
|
||
filterable: true,
|
||
minWidth: 150,
|
||
rules: textRule('项目', 100, true),
|
||
},
|
||
{
|
||
label: '客户名称',
|
||
prop: 'customerName',
|
||
search: true,
|
||
searchOrder: 5,
|
||
minWidth: 150,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
},
|
||
{
|
||
label: '计划开始日期',
|
||
prop: 'planStartDate',
|
||
type: 'date',
|
||
format: 'YYYY-MM-DD',
|
||
valueFormat: 'YYYY-MM-DD',
|
||
span: 6,
|
||
order: 350,
|
||
minWidth: 150,
|
||
rules: [{ required: true, message: '请选择计划开始日期', trigger: 'change' }],
|
||
},
|
||
{
|
||
label: '计划结束日期',
|
||
prop: 'planEndDate',
|
||
type: 'date',
|
||
format: 'YYYY-MM-DD',
|
||
valueFormat: 'YYYY-MM-DD',
|
||
span: 6,
|
||
order: 340,
|
||
minWidth: 150,
|
||
rules: [{ required: true, message: '请选择计划结束日期', trigger: 'change' }],
|
||
},
|
||
{
|
||
label: '数据来源',
|
||
prop: 'dataSource',
|
||
type: 'select',
|
||
search: true,
|
||
searchOrder: 1,
|
||
dicData: transportPlanDataSourceOptions,
|
||
minWidth: 120,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
},
|
||
{
|
||
label: '货物类型',
|
||
prop: 'cargoType',
|
||
search: true,
|
||
searchOrder: 8,
|
||
formatter: row => formatGoodsField(row, ['cargoType', 'goodsType']),
|
||
minWidth: 130,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
viewDisplay: false,
|
||
},
|
||
{
|
||
label: '货物名称',
|
||
prop: 'cargoName',
|
||
search: true,
|
||
searchOrder: 9,
|
||
formatter: row => formatGoodsField(row, ['cargoName', 'goodsName']),
|
||
minWidth: 150,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
viewDisplay: false,
|
||
},
|
||
{
|
||
label: '备注',
|
||
prop: 'remark',
|
||
type: 'textarea',
|
||
minRows: 2,
|
||
span: 24,
|
||
order: 330,
|
||
minWidth: 180,
|
||
maxlength: 200,
|
||
showWordLimit: true,
|
||
rules: textRule('备注', 200),
|
||
},
|
||
{
|
||
...auditColumn('updateUserName'),
|
||
},
|
||
{
|
||
...auditColumn('createTime'),
|
||
},
|
||
{
|
||
...auditColumn('updateTime'),
|
||
},
|
||
{
|
||
label: '调度状态',
|
||
prop: 'businessStatus',
|
||
type: 'select',
|
||
slot: true,
|
||
search: true,
|
||
searchLabel: '状态',
|
||
searchOrder: 2,
|
||
dicData: planStatusOptions,
|
||
minWidth: 82,
|
||
fixed: 'right',
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
},
|
||
{
|
||
label: '',
|
||
prop: 'shippingInfoTitle',
|
||
formslot: true,
|
||
span: 24,
|
||
order: 320,
|
||
hide: true,
|
||
labelWidth: 0,
|
||
},
|
||
{
|
||
label: '项目ID',
|
||
prop: 'projectId',
|
||
hide: true,
|
||
display: false,
|
||
},
|
||
{
|
||
label: '客户合同',
|
||
prop: 'contractName',
|
||
formslot: true,
|
||
hide: true,
|
||
span: 6,
|
||
order: 390,
|
||
minWidth: 160,
|
||
rules: textRule('客户合同', 100, true),
|
||
},
|
||
{
|
||
label: '客户合同ID',
|
||
prop: 'contractId',
|
||
hide: true,
|
||
display: false,
|
||
},
|
||
{
|
||
label: '发货地',
|
||
prop: 'departureName',
|
||
hide: true,
|
||
display: false,
|
||
minWidth: 140,
|
||
rules: textRule('发货地', 100, true),
|
||
},
|
||
{
|
||
label: '收货地',
|
||
prop: 'arrivalName',
|
||
hide: true,
|
||
display: false,
|
||
minWidth: 140,
|
||
rules: textRule('收货地', 100, true),
|
||
},
|
||
{
|
||
label: '发货联系人',
|
||
prop: 'departureContact',
|
||
hide: true,
|
||
display: false,
|
||
rules: textRule('发货联系人', 50),
|
||
},
|
||
{
|
||
label: '发货联系方式',
|
||
prop: 'departurePhone',
|
||
hide: true,
|
||
display: false,
|
||
rules: [phoneRule('发货联系方式'), ...textRule('发货联系方式', 50)],
|
||
},
|
||
{
|
||
label: '收货联系人',
|
||
prop: 'arrivalContact',
|
||
hide: true,
|
||
display: false,
|
||
rules: textRule('收货联系人', 50),
|
||
},
|
||
{
|
||
label: '收货联系方式',
|
||
prop: 'arrivalPhone',
|
||
hide: true,
|
||
display: false,
|
||
rules: [phoneRule('收货联系方式'), ...textRule('收货联系方式', 50)],
|
||
},
|
||
{
|
||
label: '',
|
||
prop: 'goodsInfoTitle',
|
||
formslot: true,
|
||
span: 24,
|
||
order: 280,
|
||
hide: true,
|
||
labelWidth: 0,
|
||
},
|
||
{
|
||
label: '计划开始日期',
|
||
prop: 'planStartDateRange',
|
||
type: 'date',
|
||
format: 'YYYY-MM-DD',
|
||
valueFormat: 'YYYY-MM-DD',
|
||
search: true,
|
||
searchRange: true,
|
||
searchOrder: 4,
|
||
hide: true,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
viewDisplay: false,
|
||
},
|
||
{
|
||
label: '计划结束日期',
|
||
prop: 'planEndDateRange',
|
||
type: 'date',
|
||
format: 'YYYY-MM-DD',
|
||
valueFormat: 'YYYY-MM-DD',
|
||
search: true,
|
||
searchRange: true,
|
||
searchOrder: 3,
|
||
hide: true,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
viewDisplay: false,
|
||
},
|
||
{
|
||
label: '所属组织',
|
||
prop: 'deptName',
|
||
hide: true,
|
||
minWidth: 150,
|
||
addDisplay: false,
|
||
editDisplay: false,
|
||
},
|
||
{
|
||
label: '',
|
||
prop: 'goodsJson',
|
||
type: 'textarea',
|
||
formslot: true,
|
||
minRows: 2,
|
||
span: 24,
|
||
order: 270,
|
||
hide: true,
|
||
labelWidth: '0px',
|
||
className: 'transport-plan-page__full-form-item',
|
||
},
|
||
{
|
||
label: '',
|
||
prop: 'attachmentTitle',
|
||
formslot: true,
|
||
span: 24,
|
||
order: 265,
|
||
hide: true,
|
||
labelWidth: 0,
|
||
},
|
||
{
|
||
label: '',
|
||
prop: 'attachmentsJson',
|
||
type: 'textarea',
|
||
formslot: true,
|
||
minRows: 2,
|
||
span: 24,
|
||
order: 260,
|
||
hide: true,
|
||
labelWidth: '0px',
|
||
className: 'transport-plan-page__full-form-item',
|
||
},
|
||
])
|
||
),
|
||
// label 固定宽度(容纳 6 汉字),覆盖 createCrudOption 默认 labelWidth:'auto'
|
||
labelWidth: 100,
|
||
dialogWidth: '96%',
|
||
dialogTop: '4vh',
|
||
dialogCustomClass: 'transport-plan-dialog',
|
||
};
|