web端:新增工作台;异动管理页面与需求说明更新

Made-with: Cursor
This commit is contained in:
王冕
2026-03-23 09:35:39 +08:00
parent 49d9e3675d
commit d3da3da73b
9 changed files with 706 additions and 104 deletions

View File

@@ -1,5 +1,5 @@
// 使 const Component
// - - -
// - - - -
const Component = function () {
var useState = React.useState;
@@ -108,8 +108,7 @@ const Component = function () {
'1.3.异动目的地:必填项,选择器,选项为:停车场、维修站、其他;',
'2.4.目的地名称:必填项,如异动目的地为停车场,则此处为停车场(选择器),如异动目的地为维修站,则此处为维修站(选择器),如异动目的地为其他,则此处为输入框(自定义输入);',
'2.5.异动类型:必填项,选择器,选项为:维修、保养、年审、其他;',
'2.6.预计异动里程输入框支持2位小数输入后缀为km',
'2.7.备注:文本域,支持自定义输入;',
'2.6.备注:文本域,支持自定义输入',
'',
'2.车辆信息:',
'2.1.车牌号:显示车牌号,支持输入框模糊搜索下拉匹配对应选项;',
@@ -117,11 +116,12 @@ const Component = function () {
'2.3.品牌:根据所选车辆品牌自动反写,默认提示为请先选择车辆;',
'2.4.型号:根据所选车辆型号自动反写,默认提示为请先选择车辆;',
'2.5.出发停车场:根据所选车辆出发时停车场自动反写,默认提示为请先选择车辆;',
'2.6.异动开始里程:必填项,输入框,精确至2位小数后缀为km',
'2.7.异动开始氢量必填项输入框精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.8.异动开始必填项输入框精确至2位小数后缀为kWh',
'2.9.操作:删除',
'2.10.新增一行:铺满整行',
'2.6.预计异动里程:输入框,支持2位小数输入后缀为km',
'2.7.异动开始里程必填项输入框精确至2位小数后缀为km',
'2.8.异动开始必填项输入框精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.9.异动开始电量必填项输入框精确至2位小数后缀为kWh',
'2.10.操作:删除',
'2.11.新增一行:铺满整行;',
'',
'3.底部为提交审核、保存、取消;'
].join('\n');
@@ -133,7 +133,6 @@ const Component = function () {
destinationName: undefined,
destinationNameOther: '',
changeType: undefined,
plannedMileageKm: '',
remark: ''
});
var form = formState[0];
@@ -153,6 +152,7 @@ const Component = function () {
model: '',
departParking: '',
h2Unit: '',
plannedMileageKm: '',
startMileageKm: '',
startHydrogen: '',
startElectricKwh: ''
@@ -176,14 +176,16 @@ const Component = function () {
var handlePlateChange = useCallback(function (index, plateNo) {
var v = vehicleDb.find(function (x) { return x.plateNo === plateNo; });
updateRow(index, {
var patch = {
plateNo: plateNo,
vehicleType: v ? v.vehicleType : '',
brand: v ? v.brand : '',
model: v ? v.model : '',
departParking: v ? v.departParking : '',
h2Unit: v ? v.h2Unit : ''
});
};
if (!v) patch.plannedMileageKm = '';
updateRow(index, patch);
}, [vehicleDb, updateRow]);
var addRow = useCallback(function () {
@@ -196,6 +198,7 @@ const Component = function () {
model: '',
departParking: '',
h2Unit: '',
plannedMileageKm: '',
startMileageKm: '',
startHydrogen: '',
startElectricKwh: ''
@@ -216,6 +219,7 @@ const Component = function () {
model: '',
departParking: '',
h2Unit: '',
plannedMileageKm: '',
startMileageKm: '',
startHydrogen: '',
startElectricKwh: ''
@@ -243,6 +247,7 @@ const Component = function () {
for (var i = 0; i < (vehicles || []).length; i++) {
var r = vehicles[i] || {};
if (!String(r.plateNo || '').trim()) continue;
if (!String(r.plannedMileageKm || '').trim()) e['row_' + i + '_plannedMileageKm'] = '请输入预计异动里程';
if (!String(r.startMileageKm || '').trim()) e['row_' + i + '_startMileageKm'] = '请输入异动开始里程';
if (!String(r.startHydrogen || '').trim()) e['row_' + i + '_startHydrogen'] = '请输入异动开始氢量';
if (!String(r.startElectricKwh || '').trim()) e['row_' + i + '_startElectricKwh'] = '请输入异动开始电量';
@@ -362,6 +367,21 @@ const Component = function () {
return React.createElement(Input, { value: r.departParking ? r.departParking : '请先选择车辆', disabled: true });
}
},
{
title: React.createElement('span', null, reqStar, '预计异动里程'),
key: 'plannedMileageKm',
width: 160,
render: function (_, r, index) {
var k = 'row_' + index + '_plannedMileageKm';
return React.createElement(Input, {
value: r.plannedMileageKm,
onChange: function (e) { updateRow(index, { plannedMileageKm: toFixed2Input(e.target.value) }); },
placeholder: '0.00',
addonAfter: 'km',
status: errors[k] ? 'error' : undefined
});
}
},
{
title: React.createElement('span', null, reqStar, '异动开始里程'),
key: 'startMileageKm',
@@ -504,15 +524,6 @@ const Component = function () {
}),
errors.changeType ? React.createElement('div', { style: { marginTop: 4, color: '#ff4d4f', fontSize: 12 } }, errors.changeType) : null
),
React.createElement('div', { style: formItemStyle },
React.createElement('div', { style: labelStyle }, '预计异动里程'),
React.createElement(Input, {
placeholder: '0.00',
value: form.plannedMileageKm,
onChange: function (e) { updateForm({ plannedMileageKm: toFixed2Input(e.target.value) }); },
addonAfter: 'km'
})
),
React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: 'span 3' }) },
React.createElement('div', { style: labelStyle }, '备注'),
@@ -534,7 +545,7 @@ const Component = function () {
dataSource: vehicles,
size: 'small',
pagination: false,
scroll: { x: 1250 }
scroll: { x: 1410 }
}),
React.createElement(Button, { type: 'dashed', style: { marginTop: 12, width: '100%' }, onClick: addRow }, '新增一行')
),

View File

@@ -82,7 +82,6 @@ const Component = function () {
destinationType: '维修站',
destinationName: '广州天河维修站',
changeType: '维修',
plannedMileageKm: '45.50',
remark: '车辆需进站检修制动系统,预计两日内完成。',
approvalStatus: '审批中',
endDateTime: getInitialDateTime('2026-02-22 17:45')
@@ -99,6 +98,7 @@ const Component = function () {
brand: '东风',
model: 'DFH1180',
departParking: '天河智慧停车场',
plannedMileageKm: '45.50',
startMileageKm: '15230.12',
startHydrogen: '28.30',
h2Unit: 'MPa',
@@ -159,6 +159,21 @@ const Component = function () {
return React.createElement(Input, { value: rowVehicleSelected(r) ? (r.departParking || '-') : '请先选择车辆', disabled: true });
}
},
{
title: '预计异动里程',
key: 'plannedMileageKm',
width: 160,
render: function (_, r) {
if (!rowVehicleSelected(r)) {
return React.createElement(Input, { value: '', disabled: true, placeholder: placeholderSelectVehicle });
}
return React.createElement(Input, {
value: fmtPlannedMileage(r.plannedMileageKm),
disabled: true,
addonAfter: 'km'
});
}
},
{
title: '异动开始里程',
key: 'startMileageKm',
@@ -256,8 +271,8 @@ const Component = function () {
'页面布局与字段与「异动管理-结束异动」一致;另含「审批状态」只读展示。',
'所有表单项、表格单元均为禁用只读,仅供查询展示。',
'',
'1.异动情况:异动开始/预计结束日期、异动目的地、目的地名称、异动类型、预计异动里程、审批状态、异动结束时间、备注 — 全部只读。',
'2.车辆信息:与结束异动表列一致(含异动结束里程/氢量/电量);仅展示单辆车(表格 1 行)— 全部只读;无新增行与删除。',
'1.异动情况:第一行开始/预计结束/目的地;第二行目的地名称、异动类型、审批状态(第三列);第三行异动结束时间(首列);备注跨三列 — 全部只读(不含预计异动里程)。',
'2.车辆信息:在出发停车场后展示预计异动里程(用例值,只读);其余与结束异动表列一致(含开始/结束里程氢量电量);仅 1 行;无新增行与删除。',
'3.底部仅「返回」按钮,返回异动管理列表(原型)。'
].join('\n');
@@ -323,14 +338,6 @@ const Component = function () {
disabled: true
})
),
React.createElement('div', { style: formItemStyle },
React.createElement('div', { style: labelStyle }, '预计异动里程'),
React.createElement(Input, {
value: fmtPlannedMileage(movementReadonly.plannedMileageKm),
disabled: true,
addonAfter: 'km'
})
),
React.createElement('div', { style: formItemStyle },
React.createElement('div', { style: labelStyle }, '审批状态'),
React.createElement(Select, {
@@ -340,8 +347,6 @@ const Component = function () {
disabled: true
})
),
React.createElement('div', { style: formItemStyle }),
React.createElement('div', { style: formItemStyle }),
React.createElement('div', { style: formItemStyle },
React.createElement('div', { style: labelStyle }, '异动结束时间'),
React.createElement(DatePicker, {
@@ -353,6 +358,8 @@ const Component = function () {
inputReadOnly: true
})
),
React.createElement('div', { style: formItemStyle }),
React.createElement('div', { style: formItemStyle }),
React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: 'span 3' }) },
React.createElement('div', { style: labelStyle }, '备注'),
React.createElement(Input.TextArea, {
@@ -371,7 +378,7 @@ const Component = function () {
dataSource: vehicles,
size: 'small',
pagination: false,
scroll: { x: 1780 }
scroll: { x: 1940 }
})
),

View File

@@ -95,7 +95,6 @@ const Component = function () {
destinationType: '其他',
destinationName: '车管所检测线',
changeType: '年审',
plannedMileageKm: '8.20',
remark: '年审上线检测,预计半日完成。'
};
}, []);
@@ -109,6 +108,7 @@ const Component = function () {
brand: '比亚迪',
model: '汉',
departParking: '南山科技园停车场',
plannedMileageKm: '8.20',
startMileageKm: '8020.50',
startHydrogen: '55.00',
h2Unit: '%',
@@ -130,7 +130,7 @@ const Component = function () {
});
}, []);
// 1.7 异动结束时间必填YYYY-MM-DD HH:mm
// 1.6 异动结束时间必填YYYY-MM-DD HH:mm
var endDateTimeState = useState(getInitialDateTime('2026-02-24 11:30'));
var endDateTime = endDateTimeState[0];
var setEndDateTime = endDateTimeState[1];
@@ -182,6 +182,21 @@ const Component = function () {
return React.createElement(Input, { value: rowVehicleSelected(r) ? (r.departParking || '-') : '请先选择车辆', disabled: true });
}
},
{
title: '预计异动里程',
key: 'plannedMileageKm',
width: 160,
render: function (_, r) {
if (!rowVehicleSelected(r)) {
return React.createElement(Input, { value: '', disabled: true, placeholder: placeholderSelectVehicle });
}
return React.createElement(Input, {
value: fmtPlannedMileage(r.plannedMileageKm),
disabled: true,
addonAfter: 'km'
});
}
},
{
title: '异动开始里程',
key: 'startMileageKm',
@@ -286,9 +301,8 @@ const Component = function () {
'1.3.异动目的地:显示异动目的地,包括:停车场、维修站、其他;',
'1.4.目的地名称:显示目的地名称,包括:停车场名称、维修站名称、其他;',
'1.5.异动类型:显示异动类型,包括:维修、保养、年审、其他;',
'1.6.预计异动里程显示预计异动里程支持2位小数后缀为km',
'1.7.异动结束时间必填项日期选择器格式为YYYY-MM-DD HH:MM',
'1.8.备注:显示备注信息;',
'1.6.异动结束时间必填项日期选择器格式为YYYY-MM-DD HH:MM',
'1.7.备注:显示备注信息',
'',
'2.车辆信息:',
'2.1.车牌号:输入框(禁用),显示车牌号;',
@@ -296,13 +310,14 @@ const Component = function () {
'2.3.品牌:根据所选车辆品牌自动反写,默认提示为请先选择车辆;',
'2.4.型号:根据所选车辆型号自动反写,默认提示为请先选择车辆;',
'2.5.出发停车场:根据所选车辆出发时停车场自动反写,默认提示为请先选择车辆;',
'2.6.异动开始里程:输入框(禁用),精确至2位小数后缀为km',
'2.7.异动结束里程:必填项,输入框精确至2位小数后缀为km',
'2.8.异动开始氢量输入框禁用精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.9.异动结束氢量:必填项,输入框精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.10.异动开始电量输入框禁用精确至2位小数后缀为kWh',
'2.11.异动结束电量:必填项,输入框精确至2位小数后缀为kWh',
'2.6.预计异动里程:显示预计异动里程,支持2位小数后缀为km',
'2.7.异动开始里程:输入框(禁用)精确至2位小数后缀为km',
'2.8.异动结束里程必填项输入框精确至2位小数后缀为km',
'2.9.异动开始氢量:输入框(禁用)精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.10.异动结束氢量必填项输入框精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.11.异动开始电量:输入框(禁用)精确至2位小数后缀为kWh',
'2.12.异动结束电量必填项输入框精确至2位小数后缀为kWh',
'2.13.异动结束电量必填项输入框精确至2位小数后缀为kWh',
'',
'3.底部为提交、取消;',
'3.1.提交:提交进行必填项校验,提交成功后计入历史记录;',
@@ -401,14 +416,6 @@ const Component = function () {
disabled: true
})
),
React.createElement('div', { style: formItemStyle },
React.createElement('div', { style: labelStyle }, '预计异动里程'),
React.createElement(Input, {
value: fmtPlannedMileage(movementReadonly.plannedMileageKm),
disabled: true,
addonAfter: 'km'
})
),
React.createElement('div', { style: formItemStyle },
labelWithRequired('异动结束时间', true),
React.createElement(DatePicker, {
@@ -438,7 +445,7 @@ const Component = function () {
dataSource: vehicles,
size: 'small',
pagination: false,
scroll: { x: 1780 }
scroll: { x: 1940 }
})
),

View File

@@ -1,5 +1,5 @@
// 【重要】必须使用 const Component 作为组件变量名
// 运维管理 - 车辆业务 - 异动管理 - 编辑
// 运维管理 - 车辆业务 - 异动管理 - 编辑(与「异动管理-新增」同步维护)
const Component = function () {
var useState = React.useState;
@@ -37,6 +37,16 @@ const Component = function () {
return s;
}
function getInitialDateTime(str) {
try {
if (window.dayjs) return window.dayjs(str);
} catch (e1) {}
try {
if (window.moment) return window.moment(str, 'YYYY-MM-DD HH:mm');
} catch (e2) {}
return null;
}
var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' };
var labelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' };
var formItemStyle = { marginBottom: 12 };
@@ -101,6 +111,7 @@ const Component = function () {
var requirementDocContent = [
'一个「数字化资产ONEOS运管平台」中的「异动管理」「编辑」模块',
'#面包屑:运维管理-车辆业务-异动管理-编辑',
'(原型)进入页面预填用例数据,联调时由详情接口按异动 ID 回填。',
'',
'1.异动情况;',
'1.1.异动开始日期必填项日期选择器格式为YYYY-MM-DD HH:MM',
@@ -108,8 +119,7 @@ const Component = function () {
'1.3.异动目的地:必填项,选择器,选项为:停车场、维修站、其他;',
'2.4.目的地名称:必填项,如异动目的地为停车场,则此处为停车场(选择器),如异动目的地为维修站,则此处为维修站(选择器),如异动目的地为其他,则此处为输入框(自定义输入);',
'2.5.异动类型:必填项,选择器,选项为:维修、保养、年审、其他;',
'2.6.预计异动里程输入框支持2位小数输入后缀为km',
'2.7.备注:文本域,支持自定义输入;',
'2.6.备注:文本域,支持自定义输入',
'',
'2.车辆信息:',
'2.1.车牌号:显示车牌号,支持输入框模糊搜索下拉匹配对应选项;',
@@ -117,24 +127,25 @@ const Component = function () {
'2.3.品牌:根据所选车辆品牌自动反写,默认提示为请先选择车辆;',
'2.4.型号:根据所选车辆型号自动反写,默认提示为请先选择车辆;',
'2.5.出发停车场:根据所选车辆出发时停车场自动反写,默认提示为请先选择车辆;',
'2.6.异动开始里程:必填项,输入框,精确至2位小数后缀为km',
'2.7.异动开始氢量必填项输入框精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.8.异动开始必填项输入框精确至2位小数后缀为kWh',
'2.9.操作:删除',
'2.10.新增一行:铺满整行',
'2.6.预计异动里程:输入框,支持2位小数输入后缀为km',
'2.7.异动开始里程必填项输入框精确至2位小数后缀为km',
'2.8.异动开始必填项输入框精确至2位小数后缀为%或MPa根据所选车辆型号中获取',
'2.9.异动开始电量必填项输入框精确至2位小数后缀为kWh',
'2.10.操作:删除',
'2.11.新增一行:铺满整行;',
'',
'3.底部为提交审核、保存、取消;'
].join('\n');
// 原型:进入编辑页时由详情接口回填;以下为联调前用例数据
var formState = useState({
startTime: null,
plannedEndTime: null,
destinationType: undefined,
destinationName: undefined,
startTime: getInitialDateTime('2026-02-20 09:30'),
plannedEndTime: getInitialDateTime('2026-02-22 18:00'),
destinationType: '维修站',
destinationName: '广州天河维修站',
destinationNameOther: '',
changeType: undefined,
plannedMileageKm: '',
remark: ''
changeType: '维修',
remark: '车辆需进站检修制动系统,预计两日内完成。'
});
var form = formState[0];
var setForm = formState[1];
@@ -143,19 +154,33 @@ const Component = function () {
var errors = errorsState[0];
var setErrors = errorsState[1];
var rowIdRef = React.useRef(2);
var rowIdRef = React.useRef(3);
var vehiclesState = useState([
{
id: 1,
plateNo: undefined,
vehicleType: '',
brand: '',
model: '',
departParking: '',
h2Unit: '',
startMileageKm: '',
startHydrogen: '',
startElectricKwh: ''
plateNo: '粤A12345',
vehicleType: '厢式货车',
brand: '东风',
model: 'DFH1180',
departParking: '天河智慧停车场',
h2Unit: 'MPa',
plannedMileageKm: '45.50',
startMileageKm: '15230.12',
startHydrogen: '28.30',
startElectricKwh: '68.40'
},
{
id: 2,
plateNo: '浙A11111',
vehicleType: 'SUV',
brand: '小鹏',
model: 'P7',
departParking: '西湖景区停车场',
h2Unit: '%',
plannedMileageKm: '120.00',
startMileageKm: '12010.00',
startHydrogen: '60.00',
startElectricKwh: '55.20'
}
]);
var vehicles = vehiclesState[0];
@@ -176,14 +201,16 @@ const Component = function () {
var handlePlateChange = useCallback(function (index, plateNo) {
var v = vehicleDb.find(function (x) { return x.plateNo === plateNo; });
updateRow(index, {
var patch = {
plateNo: plateNo,
vehicleType: v ? v.vehicleType : '',
brand: v ? v.brand : '',
model: v ? v.model : '',
departParking: v ? v.departParking : '',
h2Unit: v ? v.h2Unit : ''
});
};
if (!v) patch.plannedMileageKm = '';
updateRow(index, patch);
}, [vehicleDb, updateRow]);
var addRow = useCallback(function () {
@@ -196,6 +223,7 @@ const Component = function () {
model: '',
departParking: '',
h2Unit: '',
plannedMileageKm: '',
startMileageKm: '',
startHydrogen: '',
startElectricKwh: ''
@@ -216,6 +244,7 @@ const Component = function () {
model: '',
departParking: '',
h2Unit: '',
plannedMileageKm: '',
startMileageKm: '',
startHydrogen: '',
startElectricKwh: ''
@@ -243,6 +272,7 @@ const Component = function () {
for (var i = 0; i < (vehicles || []).length; i++) {
var r = vehicles[i] || {};
if (!String(r.plateNo || '').trim()) continue;
if (!String(r.plannedMileageKm || '').trim()) e['row_' + i + '_plannedMileageKm'] = '请输入预计异动里程';
if (!String(r.startMileageKm || '').trim()) e['row_' + i + '_startMileageKm'] = '请输入异动开始里程';
if (!String(r.startHydrogen || '').trim()) e['row_' + i + '_startHydrogen'] = '请输入异动开始氢量';
if (!String(r.startElectricKwh || '').trim()) e['row_' + i + '_startElectricKwh'] = '请输入异动开始电量';
@@ -362,6 +392,21 @@ const Component = function () {
return React.createElement(Input, { value: r.departParking ? r.departParking : '请先选择车辆', disabled: true });
}
},
{
title: React.createElement('span', null, reqStar, '预计异动里程'),
key: 'plannedMileageKm',
width: 160,
render: function (_, r, index) {
var k = 'row_' + index + '_plannedMileageKm';
return React.createElement(Input, {
value: r.plannedMileageKm,
onChange: function (e) { updateRow(index, { plannedMileageKm: toFixed2Input(e.target.value) }); },
placeholder: '0.00',
addonAfter: 'km',
status: errors[k] ? 'error' : undefined
});
}
},
{
title: React.createElement('span', null, reqStar, '异动开始里程'),
key: 'startMileageKm',
@@ -504,15 +549,6 @@ const Component = function () {
}),
errors.changeType ? React.createElement('div', { style: { marginTop: 4, color: '#ff4d4f', fontSize: 12 } }, errors.changeType) : null
),
React.createElement('div', { style: formItemStyle },
React.createElement('div', { style: labelStyle }, '预计异动里程'),
React.createElement(Input, {
placeholder: '0.00',
value: form.plannedMileageKm,
onChange: function (e) { updateForm({ plannedMileageKm: toFixed2Input(e.target.value) }); },
addonAfter: 'km'
})
),
React.createElement('div', { style: Object.assign({}, formItemStyle, { gridColumn: 'span 3' }) },
React.createElement('div', { style: labelStyle }, '备注'),
@@ -534,7 +570,7 @@ const Component = function () {
dataSource: vehicles,
size: 'small',
pagination: false,
scroll: { x: 1250 }
scroll: { x: 1410 }
}),
React.createElement(Button, { type: 'dashed', style: { marginTop: 12, width: '100%' }, onClick: addRow }, '新增一行')
),

View File

@@ -586,7 +586,7 @@ const Component = function () {
}, []);
var handleAdd = useCallback(function () {
message.info('新增异动(原型,联调时跳转新建页或打开表单');
message.info('跳转异动-新增页(原型,表单与编辑页一致,联调时按路由区分新建/编辑');
}, []);
function fmtNowYMDHM() {
@@ -747,7 +747,7 @@ const Component = function () {
}, '结束异动'));
}
if (canShowMovementEdit(r.approvalStatus)) {
nodes.push(React.createElement(Button, { key: 'edit', type: 'link', size: 'small', onClick: function () { message.info('跳转异动-编辑页原型ID' + r.id); } }, '编辑'));
nodes.push(React.createElement(Button, { key: 'edit', type: 'link', size: 'small', onClick: function () { message.info('跳转异动-编辑页(原型,表单与新增页一致ID' + r.id); } }, '编辑'));
}
return React.createElement(React.Fragment, null, nodes);
}