feat(web): 交车任务序号列、客户管理、车辆成本维护、筛选展开收起
- 新增/编辑/查看交车任务:品牌前增加序号列,与租赁合同车辆序号对应,需求说明同步更新 - 业务管理:新增客户管理.jsx(筛选+列表+查看/编辑/删除),筛选展开收起对齐租赁合同管理 - 业务管理:新增车辆成本维护.jsx(级联筛选、租赁/自营日成本、编辑) - 需求说明:提车应收款文档微调 Made-with: Cursor
This commit is contained in:
233
web端/业务管理/车辆成本维护.jsx
Normal file
233
web端/业务管理/车辆成本维护.jsx
Normal file
@@ -0,0 +1,233 @@
|
||||
// 【重要】必须使用 const Component 作为组件变量名
|
||||
// 业务管理 - 车辆成本维护(2026年3月12日版本)
|
||||
|
||||
const Component = function () {
|
||||
var useState = React.useState;
|
||||
var useMemo = React.useMemo;
|
||||
|
||||
var antd = window.antd;
|
||||
var Breadcrumb = antd.Breadcrumb;
|
||||
var Card = antd.Card;
|
||||
var Table = antd.Table;
|
||||
var Button = antd.Button;
|
||||
var Input = antd.Input;
|
||||
var Space = antd.Space;
|
||||
var Modal = antd.Modal;
|
||||
var Cascader = antd.Cascader;
|
||||
var message = antd.message;
|
||||
|
||||
var requirementModalVisible = useState(false);
|
||||
var filterCascaderValue = useState(undefined); // [brand] 或 [brand, model]
|
||||
var listDataState = useState([
|
||||
{ id: 1, brand: '东风', model: '18吨双飞翼', rentalCostPerDay: 260.00, selfOperatedCostPerDay: 250.00 },
|
||||
{ id: 2, brand: '福田', model: '18吨厢式', rentalCostPerDay: 255.00, selfOperatedCostPerDay: 245.00 },
|
||||
{ id: 3, brand: '重汽', model: '18吨栏板', rentalCostPerDay: 270.00, selfOperatedCostPerDay: 260.00 },
|
||||
{ id: 4, brand: '陕汽', model: '25吨牵引', rentalCostPerDay: 268.00, selfOperatedCostPerDay: 258.00 },
|
||||
{ id: 5, brand: '解放', model: '18吨冷藏', rentalCostPerDay: 262.00, selfOperatedCostPerDay: 252.00 },
|
||||
{ id: 6, brand: '江淮', model: '9吨厢式', rentalCostPerDay: 248.00, selfOperatedCostPerDay: 238.00 },
|
||||
{ id: 7, brand: '东风', model: '25吨栏板', rentalCostPerDay: 275.00, selfOperatedCostPerDay: 265.00 },
|
||||
{ id: 8, brand: '福田', model: '25吨飞翼', rentalCostPerDay: 272.00, selfOperatedCostPerDay: 262.00 },
|
||||
{ id: 9, brand: '重汽', model: '25吨冷藏', rentalCostPerDay: 278.00, selfOperatedCostPerDay: 268.00 },
|
||||
{ id: 10, brand: '陕汽', model: '18吨自卸', rentalCostPerDay: 265.00, selfOperatedCostPerDay: 255.00 }
|
||||
]);
|
||||
var listData = listDataState[0];
|
||||
var setListData = listDataState[1];
|
||||
var editingKeyState = useState(null);
|
||||
var editingKey = editingKeyState[0];
|
||||
var setEditingKey = editingKeyState[1];
|
||||
var editRentalState = useState('');
|
||||
var editRental = editRentalState[0];
|
||||
var setEditRental = editRentalState[1];
|
||||
var editSelfOperatedState = useState('');
|
||||
var editSelfOperated = editSelfOperatedState[0];
|
||||
var setEditSelfOperated = editSelfOperatedState[1];
|
||||
|
||||
var cascaderOptions = useMemo(function () {
|
||||
var map = {};
|
||||
listData.forEach(function (r) {
|
||||
if (!r.brand) return;
|
||||
if (!map[r.brand]) map[r.brand] = { value: r.brand, label: r.brand, children: [] };
|
||||
var children = map[r.brand].children;
|
||||
var model = r.model || '';
|
||||
if (model && children.every(function (c) { return c.value !== model; })) {
|
||||
children.push({ value: model, label: model });
|
||||
}
|
||||
});
|
||||
return Object.keys(map).map(function (k) { return map[k]; });
|
||||
}, [listData]);
|
||||
|
||||
var filteredList = useMemo(function () {
|
||||
var val = filterCascaderValue[0];
|
||||
if (!val || !Array.isArray(val) || val.length === 0) return listData;
|
||||
var brand = val[0];
|
||||
var model = val[1];
|
||||
if (model) return listData.filter(function (r) { return r.brand === brand && r.model === model; });
|
||||
return listData.filter(function (r) { return r.brand === brand; });
|
||||
}, [listData, filterCascaderValue[0]]);
|
||||
|
||||
function fmtCost(v) {
|
||||
var n = typeof v === 'number' ? v : parseFloat(v);
|
||||
return (isNaN(n) ? '0.00' : n.toFixed(2)) + '元';
|
||||
}
|
||||
|
||||
function saveRow(id) {
|
||||
var r = parseFloat(editRental);
|
||||
var s = parseFloat(editSelfOperated);
|
||||
if (isNaN(r) || r < 0 || isNaN(s) || s < 0) {
|
||||
message.warning('请输入有效的日成本(元),支持两位小数');
|
||||
return;
|
||||
}
|
||||
setListData(function (prev) {
|
||||
return prev.map(function (row) {
|
||||
if (row.id !== id) return row;
|
||||
var o = {}; for (var k in row) o[k] = row[k];
|
||||
o.rentalCostPerDay = Math.round(r * 100) / 100;
|
||||
o.selfOperatedCostPerDay = Math.round(s * 100) / 100;
|
||||
return o;
|
||||
});
|
||||
});
|
||||
setEditingKey(null);
|
||||
setEditRental('');
|
||||
setEditSelfOperated('');
|
||||
message.success('保存成功');
|
||||
}
|
||||
|
||||
function cancelEdit() {
|
||||
setEditingKey(null);
|
||||
setEditRental('');
|
||||
setEditSelfOperated('');
|
||||
}
|
||||
|
||||
var layoutStyle = { padding: '16px 24px', background: '#f5f5f5', minHeight: '100vh' };
|
||||
var cardStyle = { marginBottom: 16 };
|
||||
var filterLabelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' };
|
||||
var filterItemStyle = { marginBottom: 12 };
|
||||
var filterControlStyle = { width: '100%', maxWidth: 320 };
|
||||
|
||||
var columns = [
|
||||
{ title: '序号', key: 'idx', width: 72, align: 'center', render: function (_, __, index) { return index + 1; } },
|
||||
{ title: '品牌', dataIndex: 'brand', key: 'brand', width: 120, ellipsis: true, render: function (v) { return v || '—'; } },
|
||||
{ title: '型号', dataIndex: 'model', key: 'model', width: 160, ellipsis: true, render: function (v) { return v || '—'; } },
|
||||
{
|
||||
title: '租赁车辆日成本',
|
||||
dataIndex: 'rentalCostPerDay',
|
||||
key: 'rentalCostPerDay',
|
||||
width: 160,
|
||||
align: 'right',
|
||||
render: function (v, record) {
|
||||
var id = record.id;
|
||||
var isEditing = editingKey === id;
|
||||
if (isEditing) {
|
||||
return React.createElement(Input, {
|
||||
type: 'number',
|
||||
step: 0.01,
|
||||
min: 0,
|
||||
value: editRental,
|
||||
onChange: function (e) { setEditRental(e.target.value); },
|
||||
style: { width: 120, textAlign: 'right' },
|
||||
addonAfter: '元'
|
||||
});
|
||||
}
|
||||
return fmtCost(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '自营车辆日成本',
|
||||
dataIndex: 'selfOperatedCostPerDay',
|
||||
key: 'selfOperatedCostPerDay',
|
||||
width: 160,
|
||||
align: 'right',
|
||||
render: function (v, record) {
|
||||
var id = record.id;
|
||||
var isEditing = editingKey === id;
|
||||
if (isEditing) {
|
||||
return React.createElement(Input, {
|
||||
type: 'number',
|
||||
step: 0.01,
|
||||
min: 0,
|
||||
value: editSelfOperated,
|
||||
onChange: function (e) { setEditSelfOperated(e.target.value); },
|
||||
style: { width: 120, textAlign: 'right' },
|
||||
addonAfter: '元'
|
||||
});
|
||||
}
|
||||
return fmtCost(v);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 140,
|
||||
render: function (_, record) {
|
||||
var isEditing = editingKey === record.id;
|
||||
if (isEditing) {
|
||||
return React.createElement(Space, { size: 'small' },
|
||||
React.createElement(Button, { type: 'link', size: 'small', onClick: function () { saveRow(record.id); } }, '保存'),
|
||||
React.createElement(Button, { type: 'link', size: 'small', onClick: cancelEdit }, '取消')
|
||||
);
|
||||
}
|
||||
return React.createElement(Button, {
|
||||
type: 'link',
|
||||
size: 'small',
|
||||
onClick: function () {
|
||||
setEditingKey(record.id);
|
||||
setEditRental(record.rentalCostPerDay != null ? String(record.rentalCostPerDay) : '');
|
||||
setEditSelfOperated(record.selfOperatedCostPerDay != null ? String(record.selfOperatedCostPerDay) : '');
|
||||
}
|
||||
}, '编辑');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
var requirementContent = '车辆成本维护(2026年3月12日版本)\n一个「数字化资产ONEOS运管平台」中的「车辆成本维护」模块\n#面包屑:业务管理-车辆成本维护;\n\n页面分为2个卡片;\n1.筛选:\n#支持车辆品牌、型号筛选;\n1.1.型号:级联选择器,支持品牌、型号级联;\n\n2.车辆成本列表:列表默认显示当前系统中所有品牌和型号记录,如型号参数表有新增,则该处同步新增一条数据;\n2.1.品牌:显示车辆品牌;\n2.2.型号:显示车辆型号(如18吨双飞翼,而不是公告型号);\n2.3.租赁车辆日成本:显示格式为:xx.xx元,支持两位小数;\n2.4.自营车辆日成本:显示格式为:xx.xx元,支持两位小数;\n2.5.操作:编辑;';
|
||||
|
||||
return React.createElement('div', { style: layoutStyle },
|
||||
React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } },
|
||||
React.createElement(Breadcrumb, {
|
||||
items: [
|
||||
{ title: '业务管理' },
|
||||
{ title: '车辆成本维护' }
|
||||
]
|
||||
}),
|
||||
React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { requirementModalVisible[1](true); } }, '查看需求说明')
|
||||
),
|
||||
React.createElement(Card, { title: '筛选', style: cardStyle },
|
||||
React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'flex-end', gap: 16 } },
|
||||
React.createElement('div', { style: filterItemStyle },
|
||||
React.createElement('div', { style: filterLabelStyle }, '型号'),
|
||||
React.createElement(Cascader, {
|
||||
options: cascaderOptions,
|
||||
value: filterCascaderValue[0],
|
||||
onChange: function (v) { filterCascaderValue[1](v); },
|
||||
placeholder: '请选择品牌 / 型号',
|
||||
allowClear: true,
|
||||
style: filterControlStyle,
|
||||
changeOnSelect: true
|
||||
})
|
||||
),
|
||||
React.createElement('div', { style: { display: 'flex', gap: 8 } },
|
||||
React.createElement(Button, { onClick: function () { filterCascaderValue[1](undefined); } }, '重置'),
|
||||
React.createElement(Button, { type: 'primary' }, '查询')
|
||||
)
|
||||
)
|
||||
),
|
||||
React.createElement(Card, { title: '车辆成本列表', style: cardStyle },
|
||||
React.createElement(Table, {
|
||||
rowKey: 'id',
|
||||
columns: columns,
|
||||
dataSource: filteredList,
|
||||
pagination: { pageSize: 10, showSizeChanger: true, showTotal: function (t) { return '共 ' + t + ' 条'; } },
|
||||
size: 'middle',
|
||||
bordered: true
|
||||
})
|
||||
),
|
||||
React.createElement(Modal, {
|
||||
title: '需求说明',
|
||||
open: requirementModalVisible[0],
|
||||
onCancel: function () { requirementModalVisible[1](false); },
|
||||
width: 560,
|
||||
footer: React.createElement(Button, { onClick: function () { requirementModalVisible[1](false); } }, '关闭'),
|
||||
bodyStyle: { maxHeight: '70vh', overflow: 'auto' }
|
||||
}, React.createElement('div', { style: { padding: '8px 0', whiteSpace: 'pre-wrap', fontSize: 13, lineHeight: 1.6 } }, requirementContent))
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user