Initial commit: ONE-OS project

Made-with: Cursor
This commit is contained in:
王冕
2026-02-27 18:11:40 +08:00
commit 09cc45db36
47 changed files with 17589 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

2
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,2 @@
{
}

506
blueway/数据集管理.jsx Normal file
View File

@@ -0,0 +1,506 @@
// 【重要】必须使用 const Component 作为组件变量名
// 数据集管理 - 模仿 GitLab 项目列表风格(纯 React不依赖 antd兼容 Axhub
const Component = function () {
var useState = React.useState;
var useCallback = React.useCallback;
var useMemo = React.useMemo;
// GitLab 风格色值Pajamas 近似)
var colors = {
pageBg: '#fafafa',
cardBg: '#ffffff',
border: '#e5e5e5',
borderLight: '#ebebeb',
text: '#333333',
textSecondary: '#666666',
textMuted: '#999999',
primary: '#1f75cb',
primaryHover: '#1068bf',
link: '#1f75cb',
success: '#108548',
warning: '#c17d10',
danger: '#dd2b0e',
hoverBg: '#f5f5f5',
tabActive: '#333333',
tabInactive: '#666666'
};
var filterState = useState({
keyword: '',
datasetType: '',
status: ''
});
var filters = filterState[0];
var setFilters = filterState[1];
var activeTabState = useState('all');
var activeTab = activeTabState[0];
var setActiveTab = activeTabState[1];
var sortState = useState('updated_desc');
var sortBy = sortState[0];
var setSortBy = sortState[1];
var listState = useState([
{ id: '1', name: '销售数据集', type: '表格', recordCount: 12000, createTime: '2025-02-20 10:00', updateTime: '2025-02-24 14:00', status: '已发布', remark: '销售业务数据', isStarred: true, owner: '当前用户' },
{ id: '2', name: '客户画像数据集', type: '表格', recordCount: 8500, createTime: '2025-02-19 14:30', updateTime: '2025-02-23 09:00', status: '草稿', remark: '客户标签与画像', isStarred: false, owner: '当前用户' },
{ id: '3', name: '订单明细数据集', type: '表格', recordCount: 25600, createTime: '2025-02-18 09:15', updateTime: '2025-02-22 16:30', status: '已发布', remark: '订单明细与物流', isStarred: true, owner: '当前用户' },
{ id: '4', name: '库存数据集', type: '文件', recordCount: 5200, createTime: '2025-02-17 11:00', updateTime: '2025-02-21 10:00', status: '已下线', remark: '仓库库存快照', isStarred: false, owner: '其他用户' }
]);
var dataList = listState[0];
var setDataList = listState[1];
var pageState = useState(1);
var page = pageState[0];
var setPage = pageState[1];
var pageSizeState = useState(20);
var pageSize = pageSizeState[0];
var modalState = useState({ open: false, record: null, mode: 'view' });
var modalOpen = modalState[0].open;
var modalRecord = modalState[0].record;
var modalMode = modalState[0].mode;
var setModalState = modalState[1];
var dropdownOpenIdState = useState(null);
var dropdownOpenId = dropdownOpenIdState[0];
var setDropdownOpenId = dropdownOpenIdState[1];
var confirmState = useState({ open: false, record: null });
var confirmOpen = confirmState[0].open;
var confirmRecord = confirmState[0].record;
var setConfirmState = confirmState[1];
var toastState = useState({ show: false, text: '' });
var toastShow = toastState[0].show;
var toastText = toastState[0].text;
var setToastState = toastState[1];
var typeOptions = useMemo(function () {
return [
{ value: '表格', label: '表格' },
{ value: '文件', label: '文件' },
{ value: 'API', label: 'API' }
];
}, []);
var statusOptions = useMemo(function () {
return [
{ value: '草稿', label: '草稿' },
{ value: '已发布', label: '已发布' },
{ value: '已下线', label: '已下线' }
];
}, []);
var sortOptions = useMemo(function () {
return [
{ value: 'updated_desc', label: '最近更新' },
{ value: 'created_desc', label: '最近创建' },
{ value: 'name_asc', label: '名称 A-Z' },
{ value: 'name_desc', label: '名称 Z-A' }
];
}, []);
var filteredList = useMemo(function () {
var list = dataList.slice();
if (activeTab === 'mine') list = list.filter(function (r) { return r.owner === '当前用户'; });
if (activeTab === 'published') list = list.filter(function (r) { return r.status === '已发布'; });
if (activeTab === 'draft') list = list.filter(function (r) { return r.status === '草稿'; });
if (activeTab === 'starred') list = list.filter(function (r) { return r.isStarred; });
if (filters.keyword) {
var kw = filters.keyword.trim().toLowerCase();
list = list.filter(function (r) {
return (r.name && r.name.toLowerCase().indexOf(kw) !== -1) ||
(r.remark && r.remark.toLowerCase().indexOf(kw) !== -1);
});
}
if (filters.datasetType) list = list.filter(function (r) { return r.type === filters.datasetType; });
if (filters.status) list = list.filter(function (r) { return r.status === filters.status; });
if (sortBy === 'updated_desc') list.sort(function (a, b) { return (b.updateTime || b.createTime || '').localeCompare(a.updateTime || a.createTime || ''); });
else if (sortBy === 'created_desc') list.sort(function (a, b) { return (b.createTime || '').localeCompare(a.createTime || ''); });
else if (sortBy === 'name_asc') list.sort(function (a, b) { return (a.name || '').localeCompare(b.name || ''); });
else if (sortBy === 'name_desc') list.sort(function (a, b) { return (b.name || '').localeCompare(a.name || ''); });
return list;
}, [dataList, activeTab, filters, sortBy]);
var displayList = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredList.slice(start, start + pageSize);
}, [filteredList, page, pageSize]);
var totalCount = filteredList.length;
var handleQuery = useCallback(function () { setPage(1); }, []);
var handleReset = useCallback(function () {
setFilters({ keyword: '', datasetType: '', status: '' });
setPage(1);
}, []);
var openModal = useCallback(function (record, mode) {
setModalState({ open: true, record: record || null, mode: mode || 'view' });
setDropdownOpenId(null);
}, []);
var closeModal = useCallback(function () {
setModalState({ open: false, record: null, mode: 'view' });
}, []);
var showToast = useCallback(function (text) {
setToastState({ show: true, text: text });
setTimeout(function () { setToastState({ show: false, text: '' }); }, 2000);
}, []);
var toggleStar = useCallback(function (record, e) {
if (e) e.stopPropagation();
setDataList(dataList.map(function (r) {
if (r.id === record.id) return Object.assign({}, r, { isStarred: !r.isStarred });
return r;
}));
}, [dataList]);
var openConfirm = useCallback(function (record) {
setConfirmState({ open: true, record: record });
setDropdownOpenId(null);
}, []);
var closeConfirm = useCallback(function () {
setConfirmState({ open: false, record: null });
}, []);
var handleDelete = useCallback(function (record) {
setDataList(dataList.filter(function (r) { return r.id !== record.id; }));
closeConfirm();
showToast('已删除');
}, [dataList]);
function statusTag(status) {
var bg = status === '已发布' ? '#e7f5ec' : (status === '草稿' ? '#f0f0f0' : '#fdf3e6');
var color = status === '已发布' ? colors.success : (status === '草稿' ? colors.textSecondary : colors.warning);
return React.createElement('span', {
style: {
display: 'inline-block',
padding: '2px 8px',
borderRadius: 4,
fontSize: 12,
background: bg,
color: color
}
}, status);
}
var tabs = [
{ key: 'all', label: '全部' },
{ key: 'mine', label: '我创建的' },
{ key: 'starred', label: '已加星' },
{ key: 'published', label: '已发布' },
{ key: 'draft', label: '草稿' }
];
return React.createElement('div', {
style: { minHeight: '100vh', background: colors.pageBg, padding: '24px 24px 48px', position: 'relative' }
},
// 标题栏
React.createElement('div', {
style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16, flexWrap: 'wrap', gap: 12 }
},
React.createElement('h1', { style: { margin: 0, fontSize: 24, fontWeight: 600, color: colors.text } }, '数据集'),
React.createElement('button', {
type: 'button',
onClick: function () { openModal(null, 'add'); },
style: {
padding: '6px 16px',
border: 'none',
borderRadius: 6,
background: colors.primary,
color: '#fff',
fontSize: 14,
cursor: 'pointer',
fontWeight: 500
}
}, '新建数据集')
),
// 搜索与筛选
React.createElement('div', {
style: { background: colors.cardBg, border: '1px solid ' + colors.border, borderRadius: 6, padding: '12px 16px', marginBottom: 0 }
},
React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 12 } },
React.createElement('div', { style: { display: 'flex', width: 280 } },
React.createElement('input', {
type: 'text',
placeholder: '搜索数据集…',
value: filters.keyword,
onChange: function (e) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.keyword = e.target.value; return g; }); },
onKeyDown: function (e) { if (e.key === 'Enter') handleQuery(); },
style: {
flex: 1,
padding: '6px 12px',
border: '1px solid ' + colors.border,
borderRight: 'none',
borderRadius: '6px 0 0 6px',
fontSize: 14,
outline: 'none'
}
}),
React.createElement('button', {
type: 'button',
onClick: handleQuery,
style: {
padding: '6px 12px',
border: '1px solid ' + colors.border,
borderRadius: '0 6px 6px 0',
background: colors.pageBg,
cursor: 'pointer',
fontSize: 14
}
}, '搜索')
),
React.createElement('select', {
value: filters.datasetType,
onChange: function (e) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.datasetType = e.target.value; return g; }); },
style: { width: 100, padding: '6px 8px', border: '1px solid ' + colors.border, borderRadius: 6, fontSize: 14 }
},
React.createElement('option', { value: '' }, '类型'),
typeOptions.map(function (o) { return React.createElement('option', { key: o.value, value: o.value }, o.label); })
),
React.createElement('select', {
value: filters.status,
onChange: function (e) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.status = e.target.value; return g; }); },
style: { width: 100, padding: '6px 8px', border: '1px solid ' + colors.border, borderRadius: 6, fontSize: 14 }
},
React.createElement('option', { value: '' }, '状态'),
statusOptions.map(function (o) { return React.createElement('option', { key: o.value, value: o.value }, o.label); })
),
React.createElement('button', { type: 'button', onClick: handleQuery, style: { padding: '6px 14px', border: '1px solid ' + colors.border, borderRadius: 6, background: colors.cardBg, cursor: 'pointer', fontSize: 14 } }, '搜索'),
React.createElement('button', { type: 'button', onClick: handleReset, style: { padding: '6px 14px', border: '1px solid ' + colors.border, borderRadius: 6, background: colors.cardBg, cursor: 'pointer', fontSize: 14 } }, '重置'),
React.createElement('span', { style: { marginLeft: 'auto', color: colors.textMuted, fontSize: 12 } },
'排序:',
React.createElement('select', {
value: sortBy,
onChange: function (e) { setSortBy(e.target.value); },
style: { width: 120, marginLeft: 4, padding: '4px 8px', border: 'none', background: 'transparent', fontSize: 12, color: colors.textSecondary, cursor: 'pointer' }
},
sortOptions.map(function (o) { return React.createElement('option', { key: o.value, value: o.value }, o.label); })
)
)
)
),
// Tab
React.createElement('div', {
style: { background: colors.cardBg, border: '1px solid ' + colors.border, borderTop: 'none', borderRadius: '0 0 6px 6px', padding: '0 16px', marginBottom: 16, display: 'flex', gap: 8 }
},
tabs.map(function (t) {
var isActive = activeTab === t.key;
return React.createElement('button', {
key: t.key,
type: 'button',
onClick: function () { setActiveTab(t.key); setPage(1); },
style: {
padding: '12px 4px',
margin: 0,
border: 'none',
background: 'none',
cursor: 'pointer',
fontSize: 14,
color: isActive ? colors.tabActive : colors.tabInactive,
fontWeight: isActive ? 600 : 400,
borderBottom: '2px solid ' + (isActive ? colors.primary : 'transparent'),
marginBottom: -1
}
}, t.label);
})
),
// 列表
React.createElement('div', {
style: { background: colors.cardBg, border: '1px solid ' + colors.border, borderRadius: 6, overflow: 'hidden' }
},
displayList.length === 0
? React.createElement('div', { style: { padding: 48, textAlign: 'center', color: colors.textMuted } }, activeTab === 'all' && !filters.keyword ? '暂无数据集,点击「新建数据集」创建' : '没有匹配的数据集')
: displayList.map(function (row) {
var menuOpen = dropdownOpenId === row.id;
return React.createElement('div', {
key: row.id,
style: {
display: 'flex',
alignItems: 'flex-start',
padding: '12px 16px',
borderBottom: '1px solid ' + colors.borderLight,
cursor: 'pointer',
transition: 'background 0.15s'
},
onMouseEnter: function (e) { e.currentTarget.style.background = colors.hoverBg; },
onMouseLeave: function (e) { e.currentTarget.style.background = 'transparent'; },
onClick: function (e) {
if (e.target.closest('button') || e.target.closest('[data-dropdown]')) return;
openModal(row, 'view');
}
},
React.createElement('div', {
style: {
width: 40, height: 40, borderRadius: 6, background: colors.pageBg, border: '1px solid ' + colors.border,
marginRight: 12, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 18, color: colors.primary
}
}, '\uD83D\uDCCA'),
React.createElement('div', { style: { flex: 1, minWidth: 0 } },
React.createElement('div', { style: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 8, marginBottom: 4 } },
React.createElement('span', { style: { fontSize: 14, fontWeight: 600, color: colors.link } }, row.name),
statusTag(row.status),
React.createElement('span', { style: { fontSize: 12, color: colors.textMuted } }, row.type + ' · ' + (row.recordCount != null ? row.recordCount.toLocaleString() + ' 条' : '-'))
),
row.remark ? React.createElement('div', { style: { fontSize: 13, color: colors.textSecondary, marginBottom: 4, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, row.remark) : null,
React.createElement('div', { style: { fontSize: 12, color: colors.textMuted } }, '更新于 ' + (row.updateTime || row.createTime || '-'))
),
React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }, onClick: function (e) { e.stopPropagation(); } },
React.createElement('button', {
type: 'button',
title: row.isStarred ? '取消加星' : '加星',
onClick: function (e) { toggleStar(row, e); },
style: { border: 'none', background: 'none', cursor: 'pointer', padding: 4, fontSize: 16, color: row.isStarred ? '#c17d10' : colors.textMuted }
}, '\u2605'),
React.createElement('div', { style: { position: 'relative' }, 'data-dropdown': true },
React.createElement('button', {
type: 'button',
onClick: function (e) { e.stopPropagation(); setDropdownOpenId(menuOpen ? null : row.id); },
style: { border: 'none', background: 'none', cursor: 'pointer', padding: '2px 8px', fontSize: 16, color: colors.textSecondary }
}, '\u22EE'),
menuOpen ? React.createElement('div', {
style: {
position: 'absolute',
right: 0,
top: '100%',
marginTop: 4,
background: colors.cardBg,
border: '1px solid ' + colors.border,
borderRadius: 6,
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
minWidth: 100,
zIndex: 10
}
},
React.createElement('div', { style: { padding: '6px 12px', cursor: 'pointer', fontSize: 13 }, onClick: function () { openModal(row, 'view'); setDropdownOpenId(null); } }, '查看'),
React.createElement('div', { style: { padding: '6px 12px', cursor: 'pointer', fontSize: 13 }, onClick: function () { openModal(row, 'edit'); setDropdownOpenId(null); } }, '编辑'),
React.createElement('div', { style: { borderTop: '1px solid ' + colors.borderLight } }),
React.createElement('div', { style: { padding: '6px 12px', cursor: 'pointer', fontSize: 13, color: colors.danger }, onClick: function () { openConfirm(row); } }, '删除')
) : null
)
)
);
})
),
// 分页
totalCount > 0 ? React.createElement('div', {
style: { display: 'flex', justifyContent: 'flex-end', alignItems: 'center', padding: '16px 0', gap: 16, fontSize: 13, color: colors.textSecondary }
},
React.createElement('span', null, '共 ' + totalCount + ' 项'),
React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
React.createElement('button', {
type: 'button',
disabled: page <= 1,
onClick: function () { setPage(page - 1); },
style: { padding: '4px 10px', border: '1px solid ' + colors.border, borderRadius: 4, background: colors.cardBg, cursor: page <= 1 ? 'not-allowed' : 'pointer', opacity: page <= 1 ? 0.6 : 1 }
}, '上一页'),
React.createElement('span', null, page + ' / ' + Math.max(1, Math.ceil(totalCount / pageSize))),
React.createElement('button', {
type: 'button',
disabled: page >= Math.ceil(totalCount / pageSize),
onClick: function () { setPage(page + 1); },
style: { padding: '4px 10px', border: '1px solid ' + colors.border, borderRadius: 4, background: colors.cardBg, cursor: page >= Math.ceil(totalCount / pageSize) ? 'not-allowed' : 'pointer', opacity: page >= Math.ceil(totalCount / pageSize) ? 0.6 : 1 }
}, '下一页')
)
) : null,
// 弹窗(查看/编辑/新增)
modalOpen && React.createElement('div', {
style: { position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, background: 'rgba(0,0,0,0.45)', zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center' },
onClick: function (e) { if (e.target === e.currentTarget) closeModal(); }
},
React.createElement('div', {
style: { background: colors.cardBg, borderRadius: 8, width: 520, maxWidth: '90vw', maxHeight: '90vh', overflow: 'auto', boxShadow: '0 6px 16px rgba(0,0,0,0.2)' },
onClick: function (e) { e.stopPropagation(); }
},
React.createElement('div', { style: { padding: '16px 24px', borderBottom: '1px solid ' + colors.border, fontSize: 16, fontWeight: 600 } },
modalMode === 'view' ? '查看数据集' : (modalMode === 'edit' ? '编辑数据集' : '新建数据集')
),
(modalRecord || modalMode === 'add') && React.createElement('div', { style: { padding: 24 } },
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('div', { style: { marginBottom: 4, color: colors.textSecondary, fontSize: 13 } }, '数据集名称'),
modalMode === 'view' ? (modalRecord && modalRecord.name) : React.createElement('input', {
type: 'text',
placeholder: '请输入名称',
defaultValue: modalRecord && modalRecord.name,
style: { width: '100%', padding: '8px 12px', border: '1px solid ' + colors.border, borderRadius: 6, fontSize: 14, boxSizing: 'border-box' }
})
),
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('div', { style: { marginBottom: 4, color: colors.textSecondary, fontSize: 13 } }, '类型'),
modalMode === 'view' ? (modalRecord && modalRecord.type) : React.createElement('select', {
defaultValue: modalRecord && modalRecord.type,
style: { width: '100%', padding: '8px 12px', border: '1px solid ' + colors.border, borderRadius: 6, fontSize: 14, boxSizing: 'border-box' }
}, typeOptions.map(function (o) { return React.createElement('option', { key: o.value, value: o.value }, o.label); }))
),
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('div', { style: { marginBottom: 4, color: colors.textSecondary, fontSize: 13 } }, '备注'),
modalMode === 'view' ? (modalRecord && modalRecord.remark) || '-' : React.createElement('textarea', {
placeholder: '选填',
defaultValue: modalRecord && modalRecord.remark,
rows: 3,
style: { width: '100%', padding: '8px 12px', border: '1px solid ' + colors.border, borderRadius: 6, fontSize: 14, boxSizing: 'border-box', resize: 'vertical' }
})
)
),
React.createElement('div', { style: { padding: '12px 24px', borderTop: '1px solid ' + colors.border, display: 'flex', justifyContent: 'flex-end', gap: 8 } },
modalMode === 'view'
? React.createElement('button', { type: 'button', onClick: closeModal, style: { padding: '6px 16px', border: '1px solid ' + colors.border, borderRadius: 6, background: colors.cardBg, cursor: 'pointer', fontSize: 14 } }, '关闭')
: [
React.createElement('button', { key: 'cancel', type: 'button', onClick: closeModal, style: { padding: '6px 16px', border: '1px solid ' + colors.border, borderRadius: 6, background: colors.cardBg, cursor: 'pointer', fontSize: 14 } }, '取消'),
React.createElement('button', {
key: 'save',
type: 'button',
onClick: function () { showToast(modalMode === 'add' ? '创建成功' : '已保存'); closeModal(); },
style: { padding: '6px 16px', border: 'none', borderRadius: 6, background: colors.primary, color: '#fff', cursor: 'pointer', fontSize: 14 }
}, modalMode === 'add' ? '创建' : '保存')
]
)
)
),
// 删除确认弹窗
confirmOpen && confirmRecord && React.createElement('div', {
style: { position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, background: 'rgba(0,0,0,0.45)', zIndex: 1001, display: 'flex', alignItems: 'center', justifyContent: 'center' },
onClick: function (e) { if (e.target === e.currentTarget) closeConfirm(); }
},
React.createElement('div', {
style: { background: colors.cardBg, borderRadius: 8, padding: 24, width: 400, maxWidth: '90vw', boxShadow: '0 6px 16px rgba(0,0,0,0.2)' },
onClick: function (e) { e.stopPropagation(); }
},
React.createElement('div', { style: { fontSize: 16, fontWeight: 600, marginBottom: 8 } }, '删除数据集'),
React.createElement('div', { style: { color: colors.textSecondary, marginBottom: 24 } }, '确定要删除「' + (confirmRecord.name || '') + '」吗?此操作不可恢复。'),
React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: 8 } },
React.createElement('button', { type: 'button', onClick: closeConfirm, style: { padding: '6px 16px', border: '1px solid ' + colors.border, borderRadius: 6, background: colors.cardBg, cursor: 'pointer', fontSize: 14 } }, '取消'),
React.createElement('button', {
type: 'button',
onClick: function () { handleDelete(confirmRecord); },
style: { padding: '6px 16px', border: 'none', borderRadius: 6, background: colors.danger, color: '#fff', cursor: 'pointer', fontSize: 14 }
}, '删除')
)
)
),
// 轻提示
toastShow && React.createElement('div', {
style: {
position: 'fixed',
left: '50%',
bottom: 48,
transform: 'translateX(-50%)',
padding: '8px 16px',
background: 'rgba(0,0,0,0.75)',
color: '#fff',
borderRadius: 6,
fontSize: 14,
zIndex: 1002
}
}, toastText)
);
};

125
docs/ARCO-DESIGN-SPEC.md Normal file
View File

@@ -0,0 +1,125 @@
# Arco Design 设计规范学习笔记
> 参考:[Arco Design 设计原则](https://arco.design/docs/spec/philosophy)
## 一、设计语言定位:务实的浪漫主义
Arco Design 用「**务实的浪漫主义**」形容自己的设计语言,也代表其工作模式。
- **务实**:清晰与一致 → 清晰的效率提升是基础,品牌一致性是目的
- **浪漫**:韵律与开放 → 推敲设计的韵律,用包容开放的体系解决问题
设计原则相当于语言体系中的「修辞手法」,在实际设计中提供**模式化的思考结构**,让整个设计系统更完整、可复用。
---
## 二、八大设计原则
### 1. 及时反馈
**系统应让用户清楚当前状态,并及时给出对应反馈。**
- 操作后要有明确、即时的状态变化(如加载、成功、失败)
- 避免用户不确定「有没有生效」「进行到哪一步」
---
### 2. 贴近现实
**用用户的语言、用词和熟悉的概念,而不是系统术语。**
- 遵循现实世界的惯例
- 让信息符合自然思考逻辑
- 避免技术黑话、内部用语
---
### 3. 系统一致性
**同一用语、功能、操作在系统内保持一致。**
- 相同功能用相同名称、相同交互方式
- 相同类型的反馈用相同形式(如成功/错误提示)
- 有利于降低学习成本、建立心智模型
---
### 4. 防止错误发生
**比「出错后再提示」更好的是:用设计提前避免错误。**
- 在用户做出选择/动作之前,就减少容易混淆或错误的选择
- 通过禁用、约束、确认、默认值等方式预防问题
- 错误提示是兜底,不是主要手段
---
### 5. 遵从习惯
**减少用户对操作目标的记忆负荷,动作和选项应尽量可见。**
- 例如:填完表单后,下一步应是「生成/提交表单」,而不是笼统的「完成」
- 步骤、选项要符合用户对流程的预期
- 减少「需要记住才能操作」的情况
---
### 6. 突出重点
**用户的行为多是「扫」而不是「读」或「看」。**
- 设计中应**突出重点**,弱化或剔除无关信息
- 重要对话/流程中不堆砌无关内容
- 通过层级、对比、留白引导注意力
---
### 7. 错误帮助
**错误信息要用自然语言表达,而不是仅显示错误码(如 404**
- 准确说明问题所在
- 给出建设性的解决建议
- 帮助用户从错误中恢复,将损失降到最低
- 提供清晰的说明和下一步指引
---
### 8. 人性化帮助
**理想情况是系统本身无需帮助文档;若需要帮助,应分层、适度。**
帮助的优先级建议:
1. **无需提示**:设计自解释,用户自然能懂
2. **一次性提示**如首次使用的引导、Tooltip
3. **常驻提示**:如表单旁的说明、占位符
4. **帮助文档**:作为最后兜底,便于深度查阅
---
## 三、设计规范结构速览Arco 官网)
设计相关文档大致包括:
| 类型 | 说明 |
|------------|------|
| 设计价值观 | 务实与浪漫的价值观定义 |
| 设计原则 | 上述八大原则(本文档重点) |
| 样式指南 | 视觉与交互的样式规范 |
| 组件用法 | 各组件Button、Form、Table 等)的设计与使用规范 |
开发侧还有快速上手、暗黑模式、颜色、设计变量Token、国际化、定制主题等与设计规范配合使用。
---
## 四、在项目中的使用建议
1. **做界面时**:先对照「及时反馈、贴近现实、一致性、防错、遵从习惯、突出重点」检查一版交互与文案。
2. **写错误与帮助**:遵循「错误帮助」和「人性化帮助」,避免只扔错误码,并控制提示的侵入性。
3. **统一用语与交互**:建立一份产品用词表与组件使用规范,对齐「系统一致性」。
4. **用 Arco 组件时**:优先按官方组件用法与样式指南使用,便于保持「务实的浪漫主义」下的整体体验。
---
*文档根据 [Arco Design 设计原则](https://arco.design/docs/spec/philosophy) 整理,便于团队统一理解与落地。*

25
package.json Normal file
View File

@@ -0,0 +1,25 @@
{
"name": "one-os",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"@arco-design/web-react": "^2.67.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.28.0"
},
"devDependencies": {
"@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"typescript": "~5.6.2",
"vite": "^5.4.10"
}
}

15
src/App.tsx Normal file
View File

@@ -0,0 +1,15 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import VehicleManage from '@/pages/VehicleManage';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<VehicleManage />} />
<Route path="/vehicle/:id" element={<VehicleManage />} />
</Routes>
</BrowserRouter>
);
}
export default App;

10
src/main.tsx Normal file
View File

@@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import '@arco-design/web-react/dist/css/arco.css';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

View File

@@ -0,0 +1,116 @@
import React, { useState } from 'react';
import { Modal, Form, Input, Upload, Image, Message } from '@arco-design/web-react';
import type { VehicleRecord } from '@/types/vehicle';
type Props = {
visible: boolean;
vehicle: VehicleRecord | null;
onCancel: () => void;
onOk: (vin: string, plateNo: string) => void;
};
export default function VehiclePlateModal({ visible, vehicle, onCancel, onOk }: Props) {
const [ocrLoading, setOcrLoading] = useState(false);
const [licenseImageUrl, setLicenseImageUrl] = useState<string>('');
const [form] = Form.useForm();
const handleUploadChange = (fileList: { file?: File; url?: string }[]) => {
const file = fileList[0]?.file;
if (!file) return;
const url = URL.createObjectURL(file);
setLicenseImageUrl(url);
setOcrLoading(true);
// 模拟 OCR 识别,实际对接 OCR 接口
setTimeout(() => {
form.setFieldsValue({ vin: vehicle?.vin ?? '', plateNo: vehicle?.plateNo ?? '' });
setOcrLoading(false);
}, 1500);
};
const handleOk = () => {
form.validate().then((values) => {
const v = (values.vin ?? '').trim();
const p = (values.plateNo ?? '').trim();
if (!v || !p) {
Message.warning('请填写车辆识别代号与车牌号');
return;
}
if (vehicle && v !== vehicle.vin) {
Message.error('车辆识别代号与该车辆不匹配');
return;
}
onOk(v, p);
reset();
}).catch(() => {});
};
const reset = () => {
setLicenseImageUrl('');
setOcrLoading(false);
form.resetFields();
};
const handleCancel = () => {
reset();
onCancel();
};
return (
<>
<Modal
title="确认上牌信息"
visible={visible}
onOk={handleOk}
onCancel={handleCancel}
okText="确认"
cancelText="取消"
style={{ width: 720 }}
unmountOnExit
afterClose={reset}
>
<div style={{ display: 'flex', gap: 24, minHeight: 280 }}>
<div style={{ flex: '0 0 320px' }}>
<div style={{ marginBottom: 8, color: 'var(--color-text-2)' }}></div>
{licenseImageUrl ? (
<Image
width={320}
height={200}
src={licenseImageUrl}
style={{ objectFit: 'contain', background: 'var(--color-fill-2)', borderRadius: 4 }}
/>
) : (
<Upload
accept="image/*"
listType="picture-card"
limit={1}
onChange={handleUploadChange}
customRequest={(option) => {
const { file } = option;
if (file) handleUploadChange([{ file: file as File }]);
}}
>
<div style={{ padding: 20, textAlign: 'center' }}></div>
</Upload>
)}
</div>
<div style={{ flex: 1 }}>
{ocrLoading ? (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 200 }}>
<span style={{ color: 'var(--color-text-2)' }}></span>
</div>
) : (
<Form form={form} layout="vertical" initialValues={{ vin: vehicle?.vin ?? '', plateNo: vehicle?.plateNo ?? '' }}>
<Form.Item label="车辆识别代号VIN" field="vin" rules={[{ required: true, message: '请填写车辆识别代号' }]}>
<Input placeholder="根据行驶证照片反写,可编辑" />
</Form.Item>
<Form.Item label="车牌号" field="plateNo" rules={[{ required: true, message: '请填写车牌号' }]}>
<Input placeholder="根据行驶证照片反写,可编辑" />
</Form.Item>
</Form>
)}
</div>
</div>
</Modal>
</>
);
}

View File

@@ -0,0 +1,384 @@
import React, { useState, useCallback } from 'react';
import {
Breadcrumb,
Form,
Grid,
Select,
Cascader,
Input,
Button,
Space,
Table,
Card,
Message,
Dropdown,
Menu,
Checkbox,
Modal,
Upload,
} from '@arco-design/web-react';
import type { TableColumnProps } from '@arco-design/web-react/es/Table';
import {
IconExport,
IconImport,
IconMore,
IconSearch,
IconRefresh,
} from '@arco-design/web-react/icon';
import {
regionOptions,
vehicleTypeOptions,
brandOptions,
modelOptions,
customerOptions,
businessDeptOptions,
contractNoOptions,
registeredOwnerOptions,
mockVehicleList,
} from '@/services/vehicle';
import type { VehicleRecord, VehicleFilterForm } from '@/types/vehicle';
import VehiclePlateModal from './VehiclePlateModal';
const { Row, Col } = Grid;
const defaultFilter: VehicleFilterForm = {};
export default function VehicleManage() {
const [filter, setFilter] = useState<VehicleFilterForm>(defaultFilter);
const [plateNoQuick, setPlateNoQuick] = useState('');
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
const [data, setData] = useState<VehicleRecord[]>([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(20);
const [plateModalVisible, setPlateModalVisible] = useState(false);
const [plateModalVehicle, setPlateModalVehicle] = useState<VehicleRecord | null>(null);
const [form] = Form.useForm();
const loadList = useCallback(
(p = page, ps = pageSize) => {
setLoading(true);
setTimeout(() => {
const res = mockVehicleList({
...filter,
plateNo: plateNoQuick || undefined,
page: p,
pageSize: ps,
});
setData(res.list);
setTotal(res.total);
setLoading(false);
}, 300);
},
[filter, plateNoQuick, page, pageSize]
);
React.useEffect(() => {
loadList();
}, [loadList]);
const onFilterSubmit = (values: VehicleFilterForm) => {
setFilter(values);
setPage(1);
loadList(1, pageSize);
};
const onFilterReset = () => {
form.resetFields();
setFilter(defaultFilter);
setPlateNoQuick('');
setPage(1);
loadList(1, pageSize);
};
const onExport = () => {
if (selectedRowKeys.length === 0) {
Message.warning('请先勾选要导出的车辆');
return;
}
Message.info(`导出 ${selectedRowKeys.length} 条记录(联调时对接导出接口)`);
};
const onBatchImport = () => {
Message.info('批量导入(联调时对接导入接口)');
};
const onView = (record: VehicleRecord) => {
Message.info(`查看车辆详情:${record.plateNo || record.vin}`);
// 实际可: navigate(`/vehicle/detail/${record.id}`);
};
const onPlate = (record: VehicleRecord) => {
setPlateModalVehicle(record);
setPlateModalVisible(true);
};
const onPlateModalOk = (vin: string, plateNo: string) => {
if (plateModalVehicle && (vin !== plateModalVehicle.vin || !plateNo)) {
Message.error('车辆识别代号与该车辆不匹配');
return;
}
Message.success('上牌信息已更新');
setPlateModalVisible(false);
setPlateModalVehicle(null);
loadList();
};
const moreMenu = (record: VehicleRecord) => (
<Menu>
<Menu.Item key="plate" onClick={() => onPlate(record)}></Menu.Item>
<Menu.Item key="transfer"></Menu.Item>
<Menu.Item key="move"></Menu.Item>
<Menu.Item key="allocate"></Menu.Item>
<Menu.Item key="scrap"></Menu.Item>
<Menu.Item key="inspect"></Menu.Item>
<Menu.Item key="sale"></Menu.Item>
<Menu.Item key="fault"></Menu.Item>
</Menu>
);
const columns: TableColumnProps<VehicleRecord>[] = [
{ title: '运营城市', dataIndex: 'operationCity', width: 120, fixed: 'left' },
{ title: '车辆识别代号', dataIndex: 'vin', width: 180, fixed: 'left' },
{ title: '车牌号', dataIndex: 'plateNo', width: 100, fixed: 'left' },
{ title: '车辆编号', dataIndex: 'vehicleNo', width: 100, render: (v) => v || '-' },
{ title: '车辆类型', dataIndex: 'vehicleType', width: 100 },
{ title: '品牌', dataIndex: 'brand', width: 90 },
{ title: '型号', dataIndex: 'model', width: 90 },
{ title: '车身颜色', dataIndex: 'bodyColor', width: 90 },
{ title: '归属停车场', dataIndex: 'parkingLot', width: 110 },
{ title: '客户名称', dataIndex: 'customerName', width: 100 },
{ title: '业务部门', dataIndex: 'businessDept', width: 100 },
{ title: '业务负责人', dataIndex: 'businessOwner', width: 100 },
{ title: '运营状态', dataIndex: 'operationStatus', width: 90 },
{ title: '库位状态', dataIndex: 'libStatus', width: 180 },
{ title: '出库状态', dataIndex: 'outboundStatus', width: 100 },
{ title: '整备状态', dataIndex: 'prepStatus', width: 90 },
{ title: '过户状态', dataIndex: 'transferStatus', width: 120 },
{ title: '维修状态', dataIndex: 'repairStatus', width: 110 },
{ title: '证照状态', dataIndex: 'licenseStatus', width: 90 },
{ title: '报废状态', dataIndex: 'scrapStatus', width: 90 },
{ title: '登记所有权', dataIndex: 'registeredOwner', width: 160 },
{ title: '在线状态', dataIndex: 'onlineStatus', width: 90 },
{ title: '出厂年份', dataIndex: 'manufactureYear', width: 90 },
{ title: '行驶公里数(KM)', dataIndex: 'mileage', width: 120, render: (v) => v?.toFixed(2) ?? '-' },
{ title: '采购入库时间', dataIndex: 'purchaseTime', width: 120 },
{ title: '行驶证注册日期', dataIndex: 'licenseRegisterDate', width: 130 },
{ title: '行驶证检验有效期', dataIndex: 'licenseExpiry', width: 130 },
{ title: '上次交车时间', dataIndex: 'lastDeliveryTime', width: 120 },
{ title: '上次交车里程(KM)', dataIndex: 'lastDeliveryMileage', width: 130, render: (v) => (v ? Number(v).toFixed(2) : '-') },
{ title: '上次还车时间', dataIndex: 'lastReturnTime', width: 120 },
{ title: '上次还车里程(KM)', dataIndex: 'lastReturnMileage', width: 130, render: (v) => (v ? Number(v).toFixed(2) : '-') },
{ title: '强制报废日期', dataIndex: 'forceScrapDate', width: 120 },
{ title: '合同编号', dataIndex: 'contractNo', width: 110 },
{ title: '当前位置', dataIndex: 'currentLocation', width: 300 },
{ title: 'GPS最后上传时间', dataIndex: 'gpsLastTime', width: 160 },
{
title: '操作',
dataIndex: 'op',
width: 140,
fixed: 'right',
render: (_, record) => (
<Space>
<Button type="text" size="small" onClick={() => onView(record)}>
</Button>
<Dropdown trigger="hover" position="br" droplist={moreMenu(record)}>
<Button type="text" size="small" icon={<IconMore />}>
</Button>
</Dropdown>
</Space>
),
},
];
const watchedBrand = Form.useWatch('brand', form);
const modelOptionsByBrand = watchedBrand ? (modelOptions as Record<string, { value: string; label: string }[]>)[watchedBrand] ?? [] : [];
return (
<div style={{ padding: 16, background: 'var(--color-fill-2)', minHeight: '100vh' }}>
<Breadcrumb style={{ marginBottom: 16 }}>
<Breadcrumb.Item></Breadcrumb.Item>
<Breadcrumb.Item></Breadcrumb.Item>
</Breadcrumb>
<Card title="筛选" style={{ marginBottom: 16 }}>
<Form
form={form}
layout="inline"
initialValues={defaultFilter}
onSubmit={onFilterSubmit}
style={{ width: '100%' }}
>
<Row gutter={16}>
<Col span={6}>
<Form.Item label="运营城市" field="operationCity">
<Cascader
allowClear
placeholder="请选择省-市"
options={regionOptions}
style={{ width: '100%' }}
changeOnSelect
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="车辆类型" field="vehicleType">
<Select allowClear placeholder="请选择" options={vehicleTypeOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="品牌" field="brand">
<Select allowClear placeholder="请选择" options={brandOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="型号" field="model">
<Select
allowClear
placeholder="请选择"
options={modelOptionsByBrand}
style={{ width: '100%' }}
disabled={!watchedBrand}
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="客户名称" field="customerName">
<Select allowClear placeholder="请选择" options={customerOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="归属业务部门" field="businessDept">
<Select allowClear placeholder="请选择" options={businessDeptOptions} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="合同编号" field="contractNo">
<Select
allowClear
showSearch
placeholder="输入模糊匹配"
options={contractNoOptions}
style={{ width: '100%' }}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item label="登记所有权" field="registeredOwner">
<Select
allowClear
showSearch
placeholder="输入模糊匹配"
options={registeredOwnerOptions}
style={{ width: '100%' }}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
/>
</Form.Item>
</Col>
<Col span={24}>
<Form.Item style={{ marginBottom: 0 }}>
<Space>
<Button type="primary" htmlType="submit" icon={<IconSearch />}>
</Button>
<Button icon={<IconRefresh />} onClick={onFilterReset}>
</Button>
</Space>
</Form.Item>
</Col>
</Row>
</Form>
</Card>
<Card>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
<Space>
<Input
placeholder="输入车牌号快速筛选"
value={plateNoQuick}
onChange={setPlateNoQuick}
style={{ width: 200 }}
allowClear
onPressEnter={() => loadList(1, pageSize)}
/>
<Button type="primary" icon={<IconSearch />} onClick={() => { setPage(1); loadList(1, pageSize); }}>
</Button>
</Space>
<Space>
<Button icon={<IconExport />} onClick={onExport}>
</Button>
<Button icon={<IconImport />} onClick={onBatchImport}>
</Button>
</Space>
</div>
<Table
rowKey="id"
loading={loading}
data={data}
columns={[
{
title: (
<Checkbox
checked={selectedRowKeys.length === data.length && data.length > 0}
indeterminate={selectedRowKeys.length > 0 && selectedRowKeys.length < data.length}
onChange={(checked) => setSelectedRowKeys(checked ? data.map((r) => r.id) : [])}
/>
),
width: 48,
fixed: 'left',
render: (_, record) => (
<Checkbox
checked={selectedRowKeys.includes(record.id)}
onChange={(checked) =>
setSelectedRowKeys((prev) =>
checked ? [...prev, record.id] : prev.filter((k) => k !== record.id)
)
}
/>
),
},
...columns,
]}
scroll={{ x: 3800 }}
pagination={{
current: page,
pageSize,
total,
showTotal: true,
showJumper: true,
sizeCanChange: true,
pageSizeChange: (ps) => {
setPageSize(ps);
setPage(1);
loadList(1, ps);
},
onChange: (p) => {
setPage(p);
loadList(p, pageSize);
},
}}
/>
</Card>
<VehiclePlateModal
visible={plateModalVisible}
vehicle={plateModalVehicle}
onCancel={() => { setPlateModalVisible(false); setPlateModalVehicle(null); }}
onOk={onPlateModalOk}
/>
</div>
);
}

145
src/services/vehicle.ts Normal file
View File

@@ -0,0 +1,145 @@
import type { VehicleRecord, VehicleFilterForm } from '@/types/vehicle';
/** 模拟省-市二级地区 */
export const regionOptions = [
{
value: 'guangdong',
label: '广东省',
children: [
{ value: 'guangzhou', label: '广州市' },
{ value: 'shenzhen', label: '深圳市' },
{ value: 'dongguan', label: '东莞市' },
],
},
{
value: 'zhejiang',
label: '浙江省',
children: [
{ value: 'hangzhou', label: '杭州市' },
{ value: 'ningbo', label: '宁波市' },
],
},
{
value: 'jiangsu',
label: '江苏省',
children: [
{ value: 'nanjing', label: '南京市' },
{ value: 'suzhou', label: '苏州市' },
],
},
];
/** 车辆类型(从车辆类型表拉取) */
export const vehicleTypeOptions = [
{ value: 'light_truck', label: '轻卡' },
{ value: 'van', label: '厢式车' },
{ value: 'suv', label: 'SUV' },
{ value: 'sedan', label: '轿车' },
];
/** 品牌(从型号参数表拉取) */
export const brandOptions = [
{ value: 'brand_a', label: '品牌A' },
{ value: 'brand_b', label: '品牌B' },
{ value: 'brand_c', label: '品牌C' },
];
/** 型号(从型号参数表拉取,可按品牌联动) */
export const modelOptions: Record<string, { value: string; label: string }[]> = {
brand_a: [
{ value: 'model_a1', label: '型号A1' },
{ value: 'model_a2', label: '型号A2' },
],
brand_b: [
{ value: 'model_b1', label: '型号B1' },
{ value: 'model_b2', label: '型号B2' },
],
brand_c: [
{ value: 'model_c1', label: '型号C1' },
],
};
/** 客户名称(租赁/自营合同客户,含「无」) */
export const customerOptions = [
{ value: '__none__', label: '无' },
{ value: 'customer_1', label: '客户甲' },
{ value: 'customer_2', label: '客户乙' },
{ value: 'customer_3', label: '客户丙' },
];
/** 归属业务部门(含「无」) */
export const businessDeptOptions = [
{ value: '__none__', label: '无' },
{ value: 'dept_1', label: '业务一部' },
{ value: 'dept_2', label: '业务二部' },
{ value: 'dept_3', label: '业务三部' },
];
/** 合同编号列表(支持模糊匹配,此处为示例) */
export const contractNoOptions = [
{ value: 'HT-2024-001', label: 'HT-2024-001' },
{ value: 'HT-2024-002', label: 'HT-2024-002' },
{ value: 'HT-2024-003', label: 'HT-2024-003' },
{ value: 'ZY-2024-001', label: 'ZY-2024-001' },
];
/** 登记所有权列表(支持模糊匹配) */
export const registeredOwnerOptions = [
{ value: 'owner_1', label: '某某物流有限公司' },
{ value: 'owner_2', label: '某某租赁有限公司' },
];
function randomItem<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)];
}
/** 生成模拟列表数据 */
export function mockVehicleList(params: VehicleFilterForm & { plateNo?: string; page?: number; pageSize?: number }): { list: VehicleRecord[]; total: number } {
const total = 48;
const list: VehicleRecord[] = [];
const cities = ['广东省广州市', '广东省深圳市', '浙江省杭州市', '江苏省南京市'];
for (let i = 1; i <= (params.pageSize ?? 20); i++) {
const idx = ((params.page ?? 1) - 1) * (params.pageSize ?? 20) + i;
if (idx > total) break;
list.push({
id: `v-${idx}`,
operationCity: randomItem(cities),
vin: `L${String(idx).padStart(6, '0')}${Math.random().toString(36).slice(2, 11).toUpperCase()}`,
plateNo: `粤A${String(10000 + idx).slice(-5)}`,
vehicleNo: idx <= 10 ? `VN-${idx}` : '',
vehicleType: randomItem(vehicleTypeOptions).label,
brand: randomItem(brandOptions).label,
model: randomItem(modelOptions.brand_a).label,
bodyColor: ['白', '黑', '银', '蓝'][idx % 4],
parkingLot: idx % 3 === 0 ? '-' : `停车场${(idx % 3) + 1}`,
customerName: idx % 4 === 0 ? '-' : `客户${(idx % 4)}`,
businessDept: idx % 4 === 0 ? '-' : `业务${(idx % 4)}`,
businessOwner: idx % 4 === 0 ? '-' : `负责人${idx % 5}`,
operationStatus: randomItem(['待运营', '库存', '租赁', '自营', '退出运营']),
libStatus: randomItem(['库存车-可交付车', '已交付车-租赁交车', '新车入库-待验车']),
outboundStatus: randomItem(['无', '租赁交车', '异动出库']),
preemptStatus: '-',
prepStatus: randomItem(['待整备', '整备中', '正常', '无']),
transferStatus: randomItem(['无', '过户中', '内部过户完成']),
repairStatus: randomItem(['待服务站接单', '维修中', '正常']),
licenseStatus: randomItem(['正常', '异常']),
scrapStatus: randomItem(['无', '报废中', '已报废']),
registeredOwner: '某某物流有限公司',
onlineStatus: randomItem(['在线', '离线']),
manufactureYear: `${2020 + (idx % 5)}`,
mileage: Number((10000 + idx * 500 + Math.random() * 200).toFixed(2)),
purchaseTime: `2022-0${(idx % 9) + 1}-15`,
licenseRegisterDate: `2022-0${(idx % 9) + 1}-01`,
licenseExpiry: `2025-0${(idx % 9) + 1}-01`,
lastDeliveryTime: idx % 2 === 0 ? `2024-01-${String(10 + (idx % 20)).padStart(2, '0')}` : '-',
lastDeliveryMileage: idx % 2 === 0 ? Number((12000 + idx * 100).toFixed(2)) : 0,
lastReturnTime: idx % 2 === 1 ? `2024-02-${String(5 + (idx % 20)).padStart(2, '0')}` : '-',
lastReturnMileage: idx % 2 === 1 ? Number((12500 + idx * 100).toFixed(2)) : 0,
forceScrapDate: `2030-12-31`,
contractNo: idx % 3 === 0 ? '-' : `HT-2024-00${(idx % 3) + 1}`,
currentLocation: `广东省广州市天河区某某路${idx}`,
gpsLastTime: `2024-02-13 ${String(10 + (idx % 12)).padStart(2, '0')}:${String(idx % 60).padStart(2, '0')}`,
});
}
return { list, total };
}

129
src/types/vehicle.ts Normal file
View File

@@ -0,0 +1,129 @@
/** 车辆管理相关类型 */
export type OperationCity = { province: string; city: string };
export type VehicleTypeItem = { value: string; label: string };
export type ModelParamItem = { brand: string; model: string };
export type CustomerItem = { value: string; label: string };
export type DeptItem = { value: string; label: string };
export const OPERATION_STATUS_OPTIONS = [
{ value: 'pending', label: '待运营' },
{ value: 'in_stock', label: '库存' },
{ value: 'lease', label: '租赁' },
{ value: 'self', label: '自营' },
{ value: 'exit', label: '退出运营' },
] as const;
export const LIB_STATUS_OPTIONS = [
{ value: 'new_pending', label: '新车入库-待验车' },
{ value: 'new_license', label: '新车入库-证照办理' },
{ value: 'stock_ok', label: '库存车-可交付车' },
{ value: 'stock_no', label: '库存车-不可交付车' },
{ value: 'stock_slow', label: '库存车-呆滞车' },
{ value: 'out_lease', label: '已交付车-租赁交车' },
{ value: 'out_self', label: '已交付车-自营交车' },
{ value: 'out_replace', label: '已交付车-替换交车' },
{ value: 'exit_scrap', label: '退出运营-报废车' },
{ value: 'exit_third', label: '退出运营-三方退租车' },
{ value: 'exit_sale', label: '退出运营-过户售车' },
] as const;
export const OUTBOUND_STATUS_OPTIONS = [
{ value: 'move', label: '异动出库' },
{ value: 'transfer', label: '调拨出库' },
{ value: 'show', label: '展示出库' },
{ value: 'lease_deliver', label: '租赁交车' },
{ value: 'self_deliver', label: '自营交车' },
{ value: 'replace_deliver', label: '替换交车' },
{ value: 'sale', label: '过户售车' },
{ value: 'lease_return', label: '外租退车' },
{ value: 'scrap', label: '报废出库' },
{ value: 'none', label: '无' },
] as const;
export const PREP_STATUS_OPTIONS = [
{ value: 'pending', label: '待整备' },
{ value: 'doing', label: '整备中' },
{ value: 'normal', label: '正常' },
{ value: 'none', label: '无' },
] as const;
export const TRANSFER_STATUS_OPTIONS = [
{ value: 'doing', label: '过户中' },
{ value: 'internal_done', label: '内部过户完成' },
{ value: 'sale_done', label: '销售过户完成' },
{ value: 'none', label: '无' },
] as const;
export const REPAIR_STATUS_OPTIONS = [
{ value: 'pending', label: '待服务站接单' },
{ value: 'doing', label: '维修中' },
{ value: 'normal', label: '正常' },
] as const;
export const LICENSE_STATUS_OPTIONS = [
{ value: 'normal', label: '正常' },
{ value: 'abnormal', label: '异常' },
] as const;
export const SCRAP_STATUS_OPTIONS = [
{ value: 'doing', label: '报废中' },
{ value: 'done', label: '已报废' },
{ value: 'none', label: '无' },
] as const;
export const ONLINE_STATUS_OPTIONS = [
{ value: 'online', label: '在线' },
{ value: 'offline', label: '离线' },
] as const;
export interface VehicleRecord {
id: string;
operationCity: string;
vin: string;
plateNo: string;
vehicleNo: string;
vehicleType: string;
brand: string;
model: string;
bodyColor: string;
parkingLot: string;
customerName: string;
businessDept: string;
businessOwner: string;
operationStatus: string;
libStatus: string;
outboundStatus: string;
preemptStatus: string;
prepStatus: string;
transferStatus: string;
repairStatus: string;
licenseStatus: string;
scrapStatus: string;
registeredOwner: string;
onlineStatus: string;
manufactureYear: string;
mileage: number;
purchaseTime: string;
licenseRegisterDate: string;
licenseExpiry: string;
lastDeliveryTime: string;
lastDeliveryMileage: number;
lastReturnTime: string;
lastReturnMileage: number;
forceScrapDate: string;
contractNo: string;
currentLocation: string;
gpsLastTime: string;
}
export interface VehicleFilterForm {
operationCity?: string[];
vehicleType?: string;
brand?: string;
model?: string;
customerName?: string;
businessDept?: string;
contractNo?: string;
registeredOwner?: string;
}

23
tsconfig.json Normal file
View File

@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": { "@/*": ["src/*"] }
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

11
tsconfig.node.json Normal file
View File

@@ -0,0 +1,11 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
}

10
vite.config.ts Normal file
View File

@@ -0,0 +1,10 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: { '@': path.resolve(__dirname, 'src') },
},
});

BIN
web端.zip Normal file

Binary file not shown.

BIN
web端/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,577 @@
// 【重要】必须使用 const Component 作为组件变量名
// 数字化资产ONEOS运管平台 - 业务管理 - 交车任务
const Component = function() {
var useState = React.useState;
var useMemo = React.useMemo;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Select = antd.Select;
var Button = antd.Button;
var Table = antd.Table;
var Card = antd.Card;
var Tabs = antd.Tabs;
var DatePicker = antd.DatePicker;
var Popover = antd.Popover;
var Modal = antd.Modal;
var message = antd.message;
var App = antd.App;
var RangePicker = DatePicker.RangePicker;
// 筛选条件(表单输入)
var _contractCode = useState(undefined);
var _projectName = useState(undefined);
var _customerName = useState(undefined);
var _planDateRange = useState(null);
var _creator = useState(undefined);
// 已应用的筛选条件(点击查询后生效)
var _applied = useState({
contractCode: undefined,
projectName: undefined,
customerName: undefined,
planDateRange: null,
creator: undefined
});
// Tab进行中 / 已完成
var _activeTab = useState('ongoing');
// 筛选展开(默认显示前 3 项,与车辆租赁合同一致)
var _filterExpanded = useState(false);
// 需求说明弹窗
var _reqSpecOpen = useState(false);
// 停用/启用:重新选择预计交车日期弹窗
var _rescheduleModalVisible = useState(false);
var _rescheduleTask = useState(null);
var _rescheduleDateRange = useState(null);
// 模拟选项(可模糊搜索)
var contractOptions = [
{ value: 'JXZL20260216YW101235A', label: 'JXZL20260216YW101235A' },
{ value: 'JXZL20260216YW101236A', label: 'JXZL20260216YW101236A' },
{ value: 'JXZL20260215YW101234A', label: 'JXZL20260215YW101234A' },
{ value: 'SHZL20260210YW101200A', label: 'SHZL20260210YW101200A' }
];
var projectOptions = [
{ value: 'p1', label: '嘉兴氢能运输项目' },
{ value: 'p2', label: '上海物流租赁项目' },
{ value: 'p3', label: '杭州城配租赁项目' }
];
var customerOptions = [
{ value: 'c1', label: '嘉兴某某物流有限公司' },
{ value: 'c2', label: '上海某某运输公司' },
{ value: 'c3', label: '杭州某某租赁有限公司' }
];
var creatorOptions = [
{ value: 'u1', label: '张经理' },
{ value: 'u2', label: '李专员' },
{ value: 'u3', label: '王专员' }
];
// 进行中列表数据(未完成交车单提交),用 state 以便停用/启用后刷新
var _ongoingList = useState([
{ id: 'o1', contractCode: 'JXZL20260216YW101235A', projectName: '嘉兴氢能运输项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 2, deliveryRegion: '浙江省-嘉兴市', deliveryLocation: '嘉兴市南湖区科技大道1号', planDeliveryDisplay: '2026-03-01至2026-03-05', planDeliveryEnd: '2026-03-05', billingStartDate: '2026-03-01', creator: '张经理', createdAt: '2026-02-20', lastUpdater: '张经理', lastUpdatedAt: '2026-02-24', enabled: true },
{ id: 'o2', contractCode: 'JXZL20260216YW101236A', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 1, deliveryRegion: '上海市-上海市', deliveryLocation: '上海市浦东新区张江高科技园区', planDeliveryDisplay: '2026-03-10', planDeliveryEnd: '2026-03-10', billingStartDate: '-', creator: '李专员', createdAt: '2026-02-21', lastUpdater: '李专员', lastUpdatedAt: '2026-02-22', enabled: false },
{ id: 'o3', contractCode: 'JXZL20260215YW101234A', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 3, deliveryRegion: '浙江省-杭州市', deliveryLocation: '杭州市余杭区未来科技城', planDeliveryDisplay: '2026-02-28至2026-03-02', planDeliveryEnd: '2026-03-02', billingStartDate: '2026-02-28', creator: '王专员', createdAt: '2026-02-18', lastUpdater: '王专员', lastUpdatedAt: '2026-02-25', enabled: true },
{ id: 'o4', contractCode: 'JXZL20260101YW101200A', projectName: '嘉兴氢能运输项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, deliveryRegion: '浙江省-嘉兴市', deliveryLocation: '嘉兴市秀洲区洪兴西路288号', planDeliveryDisplay: '2026-01-05至2026-01-10', planDeliveryEnd: '2026-01-10', billingStartDate: '-', creator: '张经理', createdAt: '2026-01-02', lastUpdater: '张经理', lastUpdatedAt: '2026-01-15', enabled: false },
{ id: 'o5', contractCode: 'JXZL20260218YW101237A', projectName: '嘉兴氢能运输项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 2, deliveryRegion: '浙江省-嘉兴市', deliveryLocation: '嘉兴市南湖区广益路与亚中路交叉口', planDeliveryDisplay: '2026-03-08至2026-03-12', planDeliveryEnd: '2026-03-12', billingStartDate: '-', creator: '张经理', createdAt: '2026-02-22', lastUpdater: '张经理', lastUpdatedAt: '2026-02-26', enabled: true },
{ id: 'o6', contractCode: 'SHZL20260210YW101201A', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 1, deliveryRegion: '上海市-上海市', deliveryLocation: '上海市闵行区申滨路1051号', planDeliveryDisplay: '2026-03-15', planDeliveryEnd: '2026-03-15', billingStartDate: '-', creator: '李专员', createdAt: '2026-02-19', lastUpdater: '李专员', lastUpdatedAt: '2026-02-23', enabled: true },
{ id: 'o7', contractCode: 'JXZL20260220YW101238A', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 4, deliveryRegion: '浙江省-杭州市', deliveryLocation: '杭州市萧山区市心北路与建设一路交叉口', planDeliveryDisplay: '2026-03-20至2026-03-25', planDeliveryEnd: '2026-03-25', billingStartDate: '-', creator: '王专员', createdAt: '2026-02-23', lastUpdater: '王专员', lastUpdatedAt: '2026-02-27', enabled: true },
{ id: 'o8', contractCode: 'JXZL20260214YW101233A', projectName: '嘉兴氢能运输项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, deliveryRegion: '浙江省-嘉兴市', deliveryLocation: '嘉兴市经开区昌盛路与文昌路交叉口', planDeliveryDisplay: '2026-03-05', planDeliveryEnd: '2026-03-05', billingStartDate: '-', creator: '张经理', createdAt: '2026-02-17', lastUpdater: '李专员', lastUpdatedAt: '2026-02-24', enabled: true },
{ id: 'o9', contractCode: 'SHZL20260212YW101202A', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 2, deliveryRegion: '上海市-上海市', deliveryLocation: '上海市嘉定区安亭镇墨玉南路与博园路交叉口', planDeliveryDisplay: '2026-03-18至2026-03-22', planDeliveryEnd: '2026-03-22', billingStartDate: '-', creator: '李专员', createdAt: '2026-02-24', lastUpdater: '李专员', lastUpdatedAt: '2026-02-28', enabled: true },
{ id: 'o10', contractCode: 'JXZL20260222YW101239A', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 3, deliveryRegion: '浙江省-杭州市', deliveryLocation: '杭州市西湖区文三路与古翠路交叉口', planDeliveryDisplay: '2026-03-25至2026-03-30', planDeliveryEnd: '2026-03-30', billingStartDate: '-', creator: '王专员', createdAt: '2026-02-25', lastUpdater: '王专员', lastUpdatedAt: '2026-02-28', enabled: true }
]);
var ongoingList = _ongoingList[0];
var setOngoingList = _ongoingList[1];
// 已完成列表数据(已提交交车单),交车数量可点开气泡
var completedList = [
{ id: 'c1', contractCode: 'JXZL20260215YW101234A', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 2, deliveryRegion: '浙江省-杭州市', deliveryLocation: '杭州市余杭区未来科技城', vehicles: [{ vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '浙A10001', actualDeliveryDate: '2026-02-28', deliverer: '运维李' }, { vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '浙B20002', actualDeliveryDate: '2026-03-01', deliverer: '运维王' }], planDeliveryDisplay: '2026-02-28至2026-03-01', billingStartDate: '2026-02-28', creator: '王专员', createdAt: '2026-02-18', lastUpdater: '王专员', lastUpdatedAt: '2026-03-01' },
{ id: 'c2', contractCode: 'SHZL20260210YW101200A', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 1, deliveryRegion: '上海市-上海市', deliveryLocation: '上海市浦东新区张江高科技园区', vehicles: [{ vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '沪A30003', actualDeliveryDate: '2026-02-25', deliverer: '运维赵' }], planDeliveryDisplay: '2026-02-25', billingStartDate: '2026-02-25', creator: '李专员', createdAt: '2026-02-15', lastUpdater: '李专员', lastUpdatedAt: '2026-02-25' },
{ id: 'c3', contractCode: 'JXZL20260208YW101231A', projectName: '嘉兴氢能运输项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 2, deliveryRegion: '浙江省-嘉兴市', deliveryLocation: '嘉兴市南湖区科技大道1号', vehicles: [{ vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '浙A10002', actualDeliveryDate: '2026-02-20', deliverer: '运维李' }, { vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '浙A10003', actualDeliveryDate: '2026-02-21', deliverer: '运维王' }], planDeliveryDisplay: '2026-02-20至2026-02-21', billingStartDate: '2026-02-20', creator: '张经理', createdAt: '2026-02-10', lastUpdater: '张经理', lastUpdatedAt: '2026-02-21' },
{ id: 'c4', contractCode: 'SHZL20260205YW101198A', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 1, deliveryRegion: '上海市-上海市', deliveryLocation: '上海市闵行区申滨路1051号', vehicles: [{ vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B2', plateNo: '沪B40004', actualDeliveryDate: '2026-02-18', deliverer: '运维赵' }], planDeliveryDisplay: '2026-02-18', billingStartDate: '2026-02-18', creator: '李专员', createdAt: '2026-02-08', lastUpdater: '李专员', lastUpdatedAt: '2026-02-18' },
{ id: 'c5', contractCode: 'JXZL20260212YW101232A', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 3, deliveryRegion: '浙江省-杭州市', deliveryLocation: '杭州市萧山区市心北路与建设一路交叉口', vehicles: [{ vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A2', plateNo: '浙C50001', actualDeliveryDate: '2026-02-22', deliverer: '运维李' }, { vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '浙C50002', actualDeliveryDate: '2026-02-23', deliverer: '运维王' }, { vehicleType: '4.5吨货车-轻型厢式货车', brand: '品牌C', model: '型号C1', plateNo: '浙C50003', actualDeliveryDate: '2026-02-24', deliverer: '运维赵' }], planDeliveryDisplay: '2026-02-22至2026-02-24', billingStartDate: '2026-02-22', creator: '王专员', createdAt: '2026-02-14', lastUpdater: '王专员', lastUpdatedAt: '2026-02-24' },
{ id: 'c6', contractCode: 'JXZL20260201YW101228A', projectName: '嘉兴氢能运输项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, deliveryRegion: '浙江省-嘉兴市', deliveryLocation: '嘉兴市秀洲区洪兴西路288号', vehicles: [{ vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '浙A10004', actualDeliveryDate: '2026-02-15', deliverer: '运维李' }], planDeliveryDisplay: '2026-02-15', billingStartDate: '2026-02-15', creator: '张经理', createdAt: '2026-02-05', lastUpdater: '张经理', lastUpdatedAt: '2026-02-15' },
{ id: 'c7', contractCode: 'SHZL20260203YW101199A', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 2, deliveryRegion: '上海市-上海市', deliveryLocation: '上海市嘉定区安亭镇墨玉南路与博园路交叉口', vehicles: [{ vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '沪A30005', actualDeliveryDate: '2026-02-16', deliverer: '运维赵' }, { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '沪A30006', actualDeliveryDate: '2026-02-17', deliverer: '运维李' }], planDeliveryDisplay: '2026-02-16至2026-02-17', billingStartDate: '2026-02-16', creator: '李专员', createdAt: '2026-02-06', lastUpdater: '李专员', lastUpdatedAt: '2026-02-17' },
{ id: 'c8', contractCode: 'JXZL20260128YW101227A', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 2, deliveryRegion: '浙江省-杭州市', deliveryLocation: '杭州市西湖区文三路与古翠路交叉口', vehicles: [{ vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B2', plateNo: '浙B20004', actualDeliveryDate: '2026-02-10', deliverer: '运维王' }, { vehicleType: '4.5吨货车-轻型厢式货车', brand: '品牌C', model: '型号C1', plateNo: '浙B20005', actualDeliveryDate: '2026-02-11', deliverer: '运维赵' }], planDeliveryDisplay: '2026-02-10至2026-02-11', billingStartDate: '2026-02-10', creator: '王专员', createdAt: '2026-01-30', lastUpdater: '王专员', lastUpdatedAt: '2026-02-11' },
{ id: 'c9', contractCode: 'JXZL20260206YW101230A', projectName: '嘉兴氢能运输项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, deliveryRegion: '浙江省-嘉兴市', deliveryLocation: '嘉兴市经开区昌盛路与文昌路交叉口', vehicles: [{ vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A2', plateNo: '浙A10005', actualDeliveryDate: '2026-02-19', deliverer: '运维李' }], planDeliveryDisplay: '2026-02-19', billingStartDate: '2026-02-19', creator: '张经理', createdAt: '2026-02-09', lastUpdater: '张经理', lastUpdatedAt: '2026-02-19' },
{ id: 'c10', contractCode: 'SHZL20260215YW101203A', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 2, deliveryRegion: '上海市-上海市', deliveryLocation: '上海市浦东新区金桥镇金海路1000号', vehicles: [{ vehicleType: '18吨厢式货车-重型厢式货车', brand: '品牌B', model: '型号B1', plateNo: '沪C60001', actualDeliveryDate: '2026-02-26', deliverer: '运维赵' }, { vehicleType: '4.5吨冷链车-轻型厢式货车', brand: '品牌A', model: '型号A1', plateNo: '沪C60002', actualDeliveryDate: '2026-02-27', deliverer: '运维李' }], planDeliveryDisplay: '2026-02-26至2026-02-27', billingStartDate: '2026-02-26', creator: '李专员', createdAt: '2026-02-18', lastUpdater: '李专员', lastUpdatedAt: '2026-02-27' }
];
var applied = _applied[0];
var setApplied = _applied[1];
var getProjectLabel = function(v) { var o = projectOptions.find(function(x) { return x.value === v; }); return o ? o.label : v; };
var getCustomerLabel = function(v) { var o = customerOptions.find(function(x) { return x.value === v; }); return o ? o.label : v; };
var getCreatorLabel = function(v) { var o = creatorOptions.find(function(x) { return x.value === v; }); return o ? o.label : v; };
var filterOngoing = function(list) {
var a = applied;
if (a.contractCode) list = list.filter(function(r) { return r.contractCode === a.contractCode; });
if (a.projectName) { var pl = getProjectLabel(a.projectName); if (pl) list = list.filter(function(r) { return r.projectName === pl; }); }
if (a.customerName) { var cl = getCustomerLabel(a.customerName); if (cl) list = list.filter(function(r) { return r.customerName === cl; }); }
if (a.creator) { var ul = getCreatorLabel(a.creator); if (ul) list = list.filter(function(r) { return r.creator === ul; }); }
if (a.planDateRange && a.planDateRange.length === 2 && window.dayjs) {
var start = window.dayjs(a.planDateRange[0]).startOf('day');
var end = window.dayjs(a.planDateRange[1]).endOf('day');
list = list.filter(function(r) {
var d = r.planDeliveryEnd ? window.dayjs(r.planDeliveryEnd) : null;
return d && !d.isBefore(start) && !d.isAfter(end);
});
}
return list;
};
var filteredOngoing = useMemo(function() {
return filterOngoing(ongoingList.slice());
}, [ongoingList, applied.contractCode, applied.projectName, applied.customerName, applied.creator, applied.planDateRange]);
var filteredCompleted = useMemo(function() {
var list = completedList.slice();
if (applied.contractCode) list = list.filter(function(r) { return r.contractCode === applied.contractCode; });
if (applied.projectName) { var pl = getProjectLabel(applied.projectName); if (pl) list = list.filter(function(r) { return r.projectName === pl; }); }
if (applied.customerName) { var cl = getCustomerLabel(applied.customerName); if (cl) list = list.filter(function(r) { return r.customerName === cl; }); }
if (applied.creator) { var ul = getCreatorLabel(applied.creator); if (ul) list = list.filter(function(r) { return r.creator === ul; }); }
if (applied.planDateRange && applied.planDateRange.length === 2 && window.dayjs) {
var start = window.dayjs(applied.planDateRange[0]).startOf('day');
var end = window.dayjs(applied.planDateRange[1]).endOf('day');
list = list.filter(function(r) {
var planEnd = r.planDeliveryDisplay && r.planDeliveryDisplay.indexOf('至') >= 0
? r.planDeliveryDisplay.split('至')[1]
: r.planDeliveryDisplay;
var d = planEnd ? window.dayjs(planEnd) : null;
return d && !d.isBefore(start) && !d.isAfter(end);
});
}
return list;
}, [applied.contractCode, applied.projectName, applied.customerName, applied.creator, applied.planDateRange]);
var handleQuery = function() {
setApplied({
contractCode: _contractCode[0],
projectName: _projectName[0],
customerName: _customerName[0],
planDateRange: _planDateRange[0] && _planDateRange[0].length === 2 ? _planDateRange[0] : null,
creator: _creator[0]
});
message.info('已按筛选条件查询');
};
var handleReset = function() {
_contractCode[1](undefined);
_projectName[1](undefined);
_customerName[1](undefined);
_planDateRange[1](null);
_creator[1](undefined);
setApplied({
contractCode: undefined,
projectName: undefined,
customerName: undefined,
planDateRange: null,
creator: undefined
});
};
var handleDisableEnable = function(record) {
if (record.enabled) {
Modal.confirm({
title: '是否确认停用该交车任务?',
okText: '确定',
cancelText: '取消',
onOk: function() {
setOngoingList(function(prev) {
return prev.map(function(r) { return r.id === record.id ? Object.assign({}, r, { enabled: false }) : r; });
});
message.success('已停用');
}
});
return;
}
// 启用:判断预计交车结束日期是否已过期
var dayjs = window.dayjs;
var endDate = record.planDeliveryEnd ? (dayjs ? dayjs(record.planDeliveryEnd) : null) : null;
var now = dayjs ? dayjs() : null;
if (endDate && now && endDate.isBefore(now, 'day')) {
_rescheduleTask[1](record);
_rescheduleDateRange[1](null);
_rescheduleModalVisible[1](true);
return;
}
Modal.confirm({
title: '是否确认启用该交车任务?',
okText: '确定',
cancelText: '取消',
onOk: function() {
setOngoingList(function(prev) {
return prev.map(function(r) { return r.id === record.id ? Object.assign({}, r, { enabled: true }) : r; });
});
message.success('已启用');
}
});
};
var handleRescheduleConfirm = function() {
var task = _rescheduleTask[0];
var range = _rescheduleDateRange[0];
if (!task || !range || range.length !== 2) {
message.warning('请选择预计交车日期(单日请选择同一天为开始和结束)');
return;
}
var dayjs = window.dayjs;
var startStr = dayjs ? dayjs(range[0]).format('YYYY-MM-DD') : String(range[0]);
var endStr = dayjs ? dayjs(range[1]).format('YYYY-MM-DD') : String(range[1]);
var planDisplay = startStr === endStr ? startStr : startStr + '至' + endStr;
setOngoingList(function(prev) {
return prev.map(function(r) {
if (r.id !== task.id) return r;
return Object.assign({}, r, { planDeliveryDisplay: planDisplay, planDeliveryEnd: endStr, enabled: true });
});
});
message.success('已重新选择预计交车日期并启用');
_rescheduleModalVisible[1](false);
_rescheduleTask[1](null);
_rescheduleDateRange[1](null);
};
// 进行中表格列
var ongoingColumns = [
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 180, ellipsis: true, fixed: 'left' },
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 140, ellipsis: true, fixed: 'left' },
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 160, ellipsis: true, fixed: 'left' },
{ title: '交车数量', dataIndex: 'deliveryCount', key: 'deliveryCount', width: 100 },
{ title: '交车区域', dataIndex: 'deliveryRegion', key: 'deliveryRegion', width: 140 },
{ title: '交车地点', dataIndex: 'deliveryLocation', key: 'deliveryLocation', width: 200, ellipsis: true },
{ title: '预计交车日期', dataIndex: 'planDeliveryDisplay', key: 'planDeliveryDisplay', width: 180 },
{ title: '开始计费日期', dataIndex: 'billingStartDate', key: 'billingStartDate', width: 120 },
{ title: '创建人', dataIndex: 'creator', key: 'creator', width: 100 },
{ title: '创建时间', dataIndex: 'createdAt', key: 'createdAt', width: 120 },
{ title: '最后更新人', dataIndex: 'lastUpdater', key: 'lastUpdater', width: 100 },
{ title: '最后更新时间', dataIndex: 'lastUpdatedAt', key: 'lastUpdatedAt', width: 120 },
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
render: function(_, record) {
return React.createElement('span', null,
React.createElement(Button, { type: 'link', size: 'small', onClick: function() { message.info('请参照原型业务管理-交车任务页面'); } }, '查看'),
React.createElement(Button, { type: 'link', size: 'small', onClick: function() { message.info('请参照原型业务管理-交车任务-编辑交车任务页面'); } }, '编辑'),
React.createElement(Button, {
type: 'link',
size: 'small',
onClick: function() { handleDisableEnable(record); }
}, record.enabled ? '停用' : '启用')
);
}
}
];
// 已完成表格列(交车数量重点色+气泡)
var vehiclePopoverContent = function(vehicles) {
if (!vehicles || !vehicles.length) return React.createElement('span', null, '-');
var headers = ['车辆类型', '品牌', '型号', '车牌号', '实际交车日期', '交车人'];
return React.createElement('div', { style: { padding: 4, minWidth: 420 } },
React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 12 } },
React.createElement('thead', null,
React.createElement('tr', null,
headers.map(function(h) { return React.createElement('th', { key: h, style: { padding: '6px 8px', textAlign: 'left', borderBottom: '1px solid #eee', fontWeight: 600 } }, h); })
)
),
React.createElement('tbody', null,
vehicles.map(function(v, i) {
return React.createElement('tr', { key: i },
React.createElement('td', { style: { padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, v.vehicleType || '-'),
React.createElement('td', { style: { padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, v.brand || '-'),
React.createElement('td', { style: { padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, v.model || '-'),
React.createElement('td', { style: { padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, v.plateNo || '-'),
React.createElement('td', { style: { padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, v.actualDeliveryDate || '-'),
React.createElement('td', { style: { padding: '6px 8px', borderBottom: '1px solid #f0f0f0' } }, v.deliverer || '-')
);
})
)
)
);
};
var completedColumns = [
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 180, ellipsis: true, fixed: 'left' },
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 140, ellipsis: true, fixed: 'left' },
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 160, ellipsis: true, fixed: 'left' },
{
title: '交车数量',
dataIndex: 'deliveryCount',
key: 'deliveryCount',
width: 100,
render: function(count, record) {
var content = vehiclePopoverContent(record.vehicles);
return React.createElement(Popover, { content: content, title: '交车车辆明细', trigger: 'click' },
React.createElement('span', { style: { color: '#1890ff', cursor: 'pointer', fontWeight: 500 } }, count)
);
}
},
{ title: '交车区域', dataIndex: 'deliveryRegion', key: 'deliveryRegion', width: 140 },
{ title: '交车地点', dataIndex: 'deliveryLocation', key: 'deliveryLocation', width: 200, ellipsis: true },
{ title: '预计交车日期', dataIndex: 'planDeliveryDisplay', key: 'planDeliveryDisplay', width: 180 },
{ title: '开始计费日期', dataIndex: 'billingStartDate', key: 'billingStartDate', width: 120 },
{ title: '创建人', dataIndex: 'creator', key: 'creator', width: 100 },
{ title: '创建时间', dataIndex: 'createdAt', key: 'createdAt', width: 120 },
{ title: '最后更新人', dataIndex: 'lastUpdater', key: 'lastUpdater', width: 100 },
{ title: '最后更新时间', dataIndex: 'lastUpdatedAt', key: 'lastUpdatedAt', width: 120 },
{
title: '操作',
key: 'action',
width: 80,
fixed: 'right',
render: function(_, record) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function() { message.info('请参照原型业务管理-交车任务页面'); } }, '查看');
}
}
];
var filterOption = function(input, option) {
var label = (option && option.label) ? String(option.label) : '';
return label.toLowerCase().indexOf((input || '').toLowerCase()) >= 0;
};
var filterLabelStyle = { marginBottom: 6, fontSize: 14, color: 'rgba(0,0,0,0.65)' };
var filterItemStyle = { marginBottom: 12 };
var filterControlStyle = { width: '100%' };
var filterItems = [
React.createElement('div', { key: 'contractCode', style: filterItemStyle },
React.createElement('div', { style: filterLabelStyle }, '合同编码'),
React.createElement(Select, {
placeholder: '请输入或选择合同编码',
style: filterControlStyle,
value: _contractCode[0],
onChange: function(v) { _contractCode[1](v); },
options: contractOptions,
showSearch: true,
allowClear: true,
filterOption: filterOption
})),
React.createElement('div', { key: 'projectName', style: filterItemStyle },
React.createElement('div', { style: filterLabelStyle }, '项目名称'),
React.createElement(Select, {
placeholder: '请输入或选择项目名称',
style: filterControlStyle,
value: _projectName[0],
onChange: function(v) { _projectName[1](v); },
options: projectOptions,
showSearch: true,
allowClear: true,
filterOption: filterOption
})),
React.createElement('div', { key: 'customerName', style: filterItemStyle },
React.createElement('div', { style: filterLabelStyle }, '客户名称'),
React.createElement(Select, {
placeholder: '请输入或选择客户名称',
style: filterControlStyle,
value: _customerName[0],
onChange: function(v) { _customerName[1](v); },
options: customerOptions,
showSearch: true,
allowClear: true,
filterOption: filterOption
})),
React.createElement('div', { key: 'planDate', style: filterItemStyle },
React.createElement('div', { style: filterLabelStyle }, '预计交车日期'),
React.createElement(RangePicker, {
style: filterControlStyle,
placeholder: ['请选择预计交车开始时间', '请选择预计交车结束时间'],
value: _planDateRange[0] && _planDateRange[0].length === 2 && window.dayjs ? [_planDateRange[0][0], _planDateRange[0][1]] : null,
onChange: function(dates) { _planDateRange[1](dates && dates.length === 2 ? dates : null); }
})),
React.createElement('div', { key: 'creator', style: filterItemStyle },
React.createElement('div', { style: filterLabelStyle }, '创建人'),
React.createElement(Select, {
placeholder: '请输入或选择创建人',
style: filterControlStyle,
value: _creator[0],
onChange: function(v) { _creator[1](v); },
options: creatorOptions,
showSearch: true,
allowClear: true,
filterOption: filterOption
}))
];
var filterCount = _filterExpanded[0] ? 5 : 3;
var filterNodes = [];
for (var i = 0; i < filterCount && i < filterItems.length; i++) {
filterNodes.push(filterItems[i]);
}
// 表格单元格一行显示、根据内容适应宽度
var cellNoWrap = function() { return { style: { whiteSpace: 'nowrap' } }; };
var ongoingColumnsWithNowrap = ongoingColumns.map(function(col) { return Object.assign({}, col, { onCell: cellNoWrap }); });
var completedColumnsWithNowrap = completedColumns.map(function(col) { return Object.assign({}, col, { onCell: cellNoWrap }); });
var layoutStyle = { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh' };
var reqTitleStyle = { fontSize: 18, fontWeight: 600, marginBottom: 16, color: 'rgba(0,0,0,0.85)' };
var reqSectionStyle = { fontSize: 15, fontWeight: 600, marginTop: 16, marginBottom: 8, color: 'rgba(0,0,0,0.85)' };
var reqSubStyle = { fontSize: 14, fontWeight: 500, marginLeft: 16, marginTop: 8, marginBottom: 4, color: 'rgba(0,0,0,0.85)' };
var reqItemStyle = { fontSize: 13, marginLeft: 32, marginTop: 4, marginBottom: 2, lineHeight: 1.6, color: 'rgba(0,0,0,0.75)' };
var reqSubItemStyle = { fontSize: 13, marginLeft: 48, marginTop: 2, marginBottom: 2, lineHeight: 1.6, color: 'rgba(0,0,0,0.7)' };
var reqBlockStyle = { marginBottom: 8 };
var reqSpecContent = React.createElement('div', { style: { padding: '0 4px' } },
React.createElement('div', { style: reqTitleStyle }, '交车任务'),
React.createElement('div', { style: reqBlockStyle },
React.createElement('div', { style: reqSectionStyle }, '1.面包屑:'),
React.createElement('div', { style: reqSubStyle }, '1.1.业务管理-交车任务')
),
React.createElement('div', { style: reqBlockStyle },
React.createElement('div', { style: reqSectionStyle }, '2.筛选:'),
React.createElement('div', { style: reqItemStyle }, '支持通过合同编码、项目名称、客户名称、预计交车日期、创建人进行筛选,右侧为查询、重置按钮;'),
React.createElement('div', { style: reqItemStyle }, '2.1.合同编码:选择器,默认为所有合同;提示信息为:请输入或选择合同编码,支持从输入框输入内容进行模糊搜索,下拉显示结果;'),
React.createElement('div', { style: reqItemStyle }, '2.2.项目名称:选择器,默认为所有项目;提示信息为:请输入或选择项目名称,支持从输入框输入内容进行模糊搜索,下拉显示结果;'),
React.createElement('div', { style: reqItemStyle }, '2.3.客户名称:选择器,默认为所有客户;提示信息为:请输入或选择客户名称,支持从输入框输入内容进行模糊搜索,下拉显示结果;'),
React.createElement('div', { style: reqItemStyle }, '2.4.预计交车日期:日期选择器,默认提示信息为:请选择预计交车开始时间 请选择预计交车结束时间单输入框双日历支持时间段选择精确至天格式为YYYY-MM-DD - YYYY-MM-DD'),
React.createElement('div', { style: reqItemStyle }, '2.5.创建人:选择器,默认为所有创建人;提示信息为:请输入或选择创建人,支持从输入框输入内容进行模糊搜索,下拉显示结果;'),
React.createElement('div', { style: reqItemStyle }, '2.6.查询:点击查询,根据单个或多个筛选条件(且)联动表格进行查询;'),
React.createElement('div', { style: reqItemStyle }, '2.7.重置:点击清空查询条件至默认')
),
React.createElement('div', { style: reqBlockStyle },
React.createElement('div', { style: reqSectionStyle }, '3.列表分为2个tab进行中、已完成右侧为新增'),
React.createElement('div', { style: reqSubStyle }, '3.1进行中:显示所有已新增成功,但未完成交车单提交的任务;列表展示以下内容:合同编码、项目名称、客户名称、交车数量、预计交车日期、开始计费日期、创建人、创建时间、最后更新人、最后更新时间、操作;'),
React.createElement('div', { style: reqItemStyle }, '3.1.1合同编码:显示对应合同编码;'),
React.createElement('div', { style: reqItemStyle }, '3.1.2.项目名称:显示对应项目名称;'),
React.createElement('div', { style: reqItemStyle }, '3.1.3.客户名称:显示对应客户名称;'),
React.createElement('div', { style: reqItemStyle }, '3.1.4.交车数量:显示交车数;'),
React.createElement('div', { style: reqItemStyle }, '3.1.5.交车区域:显示交车省-市;'),
React.createElement('div', { style: reqItemStyle }, '3.1.6.交车地点:显示交车详细地址;'),
React.createElement('div', { style: reqItemStyle }, '3.1.7.预计交车日期显示预计交车日期支持某天或某个时间段格式为YYYY-MM-DD或YYYY-MM-DD至YYYY-MM-DD'),
React.createElement('div', { style: reqItemStyle }, '3.1.8.开始计费日期显示开始计费日期格式为YYYY-MM-DD在交车单完成电子签章后开始生效'),
React.createElement('div', { style: reqItemStyle }, '3.1.9.创建人:显示交车任务的创建人用户姓名;'),
React.createElement('div', { style: reqItemStyle }, '3.1.10.创建时间显示交车任务的创建时间格式为YYYY-MM-DD'),
React.createElement('div', { style: reqItemStyle }, '3.1.11.最后更新人:显示交车任务的最后一次更新人用户姓名;'),
React.createElement('div', { style: reqItemStyle }, '3.1.12.最后更新时间显示交车任务的最后一次更新时间格式为YYYY-MM-DD'),
React.createElement('div', { style: reqItemStyle }, '3.1.13.操作:支持查看、编辑、停用/启用;'),
React.createElement('div', { style: reqSubItemStyle }, '3.1.13.1.查看:跳转查看交车任务;'),
React.createElement('div', { style: reqSubItemStyle }, '3.1.13.2.编辑:跳转编辑交车任务;'),
React.createElement('div', { style: reqSubItemStyle }, '3.1.13.3.停用/启用:任务创建后为启用状态,此处为停用,点击停用后,变为启用。停用状态的交车任务不会推送给对应区域运维人员,重新启用时判断预计交车结束日期是否已经过期,如已过期则启用时需要在弹出卡片中重新选择预计交车日期;'),
React.createElement('div', { style: reqSubStyle }, '3.2.已完成:显示所有已新增成功并完成交车单提交的任务,列表展示以下内容:合同编码、项目名称、客户名称、交车数量、预计交车日期、开始计费日期、创建人、创建时间、最后更新人、最后更新时间、操作;'),
React.createElement('div', { style: reqItemStyle }, '3.2.1.合同编码:显示对应合同编码;'),
React.createElement('div', { style: reqItemStyle }, '3.2.2.项目名称:显示对应项目名称;'),
React.createElement('div', { style: reqItemStyle }, '3.2.3.客户名称:显示对应客户名称;'),
React.createElement('div', { style: reqItemStyle }, '3.2.4.交车数量:显示交车数,重点色显示,点击弹出气泡卡片,列表显示:车辆类型、品牌、型号、车牌号、实际交车日期、交车人;'),
React.createElement('div', { style: reqSubItemStyle }, '3.2.4.1.车辆类型:显示车辆类型;'),
React.createElement('div', { style: reqSubItemStyle }, '3.2.4.2.品牌:显示车辆品牌;'),
React.createElement('div', { style: reqSubItemStyle }, '3.2.4.3.型号:显示车辆型号;'),
React.createElement('div', { style: reqSubItemStyle }, '3.2.4.4.车牌号:显示交车车辆车牌号,如果该车还未交车则显示为-'),
React.createElement('div', { style: reqSubItemStyle }, '3.2.4.5.实际交车日期显示实际交车日期与列表中显示相同格式为YYYY-MM-DD如该车还未交车则显示为-'),
React.createElement('div', { style: reqSubItemStyle }, '3.2.4.6.交车人:显示实际交车人用户姓名,如该车还未还车则显示为-'),
React.createElement('div', { style: reqItemStyle }, '3.2.5.预计交车日期显示预计交车日期支持某天或某个时间段格式为YYYY-MM-DD或YYYY-MM-DD至YYYY-MM-DD'),
React.createElement('div', { style: reqItemStyle }, '3.2.6.开始计费日期显示开始计费日期格式为YYYY-MM-DD在交车单完成电子签章后开始生效'),
React.createElement('div', { style: reqItemStyle }, '3.2.7.创建人:显示交车任务的创建人用户姓名;'),
React.createElement('div', { style: reqItemStyle }, '3.2.8.创建时间显示交车任务的创建时间格式为YYYY-MM-DD'),
React.createElement('div', { style: reqItemStyle }, '3.2.9.最后更新人:显示交车任务的最后一次更新人用户姓名;'),
React.createElement('div', { style: reqItemStyle }, '3.2.10.最后更新时间显示交车任务的最后一次更新时间格式为YYYY-MM-DD'),
React.createElement('div', { style: reqItemStyle }, '3.2.11.操作:支持查看;')
),
React.createElement('div', { style: reqBlockStyle },
React.createElement('div', { style: reqSectionStyle }, '4.列表右下方为分页功能,支持单页显示条目选择;')
)
);
return React.createElement(App, null,
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() { _reqSpecOpen[1](true); } }, '查看需求说明')
),
React.createElement(Card, { style: { marginBottom: 16 } },
React.createElement('div', {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
gap: '16px 24px',
alignItems: 'start',
flex: 1,
minWidth: 0
}
}, filterNodes),
React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 16 } },
React.createElement(Button, { onClick: handleReset }, '重置'),
React.createElement(Button, { type: 'primary', onClick: handleQuery }, '查询'),
React.createElement(Button, { type: 'link', size: 'small', onClick: function() { _filterExpanded[1](!_filterExpanded[0]); } }, _filterExpanded[0] ? '收起' : '展开')
)
),
React.createElement(Card, null,
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } },
React.createElement(Tabs, {
activeKey: _activeTab[0],
onChange: function(k) { _activeTab[1](k); },
items: [
{ key: 'ongoing', label: '进行中' },
{ key: 'completed', label: '已完成' }
]
}),
React.createElement(Button, { type: 'primary', onClick: function() { message.info('请参照原型业务管理-交车任务-新增交车任务页面'); } }, '新增')
),
_activeTab[0] === 'ongoing'
? React.createElement(Table, {
rowKey: 'id',
columns: ongoingColumnsWithNowrap,
dataSource: filteredOngoing,
scroll: { x: 1860 },
size: 'small',
pagination: {
showSizeChanger: true,
showTotal: function(t) { return '共 ' + t + ' 条'; },
pageSizeOptions: ['10', '20', '50', '100']
}
})
: React.createElement(Table, {
rowKey: 'id',
columns: completedColumnsWithNowrap,
dataSource: filteredCompleted,
scroll: { x: 1860 },
size: 'small',
pagination: {
showSizeChanger: true,
showTotal: function(t) { return '共 ' + t + ' 条'; },
pageSizeOptions: ['10', '20', '50', '100']
}
})
),
React.createElement(Modal, {
title: '需求说明',
open: _reqSpecOpen[0],
onCancel: function() { _reqSpecOpen[1](false); },
width: 720,
footer: React.createElement(Button, { onClick: function() { _reqSpecOpen[1](false); } }, '关闭'),
bodyStyle: { maxHeight: '70vh', overflow: 'auto' }
}, reqSpecContent),
React.createElement(Modal, {
title: '预计交车日期已过期,请重新选择预计交车日期',
open: _rescheduleModalVisible[0],
onCancel: function() {
_rescheduleModalVisible[1](false);
_rescheduleTask[1](null);
_rescheduleDateRange[1](null);
},
onOk: handleRescheduleConfirm,
okText: '确定',
cancelText: '取消'
}, React.createElement('div', { style: { padding: '8px 0' } },
React.createElement('div', { style: { marginBottom: 8, color: '#666', fontSize: 13 } }, '支持选择单日或开始-结束时间段,单日时开始与结束选同一天即可。'),
React.createElement('span', { style: { marginRight: 8 } }, '预计交车日期:'),
React.createElement(RangePicker, {
placeholder: ['请选择开始日期', '请选择结束日期(单日请选同一天)'],
value: _rescheduleDateRange[0] && _rescheduleDateRange[0].length === 2 && window.dayjs ? [_rescheduleDateRange[0][0], _rescheduleDateRange[0][1]] : null,
onChange: function(dates) { _rescheduleDateRange[1](dates && dates.length === 2 ? dates : null); }
})
))
)
);
};

View File

@@ -0,0 +1,300 @@
// 【重要】必须使用 const Component 作为组件变量名 - Axhub 产品原型
// 数字化资产ONEOS运管平台 - 新增交车任务模块(参照新增租赁合同布局)
const Component = function() {
var antd = window.antd;
var Input = antd.Input;
var Select = antd.Select;
var Button = antd.Button;
var DatePicker = antd.DatePicker;
var message = antd.message;
var Option = Select.Option;
var Checkbox = antd.Checkbox;
var Tooltip = antd.Tooltip;
var RangePicker = DatePicker.RangePicker;
var projectId = React.useState('');
var selectedProjectId = projectId[0];
var setSelectedProjectId = projectId[1];
var expectedDelivery = React.useState(null);
var expectedDeliveryValue = expectedDelivery[0];
var setExpectedDelivery = expectedDelivery[1];
var billingDate = React.useState(null);
var billingDateValue = billingDate[0];
var setBillingDate = billingDate[1];
var selectedRowKeys = React.useState([]);
var checkedRowKeys = selectedRowKeys[0];
var setCheckedRowKeys = selectedRowKeys[1];
var formErrors = React.useState({});
var errors = formErrors[0];
var setErrors = formErrors[1];
var reqSpecState = React.useState(false);
var reqSpecOpen = reqSpecState[0];
var setReqSpecOpen = reqSpecState[1];
// Mock项目列表及车辆样例。deliveryStatus: 'none' 可选,'submitted' 已提交交车任务不可选,'completed' 已完成交车不显示
var projectList = [
{ id: 'p1', name: '嘉兴某某物流氢能运输项目', contractCode: 'JXZL20260216YW101235A', customerName: '嘉兴某某物流有限公司', deliveryRegion: '浙江省 / 嘉兴市', deliveryLocation: '浙江省嘉兴市南湖区科技大道1号', vehicles: [
{ key: 'v1', brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A10001', vin: 'LFV2BJCH8K3123456', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '首车', deliveryStatus: 'submitted' },
{ key: 'v2', brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A10002', vin: 'LFV2BJCH8K3123457', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '', deliveryStatus: 'submitted' },
{ key: 'v3', brand: '福田', model: '智蓝氢能轻卡', plateNo: '', vin: 'LZYTBACR2M1234567', monthRent: '8500', serviceFee: '500', deposit: '20000', remark: '待上牌', deliveryStatus: 'none' },
{ key: 'v4', brand: '重汽', model: '豪沃氢能牵引车', plateNo: '浙F20001', vin: 'ZZ4257N386FZ12345', monthRent: '15000', serviceFee: '1000', deposit: '35000', remark: '', deliveryStatus: 'none' },
{ key: 'v5', brand: '陕汽', model: '德龙氢能自卸', plateNo: '浙F20002', vin: 'SX1313GR456123456', monthRent: '13200', serviceFee: '880', deposit: '32000', remark: '固定线路', deliveryStatus: 'none' }
]},
{ id: 'p2', name: '上海某某运输氢能租赁项目', contractCode: 'SHZL20260201YW200123A', customerName: '上海某某运输公司', deliveryRegion: '上海市 / 上海市', deliveryLocation: '上海市浦东新区张江高科技园区', vehicles: [
{ key: 'v6', brand: '上汽红岩', model: '杰狮氢能牵引', plateNo: '沪A30003', vin: 'SH1313HY789012345', monthRent: '14500', serviceFee: '950', deposit: '34000', remark: '', deliveryStatus: 'submitted' },
{ key: 'v7', brand: '宇通', model: '氢能公交 ZK6126', plateNo: '沪B40001', vin: 'LZYTAGCF8K4567890', monthRent: '22000', serviceFee: '1200', deposit: '50000', remark: '示范线路', deliveryStatus: 'none' },
{ key: 'v8', brand: '福田', model: '欧辉氢能大巴', plateNo: '', vin: 'LZYTBACR2M2345678', monthRent: '19800', serviceFee: '1100', deposit: '45000', remark: '', deliveryStatus: 'none' }
]},
{ id: 'p3', name: '杭州某某租赁氢能项目', contractCode: 'HZZL20260115YW100089A', customerName: '杭州某某租赁有限公司', deliveryRegion: '浙江省 / 杭州市', deliveryLocation: '浙江省杭州市余杭区未来科技城', vehicles: [
{ key: 'v9', brand: '品牌C', model: '型号C1', plateNo: '浙A40004', vin: 'L4234567890ABCDEF', monthRent: '8200', serviceFee: '450', deposit: '20000', remark: '重点客户', deliveryStatus: 'completed' },
{ key: 'v10', brand: '品牌C', model: '型号C2', plateNo: '', vin: 'L5234567890ABCDEF', monthRent: '7800', serviceFee: '420', deposit: '19000', remark: '', deliveryStatus: 'submitted' },
{ key: 'v11', brand: '东风', model: '氢燃料电池厢货', plateNo: '浙A50001', vin: 'LFV2BJCH8K5678901', monthRent: '9200', serviceFee: '520', deposit: '22000', remark: '城配', deliveryStatus: 'none' },
{ key: 'v12', brand: '开沃', model: '创源氢能轻卡', plateNo: '浙A50002', vin: 'LJXTBACR9N6789012', monthRent: '8800', serviceFee: '480', deposit: '21000', remark: '', deliveryStatus: 'none' }
]}
];
var selectedProject = projectList.find(function(p) { return p.id === selectedProjectId; });
var vehicleListRaw = selectedProject ? selectedProject.vehicles : [];
var vehicleList = vehicleListRaw.filter(function(v) { return v.deliveryStatus !== 'completed'; });
var selectableVehicles = vehicleList.filter(function(v) { return v.deliveryStatus !== 'submitted'; });
var handleProjectChange = function(id) {
setSelectedProjectId(id || '');
setCheckedRowKeys([]);
};
var todayStr = (function() {
var d = new Date();
return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
})();
var validateExpectedDelivery = function() {
if (!expectedDeliveryValue || !expectedDeliveryValue.length) return '请选择预计交车日期';
var start = expectedDeliveryValue[0] && expectedDeliveryValue[0].format ? expectedDeliveryValue[0].format('YYYY-MM-DD') : null;
var end = expectedDeliveryValue[1] && expectedDeliveryValue[1].format ? expectedDeliveryValue[1].format('YYYY-MM-DD') : null;
if (!start) return '请选择预计交车日期';
if (end && end < start) return '结束日期不能早于开始日期'; // 结束可与开始相同,即单日
if (end && end < todayStr) return '结束日期不能早于当前日期';
return null;
};
var expectedDeliveryError = validateExpectedDelivery();
var billingDateError = !billingDateValue ? '请选择开始计费日期' : null;
var handleSubmit = function() {
var err = {};
if (!selectedProjectId) err.projectName = '请选择项目名称';
if (expectedDeliveryError) err.expectedDelivery = expectedDeliveryError;
if (billingDateError) err.billingDate = billingDateError;
if (checkedRowKeys.length === 0 && selectableVehicles.length > 0) err.vehicles = '请至少选择一辆车';
setErrors(err);
if (Object.keys(err).length) return;
var count = checkedRowKeys.length;
message.success('已为 ' + count + ' 辆车生成交车任务,将按交车区域分配对应运维人员。');
};
var handleCancel = function() {
message.info('取消');
};
var onSelectAll = function(checked) {
if (checked) setCheckedRowKeys(selectableVehicles.map(function(v) { return v.key; }));
else setCheckedRowKeys([]);
};
var onSelectRow = function(record, checked) {
if (checked) setCheckedRowKeys(function(prev) { return prev.indexOf(record.key) === -1 ? prev.concat(record.key) : prev; });
else setCheckedRowKeys(function(prev) { return prev.filter(function(k) { return k !== record.key; }); });
};
var styles = {
page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0' },
cardTitle: { fontSize: 16, fontWeight: 600, color: '#333' },
cardBody: { padding: '20px 24px' },
formRow: { display: 'flex', flexWrap: 'wrap', marginBottom: 16 },
formCol: { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8 },
label: { display: 'block', marginBottom: 6, color: '#333' },
labelRequired: { color: '#ff4d4f', marginRight: 4 },
errMsg: { color: '#ff4d4f', fontSize: 12, marginTop: 4 },
footer: { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, justifyContent: 'flex-start', zIndex: 99 },
tableWrap: { marginTop: 16, overflowX: 'auto' },
table: { width: '100%', borderCollapse: 'collapse', fontSize: 13 },
th: { padding: '10px 8px', textAlign: 'left', borderBottom: '1px solid #e8e8e8', backgroundColor: '#fafafa', fontWeight: 600 },
td: { padding: '8px', borderBottom: '1px solid #f0f0f0', verticalAlign: 'middle' },
inputDisabled: { width: '100%', padding: '6px 10px', border: '1px solid #d9d9d9', borderRadius: 4, backgroundColor: '#f5f5f5', color: '#666', fontSize: 13 },
modalMask: { position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.45)', zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center' },
modalBox: { backgroundColor: '#fff', borderRadius: 8, width: '90%', maxWidth: 640, maxHeight: '85vh', overflow: 'hidden', display: 'flex', flexDirection: 'column', boxShadow: '0 4px 20px rgba(0,0,0,0.15)' },
modalHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0', fontSize: 16, fontWeight: 600 },
modalBody: { padding: 20, overflow: 'auto', flex: 1 }
};
var reqSpecBlock = { marginBottom: 16 };
var reqSpecH2 = { fontSize: 14, fontWeight: 600, color: '#333', marginBottom: 6 };
var reqSpecP = { fontSize: 13, color: '#666', marginBottom: 4 };
var reqSpecLi = { fontSize: 13, color: '#666', marginBottom: 2, paddingLeft: 8 };
var reqSpecDoc = React.createElement('div', { style: { padding: '0 4px' } },
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '交车任务')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '1.面包屑:'), React.createElement('div', { style: reqSpecLi }, '1.1.业务管理-交车任务-新增交车任务')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '2.表单:'),
React.createElement('div', { style: reqSpecLi }, '2.1.选择项目名称:必选项,选择器,默认提示文本:请选择或输入项目名称,支持从输入框内输入内容进行模糊搜索,对应自营合同、租赁合同-「项目名称」字段;'),
React.createElement('div', { style: reqSpecLi }, '2.2.合同编码:输入框(禁用状态),根据所选项目名称自动反写合同编码;'),
React.createElement('div', { style: reqSpecLi }, '2.3.客户名称:输入框(禁用状态),根据所选项目名称自动反写客户名称;'),
React.createElement('div', { style: reqSpecLi }, '2.4.交车区域:输入框(禁用状态),根据所选项目名称自动反写交车区域。提交时根据交车区域,为对应区域运维人员分配对应交车任务;'),
React.createElement('div', { style: reqSpecLi }, '2.5.交车地点:输入框(禁用状态),根据所选项目名称自动反写交车地点;'),
React.createElement('div', { style: reqSpecLi }, '2.6.预计交车日期必填项日期选择器支持某天或某个时间段两种模式格式为YYYY-MM-DD或YYYY-MM-DD至YYYY-MM-DD结束日期不能早于开始日期并且结束日期不能早于当前日期'),
React.createElement('div', { style: reqSpecLi }, '2.7.开始计费日期必填项日期选择器支持单日选择格式为YYYY-MM-DD'),
React.createElement('div', { style: reqSpecLi }, '2.8.下方为列表,列表拉取该车辆租赁合同对应所有车辆信息(该合同下已提交过交车任务的车辆不可选,已完成交车的车辆不显示在列表中),列表字段为:全选/多选、品牌、型号、车牌号、车辆识别代码、车辆月租金、服务费、保证金、备注;'),
React.createElement('div', { style: reqSpecLi }, '2.8.1.全选/多选支持全选、多选模式选择对应车辆后点击提交自动生成被选中车辆交车任务需要至少选择1辆才能进行提交该合同下已提交过交车任务的车辆不可选已完成交车的车辆不显示在列表中'),
React.createElement('div', { style: reqSpecLi }, '2.8.2.品牌:输入框(禁用状态),根据所选项目名称自动反写品牌;'),
React.createElement('div', { style: reqSpecLi }, '2.8.3.型号:输入框(禁用状态),根据所选项目名称自动反写型号;'),
React.createElement('div', { style: reqSpecLi }, '2.8.4.车牌号:输入框(禁用状态),根据所选项目名称自动反写车牌号,车牌号可能为空,为空时显示为-'),
React.createElement('div', { style: reqSpecLi }, '2.8.5.车辆识别代码:输入框(禁用状态),根据所选项目名称自动反写车辆识别代码;'),
React.createElement('div', { style: reqSpecLi }, '2.8.6.车辆月租金:输入框(禁用状态),根据所选项目名称自动反写车辆月租金,后缀为元;'),
React.createElement('div', { style: reqSpecLi }, '2.8.7.服务费:输入框(禁用状态),根据所选项目名称自动反写服务费,后缀为元;'),
React.createElement('div', { style: reqSpecLi }, '2.8.8.保证金:输入框(禁用状态),根据所选项目名称自动反写保证金,后缀为元;'),
React.createElement('div', { style: reqSpecLi }, '2.8.9.备注:输入框(禁用状态),根据所选项目名称自动反写备注信息,备注为空时显示为-'),
React.createElement('div', { style: reqSpecLi }, '2.9.页面底部为提交、取消;')
));
var reqSpecModalContent = reqSpecOpen ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) setReqSpecOpen(false); } }, React.createElement('div', { style: styles.modalBox, onClick: function(e) { e.stopPropagation(); } }, React.createElement('div', { style: styles.modalHeader }, '需求说明'), React.createElement('div', { style: Object.assign({}, styles.modalBody, { maxHeight: '70vh', padding: '20px 24px' }) }, reqSpecDoc), React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right' } }, React.createElement(Button, { onClick: function() { setReqSpecOpen(false); } }, '关闭')))) : null;
var FormItem = function(props) {
return React.createElement('div', { style: styles.formCol },
React.createElement('label', { style: styles.label }, props.required ? React.createElement('span', { style: styles.labelRequired }, '*') : null, props.label),
props.children,
props.error ? React.createElement('div', { style: styles.errMsg }, props.error) : null
);
};
var projectOptions = projectList.map(function(p) { return React.createElement(Option, { key: p.id, value: p.id }, p.name); });
var formRow1 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '选择项目名称', required: true, error: errors.projectName },
React.createElement(Select, {
placeholder: '请选择或输入项目名称',
style: { width: '100%' },
value: selectedProjectId || undefined,
onChange: handleProjectChange,
showSearch: true,
allowClear: true,
filterOption: function(input, opt) { return opt.children && String(opt.children).toLowerCase().indexOf((input || '').toLowerCase()) >= 0; },
status: errors.projectName ? 'error' : undefined
}, projectOptions)),
React.createElement(FormItem, { label: '合同编码' }, React.createElement(Input, { value: selectedProject ? selectedProject.contractCode : '', disabled: true, style: { width: '100%' } })),
React.createElement(FormItem, { label: '客户名称' }, React.createElement(Input, { value: selectedProject ? selectedProject.customerName : '', disabled: true, style: { width: '100%' } })),
React.createElement(FormItem, { label: '交车区域' }, React.createElement(Input, { value: selectedProject ? selectedProject.deliveryRegion : '', disabled: true, style: { width: '100%' } })),
React.createElement(FormItem, { label: '交车地点' }, React.createElement(Input, { value: selectedProject ? selectedProject.deliveryLocation : '', disabled: true, style: { width: '100%' } }))
);
var formRow2 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '预计交车日期', required: true, error: errors.expectedDelivery },
React.createElement(RangePicker, {
style: { width: '100%' },
format: 'YYYY-MM-DD',
placeholder: ['请选择开始日期', '请选择结束日期(单日请选同一天)'],
value: expectedDeliveryValue,
onChange: function(dates) { setExpectedDelivery(dates && dates.length === 2 ? dates : null); },
status: errors.expectedDelivery ? 'error' : undefined
})),
React.createElement(FormItem, { label: '开始计费日期', required: true, error: errors.billingDate },
React.createElement(DatePicker, {
style: { width: '100%' },
format: 'YYYY-MM-DD',
placeholder: '请选择日期',
value: billingDateValue,
onChange: function(d, dateStr) { setBillingDate(d); },
status: errors.billingDate ? 'error' : undefined
}))
);
var allSelectableChecked = selectableVehicles.length > 0 && selectableVehicles.every(function(v) { return checkedRowKeys.indexOf(v.key) !== -1; });
var someSelectableChecked = selectableVehicles.some(function(v) { return checkedRowKeys.indexOf(v.key) !== -1; });
var tableHeader = React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: Object.assign({}, styles.th, { width: 48 }) },
React.createElement(Checkbox, {
checked: allSelectableChecked,
indeterminate: someSelectableChecked && !allSelectableChecked,
onChange: function(e) { onSelectAll(e.target.checked); }
})),
React.createElement('th', { style: styles.th }, '品牌'),
React.createElement('th', { style: styles.th }, '型号'),
React.createElement('th', { style: styles.th }, '车牌号'),
React.createElement('th', { style: styles.th }, '车辆识别代码'),
React.createElement('th', { style: styles.th }, '车辆月租金'),
React.createElement('th', { style: styles.th }, '服务费'),
React.createElement('th', { style: styles.th }, '保证金'),
React.createElement('th', { style: styles.th }, '备注')
)
);
var tableBody = React.createElement('tbody', null,
vehicleList.length === 0
? React.createElement('tr', null, React.createElement('td', { colSpan: 9, style: Object.assign({}, styles.td, { textAlign: 'center', color: '#999' }) }, '请先选择项目名称,将自动带出该合同下车辆信息'))
: vehicleList.map(function(row) {
var isSubmitted = row.deliveryStatus === 'submitted';
return React.createElement('tr', { key: row.key },
React.createElement('td', { style: styles.td },
isSubmitted
? React.createElement(Tooltip, { title: '该车辆已有交车任务' },
React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 6, cursor: 'not-allowed' } },
React.createElement(Checkbox, { disabled: true, checked: false }),
React.createElement('span', { style: { color: '#999', fontSize: 12 } }, '已提交')))
: React.createElement(Checkbox, { checked: checkedRowKeys.indexOf(row.key) !== -1, onChange: function(e) { onSelectRow(row, e.target.checked); } })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.brand, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.model, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.plateNo || '-', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.vin, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.monthRent + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.serviceFee + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.deposit + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.remark || '-', disabled: true, style: styles.inputDisabled }))
);
})
);
var tableEl = React.createElement('div', { style: styles.tableWrap },
React.createElement('table', { style: styles.table }, tableHeader, tableBody)
);
if (errors.vehicles) {
tableEl = React.createElement('div', null,
React.createElement('div', { style: Object.assign({}, styles.errMsg, { marginBottom: 8 }) }, errors.vehicles),
tableEl
);
}
return React.createElement('div', { style: styles.page },
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } },
React.createElement('div', { style: styles.breadcrumb },
React.createElement('span', null, '业务管理'),
React.createElement('span', { style: styles.breadcrumbSep }, ' / '),
React.createElement('span', null, '交车任务'),
React.createElement('span', { style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { style: { color: '#1890ff' } }, '新增交车任务')),
React.createElement('span', { style: { color: '#1890ff', cursor: 'pointer', fontSize: 14 }, onClick: function() { setReqSpecOpen(true); } }, '查看需求说明')),
React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader }, React.createElement('span', { style: styles.cardTitle }, '交车任务')),
React.createElement('div', { style: styles.cardBody },
formRow1,
formRow2,
tableEl)),
React.createElement('div', { style: { height: 60 } }),
reqSpecModalContent,
React.createElement('div', { style: styles.footer },
React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交'),
React.createElement(Button, { onClick: handleCancel }, '取消'))
);
};

View File

@@ -0,0 +1,123 @@
// 【重要】必须使用 const Component 作为组件变量名 - Axhub 产品原型
// 数字化资产ONEOS运管平台 - 查看交车任务模块(只读,布局参照新增交车任务)
const Component = function() {
var antd = window.antd;
var Input = antd.Input;
var Button = antd.Button;
// Mock当前查看的交车任务详情从列表跳转带入或根据 id 拉取)
var task = {
projectName: '嘉兴某某物流氢能运输项目',
contractCode: 'JXZL20260216YW101235A',
customerName: '嘉兴某某物流有限公司',
deliveryRegion: '浙江省 / 嘉兴市',
deliveryLocation: '浙江省嘉兴市南湖区科技大道1号',
planDeliveryDisplay: '2026-03-01至2026-03-05',
billingStartDate: '2026-03-06',
vehicles: [
{ brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A10001', vin: 'LFV2BJCH8K3123456', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '首车' },
{ brand: '福田', model: '智蓝氢能轻卡', plateNo: '', vin: 'LZYTBACR2M1234567', monthRent: '8500', serviceFee: '500', deposit: '20000', remark: '待上牌' },
{ brand: '重汽', model: '豪沃氢能牵引车', plateNo: '浙F20001', vin: 'ZZ4257N386FZ12345', monthRent: '15000', serviceFee: '1000', deposit: '35000', remark: '' }
]
};
var vehicleList = task.vehicles || [];
var styles = {
page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0' },
cardTitle: { fontSize: 16, fontWeight: 600, color: '#333' },
cardBody: { padding: '20px 24px' },
formRow: { display: 'flex', flexWrap: 'wrap', marginBottom: 16 },
formCol: { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8 },
label: { display: 'block', marginBottom: 6, color: '#333' },
inputDisabled: { width: '100%', padding: '6px 10px', border: '1px solid #d9d9d9', borderRadius: 4, backgroundColor: '#f5f5f5', color: '#666', fontSize: 13 },
footer: { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, justifyContent: 'flex-start', zIndex: 99 },
tableWrap: { marginTop: 16, overflowX: 'auto' },
table: { width: '100%', borderCollapse: 'collapse', fontSize: 13 },
th: { padding: '10px 8px', textAlign: 'left', borderBottom: '1px solid #e8e8e8', backgroundColor: '#fafafa', fontWeight: 600 },
td: { padding: '8px', borderBottom: '1px solid #f0f0f0', verticalAlign: 'middle' }
};
var FormItemReadOnly = function(props) {
return React.createElement('div', { style: styles.formCol },
React.createElement('label', { style: styles.label }, props.label),
React.createElement(Input, { value: props.value != null ? props.value : '', disabled: true, style: styles.inputDisabled })
);
};
var formRow1 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '选择项目名称', value: task.projectName }),
React.createElement(FormItemReadOnly, { label: '合同编码', value: task.contractCode }),
React.createElement(FormItemReadOnly, { label: '客户名称', value: task.customerName }),
React.createElement(FormItemReadOnly, { label: '交车区域', value: task.deliveryRegion }),
React.createElement(FormItemReadOnly, { label: '交车地点', value: task.deliveryLocation })
);
var formRow2 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '预计交车日期', value: task.planDeliveryDisplay }),
React.createElement(FormItemReadOnly, { label: '开始计费日期', value: task.billingStartDate })
);
var tableHeader = React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: styles.th }, '品牌'),
React.createElement('th', { style: styles.th }, '型号'),
React.createElement('th', { style: styles.th }, '车牌号'),
React.createElement('th', { style: styles.th }, '车辆识别代码'),
React.createElement('th', { style: styles.th }, '车辆月租金'),
React.createElement('th', { style: styles.th }, '服务费'),
React.createElement('th', { style: styles.th }, '保证金'),
React.createElement('th', { style: styles.th }, '备注')
)
);
var tableBody = React.createElement('tbody', null,
vehicleList.length === 0
? React.createElement('tr', null, React.createElement('td', { colSpan: 8, style: Object.assign({}, styles.td, { textAlign: 'center', color: '#999' }) }, '暂无车辆'))
: vehicleList.map(function(row, i) {
return React.createElement('tr', { key: i },
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.brand, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.model, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.plateNo || '-', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.vin, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.monthRent + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.serviceFee + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.deposit + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.remark || '-', disabled: true, style: styles.inputDisabled }))
);
})
);
var tableEl = React.createElement('div', { style: styles.tableWrap },
React.createElement('table', { style: styles.table }, tableHeader, tableBody)
);
var handleBack = function() {
if (window.history && window.history.back) window.history.back();
else antd.message.info('返回');
};
return React.createElement('div', { style: styles.page },
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('div', { style: styles.breadcrumb },
React.createElement('span', null, '业务管理'),
React.createElement('span', { style: styles.breadcrumbSep }, ' / '),
React.createElement('span', null, '交车任务'),
React.createElement('span', { style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { style: { color: '#1890ff' } }, '查看交车任务'))),
React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader }, React.createElement('span', { style: styles.cardTitle }, '交车任务')),
React.createElement('div', { style: styles.cardBody },
formRow1,
formRow2,
tableEl)),
React.createElement('div', { style: { height: 60 } }),
React.createElement('div', { style: styles.footer },
React.createElement(Button, { onClick: handleBack }, '返回'))
);
};

View File

@@ -0,0 +1,933 @@
// 【重要】必须使用 const Component 作为组件变量名
// 账单管理 - 车辆资产管理后台(按 antd 规范)
const Component = function() {
var useState = React.useState;
var useCallback = React.useCallback;
var useMemo = React.useMemo;
var useEffect = React.useEffect;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Card = antd.Card;
var Select = antd.Select;
var Button = antd.Button;
var Table = antd.Table;
var Tag = antd.Tag;
var Modal = antd.Modal;
var Input = antd.Input;
var message = antd.message;
var Space = antd.Space;
var Row = antd.Row;
var Col = antd.Col;
// 当前视图list | detail
var viewState = useState('list');
var currentView = viewState[0];
var setCurrentView = viewState[1];
// 分页
var pageState = useState(1);
var currentPage = pageState[0];
var setCurrentPage = pageState[1];
var pageSizeState = useState(10);
var pageSize = pageSizeState[0];
var setPageSize = pageSizeState[1];
// 选中项Table rowSelection 用)
var selectedRowKeysState = useState([]);
var selectedRowKeys = selectedRowKeysState[0];
var setSelectedRowKeys = selectedRowKeysState[1];
// 筛选器(表单值)
var contractFilterState = useState(undefined);
var contractFilter = contractFilterState[0];
var setContractFilter = contractFilterState[1];
var projectFilterState = useState(undefined);
var projectFilter = projectFilterState[0];
var setProjectFilter = projectFilterState[1];
var customerFilterState = useState(undefined);
var customerFilter = customerFilterState[0];
var setCustomerFilter = customerFilterState[1];
var statusFilterState = useState([]);
var statusFilter = statusFilterState[0];
var setStatusFilter = statusFilterState[1];
// 已应用的筛选条件(点击查询后生效)
var appliedFilterState = useState({ contract: '', project: '', customer: '', status: [] });
var appliedFilter = appliedFilterState[0];
var setAppliedFilter = appliedFilterState[1];
// 弹窗:应付金额明细 | 服务费明细
var popoverState = useState({ type: null, data: null });
var popover = popoverState[0];
var setPopover = popoverState[1];
// 照片查看器
var photoViewerState = useState({ visible: false, photos: [], currentIndex: 0 });
var photoViewer = photoViewerState[0];
var setPhotoViewer = photoViewerState[1];
var viewingBillIdState = useState(null);
var viewingBillId = viewingBillIdState[0];
var setViewingBillId = viewingBillIdState[1];
// 详情模式view | payment
var detailModeState = useState('view');
var detailMode = detailModeState[0];
var setDetailMode = detailModeState[1];
// 付款表单数据
var paymentFormState = useState({
discountAmount: '',
discountReason: '',
vehicleList: [],
hydrogenList: [],
violationList: [],
returnFeeList: []
});
var paymentForm = paymentFormState[0];
var setPaymentForm = paymentFormState[1];
// 列表内成本编辑
var editingListCellState = useState(null);
var editingListCell = editingListCellState[0];
var setEditingListCell = editingListCellState[1];
var editingInputValueState = useState('');
var editingInputValue = editingInputValueState[0];
var setEditingInputValue = editingInputValueState[1];
var listEditableCostsState = useState({});
var listEditableCosts = listEditableCostsState[0];
var setListEditableCosts = listEditableCostsState[1];
// 模拟选项与数据(与原文一致)
var contractOptions = useMemo(function() {
return [
{ value: 'HT001', label: 'HT001 - 租赁合同A' },
{ value: 'HT002', label: 'HT002 - 租赁合同B' },
{ value: 'HT003', label: 'HT003 - 租赁合同C' }
];
}, []);
var projectOptions = useMemo(function() {
return [
{ value: 'XM001', label: 'XM001 - 北京项目' },
{ value: 'XM002', label: 'XM002 - 上海项目' },
{ value: 'XM003', label: 'XM003 - 广州项目' }
];
}, []);
var customerOptions = useMemo(function() {
return [
{ value: 'KH001', label: 'KH001 - 科技公司A' },
{ value: 'KH002', label: 'KH002 - 制造企业B' },
{ value: 'KH003', label: 'KH003 - 物流公司C' }
];
}, []);
var statusOptions = [
{ value: 'paid', label: '已付款' },
{ value: 'partial', label: '部分付款' },
{ value: 'unpaid', label: '未付款' }
];
var mockBillList = useMemo(function() {
var list = [];
for (var i = 1; i <= 25; i++) {
var statuses = ['paid', 'partial', 'unpaid'];
var status = statuses[i % 3];
list.push({
id: 'BILL' + i,
contractCode: 'HT00' + (i % 3 + 1),
projectName: 'XM00' + (i % 3 + 1) + ' - 项目' + i,
customerName: 'KH00' + (i % 3 + 1) + ' - 客户' + i,
period: i,
payableAmount: (15000 + i * 500).toFixed(2),
paidAmount: status === 'paid' ? (15000 + i * 500).toFixed(2) : status === 'partial' ? (8000).toFixed(2) : '0.00',
discountAmount: (i % 5 === 0 ? 200 : 0).toFixed(2),
remark: status !== 'unpaid' ? '已付款备注' + i : '-',
vehicleCost: (5000 + i * 100).toFixed(2),
hydrogenCost: (300 + i * 20).toFixed(2),
otherCost: (200 + i * 10).toFixed(2),
status: status
});
}
return list;
}, []);
var mockPayableDetail = useMemo(function() {
return [
{ startDate: '2025-01-01', endDate: '2025-01-31', plateNo: '京A12345', rent: '8000.00', serviceFee: '500.00', deposit: '2000.00' },
{ startDate: '2025-01-01', endDate: '2025-01-31', plateNo: '京B67890', rent: '7000.00', serviceFee: '400.00', deposit: '1500.00' }
];
}, []);
var mockBillDetail = useMemo(function() {
return {
startDate: '2025-01-01',
endDate: '2025-01-31',
contractCode: 'HT001',
projectName: 'XM001 - 北京项目',
customerName: 'KH001 - 科技公司A',
department: '运营部',
responsible: '张三',
paymentCycle: '先付付款周期1个月',
discountTotal: '200.00',
discountReason: '长期合作客户优惠,首期账单减免部分金额'
};
}, []);
var mockVehicleList = useMemo(function() {
return [
{ brand: '奔驰', model: 'E300L', plateNo: '京A12345', planDelivery: '2024-12-25', actualDelivery: '2024-12-28', billStart: '2025-01-01', billEnd: '2025-01-31', monthlyRent: '8000.00', paidMonthlyRent: '7600.00', serviceFee: '500.00', paidServiceFee: '480.00', deposit: '2000.00', paidDeposit: '2000.00', serviceItems: [{ name: '保养服务', price: '300.00', effectiveDate: '2025-01-01' }, { name: '保险', price: '200.00', effectiveDate: '2025-01-01' }] },
{ brand: '宝马', model: '530Li', plateNo: '京B67890', planDelivery: '2024-12-20', actualDelivery: '2024-12-22', billStart: '2025-01-01', billEnd: '2025-01-31', monthlyRent: '7000.00', paidMonthlyRent: '7000.00', serviceFee: '400.00', paidServiceFee: '380.00', deposit: '1500.00', paidDeposit: '1500.00', serviceItems: [{ name: '保养服务', price: '250.00', effectiveDate: '2025-01-01' }] }
];
}, []);
var mockReturnFeeData = useMemo(function() {
return {
totalAmount: '2850.00',
paidTotalAmount: '2700.00',
list: [
{ feeName: '车辆外观损伤费', amount: '800.00', paidAmount: '760.00', photos: ['https://picsum.photos/80/80?random=1', 'https://picsum.photos/80/80?random=2'], attachments: [{ name: '外观损伤说明.pdf' }] },
{ feeName: '轮胎磨损费', amount: '1200.00', paidAmount: '1150.00', photos: ['https://picsum.photos/80/80?random=3'], attachments: [{ name: '轮胎检测报告.pdf' }, { name: '维修单据.pdf' }] },
{ feeName: '内饰清洁费', amount: '450.00', paidAmount: '430.00', photos: ['https://picsum.photos/80/80?random=4', 'https://picsum.photos/80/80?random=5', 'https://picsum.photos/80/80?random=6'], attachments: [] },
{ feeName: '油量补充费', amount: '400.00', paidAmount: '360.00', photos: [], attachments: [{ name: '加油凭证.jpg' }] }
]
};
}, []);
var mockViolationData = useMemo(function() {
return {
violationCount: 3,
totalAmount: '650.00',
paidTotalAmount: '600.00',
list: [
{ violationTime: '2025-01-10 08:30:00', plateNo: '京A12345', violationType: '违停', location: '北京市朝阳区xxx路', fineAmount: '200.00', paidFineAmount: '200.00' },
{ violationTime: '2025-01-18 14:20:00', plateNo: '京B67890', violationType: '超速', location: '北京市海淀区xxx大道', fineAmount: '200.00', paidFineAmount: '180.00' },
{ violationTime: '2025-01-25 09:15:00', plateNo: '京A12345', violationType: '闯红灯', location: '北京市东城区xxx路口', fineAmount: '250.00', paidFineAmount: '220.00' }
]
};
}, []);
var mockHydrogenData = useMemo(function() {
return {
refuelCount: 12,
balance: '3580.00',
list: [
{ refuelTime: '2025-01-15 09:30:00', stationName: '北京朝阳加氢站', plateNo: '京A12345', amount: '15.5', costPrice: '28.00', feePrice: '434.00', paidFeePrice: '420.00' },
{ refuelTime: '2025-01-18 14:20:00', stationName: '北京海淀加氢站', plateNo: '京B67890', amount: '12.0', costPrice: '28.00', feePrice: '336.00', paidFeePrice: '336.00' },
{ refuelTime: '2025-01-22 11:00:00', stationName: '北京朝阳加氢站', plateNo: '京A12345', amount: '18.2', costPrice: '28.00', feePrice: '509.60', paidFeePrice: '490.00' }
]
};
}, []);
var vehicleBillTotals = useMemo(function() {
var list = mockVehicleList || [];
var monthlyRentTotal = 0, paidRentTotal = 0, serviceFeeTotal = 0, paidServiceFeeTotal = 0, depositTotal = 0, paidDepositTotal = 0;
list.forEach(function(v) {
monthlyRentTotal += parseFloat(v.monthlyRent || 0);
paidRentTotal += parseFloat(v.paidMonthlyRent || 0);
serviceFeeTotal += parseFloat(v.serviceFee || 0);
paidServiceFeeTotal += parseFloat(v.paidServiceFee || 0);
depositTotal += parseFloat(v.deposit || 0);
paidDepositTotal += parseFloat(v.paidDeposit || 0);
});
return {
monthlyRentTotal: monthlyRentTotal.toFixed(2),
paidRentTotal: paidRentTotal.toFixed(2),
serviceFeeTotal: serviceFeeTotal.toFixed(2),
paidServiceFeeTotal: paidServiceFeeTotal.toFixed(2),
depositTotal: depositTotal.toFixed(2),
paidDepositTotal: paidDepositTotal.toFixed(2)
};
}, [mockVehicleList]);
var billInfoTotals = useMemo(function() {
var monthlyRentTotal = parseFloat(vehicleBillTotals.monthlyRentTotal || 0);
var serviceFeeTotal = parseFloat(vehicleBillTotals.serviceFeeTotal || 0);
var depositTotal = parseFloat(vehicleBillTotals.depositTotal || 0);
var hydrogenTotal = 0;
(mockHydrogenData.list || []).forEach(function(item) { hydrogenTotal += parseFloat(item.feePrice || 0); });
var violationTotal = parseFloat(mockViolationData.totalAmount || 0);
var returnFeeTotal = parseFloat(mockReturnFeeData.totalAmount || 0);
var payableTotal = monthlyRentTotal + serviceFeeTotal + depositTotal + hydrogenTotal + violationTotal + returnFeeTotal;
var paidTotal = 0;
(mockVehicleList || []).forEach(function(v) {
paidTotal += parseFloat(v.paidMonthlyRent || 0) + parseFloat(v.paidServiceFee || 0) + parseFloat(v.paidDeposit || 0);
});
var discountTotal = parseFloat(mockBillDetail.discountTotal || 0);
var unpaidTotal = Math.max(0, payableTotal - paidTotal - discountTotal);
return {
payableTotal: payableTotal.toFixed(2),
paidTotal: paidTotal.toFixed(2),
unpaidTotal: unpaidTotal.toFixed(2)
};
}, [vehicleBillTotals, mockHydrogenData, mockViolationData, mockReturnFeeData, mockVehicleList, mockBillDetail]);
var vehicleTotals = billInfoTotals;
var filteredList = useMemo(function() {
var list = (mockBillList || []).slice();
var c = (appliedFilter.contract || '').trim();
var p = (appliedFilter.project || '').trim();
var cust = (appliedFilter.customer || '').trim();
var st = Array.isArray(appliedFilter.status) ? appliedFilter.status : [];
if (c) list = list.filter(function(item) { return String(item.contractCode || '').toLowerCase().indexOf(c.toLowerCase()) >= 0; });
if (p) list = list.filter(function(item) { return String(item.projectName || '').toLowerCase().indexOf(p.toLowerCase()) >= 0; });
if (cust) list = list.filter(function(item) { return String(item.customerName || '').toLowerCase().indexOf(cust.toLowerCase()) >= 0; });
if (st.length > 0) {
var statusSet = {};
st.forEach(function(s) { statusSet[s] = true; });
list = list.filter(function(item) { return statusSet[item.status]; });
}
return list;
}, [mockBillList, appliedFilter.contract, appliedFilter.project, appliedFilter.customer, appliedFilter.status]);
var totalCount = filteredList.length;
var paginatedList = useMemo(function() {
var start = (currentPage - 1) * pageSize;
return filteredList.slice(start, start + pageSize);
}, [filteredList, currentPage, pageSize]);
var handleSearch = useCallback(function() {
setAppliedFilter({
contract: (contractFilter != null && contractFilter !== '') ? String(contractFilter) : '',
project: (projectFilter != null && projectFilter !== '') ? String(projectFilter) : '',
customer: (customerFilter != null && customerFilter !== '') ? String(customerFilter) : '',
status: Array.isArray(statusFilter) ? statusFilter.slice() : []
});
setCurrentPage(1);
}, [contractFilter, projectFilter, customerFilter, statusFilter]);
var handleReset = useCallback(function() {
setContractFilter(undefined);
setProjectFilter(undefined);
setCustomerFilter(undefined);
setStatusFilter([]);
setAppliedFilter({ contract: '', project: '', customer: '', status: [] });
setCurrentPage(1);
}, []);
var handleExport = useCallback(function() {
if (selectedRowKeys.length === 0) {
message.warning('请先选择要导出的数据');
return;
}
message.success('导出 ' + selectedRowKeys.length + ' 条数据');
}, [selectedRowKeys.length]);
var handleView = useCallback(function(id, isPayment) {
setViewingBillId(id);
setDetailMode(isPayment ? 'payment' : 'view');
if (isPayment) {
var vl = mockVehicleList.map(function(v) {
return { paidMonthlyRent: v.paidMonthlyRent || '', paidServiceFee: v.paidServiceFee || '', paidDeposit: v.paidDeposit || '' };
});
var hl = mockHydrogenData.list.map(function(item) { return { paidFeePrice: item.paidFeePrice || '' }; });
var viol = mockViolationData.list.map(function(item) { return { paidFineAmount: item.paidFineAmount || '' }; });
var rfl = mockReturnFeeData.list.map(function(item) { return { paidAmount: item.paidAmount || '' }; });
setPaymentForm({
discountAmount: mockBillDetail.discountTotal || '',
discountReason: mockBillDetail.discountReason || '',
vehicleList: vl,
hydrogenList: hl,
violationList: viol,
returnFeeList: rfl
});
}
setCurrentView('detail');
}, []);
var handleBackToList = useCallback(function() {
setCurrentView('list');
setViewingBillId(null);
setDetailMode('view');
}, []);
var handlePaymentFormChange = useCallback(function(section, index, field, value) {
setPaymentForm(function(prev) {
var next = {
discountAmount: prev.discountAmount,
discountReason: prev.discountReason,
vehicleList: prev.vehicleList.slice(),
hydrogenList: prev.hydrogenList.slice(),
violationList: prev.violationList.slice(),
returnFeeList: prev.returnFeeList.slice()
};
if (section === 'bill') {
if (field === 'discountAmount') next.discountAmount = value;
if (field === 'discountReason') next.discountReason = value;
} else if (section === 'vehicle' && index >= 0 && index < next.vehicleList.length) {
next.vehicleList[index] = Object.assign({}, next.vehicleList[index], { [field]: value });
} else if (section === 'hydrogen' && index >= 0 && index < next.hydrogenList.length) {
next.hydrogenList[index] = Object.assign({}, next.hydrogenList[index], { [field]: value });
} else if (section === 'violation' && index >= 0 && index < next.violationList.length) {
next.violationList[index] = Object.assign({}, next.violationList[index], { [field]: value });
} else if (section === 'returnFee' && index >= 0 && index < next.returnFeeList.length) {
next.returnFeeList[index] = Object.assign({}, next.returnFeeList[index], { [field]: value });
}
return next;
});
}, []);
var handleSubmit = useCallback(function() {
var errors = [];
if (!paymentForm.discountAmount || String(paymentForm.discountAmount).trim() === '') errors.push('减免金额');
if (!paymentForm.discountReason || String(paymentForm.discountReason).trim() === '') errors.push('减免原因');
paymentForm.vehicleList.forEach(function(v, i) {
if (!v.paidMonthlyRent || String(v.paidMonthlyRent).trim() === '') errors.push('车辆账单-实付月租金(第' + (i + 1) + '行)');
if (!v.paidServiceFee || String(v.paidServiceFee).trim() === '') errors.push('车辆账单-实付服务费(第' + (i + 1) + '行)');
if (!v.paidDeposit || String(v.paidDeposit).trim() === '') errors.push('车辆账单-实付保证金(第' + (i + 1) + '行)');
});
paymentForm.hydrogenList.forEach(function(h, i) {
if (!h.paidFeePrice || String(h.paidFeePrice).trim() === '') errors.push('氢费账单-实付氢费金额(第' + (i + 1) + '行)');
});
paymentForm.violationList.forEach(function(v, i) {
if (!v.paidFineAmount || String(v.paidFineAmount).trim() === '') errors.push('违章费用-实付罚款金额(第' + (i + 1) + '行)');
});
paymentForm.returnFeeList.forEach(function(r, i) {
if (!r.paidAmount || String(r.paidAmount).trim() === '') errors.push('还车费用-实付金额(第' + (i + 1) + '行)');
});
if (errors.length > 0) {
message.warning('请填写必填项:' + errors.join('、'));
return;
}
message.success('提交成功');
handleBackToList();
}, [paymentForm, handleBackToList]);
var handleSave = useCallback(function() {
message.success('保存成功');
}, []);
function getStatusText(status) {
if (status === 'paid') return '已付款';
if (status === 'partial') return '部分付款';
return '未付款';
}
function getStatusTagColor(status) {
if (status === 'paid') return 'success';
if (status === 'partial') return 'warning';
return 'error';
}
// 列表表格列(含行内编辑氢费/其他成本)
function renderEditableCost(row, field, label) {
var rowId = row.id;
var val = (listEditableCosts[rowId] && listEditableCosts[rowId][field] !== undefined)
? listEditableCosts[rowId][field]
: (row[field] != null ? row[field] : '0.00');
var num = (parseFloat(val) || 0).toFixed(2);
var isEditing = editingListCell && editingListCell.rowId === rowId && editingListCell.field === field;
if (isEditing) {
return React.createElement(Space, { key: 'edit', size: 4 },
React.createElement(Input, {
value: editingInputValue,
onChange: function(e) { setEditingInputValue(e.target.value); },
onBlur: function() {
var n = parseFloat(editingInputValue);
var formatted = (isNaN(n) ? 0 : n).toFixed(2);
setListEditableCosts(function(prev) {
var next = Object.assign({}, prev);
next[rowId] = Object.assign({}, next[rowId], { [field]: formatted });
return next;
});
setEditingListCell(null);
setEditingInputValue('');
},
style: { width: 80 },
autoFocus: true
}),
React.createElement('span', null, '元')
);
}
return React.createElement('span', {
style: { cursor: 'pointer' },
onClick: function() {
setEditingInputValue(num);
setEditingListCell({ rowId: rowId, field: field });
}
}, num);
}
var listColumns = useMemo(function() {
return [
{ title: '付款状态', dataIndex: 'status', key: 'status', width: 100, render: function(s) { return React.createElement(Tag, { color: getStatusTagColor(s) }, getStatusText(s)); } },
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 120 },
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 160 },
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 160 },
{ title: '当前期数', dataIndex: 'period', key: 'period', width: 90 },
{ title: '应付金额', dataIndex: 'payableAmount', key: 'payableAmount', width: 110, render: function(_, row) {
return React.createElement('a', {
onClick: function() { setPopover({ type: 'payable', data: mockPayableDetail }); },
style: { color: '#1677ff', fontWeight: 600, textDecoration: 'underline', cursor: 'pointer' }
}, row.payableAmount);
}},
{ title: '实付金额', dataIndex: 'paidAmount', key: 'paidAmount', width: 110 },
{ title: '减免金额', dataIndex: 'discountAmount', key: 'discountAmount', width: 100 },
{ title: '未付金额', key: 'unpaid', width: 100, render: function(_, row) {
return (parseFloat(row.payableAmount || 0) - parseFloat(row.paidAmount || 0) - parseFloat(row.discountAmount || 0)).toFixed(2);
}},
{ title: '备注', dataIndex: 'remark', key: 'remark', width: 120 },
{ title: '车辆成本(元)', dataIndex: 'vehicleCost', key: 'vehicleCost', width: 120, render: function(val) { return (parseFloat(val) || 0).toFixed(2); } },
{ title: '氢费成本(元)', key: 'hydrogenCost', width: 120, render: function(_, row) { return renderEditableCost(row, 'hydrogenCost', '氢费'); } },
{ title: '其他成本(元)', key: 'otherCost', width: 120, render: function(_, row) { return renderEditableCost(row, 'otherCost', '其他'); } },
{ title: '操作', key: 'action', width: 140, fixed: 'right', render: function(_, row) {
return React.createElement(Space, null,
React.createElement(Button, { type: 'link', size: 'small', onClick: function() { handleView(row.id, false); } }, '查看'),
React.createElement(Button, { type: 'link', size: 'small', style: { color: '#52c41a' }, onClick: function() { handleView(row.id, true); } }, '收费')
);
}}
];
}, [listEditableCosts, editingListCell, editingInputValue, handleView]);
var rowSelection = useMemo(function() {
return {
selectedRowKeys: selectedRowKeys,
onChange: function(keys) { setSelectedRowKeys(keys || []); }
};
}, [selectedRowKeys]);
var tablePagination = useMemo(function() {
return {
current: currentPage,
pageSize: pageSize,
total: totalCount,
showSizeChanger: true,
showTotal: function(t) { return '共 ' + t + ' 条'; },
pageSizeOptions: ['10', '20', '50'],
onChange: function(page, size) {
setCurrentPage(page);
if (size !== pageSize) setPageSize(size);
}
};
}, [currentPage, pageSize, totalCount]);
// —————— 详情视图 ——————
if (currentView === 'detail') {
var detailBreadcrumbItems = [
{ title: '运维管理' },
{ title: '业务管理' },
{ title: '租赁账单' },
{ title: detailMode === 'payment' ? '收费' : '查看' }
];
var billInfoCols = [
{ label: '账单开始日期', value: mockBillDetail.startDate },
{ label: '账单结束日期', value: mockBillDetail.endDate },
{ label: '合同编码', value: mockBillDetail.contractCode },
{ label: '项目名称', value: mockBillDetail.projectName },
{ label: '客户名称', value: mockBillDetail.customerName },
{ label: '业务部门', value: mockBillDetail.department },
{ label: '业务负责人', value: mockBillDetail.responsible },
{ label: '付款周期', value: mockBillDetail.paymentCycle }
];
return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } },
React.createElement(Breadcrumb, { items: detailBreadcrumbItems, style: { marginBottom: 16 } }),
React.createElement(Card, { style: { marginBottom: 16 } },
React.createElement('div', { style: { fontSize: 16, fontWeight: 600, marginBottom: 16, paddingBottom: 12, borderBottom: '1px solid #f0f0f0' } }, '账单信息'),
React.createElement(Row, { gutter: [24, 24] },
billInfoCols.map(function(item, i) {
return React.createElement(Col, { key: i, span: 8 },
React.createElement('div', { style: { marginBottom: 8 } },
React.createElement('span', { style: { color: '#666', marginRight: 8 } }, item.label + ''),
React.createElement('span', null, item.value)
)
);
}),
React.createElement(Col, { span: 8 },
React.createElement('div', { style: { marginBottom: 8 } },
React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '应付款总额:'),
React.createElement('span', { style: { color: '#1890ff', fontWeight: 600 } }, vehicleTotals.payableTotal + ' 元')
)
),
React.createElement(Col, { span: 8 },
React.createElement('div', { style: { marginBottom: 8 } },
React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '实付款总额:'),
React.createElement('span', { style: { color: '#52c41a', fontWeight: 600 } }, vehicleTotals.paidTotal + ' 元')
)
),
React.createElement(Col, { span: 8 },
React.createElement('div', { style: { marginBottom: 8 } },
React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '减免金额:'),
detailMode === 'payment'
? React.createElement(Input, {
value: paymentForm.discountAmount,
onChange: function(e) { handlePaymentFormChange('bill', -1, 'discountAmount', e.target.value); },
style: { width: 120 },
placeholder: '0.00',
addonAfter: '元'
})
: React.createElement('span', { style: { fontWeight: 600 } }, mockBillDetail.discountTotal + ' 元')
)
),
React.createElement(Col, { span: 8 },
React.createElement('div', { style: { marginBottom: 8 } },
React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '未付款总额:'),
React.createElement('span', { style: { color: '#ff4d4f', fontWeight: 600 } }, vehicleTotals.unpaidTotal + ' 元')
)
),
React.createElement(Col, { span: 24 },
React.createElement('div', { style: { marginBottom: 8 } },
React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '减免原因:'),
detailMode === 'payment'
? React.createElement(Input.TextArea, {
value: paymentForm.discountReason,
onChange: function(e) { handlePaymentFormChange('bill', -1, 'discountReason', e.target.value); },
placeholder: '请输入减免原因',
rows: 3,
style: { maxWidth: 400 }
})
: React.createElement('span', null, mockBillDetail.discountReason || '-')
)
)
)
),
// 车辆账单
React.createElement(Card, { title: '车辆账单', style: { marginBottom: 16 } },
React.createElement(Table, {
dataSource: mockVehicleList,
rowKey: 'plateNo',
pagination: false,
scroll: { x: 1200 },
columns: [
{ title: '品牌', dataIndex: 'brand', width: 80 },
{ title: '型号', dataIndex: 'model', width: 90 },
{ title: '车牌号', dataIndex: 'plateNo', width: 100 },
{ title: '计划交车日期', dataIndex: 'planDelivery', width: 120 },
{ title: '实际交车日期', dataIndex: 'actualDelivery', width: 120 },
{ title: '账单开始日期', dataIndex: 'billStart', width: 120 },
{ title: '计费结束日期', dataIndex: 'billEnd', width: 120 },
{ title: '车辆月租金', dataIndex: 'monthlyRent', width: 110 },
{ title: '实付月租金', dataIndex: 'paidMonthlyRent', width: 110, render: function(_, record, idx) {
if (detailMode !== 'payment') return (parseFloat(record.paidMonthlyRent || 0)).toFixed(2);
var pf = paymentForm.vehicleList[idx] || {};
return React.createElement(Input, { value: pf.paidMonthlyRent, onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidMonthlyRent', e.target.value); }, style: { width: 100 }, addonAfter: '元' });
}},
{ title: '服务费', dataIndex: 'serviceFee', width: 90, render: function(val, record) {
if (detailMode === 'payment') return val;
return React.createElement('a', { onClick: function() { setPopover({ type: 'service', data: record.serviceItems }); } }, val);
}},
{ title: '实付服务费', dataIndex: 'paidServiceFee', width: 110, render: function(_, record, idx) {
if (detailMode !== 'payment') return (parseFloat(record.paidServiceFee || 0)).toFixed(2);
var pf = paymentForm.vehicleList[idx] || {};
return React.createElement(Input, { value: pf.paidServiceFee, onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidServiceFee', e.target.value); }, style: { width: 100 }, addonAfter: '元' });
}},
{ title: '保证金', dataIndex: 'deposit', width: 90 },
{ title: '实付保证金', dataIndex: 'paidDeposit', width: 110, render: function(_, record, idx) {
if (detailMode !== 'payment') return (parseFloat(record.paidDeposit || 0)).toFixed(2);
var pf = paymentForm.vehicleList[idx] || {};
return React.createElement(Input, { value: pf.paidDeposit, onChange: function(e) { handlePaymentFormChange('vehicle', idx, 'paidDeposit', e.target.value); }, style: { width: 100 }, addonAfter: '元' });
}}
],
summary: function() {
return React.createElement(Table.Summary, null,
React.createElement(Table.Summary.Row, null,
React.createElement(Table.Summary.Cell, { index: 0, colSpan: 7 }, '总计'),
React.createElement(Table.Summary.Cell, { index: 7 }, vehicleBillTotals.monthlyRentTotal),
React.createElement(Table.Summary.Cell, { index: 8 }, vehicleBillTotals.paidRentTotal),
React.createElement(Table.Summary.Cell, { index: 9 }, vehicleBillTotals.serviceFeeTotal),
React.createElement(Table.Summary.Cell, { index: 10 }, vehicleBillTotals.paidServiceFeeTotal),
React.createElement(Table.Summary.Cell, { index: 11 }, vehicleBillTotals.depositTotal),
React.createElement(Table.Summary.Cell, { index: 12 }, vehicleBillTotals.paidDepositTotal)
)
);
}
})
),
// 氢费账单
React.createElement(Card, { title: '氢费账单', style: { marginBottom: 16 } },
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('span', { style: { marginRight: 24 } }, '加氢次数:', React.createElement('span', { style: { fontWeight: 600 } }, mockHydrogenData.refuelCount + ' 次')),
React.createElement('span', null, '当前氢费余额:', React.createElement('span', { style: { fontWeight: 600, color: '#1890ff' } }, mockHydrogenData.balance + ' 元'))
),
React.createElement(Table, {
dataSource: mockHydrogenData.list,
rowKey: function(item, i) { return i; },
pagination: false,
columns: [
{ title: '加氢时间', dataIndex: 'refuelTime', width: 180 },
{ title: '加氢站名称', dataIndex: 'stationName', width: 140 },
{ title: '车牌号', dataIndex: 'plateNo', width: 100 },
{ title: '加氢量', dataIndex: 'amount', width: 90 },
{ title: '成本单价(元/KG', dataIndex: 'costPrice', width: 120 },
{ title: '氢费价格(元)', dataIndex: 'feePrice', width: 120 },
{ title: '实付氢费金额(元)', dataIndex: 'paidFeePrice', width: 140, render: function(_, record, i) {
if (detailMode !== 'payment') return (parseFloat(record.paidFeePrice || 0)).toFixed(2);
var pf = paymentForm.hydrogenList[i] || {};
return React.createElement(Input, { value: pf.paidFeePrice, onChange: function(e) { handlePaymentFormChange('hydrogen', i, 'paidFeePrice', e.target.value); }, style: { width: 100 }, addonAfter: '元' });
}}
],
summary: function() {
var totalFee = mockHydrogenData.list.reduce(function(s, item) { return s + parseFloat(item.feePrice || 0); }, 0).toFixed(2);
var totalPaid = mockHydrogenData.list.reduce(function(s, item) { return s + parseFloat(item.paidFeePrice || 0); }, 0).toFixed(2);
return React.createElement(Table.Summary, null,
React.createElement(Table.Summary.Row, null,
React.createElement(Table.Summary.Cell, { index: 0, colSpan: 5 }, '总计'),
React.createElement(Table.Summary.Cell, { index: 5 }, totalFee),
React.createElement(Table.Summary.Cell, { index: 6 }, totalPaid)
)
);
}
})
),
// 违章费用
React.createElement(Card, { title: '违章费用', style: { marginBottom: 16 } },
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('span', null, '违章次数:', React.createElement('span', { style: { fontWeight: 600 } }, mockViolationData.violationCount + ' 次'))
),
React.createElement(Table, {
dataSource: mockViolationData.list,
rowKey: function(item, i) { return i; },
pagination: false,
columns: [
{ title: '违章时间', dataIndex: 'violationTime', width: 180 },
{ title: '车牌号', dataIndex: 'plateNo', width: 100 },
{ title: '违章类型', dataIndex: 'violationType', width: 100 },
{ title: '违章地点', dataIndex: 'location', width: 200 },
{ title: '罚款金额', dataIndex: 'fineAmount', width: 100 },
{ title: '实付罚款金额(元)', dataIndex: 'paidFineAmount', width: 140, render: function(_, record, i) {
if (detailMode !== 'payment') return (parseFloat(record.paidFineAmount || 0)).toFixed(2);
var pf = paymentForm.violationList[i] || {};
return React.createElement(Input, { value: pf.paidFineAmount, onChange: function(e) { handlePaymentFormChange('violation', i, 'paidFineAmount', e.target.value); }, style: { width: 100 }, addonAfter: '元' });
}}
],
summary: function() {
var totalPaid = mockViolationData.list.reduce(function(s, item) { return s + parseFloat(item.paidFineAmount || 0); }, 0).toFixed(2);
return React.createElement(Table.Summary, null,
React.createElement(Table.Summary.Row, null,
React.createElement(Table.Summary.Cell, { index: 0, colSpan: 4 }, '总计'),
React.createElement(Table.Summary.Cell, { index: 4 }, mockViolationData.totalAmount),
React.createElement(Table.Summary.Cell, { index: 5 }, totalPaid)
)
);
}
})
),
// 还车费用
React.createElement(Card, { title: '还车费用', style: { marginBottom: 16 } },
React.createElement(Table, {
dataSource: mockReturnFeeData.list,
rowKey: function(item, i) { return i; },
pagination: false,
columns: [
{ title: '费用名称', dataIndex: 'feeName', width: 140 },
{ title: '金额', dataIndex: 'amount', width: 100 },
{ title: '实付金额(元)', dataIndex: 'paidAmount', width: 120, render: function(_, record, i) {
if (detailMode !== 'payment') return (parseFloat(record.paidAmount || 0)).toFixed(2);
var pf = paymentForm.returnFeeList[i] || {};
return React.createElement(Input, { value: pf.paidAmount, onChange: function(e) { handlePaymentFormChange('returnFee', i, 'paidAmount', e.target.value); }, style: { width: 100 }, addonAfter: '元' });
}},
{ title: '照片', dataIndex: 'photos', width: 200, render: function(photos) {
if (!photos || photos.length === 0) return '-';
return React.createElement(Space, null, photos.slice(0, 5).map(function(url, idx) {
return React.createElement('img', {
key: idx,
src: url,
alt: '',
style: { width: 40, height: 40, objectFit: 'cover', borderRadius: 4, cursor: 'pointer' },
onClick: function() { setPhotoViewer({ visible: true, photos: photos, currentIndex: idx }); }
});
}));
}},
{ title: '附件', dataIndex: 'attachments', render: function(attachments) {
if (!attachments || attachments.length === 0) return '-';
return React.createElement(Space, { wrap: true }, attachments.map(function(att, idx) {
return React.createElement('a', { key: idx, onClick: function() { message.info('下载附件:' + att.name); } }, att.name);
}));
}}
],
summary: function() {
var totalPaid = mockReturnFeeData.list.reduce(function(s, item) { return s + parseFloat(item.paidAmount || 0); }, 0).toFixed(2);
return React.createElement(Table.Summary, null,
React.createElement(Table.Summary.Row, null,
React.createElement(Table.Summary.Cell, { index: 0 }, '总计'),
React.createElement(Table.Summary.Cell, { index: 1 }, mockReturnFeeData.totalAmount),
React.createElement(Table.Summary.Cell, { index: 2 }, totalPaid),
React.createElement(Table.Summary.Cell, { index: 3 }, ''),
React.createElement(Table.Summary.Cell, { index: 4 }, '')
)
);
}
})
),
React.createElement('div', { style: { marginTop: 24, textAlign: 'center' } },
React.createElement(Space, null,
detailMode === 'payment' && React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交审核'),
detailMode === 'payment' && React.createElement(Button, { onClick: handleSave }, '保存'),
detailMode === 'payment' && React.createElement(Button, { onClick: handleBackToList }, '取消'),
detailMode === 'view' && React.createElement(Button, { onClick: handleBackToList }, '返回')
)
),
// 照片查看器 Modal
React.createElement(Modal, {
title: '照片查看',
open: photoViewer.visible && photoViewer.photos.length > 0,
onCancel: function() { setPhotoViewer({ visible: false, photos: [], currentIndex: 0 }); },
footer: null,
width: '90vw',
centered: true
}, photoViewer.photos.length > 0 ? React.createElement('div', { style: { textAlign: 'center' } },
React.createElement('img', {
src: photoViewer.photos[photoViewer.currentIndex].replace('80/80', '600/600'),
alt: '',
style: { maxWidth: '100%', maxHeight: '70vh', objectFit: 'contain' }
}),
React.createElement('div', { style: { marginTop: 16 } },
React.createElement(Button, {
disabled: photoViewer.currentIndex <= 0,
onClick: function() { setPhotoViewer({ visible: true, photos: photoViewer.photos, currentIndex: photoViewer.currentIndex - 1 }); }
}, '上一张'),
React.createElement('span', { style: { margin: '0 16px' } }, (photoViewer.currentIndex + 1) + ' / ' + photoViewer.photos.length),
React.createElement(Button, {
disabled: photoViewer.currentIndex >= photoViewer.photos.length - 1,
onClick: function() { setPhotoViewer({ visible: true, photos: photoViewer.photos, currentIndex: photoViewer.currentIndex + 1 }); }
}, '下一张')
)
) : null),
// 服务费明细 Modal
popover.type === 'service' && React.createElement(Modal, {
title: '服务费明细',
open: true,
onCancel: function() { setPopover({ type: null, data: null }); },
footer: React.createElement(Button, { onClick: function() { setPopover({ type: null, data: null }); } }, '关闭')
}, React.createElement(Table, {
dataSource: popover.data,
rowKey: function(item, i) { return i; },
pagination: false,
columns: [
{ title: '服务项', dataIndex: 'name' },
{ title: '价格', dataIndex: 'price' },
{ title: '服务生效日期', dataIndex: 'effectiveDate' }
]
}))
);
}
// —————— 列表视图 ——————
var listBreadcrumbItems = [
{ title: '运维管理' },
{ title: '业务管理' },
{ title: '租赁账单' }
];
return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } },
React.createElement(Breadcrumb, { items: listBreadcrumbItems, style: { marginBottom: 16 } }),
React.createElement(Card, null,
React.createElement(Row, { gutter: [16, 16], style: { marginBottom: 16 }, align: 'middle' },
React.createElement(Col, null,
React.createElement('span', { style: { marginRight: 8 } }, '合同编码:'),
React.createElement(Select, {
placeholder: '请选择合同编码',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: contractFilter,
onChange: setContractFilter,
style: { width: 200 },
options: contractOptions
})
),
React.createElement(Col, null,
React.createElement('span', { style: { marginRight: 8 } }, '项目名称:'),
React.createElement(Select, {
placeholder: '请选择项目名称',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: projectFilter,
onChange: setProjectFilter,
style: { width: 200 },
options: projectOptions
})
),
React.createElement(Col, null,
React.createElement('span', { style: { marginRight: 8 } }, '客户名称:'),
React.createElement(Select, {
placeholder: '请选择客户名称',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: customerFilter,
onChange: setCustomerFilter,
style: { width: 200 },
options: customerOptions
})
),
React.createElement(Col, null,
React.createElement('span', { style: { marginRight: 8 } }, '付款状态:'),
React.createElement(Select, {
mode: 'multiple',
placeholder: '全部',
allowClear: true,
value: statusFilter,
onChange: setStatusFilter,
style: { width: 200 },
options: statusOptions,
maxTagCount: 'responsive'
})
),
React.createElement(Col, null,
React.createElement(Space, null,
React.createElement(Button, { type: 'primary', onClick: handleSearch }, '查询'),
React.createElement(Button, { onClick: handleReset }, '重置')
)
)
),
React.createElement('div', { style: { marginBottom: 16, display: 'flex', justifyContent: 'flex-end' } },
React.createElement(Button, { type: 'primary', onClick: handleExport }, '导出')
),
React.createElement(Table, {
rowSelection: rowSelection,
columns: listColumns,
dataSource: paginatedList,
rowKey: 'id',
pagination: tablePagination,
scroll: { x: 1600 },
size: 'middle'
})
),
// 应付金额明细 Modal列表按内容一行显示、宽度随内容调整
React.createElement(Modal, {
title: '应付金额明细',
open: popover.type === 'payable',
onCancel: function() { setPopover({ type: null, data: null }); },
footer: React.createElement(Button, { onClick: function() { setPopover({ type: null, data: null }); } }, '关闭'),
width: 'fit-content',
style: { maxWidth: '90vw' },
styles: { body: { paddingBottom: 24 } }
}, popover.type === 'payable' && popover.data ? React.createElement(Table, {
dataSource: popover.data,
rowKey: function(item, i) { return i; },
pagination: false,
tableLayout: 'auto',
style: { minWidth: 0 },
columns: [
{ title: '账单开始日期', dataIndex: 'startDate', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } },
{ title: '账单结束日期', dataIndex: 'endDate', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } },
{ title: '车牌号', dataIndex: 'plateNo', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } },
{ title: '车辆租金', dataIndex: 'rent', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } },
{ title: '服务费', dataIndex: 'serviceFee', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } },
{ title: '保证金', dataIndex: 'deposit', onCell: function() { return { style: { whiteSpace: 'nowrap' } }; } }
]
}) : null)
);
};
if (typeof window !== 'undefined') {
window.Component = Component;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
});
} else {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
}

View File

@@ -0,0 +1,283 @@
// 【重要】必须使用 const Component 作为组件变量名 - Axhub 产品原型
// 数字化资产ONEOS运管平台 - 编辑交车任务模块(布局同新增交车任务,项目名称禁用不可改)
const Component = function() {
var antd = window.antd;
var Input = antd.Input;
var Select = antd.Select;
var Button = antd.Button;
var DatePicker = antd.DatePicker;
var message = antd.message;
var Option = Select.Option;
var Checkbox = antd.Checkbox;
var Tooltip = antd.Tooltip;
var RangePicker = DatePicker.RangePicker;
var projectId = React.useState('p1');
var selectedProjectId = projectId[0];
var setSelectedProjectId = projectId[1];
var expectedDelivery = React.useState(null);
var expectedDeliveryValue = expectedDelivery[0];
var setExpectedDelivery = expectedDelivery[1];
var billingDate = React.useState(null);
var billingDateValue = billingDate[0];
var setBillingDate = billingDate[1];
var selectedRowKeys = React.useState(['v3', 'v4']);
var checkedRowKeys = selectedRowKeys[0];
var setCheckedRowKeys = selectedRowKeys[1];
var formErrors = React.useState({});
var errors = formErrors[0];
var setErrors = formErrors[1];
var reqSpecState = React.useState(false);
var reqSpecOpen = reqSpecState[0];
var setReqSpecOpen = reqSpecState[1];
// Mock项目列表及车辆样例。deliveryStatus: 'none' 可选,'submitted' 已提交交车任务不可选,'completed' 已完成交车不显示
var projectList = [
{ id: 'p1', name: '嘉兴某某物流氢能运输项目', contractCode: 'JXZL20260216YW101235A', customerName: '嘉兴某某物流有限公司', deliveryRegion: '浙江省 / 嘉兴市', deliveryLocation: '浙江省嘉兴市南湖区科技大道1号', vehicles: [
{ key: 'v1', brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A10001', vin: 'LFV2BJCH8K3123456', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '首车', deliveryStatus: 'submitted' },
{ key: 'v2', brand: '东风', model: '氢燃料电池重卡 H31', plateNo: '浙A10002', vin: 'LFV2BJCH8K3123457', monthRent: '12800', serviceFee: '800', deposit: '30000', remark: '', deliveryStatus: 'submitted' },
{ key: 'v3', brand: '福田', model: '智蓝氢能轻卡', plateNo: '', vin: 'LZYTBACR2M1234567', monthRent: '8500', serviceFee: '500', deposit: '20000', remark: '待上牌', deliveryStatus: 'none' },
{ key: 'v4', brand: '重汽', model: '豪沃氢能牵引车', plateNo: '浙F20001', vin: 'ZZ4257N386FZ12345', monthRent: '15000', serviceFee: '1000', deposit: '35000', remark: '', deliveryStatus: 'none' },
{ key: 'v5', brand: '陕汽', model: '德龙氢能自卸', plateNo: '浙F20002', vin: 'SX1313GR456123456', monthRent: '13200', serviceFee: '880', deposit: '32000', remark: '固定线路', deliveryStatus: 'none' }
]},
{ id: 'p2', name: '上海某某运输氢能租赁项目', contractCode: 'SHZL20260201YW200123A', customerName: '上海某某运输公司', deliveryRegion: '上海市 / 上海市', deliveryLocation: '上海市浦东新区张江高科技园区', vehicles: [
{ key: 'v6', brand: '上汽红岩', model: '杰狮氢能牵引', plateNo: '沪A30003', vin: 'SH1313HY789012345', monthRent: '14500', serviceFee: '950', deposit: '34000', remark: '', deliveryStatus: 'submitted' },
{ key: 'v7', brand: '宇通', model: '氢能公交 ZK6126', plateNo: '沪B40001', vin: 'LZYTAGCF8K4567890', monthRent: '22000', serviceFee: '1200', deposit: '50000', remark: '示范线路', deliveryStatus: 'none' },
{ key: 'v8', brand: '福田', model: '欧辉氢能大巴', plateNo: '', vin: 'LZYTBACR2M2345678', monthRent: '19800', serviceFee: '1100', deposit: '45000', remark: '', deliveryStatus: 'none' }
]},
{ id: 'p3', name: '杭州某某租赁氢能项目', contractCode: 'HZZL20260115YW100089A', customerName: '杭州某某租赁有限公司', deliveryRegion: '浙江省 / 杭州市', deliveryLocation: '浙江省杭州市余杭区未来科技城', vehicles: [
{ key: 'v9', brand: '品牌C', model: '型号C1', plateNo: '浙A40004', vin: 'L4234567890ABCDEF', monthRent: '8200', serviceFee: '450', deposit: '20000', remark: '重点客户', deliveryStatus: 'completed' },
{ key: 'v10', brand: '品牌C', model: '型号C2', plateNo: '', vin: 'L5234567890ABCDEF', monthRent: '7800', serviceFee: '420', deposit: '19000', remark: '', deliveryStatus: 'submitted' },
{ key: 'v11', brand: '东风', model: '氢燃料电池厢货', plateNo: '浙A50001', vin: 'LFV2BJCH8K5678901', monthRent: '9200', serviceFee: '520', deposit: '22000', remark: '城配', deliveryStatus: 'none' },
{ key: 'v12', brand: '开沃', model: '创源氢能轻卡', plateNo: '浙A50002', vin: 'LJXTBACR9N6789012', monthRent: '8800', serviceFee: '480', deposit: '21000', remark: '', deliveryStatus: 'none' }
]}
];
var selectedProject = projectList.find(function(p) { return p.id === selectedProjectId; });
var vehicleListRaw = selectedProject ? selectedProject.vehicles : [];
var vehicleList = vehicleListRaw.filter(function(v) { return v.deliveryStatus !== 'completed'; });
var selectableVehicles = vehicleList.filter(function(v) { return v.deliveryStatus !== 'submitted'; });
var handleProjectChange = function(id) {
setSelectedProjectId(id || '');
setCheckedRowKeys([]);
};
var todayStr = (function() {
var d = new Date();
return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
})();
var validateExpectedDelivery = function() {
if (!expectedDeliveryValue || !expectedDeliveryValue.length) return '请选择预计交车日期';
var start = expectedDeliveryValue[0] && expectedDeliveryValue[0].format ? expectedDeliveryValue[0].format('YYYY-MM-DD') : null;
var end = expectedDeliveryValue[1] && expectedDeliveryValue[1].format ? expectedDeliveryValue[1].format('YYYY-MM-DD') : null;
if (!start) return '请选择预计交车日期';
if (end && end < start) return '结束日期不能早于开始日期';
if (end && end < todayStr) return '结束日期不能早于当前日期';
return null;
};
var expectedDeliveryError = validateExpectedDelivery();
var billingDateError = !billingDateValue ? '请选择开始计费日期' : null;
var handleSubmit = function() {
var err = {};
if (!selectedProjectId) err.projectName = '请选择项目名称';
if (expectedDeliveryError) err.expectedDelivery = expectedDeliveryError;
if (billingDateError) err.billingDate = billingDateError;
if (checkedRowKeys.length === 0 && selectableVehicles.length > 0) err.vehicles = '请至少选择一辆车';
setErrors(err);
if (Object.keys(err).length) return;
message.success('交车任务已保存。');
};
var handleCancel = function() {
message.info('取消');
};
var onSelectAll = function(checked) {
if (checked) setCheckedRowKeys(selectableVehicles.map(function(v) { return v.key; }));
else setCheckedRowKeys([]);
};
var onSelectRow = function(record, checked) {
if (checked) setCheckedRowKeys(function(prev) { return prev.indexOf(record.key) === -1 ? prev.concat(record.key) : prev; });
else setCheckedRowKeys(function(prev) { return prev.filter(function(k) { return k !== record.key; }); });
};
var styles = {
page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0' },
cardTitle: { fontSize: 16, fontWeight: 600, color: '#333' },
cardBody: { padding: '20px 24px' },
formRow: { display: 'flex', flexWrap: 'wrap', marginBottom: 16 },
formCol: { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8 },
label: { display: 'block', marginBottom: 6, color: '#333' },
labelRequired: { color: '#ff4d4f', marginRight: 4 },
errMsg: { color: '#ff4d4f', fontSize: 12, marginTop: 4 },
footer: { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, justifyContent: 'flex-start', zIndex: 99 },
tableWrap: { marginTop: 16, overflowX: 'auto' },
table: { width: '100%', borderCollapse: 'collapse', fontSize: 13 },
th: { padding: '10px 8px', textAlign: 'left', borderBottom: '1px solid #e8e8e8', backgroundColor: '#fafafa', fontWeight: 600 },
td: { padding: '8px', borderBottom: '1px solid #f0f0f0', verticalAlign: 'middle' },
inputDisabled: { width: '100%', padding: '6px 10px', border: '1px solid #d9d9d9', borderRadius: 4, backgroundColor: '#f5f5f5', color: '#666', fontSize: 13 },
modalMask: { position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.45)', zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center' },
modalBox: { backgroundColor: '#fff', borderRadius: 8, width: '90%', maxWidth: 640, maxHeight: '85vh', overflow: 'hidden', display: 'flex', flexDirection: 'column', boxShadow: '0 4px 20px rgba(0,0,0,0.15)' },
modalHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0', fontSize: 16, fontWeight: 600 },
modalBody: { padding: 20, overflow: 'auto', flex: 1 }
};
var reqSpecBlock = { marginBottom: 16 };
var reqSpecH2 = { fontSize: 14, fontWeight: 600, color: '#333', marginBottom: 6 };
var reqSpecLi = { fontSize: 13, color: '#666', marginBottom: 2, paddingLeft: 8 };
var reqSpecDoc = React.createElement('div', { style: { padding: '0 4px' } },
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '交车任务')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '1.面包屑:'), React.createElement('div', { style: reqSpecLi }, '1.1.业务管理-交车任务-编辑交车任务')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '2.表单:'),
React.createElement('div', { style: reqSpecLi }, '2.1.选择项目名称:已选择禁用,不可修改;'),
React.createElement('div', { style: reqSpecLi }, '2.2.合同编码、客户名称、交车区域、交车地点、预计交车日期、开始计费日期、车辆列表等可修改;'),
React.createElement('div', { style: reqSpecLi }, '预计交车日期:不能早于当前日期'),
React.createElement('div', { style: reqSpecLi }, '2.9.页面底部为提交、取消;')
));
var reqSpecModalContent = reqSpecOpen ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) setReqSpecOpen(false); } }, React.createElement('div', { style: styles.modalBox, onClick: function(e) { e.stopPropagation(); } }, React.createElement('div', { style: styles.modalHeader }, '需求说明'), React.createElement('div', { style: Object.assign({}, styles.modalBody, { maxHeight: '70vh', padding: '20px 24px' }) }, reqSpecDoc), React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right' } }, React.createElement(Button, { onClick: function() { setReqSpecOpen(false); } }, '关闭')))) : null;
var FormItem = function(props) {
return React.createElement('div', { style: styles.formCol },
React.createElement('label', { style: styles.label }, props.required ? React.createElement('span', { style: styles.labelRequired }, '*') : null, props.label),
props.children,
props.error ? React.createElement('div', { style: styles.errMsg }, props.error) : null
);
};
var projectOptions = projectList.map(function(p) { return React.createElement(Option, { key: p.id, value: p.id }, p.name); });
var formRow1 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '选择项目名称', required: true, error: errors.projectName },
React.createElement(Select, {
placeholder: '请选择或输入项目名称',
style: { width: '100%' },
value: selectedProjectId || undefined,
disabled: true,
showSearch: true,
filterOption: function(input, opt) { return opt.children && String(opt.children).toLowerCase().indexOf((input || '').toLowerCase()) >= 0; },
status: errors.projectName ? 'error' : undefined
}, projectOptions)),
React.createElement(FormItem, { label: '合同编码' }, React.createElement(Input, { value: selectedProject ? selectedProject.contractCode : '', disabled: true, style: { width: '100%' } })),
React.createElement(FormItem, { label: '客户名称' }, React.createElement(Input, { value: selectedProject ? selectedProject.customerName : '', disabled: true, style: { width: '100%' } })),
React.createElement(FormItem, { label: '交车区域' }, React.createElement(Input, { value: selectedProject ? selectedProject.deliveryRegion : '', disabled: true, style: { width: '100%' } })),
React.createElement(FormItem, { label: '交车地点' }, React.createElement(Input, { value: selectedProject ? selectedProject.deliveryLocation : '', disabled: true, style: { width: '100%' } }))
);
var formRow2 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '预计交车日期', required: true, error: errors.expectedDelivery },
React.createElement(RangePicker, {
style: { width: '100%' },
format: 'YYYY-MM-DD',
placeholder: ['请选择开始日期', '请选择结束日期(单日请选同一天)'],
value: expectedDeliveryValue,
onChange: function(dates) { setExpectedDelivery(dates && dates.length === 2 ? dates : null); },
status: errors.expectedDelivery ? 'error' : undefined
})),
React.createElement(FormItem, { label: '开始计费日期', required: true, error: errors.billingDate },
React.createElement(DatePicker, {
style: { width: '100%' },
format: 'YYYY-MM-DD',
placeholder: '请选择日期',
value: billingDateValue,
onChange: function(d, dateStr) { setBillingDate(d); },
status: errors.billingDate ? 'error' : undefined
}))
);
var allSelectableChecked = selectableVehicles.length > 0 && selectableVehicles.every(function(v) { return checkedRowKeys.indexOf(v.key) !== -1; });
var someSelectableChecked = selectableVehicles.some(function(v) { return checkedRowKeys.indexOf(v.key) !== -1; });
var tableHeader = React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: Object.assign({}, styles.th, { width: 48 }) },
React.createElement(Checkbox, {
checked: allSelectableChecked,
indeterminate: someSelectableChecked && !allSelectableChecked,
onChange: function(e) { onSelectAll(e.target.checked); }
})),
React.createElement('th', { style: styles.th }, '品牌'),
React.createElement('th', { style: styles.th }, '型号'),
React.createElement('th', { style: styles.th }, '车牌号'),
React.createElement('th', { style: styles.th }, '车辆识别代码'),
React.createElement('th', { style: styles.th }, '车辆月租金'),
React.createElement('th', { style: styles.th }, '服务费'),
React.createElement('th', { style: styles.th }, '保证金'),
React.createElement('th', { style: styles.th }, '备注')
)
);
var tableBody = React.createElement('tbody', null,
vehicleList.length === 0
? React.createElement('tr', null, React.createElement('td', { colSpan: 9, style: Object.assign({}, styles.td, { textAlign: 'center', color: '#999' }) }, '该合同下暂无车辆信息'))
: vehicleList.map(function(row) {
var isSubmitted = row.deliveryStatus === 'submitted';
return React.createElement('tr', { key: row.key },
React.createElement('td', { style: styles.td },
isSubmitted
? React.createElement(Tooltip, { title: '该车辆已有交车任务' },
React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 6, cursor: 'not-allowed' } },
React.createElement(Checkbox, { disabled: true, checked: false }),
React.createElement('span', { style: { color: '#999', fontSize: 12 } }, '已提交')))
: React.createElement(Checkbox, { checked: checkedRowKeys.indexOf(row.key) !== -1, onChange: function(e) { onSelectRow(row, e.target.checked); } })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.brand, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.model, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.plateNo || '-', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.vin, disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.monthRent + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.serviceFee + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.deposit + '元', disabled: true, style: styles.inputDisabled })),
React.createElement('td', { style: styles.td }, React.createElement(Input, { value: row.remark || '-', disabled: true, style: styles.inputDisabled }))
);
})
);
var tableEl = React.createElement('div', { style: styles.tableWrap },
React.createElement('table', { style: styles.table }, tableHeader, tableBody)
);
if (errors.vehicles) {
tableEl = React.createElement('div', null,
React.createElement('div', { style: Object.assign({}, styles.errMsg, { marginBottom: 8 }) }, errors.vehicles),
tableEl
);
}
return React.createElement('div', { style: styles.page },
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } },
React.createElement('div', { style: styles.breadcrumb },
React.createElement('span', null, '业务管理'),
React.createElement('span', { style: styles.breadcrumbSep }, ' / '),
React.createElement('span', null, '交车任务'),
React.createElement('span', { style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { style: { color: '#1890ff' } }, '编辑交车任务')),
React.createElement('span', { style: { color: '#1890ff', cursor: 'pointer', fontSize: 14 }, onClick: function() { setReqSpecOpen(true); } }, '查看需求说明')),
React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader }, React.createElement('span', { style: styles.cardTitle }, '交车任务')),
React.createElement('div', { style: styles.cardBody },
formRow1,
formRow2,
tableEl)),
React.createElement('div', { style: { height: 60 } }),
reqSpecModalContent,
React.createElement('div', { style: styles.footer },
React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交'),
React.createElement(Button, { onClick: handleCancel }, '取消'))
);
};

446
web端/登录.jsx Normal file
View File

@@ -0,0 +1,446 @@
// 【重要】必须使用 const Component 作为组件变量名
// 参考 Arco Design Pro 登录页布局:左侧品牌区 + 右侧登录表单
const Component = function () {
var antd = window.antd;
var useState = React.useState;
var useRef = React.useRef;
var useEffect = React.useEffect;
var _state = useState({ username: '', password: '', remember: true, agreeTerms: false, phone: '', smsCode: '' });
var formData = _state[0];
var setFormData = _state[1];
var _mode = useState('account');
var loginMode = _mode[0];
var setLoginMode = _mode[1];
var _countdown = useState(0);
var countdown = _countdown[0];
var setCountdown = _countdown[1];
var _hasRequestedCode = useState(false);
var hasRequestedCode = _hasRequestedCode[0];
var setHasRequestedCode = _hasRequestedCode[1];
var timerRef = useRef(null);
useEffect(function () {
return function () {
if (timerRef.current) {
clearInterval(timerRef.current);
}
};
}, []);
var handleChange = function (field, value) {
var next = {};
next[field] = value;
setFormData(function (prev) {
return Object.assign({}, prev, next);
});
};
var handleGetCode = function () {
if (countdown > 0) return;
setHasRequestedCode(true);
setCountdown(60);
timerRef.current = setInterval(function () {
setCountdown(function (prev) {
if (prev <= 1) {
clearInterval(timerRef.current);
timerRef.current = null;
return 0;
}
return prev - 1;
});
}, 1000);
};
var handleSubmit = function () {
if (!formData.agreeTerms) {
antd.message.warning('请阅读并同意《用户服务协议》和《隐私政策》');
return;
}
if (loginMode === 'phone') {
if (!formData.phone) {
antd.message.warning('请输入手机号');
return;
}
if (!formData.smsCode) {
antd.message.warning('请输入验证码');
return;
}
} else {
if (!formData.username) {
antd.message.warning('请输入用户名');
return;
}
if (!formData.password) {
antd.message.warning('请输入密码');
return;
}
}
antd.message.success('登录成功(原型演示)');
if (window.$axure && typeof window.$axure.navigateToUrl === 'function') {
window.$axure.navigateToUrl('工作台');
} else {
window.location.hash = '工作台';
}
};
var switchToPhone = function (e) {
if (e && e.preventDefault) e.preventDefault();
setLoginMode('phone');
};
var switchToAccount = function (e) {
if (e && e.preventDefault) e.preventDefault();
setLoginMode('account');
};
var styles = {
wrap: {
display: 'flex',
minHeight: '100vh',
width: '100%',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
backgroundColor: '#f5f5f5'
},
left: {
flex: '1',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
padding: '48px',
background: 'linear-gradient(135deg, #1d2129 0%, #2d3748 50%, #1d2129 100%)',
color: '#fff'
},
leftContent: {
maxWidth: '400px',
textAlign: 'center'
},
title: {
fontSize: '28px',
fontWeight: '600',
marginBottom: '16px',
letterSpacing: '0.5px'
},
desc: {
fontSize: '14px',
opacity: 0.85,
lineHeight: 1.6
},
right: {
width: '480px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
padding: '48px',
backgroundColor: '#fff',
boxShadow: '-4px 0 24px rgba(0,0,0,0.06)'
},
formCard: {
width: '100%',
maxWidth: '360px'
},
formTitle: {
fontSize: '24px',
fontWeight: '600',
color: '#1d2129',
marginBottom: '8px',
textAlign: 'center'
},
formSub: {
fontSize: '14px',
color: '#86909c',
marginBottom: '32px',
textAlign: 'center'
},
formItem: {
marginBottom: '20px'
},
label: {
display: 'block',
fontSize: '14px',
color: '#4e5969',
marginBottom: '8px'
},
input: {
width: '100%',
height: '40px',
padding: '8px 12px',
fontSize: '14px',
border: '1px solid #e5e6eb',
borderRadius: '6px',
boxSizing: 'border-box',
outline: 'none'
},
codeRow: {
display: 'flex',
gap: '8px',
alignItems: 'center'
},
codeInput: {
flex: '1',
height: '40px',
padding: '8px 12px',
fontSize: '14px',
border: '1px solid #e5e6eb',
borderRadius: '6px',
boxSizing: 'border-box',
outline: 'none'
},
getCodeBtn: {
flexShrink: 0,
height: '40px',
padding: '0 16px',
fontSize: '14px',
color: '#165dff',
backgroundColor: '#fff',
border: '1px solid #165dff',
borderRadius: '6px',
cursor: 'pointer'
},
getCodeBtnDisabled: {
color: '#86909c',
borderColor: '#e5e6eb',
cursor: 'not-allowed'
},
row: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '24px'
},
submitBtn: {
width: '100%',
height: '44px',
fontSize: '16px',
fontWeight: '500',
borderRadius: '6px'
},
tabBar: {
display: 'flex',
marginBottom: '24px',
borderBottom: '1px solid #e5e6eb'
},
tab: {
flex: 1,
textAlign: 'center',
padding: '12px 0',
fontSize: '15px',
color: '#86909c',
cursor: 'pointer',
borderBottom: '2px solid transparent',
marginBottom: '-1px'
},
tabActive: {
color: '#165dff',
fontWeight: '500',
borderBottomColor: '#165dff'
}
};
return React.createElement(
React.Fragment,
null,
React.createElement('style', {
dangerouslySetInnerHTML: {
__html: '@media (max-width: 768px) { .login-right { width: 100% !important; min-width: 100% !important; } .login-left { min-height: 200px !important; } .login-wrap { flex-direction: column !important; } }'
}
}),
React.createElement(
'div',
{ style: styles.wrap, className: 'login-wrap' },
React.createElement(
'div',
{ style: styles.left, className: 'login-left' },
React.createElement(
'div',
{ style: styles.leftContent },
React.createElement('h1', { style: styles.title }, '羚牛氢能'),
React.createElement('p', { style: styles.desc }, '数字化资产ONE-OS运管平台')
)
),
React.createElement(
'div',
{ style: styles.right, className: 'login-right' },
React.createElement(
'div',
{ style: styles.formCard },
React.createElement('h2', { style: styles.formTitle }, '欢迎登录'),
React.createElement(
'div',
{ style: styles.tabBar },
React.createElement(
'div',
{
style: loginMode === 'account' ? Object.assign({}, styles.tab, styles.tabActive) : styles.tab,
onClick: switchToAccount,
role: 'button',
tabIndex: 0
},
'账号密码登录'
),
React.createElement(
'div',
{
style: loginMode === 'phone' ? Object.assign({}, styles.tab, styles.tabActive) : styles.tab,
onClick: switchToPhone,
role: 'button',
tabIndex: 0
},
'手机号登录'
)
),
React.createElement('p', { style: styles.formSub }, loginMode === 'phone' ? '请输入手机号与验证码' : '请输入您的账号与密码'),
loginMode === 'phone'
? React.createElement(
React.Fragment,
null,
React.createElement(
'div',
{ style: styles.formItem },
React.createElement('label', { style: styles.label }, '手机号'),
React.createElement('input', {
style: styles.input,
placeholder: '请输入手机号',
value: formData.phone,
onChange: function (e) {
handleChange('phone', e.target.value);
}
})
),
React.createElement(
'div',
{ style: styles.formItem },
React.createElement('label', { style: styles.label }, '验证码'),
React.createElement(
'div',
{ style: styles.codeRow },
React.createElement('input', {
style: styles.codeInput,
placeholder: '请输入验证码',
value: formData.smsCode,
onChange: function (e) {
handleChange('smsCode', e.target.value);
}
}),
React.createElement(
'button',
{
type: 'button',
style: countdown > 0 ? Object.assign({}, styles.getCodeBtn, styles.getCodeBtnDisabled) : styles.getCodeBtn,
disabled: countdown > 0,
onClick: handleGetCode
},
countdown > 0 ? countdown + '秒后重新获取' : (hasRequestedCode ? '再次获取' : '获取验证码')
)
)
)
)
: React.createElement(
React.Fragment,
null,
React.createElement(
'div',
{ style: styles.formItem },
React.createElement('label', { style: styles.label }, '用户名'),
React.createElement('input', {
style: styles.input,
placeholder: '请输入用户名',
value: formData.username,
onChange: function (e) {
handleChange('username', e.target.value);
}
})
),
React.createElement(
'div',
{ style: styles.formItem },
React.createElement('label', { style: styles.label }, '密码'),
React.createElement('input', {
style: styles.input,
type: 'password',
placeholder: '请输入密码',
value: formData.password,
onChange: function (e) {
handleChange('password', e.target.value);
}
})
)
),
React.createElement(
'div',
{ style: styles.row },
React.createElement(
'label',
{ style: { display: 'flex', alignItems: 'center', cursor: 'pointer', fontSize: '14px', color: '#4e5969' } },
React.createElement('input', {
type: 'checkbox',
checked: formData.remember,
onChange: function (e) {
handleChange('remember', e.target.checked);
},
style: { marginRight: '8px' }
}),
'记住我'
)
),
React.createElement(
'label',
{
style: {
display: 'flex',
alignItems: 'flex-start',
cursor: 'pointer',
fontSize: '14px',
color: '#4e5969',
marginBottom: '20px',
lineHeight: 1.5
}
},
React.createElement('input', {
type: 'checkbox',
checked: formData.agreeTerms,
onChange: function (e) {
handleChange('agreeTerms', e.target.checked);
},
style: { marginRight: '8px', marginTop: '3px', flexShrink: 0 }
}),
React.createElement(
'span',
null,
'阅读并同意',
React.createElement('a', { href: '#', style: { color: '#165dff', marginLeft: '2px' }, onClick: function (e) { e.preventDefault(); } }, '《用户服务协议》'),
'和',
React.createElement('a', { href: '#', style: { color: '#165dff' }, onClick: function (e) { e.preventDefault(); } }, '《隐私政策》')
)
),
antd && antd.Button
? React.createElement(antd.Button, {
type: 'primary',
block: true,
size: 'large',
style: styles.submitBtn,
onClick: handleSubmit
}, '登 录')
: React.createElement(
'button',
{
style: Object.assign({}, styles.submitBtn, {
backgroundColor: '#165dff',
color: '#fff',
border: 'none',
cursor: 'pointer'
}),
onClick: handleSubmit
},
'登 录'
)
)
)
)
);
};

File diff suppressed because it is too large Load Diff

BIN
web端/车辆租赁合同/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,448 @@
// 【重要】必须使用 const Component 作为组件变量名
// 业务管理 - 车辆租赁合同 - 新增车辆(与查看合同页布局一致,仅新增车辆信息卡片可编辑)
const Component = function() {
var useState = React.useState;
var useCallback = React.useCallback;
var antd = window.antd;
var Select = antd.Select;
var Input = antd.Input;
var Button = antd.Button;
var Table = antd.Table;
var DatePicker = antd.DatePicker;
var message = antd.message;
var Option = Select.Option;
var cc1State = React.useState(false);
var cc1 = cc1State[0];
var setCc1 = cc1State[1];
var cc2State = React.useState(false);
var cc2 = cc2State[0];
var setCc2 = cc2State[1];
var cc3State = React.useState(false);
var cc3 = cc3State[0];
var setCc3 = cc3State[1];
var cc4State = React.useState(false);
var cc4 = cc4State[0];
var setCc4 = cc4State[1];
var cc5State = React.useState(false);
var cc5 = cc5State[0];
var setCc5 = cc5State[1];
var cc6State = React.useState(false);
var cc6 = cc6State[0];
var setCc6 = cc6State[1];
var cc7State = React.useState(false);
var cc7 = cc7State[0];
var setCc7 = cc7State[1];
var emptyNewRow = { brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' };
var _newVehicleRows = useState([Object.assign({}, emptyNewRow)]);
var newVehicleRows = _newVehicleRows[0];
var setNewVehicleRows = _newVehicleRows[1];
var _serviceModalRowIndex = useState(null);
var serviceModalRowIndex = _serviceModalRowIndex[0];
var setServiceModalRowIndex = _serviceModalRowIndex[1];
var brandList = ['品牌A', '品牌B', '品牌C', '品牌D'];
var serviceItemOptions = ['代处理费用', '罚款', '违章处理违约金', '未参加安全培训', '车辆出险', '年检年审违约', '停车费', '设备损坏金(包含易损件)', '清洗费', '上门收车人工费', '上门收车送车行驶费', '上门收车基础服务费', '保险上浮', '保养费用', '补办驾驶证', '补办牌照', '补办营运证', '补办加氢证', '借用备用钥匙', '补配钥匙', '租金', '氢气费-客', '退还车氢量差', '能源费补缴', '能源费退款', '送车上门人工费', '送车上门送车行驶费', '送车上门基础服务费', '保证金', '氢气预付费', '维修费用', 'ETC-客', 'ETC卡缺损费', 'ETC设备缺损费', '电费-客', '未结算保养费', '未结算维修费', '车损费', '工具损坏或丢失费', '证件费', '广告损坏费', '送车服务费', '接车服务费', '补办行驶证', '超赔险', '轮胎磨损费', '无忧包', '轮胎保', '养护保', '尾板'];
var modelByBrand = { '品牌A': ['型号A1', '型号A2', '型号A3'], '品牌B': ['型号B1', '型号B2'], '品牌C': ['型号C1', '型号C2'], '品牌D': ['型号D1'] };
var plateNoOptions = ['浙A10001', '浙A10002', '浙B20001', '浙B20002', '浙C30001', '浙C30002', '沪D40001', '沪D40002', '苏E50001', '苏E50002', '京F60001', '京F60002'].map(function(p) { return { value: p, label: p }; });
var addNewVehicleRow = useCallback(function() {
setNewVehicleRows(function(prev) { return prev.concat([{ brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }]); });
}, []);
var removeNewVehicleRow = useCallback(function(index) {
setNewVehicleRows(function(prev) {
var next = prev.slice();
next.splice(index, 1);
if (next.length === 0) next = [{ brand: '', model: '', plateNo: '', vin: '', monthRent: '', serviceItems: [{ project: '', fee: '', effectiveDate: '' }], deposit: '', remark: '' }];
return next;
});
}, []);
var updateNewVehicleRow = useCallback(function(index, field, value) {
setNewVehicleRows(function(prev) {
var next = prev.slice();
var row = next[index] || emptyNewRow;
var o = {};
o[field] = value;
if (field === 'brand') o.model = '';
if (field === 'plateNo') o.vin = value;
next[index] = Object.assign({}, row, o);
return next;
});
}, []);
var calcRowServiceFee = function(row) {
var sum = 0;
for (var i = 0; i < (row.serviceItems || []).length; i++) {
var fee = parseFloat(row.serviceItems[i].fee);
if (!isNaN(fee)) sum += fee;
}
return sum.toFixed(2);
};
var openServiceModal = function(index) { setServiceModalRowIndex(index); };
var closeServiceModal = function() { setServiceModalRowIndex(null); };
var addServiceItem = function() {
if (serviceModalRowIndex === null) return;
var next = newVehicleRows.slice();
var row = next[serviceModalRowIndex];
var items = (row.serviceItems || []).concat([{ project: '', fee: '', effectiveDate: '' }]);
var newRow = {};
for (var k in row) { if (row.hasOwnProperty(k) && k !== 'serviceItems') newRow[k] = row[k]; }
newRow.serviceItems = items;
next[serviceModalRowIndex] = newRow;
setNewVehicleRows(next);
};
var removeServiceItem = function(siIndex) {
if (serviceModalRowIndex === null) return;
var next = newVehicleRows.slice();
var row = next[serviceModalRowIndex];
var items = (row.serviceItems || []).slice();
items.splice(siIndex, 1);
if (items.length === 0) items = [{ project: '', fee: '', effectiveDate: '' }];
var newRow = {};
for (var k in row) { if (row.hasOwnProperty(k) && k !== 'serviceItems') newRow[k] = row[k]; }
newRow.serviceItems = items;
next[serviceModalRowIndex] = newRow;
setNewVehicleRows(next);
};
var updateServiceItem = function(siIndex, field, value) {
if (serviceModalRowIndex === null) return;
var next = newVehicleRows.slice();
var row = next[serviceModalRowIndex];
var items = (row.serviceItems || []).slice();
var item = items[siIndex] || {};
var newItem = {};
for (var k in item) { if (item.hasOwnProperty(k)) newItem[k] = item[k]; }
newItem[field] = value;
items[siIndex] = newItem;
var newRow = {};
for (var rk in row) { if (row.hasOwnProperty(rk) && rk !== 'serviceItems') newRow[rk] = row[rk]; }
newRow.serviceItems = items;
next[serviceModalRowIndex] = newRow;
setNewVehicleRows(next);
};
var newOrderSummary = (function() {
var count = newVehicleRows.length;
var rentService = 0;
var depositTotal = 0;
for (var i = 0; i < newVehicleRows.length; i++) {
rentService += parseFloat(newVehicleRows[i].monthRent) || 0;
rentService += parseFloat(calcRowServiceFee(newVehicleRows[i])) || 0;
depositTotal += parseFloat(newVehicleRows[i].deposit) || 0;
}
return { vehicleCount: count, totalRentService: rentService.toFixed(2), totalDeposit: depositTotal.toFixed(2) };
})();
var scrollToCard = function(id) {
var el = document.getElementById(id);
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
var styles = {
page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
anchorWrap: { position: 'fixed', top: 80, right: 24, zIndex: 100, backgroundColor: '#fff', borderRadius: 8, boxShadow: '0 2px 8px rgba(0,0,0,0.12)', padding: '12px 16px', minWidth: 160 },
anchorItem: { display: 'block', padding: '6px 0', color: '#1890ff', cursor: 'pointer', border: 'none', background: 'none', width: '100%', textAlign: 'left', fontSize: 13 },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardHeader: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 20px', borderBottom: '1px solid #f0f0f0', cursor: 'pointer' },
cardTitle: { fontSize: 16, fontWeight: 600, color: '#333' },
cardToggle: { color: '#999', fontSize: 14 },
cardBody: { padding: '20px 24px' },
formRow: { display: 'flex', flexWrap: 'wrap', marginBottom: 16 },
formCol: { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8 },
formColFull: { flex: '0 0 100%', marginBottom: 8 },
label: { display: 'block', marginBottom: 6, color: '#333' },
input: { width: '100%', padding: '8px 12px', border: '1px solid #d9d9d9', borderRadius: 4, fontSize: 14 },
inputDisabled: { backgroundColor: '#f5f5f5', color: '#666', cursor: 'default', borderColor: '#e8e8e8' },
summaryList: { marginBottom: 16, display: 'flex', flexWrap: 'wrap', gap: 16 },
summaryListItem: { flex: '0 0 calc(50% - 8px)', display: 'flex', alignItems: 'center', padding: '12px 16px', border: '1px solid #e8e8e8', borderRadius: 4, backgroundColor: '#fafafa', fontSize: 14, boxSizing: 'border-box' },
summaryListLabel: { flex: '0 0 140px', color: '#666' },
summaryListValue: { flex: 1, fontWeight: 600, color: '#333' },
rentalTable: { width: '100%', borderCollapse: 'collapse', fontSize: 13 },
rentalTh: { padding: '10px 8px', textAlign: 'left', borderBottom: '1px solid #e8e8e8', backgroundColor: '#fafafa', fontWeight: 600 },
rentalTd: { padding: '8px', borderBottom: '1px solid #f0f0f0', verticalAlign: 'middle' },
rentalInputDisabled: { backgroundColor: '#f5f5f5', color: '#666', border: '1px solid #e8e8e8', padding: '6px 10px', borderRadius: 4, width: '100%', fontSize: 13 },
footer: { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, justifyContent: 'flex-start', zIndex: 99 },
btn: { padding: '8px 24px', borderRadius: 4, border: '1px solid #d9d9d9', cursor: 'pointer', fontSize: 14 },
btnDefault: { backgroundColor: '#fff', color: '#333' },
btnPrimary: { backgroundColor: '#1890ff', color: '#fff', borderColor: '#1890ff' },
feeSectionTitle: { fontSize: 15, fontWeight: 600, color: '#333', marginTop: 20, marginBottom: 10 },
feeSectionTitleFirst: { marginTop: 0 },
sectionTitle: { fontSize: 15, fontWeight: 600, color: '#333', marginBottom: 12 },
modalMask: { position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.45)', zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center' },
modalBox: { backgroundColor: '#fff', borderRadius: 8, width: '90%', maxWidth: 720, maxHeight: '85vh', overflow: 'hidden', display: 'flex', flexDirection: 'column', boxShadow: '0 4px 20px rgba(0,0,0,0.15)' },
modalHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0', fontSize: 16, fontWeight: 600 },
modalBody: { padding: 20, overflow: 'auto', flex: 1 },
rentalTdCenter: { padding: '8px', borderBottom: '1px solid #f0f0f0', verticalAlign: 'middle' }
};
var CardBlock = function(props) {
return React.createElement('div', { id: props.id, style: styles.card },
React.createElement('div', { style: styles.cardHeader, onClick: function() { props.setCollapsed(!props.collapsed); } },
React.createElement('span', { style: styles.cardTitle }, props.title),
React.createElement('span', { style: styles.cardToggle }, props.collapsed ? '展开' : '收起')
),
!props.collapsed ? React.createElement('div', { style: styles.cardBody }, props.children) : null
);
};
var FormItemReadOnly = function(props) {
var colStyle = props.fullWidth ? styles.formColFull : styles.formCol;
return React.createElement('div', { style: colStyle },
React.createElement('label', { style: styles.label }, props.label),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled) }, props.value || '—')
);
};
var mockCustomer = { name: '嘉兴某某物流有限公司', creditCode: '91330400MA2XXXXX1', address: '浙江省嘉兴市南湖区科技大道1号', contact: '张三', phone: '13800138001', email: 'zhangsan@example.com', companyName: '嘉兴某某物流有限公司', companyPhone: '0571-88888888', mailingAddress: '浙江省嘉兴市南湖区科技大道1号', bank: '中国工商银行嘉兴分行', bankAccount: '6222021234567890123', taxId: '91330400MA2XXXXX1' };
var contractOriginal = { name: '租赁合同-原件.pdf', size: '1.2 MB', uploadTime: '2026-02-16 14:30' };
var mockContract = { projectName: '嘉兴氢能运输项目', contractCode: 'JXZL20260216YW101235A', contractType: '正式合同', effectiveDate: '2026-02-16', paymentMethod: '预付', mainVehicleModels: '型号A1、型号A2', endDate: '2027-02-16', paymentPeriod: '1个月', signingCompany: '嘉兴羚牛', deliveryRegion: '浙江省 / 嘉兴市', deliveryLocation: '嘉兴市南湖区科技大道1号', remarks: '' };
var mockAuthorized = [{ name: '张三', phone: '13800138001', idCard: '330102199001011234' }];
var mockRentalOrders = [{ brand: '品牌A', model: '型号A1', plateNo: '浙A10001', vin: 'L1234567890ABCDEF', monthRent: '8000', serviceFee: '500', deposit: '10000', remark: '' }, { brand: '品牌A', model: '型号A2', plateNo: '浙B20002', vin: 'L2234567890ABCDEF', monthRent: '8000', serviceFee: '500', deposit: '10000', remark: '' }];
var mockRentalSummary = { vehicleCount: 2, totalRentService: '17000.00', totalDeposit: '20000.00', hydrogenPrepay: '5000.00' };
var mockHydrogen = { bearer: '客户', paymentMethod: '预付', hydrogenPrepay: '5000', returnPrice: '80' };
var mockFeeTemplate = '标准费用模板A';
var mockBillingMethod = '按自然月结算';
var feeTemplateCertFees = [{ project: '补办行驶证', standard: '50元/次', serviceFee: '20' }, { project: '补办驾驶证', standard: '30元/次', serviceFee: '10' }, { project: '补办牌照', standard: '100元/次', serviceFee: '50' }];
var feeTemplatePenaltyFees = [{ project: '提前退车违约金', standard: '月租金×1', serviceFee: '0' }, { project: '违章处理违约金', standard: '按实际发生', serviceFee: '50' }];
var feeTemplateConsumables = [{ category: '轮胎', part: '前轮', partName: '轮胎A型', qty: 1, feeDetail: '500.00' }, { category: '易损件', part: '雨刮', partName: '雨刮片', qty: 2, feeDetail: '80.00' }];
var feeTemplateOtherFees = [{ project: '上门送车费', standard: '100元/次', serviceFee: '50' }, { project: '上门收车费', standard: '100元/次', serviceFee: '50' }, { project: '清洗费', standard: '80元/次', serviceFee: '30' }];
var feeTableHeader3 = React.createElement('tr', null, React.createElement('th', { style: styles.rentalTh }, '项目'), React.createElement('th', { style: styles.rentalTh }, '收费标准'), React.createElement('th', { style: styles.rentalTh }, '服务费'));
var feeTableHeader5 = React.createElement('tr', null, React.createElement('th', { style: styles.rentalTh }, '类别'), React.createElement('th', { style: styles.rentalTh }, '损坏部位'), React.createElement('th', { style: styles.rentalTh }, '配件'), React.createElement('th', { style: styles.rentalTh }, '数量'), React.createElement('th', { style: styles.rentalTh }, '费用明细'));
var makeFeeRow3 = function(r, i) { return React.createElement('tr', { key: i }, React.createElement('td', { style: styles.rentalTd }, r.project), React.createElement('td', { style: styles.rentalTd }, r.standard), React.createElement('td', { style: styles.rentalTd }, r.serviceFee)); };
var makeFeeRow5 = function(r, i) { return React.createElement('tr', { key: i }, React.createElement('td', { style: styles.rentalTd }, r.category), React.createElement('td', { style: styles.rentalTd }, r.part), React.createElement('td', { style: styles.rentalTd }, r.partName), React.createElement('td', { style: styles.rentalTd }, r.qty), React.createElement('td', { style: styles.rentalTd }, r.feeDetail)); };
var feeCertTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader3), React.createElement('tbody', null, feeTemplateCertFees.map(makeFeeRow3)));
var feePenaltyTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader3), React.createElement('tbody', null, feeTemplatePenaltyFees.map(makeFeeRow3)));
var feeConsumablesTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader5), React.createElement('tbody', null, feeTemplateConsumables.map(makeFeeRow5)));
var feeOtherTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader3), React.createElement('tbody', null, feeTemplateOtherFees.map(makeFeeRow3)));
var feeTemplateBody = React.createElement('div', null,
React.createElement('div', { style: Object.assign({}, styles.feeSectionTitle, styles.feeSectionTitleFirst) }, '证照补办费用'), feeCertTable,
React.createElement('div', { style: styles.feeSectionTitle }, '违约金费用'), feePenaltyTable,
React.createElement('div', { style: styles.feeSectionTitle }, '易损件信息'), feeConsumablesTable,
React.createElement('div', { style: styles.feeSectionTitle }, '其他费用信息'), feeOtherTable
);
var customerFields = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '客户名称', value: mockCustomer.name }),
React.createElement(FormItemReadOnly, { label: '客户统一信用代码', value: mockCustomer.creditCode }),
React.createElement(FormItemReadOnly, { label: '客户地址', value: mockCustomer.address }),
React.createElement(FormItemReadOnly, { label: '客户联系人', value: mockCustomer.contact }),
React.createElement(FormItemReadOnly, { label: '客户电话', value: mockCustomer.phone }),
React.createElement(FormItemReadOnly, { label: '客户电子邮箱', value: mockCustomer.email }),
React.createElement(FormItemReadOnly, { label: '企业名称', value: mockCustomer.companyName }),
React.createElement(FormItemReadOnly, { label: '企业电话', value: mockCustomer.companyPhone }),
React.createElement(FormItemReadOnly, { label: '邮寄地址', value: mockCustomer.mailingAddress }),
React.createElement(FormItemReadOnly, { label: '开户银行', value: mockCustomer.bank }),
React.createElement(FormItemReadOnly, { label: '银行账号', value: mockCustomer.bankAccount }),
React.createElement(FormItemReadOnly, { label: '纳税人识别号', value: mockCustomer.taxId }),
React.createElement(FormItemReadOnly, { label: '业务部门', value: '业务1部' }),
React.createElement(FormItemReadOnly, { label: '业务负责人', value: '张经理' })
);
var contractFormRow1 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '项目名称', value: mockContract.projectName }),
React.createElement(FormItemReadOnly, { label: '合同编码', value: mockContract.contractCode }),
React.createElement(FormItemReadOnly, { label: '合同类型', value: mockContract.contractType }),
React.createElement(FormItemReadOnly, { label: '生效日期', value: mockContract.effectiveDate }),
React.createElement(FormItemReadOnly, { label: '付款方式', value: mockContract.paymentMethod }),
React.createElement(FormItemReadOnly, { label: '主要车型', value: mockContract.mainVehicleModels }),
React.createElement(FormItemReadOnly, { label: '结束日期', value: mockContract.endDate }),
React.createElement(FormItemReadOnly, { label: '付款周期', value: mockContract.paymentPeriod }),
React.createElement(FormItemReadOnly, { label: '签约公司', value: mockContract.signingCompany }),
React.createElement('div', { style: styles.formCol },
React.createElement(FormItemReadOnly, { label: '交车区域', value: mockContract.deliveryRegion }),
React.createElement('div', null,
React.createElement('label', { style: styles.label }, '合同原件'),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { padding: '8px 12px' }) },
contractOriginal
? React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
React.createElement('a', { href: '#', style: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none' }, onClick: function(e) { e.preventDefault(); window.open('#', '_blank'); } }, contractOriginal.name),
(contractOriginal.size || contractOriginal.uploadTime) ? React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (contractOriginal.size || '') + (contractOriginal.size && contractOriginal.uploadTime ? ' · ' : '') + (contractOriginal.uploadTime || '')) : null
)
: '—'
)
)
),
React.createElement(FormItemReadOnly, { label: '交车地点', value: mockContract.deliveryLocation })
);
var contractFormRow2 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItemReadOnly, { label: '备注', fullWidth: true, value: mockContract.remarks || '—' }));
var authorizedContent = React.createElement('div', null,
React.createElement('div', { style: { display: 'flex', gap: 12, alignItems: 'center', marginBottom: 8 } },
React.createElement('span', { style: { flex: 1, fontWeight: 600, fontSize: 13 } }, '被授权人姓名'),
React.createElement('span', { style: { flex: 1, fontWeight: 600, fontSize: 13 } }, '被授权人联系电话'),
React.createElement('span', { style: { flex: 1, fontWeight: 600, fontSize: 13 } }, '被授权人身份证')
),
mockAuthorized.map(function(item, index) {
return React.createElement('div', { key: index, style: { display: 'flex', gap: 12, alignItems: 'center', marginBottom: 12 } },
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { flex: 1 }) }, item.name),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { flex: 1 }) }, item.phone),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { flex: 1 }) }, item.idCard)
);
})
);
var rentalSummaryEl = React.createElement('div', { style: styles.summaryList },
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '租赁车辆数'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.vehicleCount + ' 辆')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '租金及服务费合计'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.totalRentService + ' 元')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '保证金总额'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.totalDeposit + ' 元')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '氢气预付款金额'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.hydrogenPrepay + ' 元'))
);
var rentalTableBody = mockRentalOrders.map(function(row, idx) {
return React.createElement('tr', { key: idx },
React.createElement('td', { style: styles.rentalTd }, idx + 1),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.brand)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.model)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.plateNo)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.vin)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.monthRent + ' 元')),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.serviceFee + ' 元')),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.deposit + ' 元')),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.remark || '—'))
);
});
var rentalTableEl = React.createElement('table', { style: styles.rentalTable },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: styles.rentalTh, width: 50 }, '序号'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '品牌'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '型号'),
React.createElement('th', { style: styles.rentalTh, width: 120 }, '车牌号'),
React.createElement('th', { style: styles.rentalTh, width: 160 }, '车辆识别代码'),
React.createElement('th', { style: styles.rentalTh, width: 120 }, '车辆月租金'),
React.createElement('th', { style: styles.rentalTh, width: 90 }, '服务费'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '保证金'),
React.createElement('th', { style: styles.rentalTh, width: 80 }, '备注')
)
),
React.createElement('tbody', null, rentalTableBody)
);
var hydrogenReadOnly = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '氢费承担方', value: mockHydrogen.bearer }),
React.createElement(FormItemReadOnly, { label: '付款方式', value: mockHydrogen.paymentMethod }),
React.createElement(FormItemReadOnly, { label: '氢气预付款', value: mockHydrogen.hydrogenPrepay + ' 元' }),
React.createElement(FormItemReadOnly, { label: '退还车氢气单价', value: mockHydrogen.returnPrice + ' 元' })
);
var rentalContent = React.createElement('div', null, rentalSummaryEl, React.createElement('div', { style: { overflowX: 'auto', marginBottom: 16 } }, rentalTableEl), hydrogenReadOnly);
var newVehicleColumns = [
{ title: '序号', key: 'no', width: 60, render: function(_, __, i) { return i + 1; } },
{ title: '品牌', key: 'brand', width: 90, render: function(_, row, i) { return React.createElement(Select, { placeholder: '请选择', style: { width: '100%' }, value: row.brand || undefined, onChange: function(v) { updateNewVehicleRow(i, 'brand', v || ''); }, options: brandList.map(function(b) { return { value: b, label: b }; }), allowClear: true }); } },
{ title: '型号', key: 'model', width: 100, render: function(_, row, i) { var opts = (row.brand && modelByBrand[row.brand]) ? modelByBrand[row.brand].map(function(m) { return { value: m, label: m }; }) : []; return React.createElement(Select, { placeholder: '请选择', style: { width: '100%' }, value: row.model || undefined, onChange: function(v) { updateNewVehicleRow(i, 'model', v || ''); }, options: opts, allowClear: true, disabled: !row.brand }); } },
{ title: '车牌号', key: 'plateNo', width: 120, render: function(_, row, i) { return React.createElement(Select, { placeholder: '请选择或输入搜索', style: { width: '100%' }, value: row.plateNo || undefined, onChange: function(v) { updateNewVehicleRow(i, 'plateNo', v || ''); }, options: plateNoOptions, allowClear: true, showSearch: true, filterOption: function(input, option) { var label = (option && option.label) ? option.label : ''; return label.toLowerCase().indexOf((input || '').toLowerCase()) >= 0; } }); } },
{ title: '车辆识别代码', key: 'vin', width: 160, render: function(_, row, i) { return React.createElement(Input, { placeholder: '由车牌号反写', value: row.plateNo || row.vin || '', disabled: true }); } },
{ title: '车辆月租金', key: 'monthRent', width: 120, render: function(_, row, i) { return React.createElement(Input, { placeholder: '0.00', value: row.monthRent || '', onChange: function(e) { updateNewVehicleRow(i, 'monthRent', e.target.value); }, addonAfter: '元' }); } },
{ title: '服务费项目', key: 'serviceItems', width: 80, render: function(_, row, i) { return React.createElement(Button, { type: 'link', size: 'small', onClick: function() { openServiceModal(i); } }, '管理'); } },
{ title: '服务费', key: 'serviceFee', width: 90, render: function(_, row, i) { return calcRowServiceFee(row) + ' 元'; } },
{ title: '保证金', key: 'deposit', width: 100, render: function(_, row, i) { return React.createElement(Input, { placeholder: '0.00', value: row.deposit || '', onChange: function(e) { updateNewVehicleRow(i, 'deposit', e.target.value); }, addonAfter: '元' }); } },
{ title: '备注', key: 'remark', width: 80, render: function(_, row, i) { return React.createElement(Input, { placeholder: '请输入', value: row.remark || '', onChange: function(e) { updateNewVehicleRow(i, 'remark', e.target.value); } }); } },
{ title: '操作', key: 'action', width: 80, render: function(_, row, i) { return React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeNewVehicleRow(i); } }, '删除'); } }
];
var newOrderSummaryEl = React.createElement('div', { style: styles.summaryList },
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '租赁车辆数'), React.createElement('span', { style: styles.summaryListValue }, newOrderSummary.vehicleCount + ' 辆')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '租金及服务费合计'), React.createElement('span', { style: styles.summaryListValue }, newOrderSummary.totalRentService + ' 元')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '保证金总额'), React.createElement('span', { style: styles.summaryListValue }, newOrderSummary.totalDeposit + ' 元'))
);
var serviceModalRows = serviceModalRowIndex !== null && newVehicleRows[serviceModalRowIndex] ? newVehicleRows[serviceModalRowIndex].serviceItems : [];
var serviceModalContent = serviceModalRowIndex !== null ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) closeServiceModal(); } },
React.createElement('div', { style: styles.modalBox, onClick: function(e) { e.stopPropagation(); } },
React.createElement('div', { style: styles.modalHeader }, '服务项目'),
React.createElement('div', { style: styles.modalBody },
React.createElement('table', { style: styles.rentalTable },
React.createElement('thead', null, React.createElement('tr', null, React.createElement('th', { style: styles.rentalTh }, '服务项目'), React.createElement('th', { style: styles.rentalTh }, '费用'), React.createElement('th', { style: styles.rentalTh }, '生效时间'), React.createElement('th', { style: Object.assign({}, styles.rentalTh, { width: 80 }) }, '操作'))),
React.createElement('tbody', null, serviceModalRows.map(function(si, siIdx) {
return React.createElement('tr', { key: siIdx },
React.createElement('td', { style: styles.rentalTd }, React.createElement(Select, { style: { width: '100%' }, placeholder: '请选择服务项目', value: si.project || undefined, onChange: function(v) { updateServiceItem(siIdx, 'project', v || ''); }, showSearch: true, filterOption: function(input, opt) { return opt && opt.children && String(opt.children).toLowerCase().indexOf((input || '').toLowerCase()) >= 0; }, allowClear: true }, serviceItemOptions.map(function(opt, oi) { return React.createElement(Option, { key: oi, value: opt }, opt); }))),
React.createElement('td', { style: styles.rentalTd }, React.createElement(Input, { placeholder: '0.00', value: si.fee || '', onChange: function(e) { updateServiceItem(siIdx, 'fee', e.target.value); }, addonAfter: '元', style: { width: '100%' } })),
React.createElement('td', { style: styles.rentalTd }, React.createElement(DatePicker, { style: { width: '100%' }, format: 'YYYY-MM-DD', placeholder: '请选择生效时间', value: si.effectiveDate && window.moment ? window.moment(si.effectiveDate, 'YYYY-MM-DD') : null, onChange: function(d, dateStr) { updateServiceItem(siIdx, 'effectiveDate', dateStr || ''); } })),
React.createElement('td', { style: styles.rentalTd }, React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function() { removeServiceItem(siIdx); } }, '删除'))
);
}))
),
React.createElement(Button, { type: 'dashed', style: { marginTop: 12, width: '100%' }, onClick: addServiceItem }, '添加一行')
),
React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right', display: 'flex', gap: 12, justifyContent: 'flex-end' } },
React.createElement(Button, { type: 'primary', onClick: function() { closeServiceModal(); } }, '保存'),
React.createElement(Button, { onClick: closeServiceModal }, '关闭')
)
)
) : null;
var newVehicleCardContent = React.createElement('div', null,
React.createElement('div', { style: styles.sectionTitle }, '新增订单'),
newOrderSummaryEl,
React.createElement(Table, { rowKey: function(_, i) { return String(i); }, size: 'small', columns: newVehicleColumns, dataSource: newVehicleRows, pagination: false, scroll: { x: 1100 } }),
React.createElement(Button, { type: 'dashed', style: { marginTop: 12, width: '100%' }, onClick: addNewVehicleRow }, '添加一行')
);
var feeContent = React.createElement('div', null, React.createElement('div', { style: styles.formRow }, React.createElement(FormItemReadOnly, { label: '选择费用模板', value: mockFeeTemplate })), feeTemplateBody);
var billingContent = React.createElement('div', null, React.createElement('div', { style: { padding: '12px 16px', border: '1px solid #e8e8e8', borderRadius: 4, backgroundColor: '#fafafa', fontSize: 14, color: '#333' } }, mockBillingMethod));
var attachmentContent = React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader }, React.createElement('span', { style: styles.cardTitle }, '盖章合同附件')),
React.createElement('div', { style: styles.cardBody }, React.createElement('div', { style: { color: '#666', fontSize: 14 } }, '租赁合同-盖章版.pdf · 1.2 MB · 2026-02-16 14:30'))
);
var changeHistorySorted = [{ changeTime: '2026-02-16 14:00', opType: '变更内容', operator: '张三', remark: '"结束日期"由"2027-01-16"修改为"2027-02-16"' }];
var historyTableRows = changeHistorySorted.map(function(row, index) {
return React.createElement('tr', { key: index },
React.createElement('td', { style: styles.rentalTd }, index + 1),
React.createElement('td', { style: styles.rentalTd }, row.changeTime),
React.createElement('td', { style: styles.rentalTd }, row.opType),
React.createElement('td', { style: styles.rentalTd }, row.operator),
React.createElement('td', { style: styles.rentalTd }, row.remark)
);
});
var historyTable = React.createElement('table', { style: styles.rentalTable },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: styles.rentalTh, width: 60 }, '序号'),
React.createElement('th', { style: styles.rentalTh, width: 140 }, '变更时间'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '操作类型'),
React.createElement('th', { style: styles.rentalTh, width: 90 }, '操作人'),
React.createElement('th', { style: styles.rentalTh }, '备注')
)
),
React.createElement('tbody', null, historyTableRows)
);
var changeHistoryContent = React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader }, React.createElement('span', { style: styles.cardTitle }, '合同变更历史记录')),
React.createElement('div', { style: styles.cardBody }, React.createElement('div', { style: { overflowX: 'auto' } }, historyTable))
);
return React.createElement('div', { style: styles.page },
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } },
React.createElement('div', { style: styles.breadcrumb }, React.createElement('span', null, '业务管理'), React.createElement('span', { style: styles.breadcrumbSep }, ' / '), React.createElement('span', null, '车辆租赁合同'), React.createElement('span', { style: styles.breadcrumbSep }, ' / '), React.createElement('span', { style: { color: '#1890ff' } }, '新增车辆'))
),
React.createElement('div', { style: styles.anchorWrap },
React.createElement('div', { style: { marginBottom: 8, fontWeight: 600, fontSize: 14 } }, '锚点导航'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-customer'); } }, '客户基本信息'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-contract'); } }, '合同基本信息'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-authorized'); } }, '被授权人信息'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-rental'); } }, '租赁订单信息'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-new-vehicle'); } }, '新增车辆信息'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-fee'); } }, '其他费用信息'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-billing'); } }, '账单计算方式'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-attachment'); } }, '盖章合同附件'),
React.createElement('button', { type: 'button', style: styles.anchorItem, onClick: function() { scrollToCard('card-history'); } }, '合同变更历史记录')
),
React.createElement('div', { id: 'card-customer' }, React.createElement(CardBlock, { title: '客户基本信息', collapsed: cc1, setCollapsed: setCc1 }, customerFields)),
React.createElement('div', { id: 'card-contract', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '合同基本信息', collapsed: cc2, setCollapsed: setCc2 }, React.createElement('div', null, contractFormRow1, contractFormRow2))),
React.createElement('div', { id: 'card-authorized', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '被授权人信息', collapsed: cc3, setCollapsed: setCc3 }, authorizedContent)),
React.createElement('div', { id: 'card-rental', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '租赁订单信息', collapsed: cc4, setCollapsed: setCc4 }, rentalContent)),
React.createElement('div', { id: 'card-new-vehicle', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '新增车辆信息', collapsed: cc7, setCollapsed: setCc7 }, newVehicleCardContent)),
React.createElement('div', { id: 'card-fee', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '其他费用信息', collapsed: cc5, setCollapsed: setCc5 }, feeContent)),
React.createElement('div', { id: 'card-billing', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '账单计算方式', collapsed: cc6, setCollapsed: setCc6 }, billingContent)),
React.createElement('div', { id: 'card-attachment', style: { marginTop: 16 } }, attachmentContent),
React.createElement('div', { id: 'card-history', style: { marginTop: 16 } }, changeHistoryContent),
React.createElement('div', { style: { height: 60 } }),
serviceModalContent,
React.createElement('div', { style: styles.footer },
React.createElement('button', { type: 'button', style: Object.assign({}, styles.btn, styles.btnDefault), onClick: function() { message.info('取消(原型)'); } }, '取消'),
React.createElement('button', { type: 'button', style: Object.assign({}, styles.btn, styles.btnPrimary), onClick: function() { message.success('已提交审核,审核通过后生效(原型)'); } }, '提交审核')
)
);
};

View File

@@ -0,0 +1,448 @@
// 【重要】必须使用 const Component 作为组件变量名 - Axhub 产品原型
// 车辆资产管理系统 - 查看租赁合同模块(只读 + 审批状态 + 盖章附件IE11+ 兼容)
const Component = function() {
var cc1State = React.useState(false);
var cc1 = cc1State[0];
var setCc1 = cc1State[1];
var cc2State = React.useState(false);
var cc2 = cc2State[0];
var setCc2 = cc2State[1];
var cc3State = React.useState(false);
var cc3 = cc3State[0];
var setCc3 = cc3State[1];
var cc4State = React.useState(false);
var cc4 = cc4State[0];
var setCc4 = cc4State[1];
var cc5State = React.useState(false);
var cc5 = cc5State[0];
var setCc5 = cc5State[1];
var cc6State = React.useState(false);
var cc6 = cc6State[0];
var setCc6 = cc6State[1];
var attachmentHoverState = React.useState(false);
var attachmentHover = attachmentHoverState[0];
var setAttachmentHover = attachmentHoverState[1];
var reqSpecState = React.useState(false);
var reqSpecOpen = reqSpecState[0];
var setReqSpecOpen = reqSpecState[1];
var servicePopoverRowState = React.useState(null);
var servicePopoverRow = servicePopoverRowState[0];
var setServicePopoverRow = servicePopoverRowState[1];
// 模拟已上传的盖章合同附件
var uploadedFile = { name: '租赁合同-盖章版.pdf', size: '1.2 MB', uploadTime: '2026-02-16 14:30' };
// 合同变更历史记录(变更时间倒序,序号 1.2.3...
var changeHistoryRaw = [
{ changeTime: '2026-02-16 14:00', opType: '变更内容', operator: '张三', remark: '"结束日期"由"2027-01-16"修改为"2027-02-16"' },
{ changeTime: '2026-02-16 10:30', opType: '附加费用', operator: '李四', remark: '添加服务项目"保养费用",费用为"200",生效时间为"2026-03-01"\n添加服务项目"清洗费",费用为"80",生效时间为"2026-03-01"' },
{ changeTime: '2026-02-15 16:20', opType: '添加授权人', operator: '王五', remark: '添加授权人"李四"' },
{ changeTime: '2026-02-14 09:15', opType: '合同续签', operator: '赵六', remark: '原合同编码"JXZL20250210YW101100A"' },
{ changeTime: '2026-02-13 10:00', opType: '终止合同', operator: '周九', remark: '终止原因"客户提前解约"' },
{ changeTime: '2026-02-12 11:00', opType: '撤回合同', operator: '钱七', remark: '-' },
{ changeTime: '2026-02-10 14:30', opType: '转正式合同', operator: '孙八', remark: '原合同编码"JXZL20260210YW101230B"' }
];
var changeHistorySorted = changeHistoryRaw.slice().sort(function(a, b) { return b.changeTime.localeCompare(a.changeTime); });
var scrollToCard = function(id) {
var el = document.getElementById(id);
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
var styles = {
page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
anchorWrap: { position: 'fixed', top: 80, right: 24, zIndex: 100, backgroundColor: '#fff', borderRadius: 8, boxShadow: '0 2px 8px rgba(0,0,0,0.12)', padding: '12px 16px', minWidth: 160 },
anchorItem: { display: 'block', padding: '6px 0', color: '#1890ff', cursor: 'pointer', border: 'none', background: 'none', width: '100%', textAlign: 'left', fontSize: 13 },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardHeader: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 20px', borderBottom: '1px solid #f0f0f0', cursor: 'pointer' },
cardTitle: { fontSize: 16, fontWeight: 600, color: '#333' },
cardToggle: { color: '#999', fontSize: 14 },
cardBody: { padding: '20px 24px' },
formRow: { display: 'flex', flexWrap: 'wrap', marginBottom: 16 },
formCol: { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8 },
formColFull: { flex: '0 0 100%', marginBottom: 8 },
label: { display: 'block', marginBottom: 6, color: '#333' },
input: { width: '100%', padding: '8px 12px', border: '1px solid #d9d9d9', borderRadius: 4, fontSize: 14 },
inputDisabled: { backgroundColor: '#f5f5f5', color: '#666', cursor: 'default', borderColor: '#e8e8e8' },
summaryList: { marginBottom: 16, display: 'flex', flexWrap: 'wrap', gap: 16 },
summaryListItem: { flex: '0 0 calc(50% - 8px)', display: 'flex', alignItems: 'center', padding: '12px 16px', border: '1px solid #e8e8e8', borderRadius: 4, backgroundColor: '#fafafa', fontSize: 14, boxSizing: 'border-box' },
summaryListLabel: { flex: '0 0 140px', color: '#666' },
summaryListValue: { flex: 1, fontWeight: 600, color: '#333' },
rentalTable: { width: '100%', borderCollapse: 'collapse', fontSize: 13 },
rentalTh: { padding: '10px 8px', textAlign: 'left', borderBottom: '1px solid #e8e8e8', backgroundColor: '#fafafa', fontWeight: 600 },
rentalTd: { padding: '8px', borderBottom: '1px solid #f0f0f0', verticalAlign: 'middle' },
rentalInputDisabled: { backgroundColor: '#f5f5f5', color: '#666', border: '1px solid #e8e8e8', padding: '6px 10px', borderRadius: 4, width: '100%', fontSize: 13 },
tag: { display: 'inline-block', padding: '2px 8px', marginRight: 8, marginBottom: 4, backgroundColor: '#e6f7ff', color: '#1890ff', borderRadius: 4, fontSize: 12 },
footer: { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, justifyContent: 'flex-start', zIndex: 99 },
btn: { padding: '8px 24px', borderRadius: 4, border: '1px solid #d9d9d9', cursor: 'pointer', fontSize: 14 },
btnDefault: { backgroundColor: '#fff', color: '#333' },
approvalCard: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
approvalCardHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0', fontSize: 16, fontWeight: 600, color: '#333', textAlign: 'center' },
approvalCardBody: { padding: '24px 20px', display: 'flex', justifyContent: 'center' },
stepWrap: { display: 'flex', alignItems: 'flex-start', flexWrap: 'wrap', justifyContent: 'center' },
stepItem: { flex: '1 1 0', minWidth: 140, maxWidth: 220, textAlign: 'center', position: 'relative' },
stepIcon: { width: 32, height: 32, borderRadius: '50%', margin: '0 auto 8px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 16, fontWeight: 600 },
stepIconDone: { backgroundColor: '#52c41a', color: '#fff' },
stepLine: { position: 'absolute', top: 16, left: '50%', right: '-50%', height: 2, backgroundColor: '#e8e8e8', zIndex: 0 },
stepLineDone: { backgroundColor: '#52c41a' },
stepTitle: { fontSize: 13, color: '#333', fontWeight: 500, marginBottom: 4 },
stepDesc: { fontSize: 12, color: '#666' },
stepStatus: { fontSize: 12, color: '#52c41a', marginTop: 4 },
stepTime: { fontSize: 12, color: '#999', marginTop: 2 },
attachmentRow: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 12 },
attachmentFile: { display: 'inline-flex', alignItems: 'center', padding: '8px 12px', backgroundColor: '#f5f5f5', borderRadius: 4, border: '1px solid #d9d9d9', fontSize: 14, color: '#1890ff', cursor: 'pointer', textDecoration: 'none', fontFamily: 'inherit', margin: 0, outline: 'none' },
attachmentFileHover: { color: '#40a9ff', borderColor: '#1890ff', backgroundColor: '#e6f7ff' },
attachmentMeta: { fontSize: 12, color: '#999', marginLeft: 8 },
feeSectionTitle: { fontSize: 15, fontWeight: 600, color: '#333', marginTop: 20, marginBottom: 10 },
feeSectionTitleFirst: { marginTop: 0 },
historyLink: { color: '#1890ff', cursor: 'pointer', background: 'none', border: 'none', padding: 0, fontSize: 14 },
modalMask: { position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.45)', zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center' },
modalBox: { backgroundColor: '#fff', borderRadius: 8, width: '90%', maxWidth: 640, maxHeight: '85vh', overflow: 'hidden', display: 'flex', flexDirection: 'column', boxShadow: '0 4px 20px rgba(0,0,0,0.15)' },
modalHeader: { padding: '16px 20px', borderBottom: '1px solid #f0f0f0', fontSize: 16, fontWeight: 600 },
modalBody: { padding: 20, overflow: 'auto', flex: 1 }
};
var CardBlock = function(props) {
return React.createElement('div', { id: props.id, style: styles.card },
React.createElement('div', { style: styles.cardHeader, onClick: function() { props.setCollapsed(!props.collapsed); } },
React.createElement('span', { style: styles.cardTitle }, props.title),
React.createElement('span', { style: styles.cardToggle }, props.collapsed ? '展开' : '收起')
),
!props.collapsed ? React.createElement('div', { style: styles.cardBody }, props.children) : null
);
};
var FormItemReadOnly = function(props) {
var colStyle = props.fullWidth ? styles.formColFull : styles.formCol;
return React.createElement('div', { style: colStyle },
React.createElement('label', { style: styles.label }, props.label),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled) }, props.value || '—')
);
};
// 审批流程步骤数据(全部已通过,含审核时间 YYYY-MM-DD HH:MM
var approvalSteps = [
{ title: '业务部主管', person: '姚守涛', status: '已通过', approveTime: '2026-02-16 09:30' },
{ title: '事业部主管', person: '尚建华', status: '已通过', approveTime: '2026-02-16 10:15' },
{ title: '财务部', person: '宋欣怡 / 吕红', status: '已通过', approveTime: '2026-02-16 11:20' },
{ title: '法务部', person: '高洁 / 彭青松', status: '已通过', approveTime: '2026-02-16 14:00' }
];
var approvalStepEls = approvalSteps.map(function(step, index) {
var isLast = index === approvalSteps.length - 1;
var lineStyle = Object.assign({}, styles.stepLine, step.status === '已通过' ? styles.stepLineDone : {});
if (isLast) lineStyle.display = 'none';
return React.createElement('div', { key: index, style: Object.assign({}, styles.stepItem, { zIndex: approvalSteps.length - index }) },
!isLast ? React.createElement('div', { style: lineStyle }) : null,
React.createElement('div', { style: Object.assign({}, styles.stepIcon, styles.stepIconDone) }, '✓'),
React.createElement('div', { style: styles.stepTitle }, step.title),
React.createElement('div', { style: styles.stepDesc }, step.person),
React.createElement('div', { style: styles.stepStatus }, step.status),
step.approveTime ? React.createElement('div', { style: styles.stepTime }, step.approveTime) : null
);
});
var approvalCardEl = React.createElement('div', { style: styles.approvalCard },
React.createElement('div', { style: styles.approvalCardHeader }, '审批状态'),
React.createElement('div', { style: styles.approvalCardBody },
React.createElement('div', { style: styles.stepWrap }, approvalStepEls)
)
);
// 模拟只读数据(与新增合同同结构)
var mockCustomer = { name: '嘉兴某某物流有限公司', creditCode: '91330400MA2XXXXX1', address: '浙江省嘉兴市南湖区科技大道1号', contact: '张三', phone: '13800138001', email: 'zhangsan@example.com', companyName: '嘉兴某某物流有限公司', companyPhone: '0571-88888888', mailingAddress: '浙江省嘉兴市南湖区科技大道1号', bank: '中国工商银行嘉兴分行', bankAccount: '6222021234567890123', taxId: '91330400MA2XXXXX1' };
var contractOriginal = { name: '租赁合同-原件.pdf', size: '1.2 MB', uploadTime: '2026-02-16 14:30' };
var mockContract = { projectName: '嘉兴氢能运输项目', contractCode: 'JXZL20260216YW101235A', contractType: '正式合同', effectiveDate: '2026-02-16', paymentMethod: '预付', mainVehicleModels: '型号A1、型号A2', endDate: '2027-02-16', paymentPeriod: '1个月', signingCompany: '嘉兴羚牛', deliveryRegion: '浙江省 / 嘉兴市', deliveryLocation: '嘉兴市南湖区科技大道1号', remarks: '' };
var mockAuthorized = [{ name: '张三', phone: '13800138001', idCard: '330102199001011234' }];
var mockRentalOrders = [
{ brand: '品牌A', model: '型号A1', plateNo: '浙A10001', vin: 'L1234567890ABCDEF', monthRent: '8000', serviceFee: '500', deposit: '10000', remark: '', serviceItems: [{ project: '保养费用', fee: '200', effectiveDate: '2026-03-01' }, { project: '清洗费', fee: '80', effectiveDate: '2026-03-01' }] },
{ brand: '品牌A', model: '型号A2', plateNo: '浙B20002', vin: 'L2234567890ABCDEF', monthRent: '8000', serviceFee: '500', deposit: '10000', remark: '', serviceItems: [{ project: '清洗费', fee: '80', effectiveDate: '2026-03-01' }] }
];
var mockRentalSummary = { vehicleCount: 2, totalRentService: '17000.00', totalDeposit: '20000.00', hydrogenPrepay: '5000.00' };
var mockHydrogen = { bearer: '客户', paymentMethod: '预付', hydrogenPrepay: '5000', returnPrice: '80' };
var mockFeeTemplate = '标准费用模板A';
var mockBillingMethod = '按自然月结算';
var feeTemplateCertFees = [{ project: '补办行驶证', standard: '50元/次', serviceFee: '20' }, { project: '补办驾驶证', standard: '30元/次', serviceFee: '10' }, { project: '补办牌照', standard: '100元/次', serviceFee: '50' }];
var feeTemplatePenaltyFees = [{ project: '提前退车违约金', standard: '月租金×1', serviceFee: '0' }, { project: '违章处理违约金', standard: '按实际发生', serviceFee: '50' }];
var feeTemplateConsumables = [{ category: '轮胎', part: '前轮', partName: '轮胎A型', qty: 1, feeDetail: '500.00' }, { category: '易损件', part: '雨刮', partName: '雨刮片', qty: 2, feeDetail: '80.00' }];
var feeTemplateOtherFees = [{ project: '上门送车费', standard: '100元/次', serviceFee: '50' }, { project: '上门收车费', standard: '100元/次', serviceFee: '50' }, { project: '清洗费', standard: '80元/次', serviceFee: '30' }];
var feeTableHeader3 = React.createElement('tr', null, React.createElement('th', { style: styles.rentalTh }, '项目'), React.createElement('th', { style: styles.rentalTh }, '收费标准'), React.createElement('th', { style: styles.rentalTh }, '服务费'));
var feeTableHeader5 = React.createElement('tr', null, React.createElement('th', { style: styles.rentalTh }, '类别'), React.createElement('th', { style: styles.rentalTh }, '损坏部位'), React.createElement('th', { style: styles.rentalTh }, '配件'), React.createElement('th', { style: styles.rentalTh }, '数量'), React.createElement('th', { style: styles.rentalTh }, '费用明细'));
var makeFeeRow3 = function(r, i) {
var td1 = React.createElement('td', { style: styles.rentalTd }, r.project);
var td2 = React.createElement('td', { style: styles.rentalTd }, r.standard);
var td3 = React.createElement('td', { style: styles.rentalTd }, r.serviceFee);
return React.createElement('tr', { key: i }, td1, td2, td3);
};
var makeFeeRow5 = function(r, i) {
var td1 = React.createElement('td', { style: styles.rentalTd }, r.category);
var td2 = React.createElement('td', { style: styles.rentalTd }, r.part);
var td3 = React.createElement('td', { style: styles.rentalTd }, r.partName);
var td4 = React.createElement('td', { style: styles.rentalTd }, r.qty);
var td5 = React.createElement('td', { style: styles.rentalTd }, r.feeDetail);
return React.createElement('tr', { key: i }, td1, td2, td3, td4, td5);
};
var feeCertRows = feeTemplateCertFees.map(makeFeeRow3);
var feePenaltyRows = feeTemplatePenaltyFees.map(makeFeeRow3);
var feeConsumablesRows = feeTemplateConsumables.map(makeFeeRow5);
var feeOtherRows = feeTemplateOtherFees.map(makeFeeRow3);
var feeCertTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader3), React.createElement('tbody', null, feeCertRows));
var feePenaltyTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader3), React.createElement('tbody', null, feePenaltyRows));
var feeConsumablesTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader5), React.createElement('tbody', null, feeConsumablesRows));
var feeOtherTable = React.createElement('table', { style: styles.rentalTable }, React.createElement('thead', null, feeTableHeader3), React.createElement('tbody', null, feeOtherRows));
var feeTemplateBody = React.createElement('div', null,
React.createElement('div', { style: Object.assign({}, styles.feeSectionTitle, styles.feeSectionTitleFirst) }, '证照补办费用'),
feeCertTable,
React.createElement('div', { style: styles.feeSectionTitle }, '违约金费用'),
feePenaltyTable,
React.createElement('div', { style: styles.feeSectionTitle }, '易损件信息'),
feeConsumablesTable,
React.createElement('div', { style: styles.feeSectionTitle }, '其他费用信息'),
feeOtherTable
);
var customerFields = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '客户名称', value: mockCustomer.name }),
React.createElement(FormItemReadOnly, { label: '客户统一信用代码', value: mockCustomer.creditCode }),
React.createElement(FormItemReadOnly, { label: '客户地址', value: mockCustomer.address }),
React.createElement(FormItemReadOnly, { label: '客户联系人', value: mockCustomer.contact }),
React.createElement(FormItemReadOnly, { label: '客户电话', value: mockCustomer.phone }),
React.createElement(FormItemReadOnly, { label: '客户电子邮箱', value: mockCustomer.email }),
React.createElement(FormItemReadOnly, { label: '企业名称', value: mockCustomer.companyName }),
React.createElement(FormItemReadOnly, { label: '企业电话', value: mockCustomer.companyPhone }),
React.createElement(FormItemReadOnly, { label: '邮寄地址', value: mockCustomer.mailingAddress }),
React.createElement(FormItemReadOnly, { label: '开户银行', value: mockCustomer.bank }),
React.createElement(FormItemReadOnly, { label: '银行账号', value: mockCustomer.bankAccount }),
React.createElement(FormItemReadOnly, { label: '纳税人识别号', value: mockCustomer.taxId }),
React.createElement(FormItemReadOnly, { label: '业务部门', value: '业务1部' }),
React.createElement(FormItemReadOnly, { label: '业务负责人', value: '张经理' })
);
var contractFormRow1 = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '项目名称', value: mockContract.projectName }),
React.createElement(FormItemReadOnly, { label: '合同编码', value: mockContract.contractCode }),
React.createElement(FormItemReadOnly, { label: '合同类型', value: mockContract.contractType }),
React.createElement(FormItemReadOnly, { label: '生效日期', value: mockContract.effectiveDate }),
React.createElement(FormItemReadOnly, { label: '付款方式', value: mockContract.paymentMethod }),
React.createElement(FormItemReadOnly, { label: '主要车型', value: mockContract.mainVehicleModels }),
React.createElement(FormItemReadOnly, { label: '结束日期', value: mockContract.endDate }),
React.createElement(FormItemReadOnly, { label: '付款周期', value: mockContract.paymentPeriod }),
React.createElement(FormItemReadOnly, { label: '签约公司', value: mockContract.signingCompany }),
React.createElement('div', { style: styles.formCol },
React.createElement(FormItemReadOnly, { label: '交车区域', value: mockContract.deliveryRegion }),
React.createElement('div', null,
React.createElement('label', { style: styles.label }, '合同原件'),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { padding: '8px 12px' }) },
contractOriginal
? React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
React.createElement('a', { href: '#', style: { color: '#1890ff', cursor: 'pointer', textDecoration: 'none' }, onClick: function(e) { e.preventDefault(); window.open('#', '_blank'); } }, contractOriginal.name),
(contractOriginal.size || contractOriginal.uploadTime) ? React.createElement('span', { style: { color: '#999', fontSize: 12 } }, (contractOriginal.size || '') + (contractOriginal.size && contractOriginal.uploadTime ? ' · ' : '') + (contractOriginal.uploadTime || '')) : null
)
: '—'
)
)
),
React.createElement(FormItemReadOnly, { label: '交车地点', value: mockContract.deliveryLocation })
);
var contractFormRow2 = React.createElement('div', { style: styles.formRow }, React.createElement(FormItemReadOnly, { label: '备注', fullWidth: true, value: mockContract.remarks || '—' }));
var authorizedContent = React.createElement('div', null,
React.createElement('div', { style: { display: 'flex', gap: 12, alignItems: 'center', marginBottom: 8 } },
React.createElement('span', { style: { flex: 1, fontWeight: 600, fontSize: 13 } }, '被授权人姓名'),
React.createElement('span', { style: { flex: 1, fontWeight: 600, fontSize: 13 } }, '被授权人联系电话'),
React.createElement('span', { style: { flex: 1, fontWeight: 600, fontSize: 13 } }, '被授权人身份证')
),
mockAuthorized.map(function(item, index) {
return React.createElement('div', { key: index, style: { display: 'flex', gap: 12, alignItems: 'center', marginBottom: 12 } },
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { flex: 1 }) }, item.name),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { flex: 1 }) }, item.phone),
React.createElement('div', { style: Object.assign({}, styles.input, styles.inputDisabled, { flex: 1 }) }, item.idCard)
);
})
);
var rentalSummaryEl = React.createElement('div', { style: styles.summaryList },
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '租赁车辆数'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.vehicleCount + ' 辆')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '租金及服务费合计'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.totalRentService + ' 元')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '保证金总额'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.totalDeposit + ' 元')),
React.createElement('div', { style: styles.summaryListItem }, React.createElement('span', { style: styles.summaryListLabel }, '氢气预付款金额'), React.createElement('span', { style: styles.summaryListValue }, mockRentalSummary.hydrogenPrepay + ' 元'))
);
var Popover = window.antd && window.antd.Popover;
var renderServiceItemsPopover = function(row) {
var items = row.serviceItems || [];
if (items.length === 0) {
return React.createElement('div', { style: { padding: 12, minWidth: 320, fontSize: 13 } }, '暂无服务项明细');
}
var thead = React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: styles.rentalTh }, '服务项目'),
React.createElement('th', { style: styles.rentalTh }, '费用'),
React.createElement('th', { style: styles.rentalTh }, '生效时间')
)
);
var tbody = React.createElement('tbody', null,
items.map(function(si, i) {
return React.createElement('tr', { key: i },
React.createElement('td', { style: styles.rentalTd }, si.project || '—'),
React.createElement('td', { style: styles.rentalTd }, si.fee != null && si.fee !== '' ? si.fee + ' 元' : '—'),
React.createElement('td', { style: styles.rentalTd }, si.effectiveDate || '—')
);
})
);
return React.createElement('div', { style: { padding: 8 } },
React.createElement('table', { style: styles.rentalTable }, thead, tbody)
);
};
var rentalTableBody = mockRentalOrders.map(function(row, idx) {
var servicePopoverContent = renderServiceItemsPopover(row);
var serviceCell = Popover
? React.createElement(Popover, { content: servicePopoverContent, title: '服务项明细', trigger: 'click' },
React.createElement('span', { style: { color: '#1890ff', cursor: 'pointer', fontSize: 13 } }, '查看'))
: React.createElement('span', {
style: { color: '#1890ff', cursor: 'pointer', fontSize: 13 },
onClick: function() { setServicePopoverRow(servicePopoverRow === idx ? null : idx); }
}, '查看');
return React.createElement('tr', { key: idx },
React.createElement('td', { style: styles.rentalTd }, idx + 1),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.brand)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.model)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.plateNo)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.vin)),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.monthRent + ' 元')),
React.createElement('td', { style: styles.rentalTd }, serviceCell),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.serviceFee + ' 元')),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.deposit + ' 元')),
React.createElement('td', { style: styles.rentalTd }, React.createElement('div', { style: styles.rentalInputDisabled }, row.remark || '—'))
);
});
var rentalTableEl = React.createElement('table', { style: styles.rentalTable },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: styles.rentalTh, width: 50 }, '序号'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '品牌'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '型号'),
React.createElement('th', { style: styles.rentalTh, width: 120 }, '车牌号'),
React.createElement('th', { style: styles.rentalTh, width: 160 }, '车辆识别代码'),
React.createElement('th', { style: styles.rentalTh, width: 120 }, '车辆月租金'),
React.createElement('th', { style: styles.rentalTh, width: 80 }, '服务费项目'),
React.createElement('th', { style: styles.rentalTh, width: 90 }, '服务费'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '保证金'),
React.createElement('th', { style: styles.rentalTh, width: 80 }, '备注')
)
),
React.createElement('tbody', null, rentalTableBody)
);
var hydrogenReadOnly = React.createElement('div', { style: styles.formRow },
React.createElement(FormItemReadOnly, { label: '氢费承担方', value: mockHydrogen.bearer }),
React.createElement(FormItemReadOnly, { label: '付款方式', value: mockHydrogen.paymentMethod }),
React.createElement(FormItemReadOnly, { label: '氢气预付款', value: mockHydrogen.hydrogenPrepay + ' 元' }),
React.createElement(FormItemReadOnly, { label: '退还车氢气单价', value: mockHydrogen.returnPrice + ' 元' })
);
var rentalContent = React.createElement('div', null, rentalSummaryEl, React.createElement('div', { style: { overflowX: 'auto', marginBottom: 16 } }, rentalTableEl), hydrogenReadOnly);
var feeContent = React.createElement('div', null, React.createElement('div', { style: styles.formRow }, React.createElement(FormItemReadOnly, { label: '选择费用模板', value: mockFeeTemplate })), feeTemplateBody);
var billingContent = React.createElement('div', null, React.createElement('div', { style: { padding: '12px 16px', border: '1px solid #e8e8e8', borderRadius: 4, backgroundColor: '#fafafa', fontSize: 14, color: '#333' } }, mockBillingMethod));
var attachmentContent = React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader },
React.createElement('span', { style: styles.cardTitle }, '盖章合同附件')
),
React.createElement('div', { style: styles.cardBody },
React.createElement('div', { style: styles.attachmentRow },
React.createElement('button', {
type: 'button',
style: Object.assign({}, styles.attachmentFile, attachmentHover ? styles.attachmentFileHover : {}),
onMouseEnter: function() { setAttachmentHover(true); },
onMouseLeave: function() { setAttachmentHover(false); },
onClick: function() { window.open('#', '_blank'); }
}, '📄 ' + uploadedFile.name, React.createElement('span', { style: styles.attachmentMeta }, uploadedFile.size + ' · ' + uploadedFile.uploadTime))
)
)
);
var historyTableRows = changeHistorySorted.map(function(row, index) {
return React.createElement('tr', { key: index },
React.createElement('td', { style: styles.rentalTd }, index + 1),
React.createElement('td', { style: styles.rentalTd }, row.changeTime),
React.createElement('td', { style: styles.rentalTd }, row.opType),
React.createElement('td', { style: styles.rentalTd }, row.operator),
React.createElement('td', { style: styles.rentalTd }, React.createElement('button', { type: 'button', style: styles.historyLink, onClick: function() { window.open('#', '_blank'); } }, '查看变更前记录')),
React.createElement('td', { style: Object.assign({}, styles.rentalTd, { verticalAlign: 'top', whiteSpace: 'pre-line' }) }, row.remark)
);
});
var historyTable = React.createElement('table', { style: styles.rentalTable },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: styles.rentalTh, width: 60 }, '序号'),
React.createElement('th', { style: styles.rentalTh, width: 140 }, '变更时间'),
React.createElement('th', { style: styles.rentalTh, width: 100 }, '操作类型'),
React.createElement('th', { style: styles.rentalTh, width: 90 }, '操作人'),
React.createElement('th', { style: styles.rentalTh, width: 120 }, '原始记录'),
React.createElement('th', { style: styles.rentalTh }, '备注')
)
),
React.createElement('tbody', null, historyTableRows)
);
var changeHistoryContent = React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardHeader },
React.createElement('span', { style: styles.cardTitle }, '合同变更历史记录')
),
React.createElement('div', { style: styles.cardBody },
React.createElement('div', { style: { overflowX: 'auto' } }, historyTable)
)
);
var reqSpecBlock = { marginBottom: 8 };
var reqSpecH2 = { fontSize: 14, fontWeight: 600, marginTop: 16, marginBottom: 8, color: '#333' };
var reqSpecH2First = { marginTop: 0 };
var reqSpecP = { fontSize: 13, lineHeight: 1.6, marginBottom: 6, color: '#555' };
var reqSpecLi = { fontSize: 13, lineHeight: 1.6, marginBottom: 4, marginLeft: 20, color: '#555' };
var reqSpecDoc = React.createElement('div', { style: { padding: '0 4px' } },
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: Object.assign({}, reqSpecH2, reqSpecH2First) }, '1.其他部分与新增租赁合同相同,只是不可编辑,新增以下几块内容:')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '2.审批状态卡片:'), React.createElement('div', { style: reqSpecP }, '显示所有审批步骤及当前节点、审批人姓名、已通过/待审批/驳回三种状态;最下方为对应审批节点审批操作时间,格式为 YYYY-MM-DD HH:MM。')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '3.盖章合同附件:'), React.createElement('div', { style: reqSpecP }, '当法务未完成审核并上传盖章合同时盖章合同附件显示为暂无附件已上传盖章合同时显示合同文件名称、文件大小、上传时间YYYY-MM-DD HH:MM。')),
React.createElement('div', { style: reqSpecBlock }, React.createElement('div', { style: reqSpecH2 }, '4.合同变更历史记录:'), React.createElement('div', { style: reqSpecP }, '列表字段为序号、变更时间、操作类型、操作人、原始记录、备注。'), React.createElement('div', { style: reqSpecLi }, '4.1.序号1.2.3...以此类推;'), React.createElement('div', { style: reqSpecLi }, '4.2.变更时间YYYY-MM-DD HH:MM 格式,倒序展示数据;'), React.createElement('div', { style: reqSpecLi }, '4.3.操作类型:包括变更内容、合同续签、撤回合同、添加授权人、附加费用、转正式合同、终止合同;'), React.createElement('div', { style: reqSpecLi }, '4.4.操作人:记录对应操作用户名称;'), React.createElement('div', { style: reqSpecLi }, '4.5.原始记录:显示查看变更前记录,点击会新开页查看未修改前合同原始记录;'), React.createElement('div', { style: reqSpecLi }, '4.6.备注:'), React.createElement('div', { style: Object.assign({}, reqSpecLi, { marginLeft: 36 }) }, '4.6.1.操作类型为变更内容时,显示:"字段名"由"xx"修改为"xxx"'), React.createElement('div', { style: Object.assign({}, reqSpecLi, { marginLeft: 36 }) }, '4.6.2.操作类型为合同续签时,显示:原合同编码"xxxxxxxxx"'), React.createElement('div', { style: Object.assign({}, reqSpecLi, { marginLeft: 36 }) }, '4.6.3.操作类型为撤回合同时,显示:-'), React.createElement('div', { style: Object.assign({}, reqSpecLi, { marginLeft: 36 }) }, '4.6.4.操作类型为添加授权人时,显示:添加授权人"xxx"'), React.createElement('div', { style: Object.assign({}, reqSpecLi, { marginLeft: 36 }) }, '4.6.5.操作类型为附加费用时,显示:添加服务项目"xxxxxx",费用为"xxxxxxx",生效时间为"YYYY-MM-DD",如果有多条附加费用,支持多行显示;'), React.createElement('div', { style: Object.assign({}, reqSpecLi, { marginLeft: 36 }) }, '4.6.6.操作类型为转正式合同时,显示:原合同编码"xxxxxxxx"'), React.createElement('div', { style: Object.assign({}, reqSpecLi, { marginLeft: 36 }) }, '4.6.7.操作类型为终止合同时,显示:终止原因"xxxxxx"。'))
);
var reqSpecModalContent = reqSpecOpen ? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) setReqSpecOpen(false); } }, React.createElement('div', { style: styles.modalBox, onClick: function(e) { e.stopPropagation(); } }, React.createElement('div', { style: styles.modalHeader }, '需求说明'), React.createElement('div', { style: Object.assign({}, styles.modalBody, { maxHeight: '70vh', padding: '20px 24px' }) }, reqSpecDoc), React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right' } }, React.createElement('button', { style: Object.assign({}, styles.btn, styles.btnDefault), onClick: function() { setReqSpecOpen(false); } }, '关闭')))) : null;
var servicePopoverContentCustom = !Popover && servicePopoverRow !== null && mockRentalOrders[servicePopoverRow]
? React.createElement('div', { style: styles.modalMask, onClick: function(e) { if (e.target === e.currentTarget) setServicePopoverRow(null); } },
React.createElement('div', { style: Object.assign({}, styles.modalBox, { maxWidth: 480 }), onClick: function(e) { e.stopPropagation(); } },
React.createElement('div', { style: styles.modalHeader }, '服务项明细'),
React.createElement('div', { style: Object.assign({}, styles.modalBody, { padding: '16px 20px' }) }, renderServiceItemsPopover(mockRentalOrders[servicePopoverRow])),
React.createElement('div', { style: { padding: '12px 20px', borderTop: '1px solid #f0f0f0', textAlign: 'right' } }, React.createElement('button', { style: Object.assign({}, styles.btn, styles.btnDefault), onClick: function() { setServicePopoverRow(null); } }, '关闭'))
))
: null;
return React.createElement('div', { style: styles.page },
servicePopoverContentCustom,
React.createElement('div', { style: { marginBottom: 16 } }, React.createElement('div', { style: styles.breadcrumb }, React.createElement('span', null, '业务管理'), React.createElement('span', { style: styles.breadcrumbSep }, ' / '), React.createElement('span', null, '车辆租赁合同'), React.createElement('span', { style: styles.breadcrumbSep }, ' / '), React.createElement('span', { style: { color: '#1890ff' } }, '查看租赁合同'))),
approvalCardEl,
React.createElement('div', { style: styles.anchorWrap },
React.createElement('div', { style: { marginBottom: 8, fontWeight: 600, fontSize: 14 } }, '锚点导航'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-customer'); } }, '客户基本信息'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-contract'); } }, '合同基本信息'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-authorized'); } }, '被授权人信息'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-rental'); } }, '租赁订单信息'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-fee'); } }, '其他费用信息'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-billing'); } }, '账单计算方式'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-attachment'); } }, '盖章合同附件'),
React.createElement('button', { style: styles.anchorItem, onClick: function() { scrollToCard('card-history'); } }, '合同变更历史记录')
),
React.createElement('div', { id: 'card-customer' }, React.createElement(CardBlock, { id: 'card-customer', title: '客户基本信息', collapsed: cc1, setCollapsed: setCc1 }, customerFields)),
React.createElement('div', { id: 'card-contract', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '合同基本信息', collapsed: cc2, setCollapsed: setCc2 }, React.createElement('div', null, contractFormRow1, contractFormRow2))),
React.createElement('div', { id: 'card-authorized', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '被授权人信息', collapsed: cc3, setCollapsed: setCc3 }, authorizedContent)),
React.createElement('div', { id: 'card-rental', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '租赁订单信息', collapsed: cc4, setCollapsed: setCc4 }, rentalContent)),
React.createElement('div', { id: 'card-fee', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '其他费用信息', collapsed: cc5, setCollapsed: setCc5 }, feeContent)),
React.createElement('div', { id: 'card-billing', style: { marginTop: 16 } }, React.createElement(CardBlock, { title: '账单计算方式', collapsed: cc6, setCollapsed: setCc6 }, billingContent)),
React.createElement('div', { id: 'card-attachment', style: { marginTop: 16 } }, attachmentContent),
React.createElement('div', { id: 'card-history', style: { marginTop: 16 } }, changeHistoryContent),
React.createElement('div', { style: { height: 60 } }),
reqSpecModalContent,
React.createElement('div', { style: styles.footer }, React.createElement('button', { style: Object.assign({}, styles.btn, styles.btnDefault) }, '返回'))
);
};

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

591
web端/车辆管理.jsx Normal file

File diff suppressed because one or more lines are too long

BIN
web端/运维管理/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,938 @@
// 【重要】必须使用 const Component 作为组件变量名
// 车辆上牌管理 - 车辆资产管理后台模块
var ARCO_TOKEN = {
primary: '#165DFF',
primaryHover: '#4080FF',
danger: '#F53F3F',
success: '#00B42A',
neutral1: '#FFFFFF',
neutral2: '#F7F8FA',
neutral3: '#F2F3F5',
neutral4: '#E5E6EB',
neutral5: '#C9CDD4',
neutral6: '#86909C',
neutral7: '#4E5969',
neutral8: '#1D2129',
border: '#E5E6EB',
fill: '#F2F3F5',
fillSecondary: '#F7F8FA',
shadowLight: '0 1px 2px rgba(0,0,0,0.05)',
shadowMedium: '0 2px 8px rgba(0,0,0,0.08)',
radiusSmall: '2px',
radiusMedium: '4px',
radiusLarge: '8px',
spacing8: '8px',
spacing12: '12px',
spacing16: '16px',
spacing24: '24px',
fontSize14: '14px',
fontSize16: '16px',
fontFamily: '-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif',
link: '#165DFF'
};
const Component = function () {
var antd = window.antd;
var Input = antd.Input;
var Select = antd.Select;
var Button = antd.Button;
var DatePicker = antd.DatePicker;
var Table = antd.Table;
var Modal = antd.Modal;
var message = antd.message;
var Option = Select.Option;
var Spin = antd.Spin;
var _useState = React.useState('');
var filterDateStart = _useState[0];
var setFilterDateStart = _useState[1];
var _useState2 = React.useState('');
var filterDateEnd = _useState2[0];
var setFilterDateEnd = _useState2[1];
var _useState3 = React.useState('');
var filterOperator = _useState3[0];
var setFilterOperator = _useState3[1];
var _useState4 = React.useState('');
var filterPlateNo = _useState4[0];
var setFilterPlateNo = _useState4[1];
var _useState5 = React.useState('');
var filterVin = _useState5[0];
var setFilterVin = _useState5[1];
var _useState5h = React.useState('');
var appliedDateStart = _useState5h[0];
var setAppliedDateStart = _useState5h[1];
var _useState5i = React.useState('');
var appliedDateEnd = _useState5i[0];
var setAppliedDateEnd = _useState5i[1];
var _useState5j = React.useState('');
var appliedOperator = _useState5j[0];
var setAppliedOperator = _useState5j[1];
var _useState5k = React.useState('');
var appliedPlateNo = _useState5k[0];
var setAppliedPlateNo = _useState5k[1];
var _useState5l = React.useState('');
var appliedVin = _useState5l[0];
var setAppliedVin = _useState5l[1];
var _useState6 = React.useState(1);
var currentPage = _useState6[0];
var setCurrentPage = _useState6[1];
var _useState7 = React.useState(10);
var pageSize = _useState7[0];
var setPageSize = _useState7[1];
var _useState9 = React.useState(null);
var viewPhotoRecord = _useState9[0];
var setViewPhotoRecord = _useState9[1];
var _useState10 = React.useState(false);
var ocrModalVisible = _useState10[0];
var setOcrModalVisible = _useState10[1];
var _useState11 = React.useState(false);
var confirmModalVisible = _useState11[0];
var setConfirmModalVisible = _useState11[1];
var _useState12 = React.useState(null);
var confirmData = _useState12[0];
var setConfirmData = _useState12[1];
var _useState13 = React.useState([]);
var batchConfirmList = _useState13[0];
var setBatchConfirmList = _useState13[1];
var _useState14 = React.useState(0);
var batchConfirmIndex = _useState14[0];
var setBatchConfirmIndex = _useState14[1];
var _useState15 = React.useState(false);
var isBatchMode = _useState15[0];
var setIsBatchMode = _useState15[1];
var _useState15b = React.useState(0);
var batchTotalCount = _useState15b[0];
var setBatchTotalCount = _useState15b[1];
var _useState16 = React.useState('');
var confirmVin = _useState16[0];
var setConfirmVin = _useState16[1];
var _useState17 = React.useState('');
var confirmPlateNo = _useState17[0];
var setConfirmPlateNo = _useState17[1];
var _useState17a = React.useState('');
var confirmScrapDate = _useState17a[0];
var setConfirmScrapDate = _useState17a[1];
var _useState17b = React.useState('');
var confirmInspectionExpiry = _useState17b[0];
var setConfirmInspectionExpiry = _useState17b[1];
var _useState18b = React.useState(false);
var showRequirementModal = _useState18b[0];
var setShowRequirementModal = _useState18b[1];
var _useState18c = React.useState(false);
var batchTaskCardVisible = _useState18c[0];
var setBatchTaskCardVisible = _useState18c[1];
var fileInputRef = React.useRef(null);
var batchFullListRef = React.useRef(null);
var batchUploadFromCardRef = React.useRef(false);
var batchFileInputRef = React.useRef(null);
var _useState18e = React.useState([]);
var batchTaskList = _useState18e[0];
var setBatchTaskList = _useState18e[1];
var mockVehicleList = [
{ id: 'v001', frameNo: 'LGW123456', brand: '比亚迪', model: '秦', vehicleType: '轿车' },
{ id: 'v002', frameNo: 'LGW789012', brand: '特斯拉', model: 'Model 3', vehicleType: '轿车' },
{ id: 'v003', frameNo: 'HZ111222', brand: '小鹏', model: 'P7', vehicleType: '轿车' }
];
var initialRecordList = [
{
id: 'r001',
plateDate: '2025-02-01',
operator: '张明',
plateNo: '粤A12345',
vin: 'LGW123456',
vehicleType: '轿车',
brand: '比亚迪',
model: '秦',
photoUrl: 'https://picsum.photos/300/200?random=1'
},
{
id: 'r002',
plateDate: '2025-02-03',
operator: '王芳',
plateNo: '粤A67890',
vin: 'LGW789012',
vehicleType: '轿车',
brand: '特斯拉',
model: 'Model 3',
photoUrl: 'https://picsum.photos/300/200?random=2'
}
];
// 近5条批量上牌任务时间、照片数量、完成进度进度100%时有 items 用于「识别」进入确认界面
var getInitialBatchTaskList = function () {
return [
{ id: 'bt1', createTime: '2025-02-12 10:30', photoCount: 3, progress: 100, items: [
{ photoUrl: 'https://picsum.photos/300/200?random=b1', vin: 'LGW123456', plateNo: '粤A11111', vehicle: mockVehicleList[0] },
{ photoUrl: 'https://picsum.photos/300/200?random=b2', vin: 'LGW789012', plateNo: '粤A22222', vehicle: mockVehicleList[1] },
{ photoUrl: 'https://picsum.photos/300/200?random=b3', vin: 'HZ111222', plateNo: '粤A33333', vehicle: mockVehicleList[2] }
]},
{ id: 'bt2', createTime: '2025-02-12 09:15', photoCount: 5, progress: 100, items: [
{ photoUrl: 'https://picsum.photos/300/200?random=b4', vin: 'LGW123456', plateNo: '粤A44444', vehicle: mockVehicleList[0] },
{ photoUrl: 'https://picsum.photos/300/200?random=b5', vin: 'LGW789012', plateNo: '粤A55555', vehicle: mockVehicleList[1] }
]},
{ id: 'bt3', createTime: '2025-02-11 16:20', photoCount: 4, progress: 80, items: null },
{ id: 'bt4', createTime: '2025-02-11 14:00', photoCount: 2, progress: 50, items: null },
{ id: 'bt5', createTime: '2025-02-10 11:30', photoCount: 6, progress: 30, items: null }
];
};
React.useEffect(function () {
setBatchTaskList(function (prev) {
if (prev.length === 0) return getInitialBatchTaskList();
return prev;
});
}, []);
var _useState18 = React.useState(initialRecordList);
var recordList = _useState18[0];
var setRecordList = _useState18[1];
var getUniqueOperators = function () {
var seen = {};
var list = [];
recordList.forEach(function (r) {
if (r.operator && !seen[r.operator]) {
seen[r.operator] = true;
list.push(r.operator);
}
});
return list.sort();
};
var getUniquePlateNos = function () {
var seen = {};
var list = [];
recordList.forEach(function (r) {
if (r.plateNo && !seen[r.plateNo]) {
seen[r.plateNo] = true;
list.push(r.plateNo);
}
});
return list.sort();
};
var getUniqueVins = function () {
var seen = {};
var list = [];
recordList.forEach(function (r) {
if (r.vin && !seen[r.vin]) {
seen[r.vin] = true;
list.push(r.vin);
}
});
mockVehicleList.forEach(function (v) {
if (v.frameNo && !seen[v.frameNo]) {
seen[v.frameNo] = true;
list.push(v.frameNo);
}
});
return list.sort();
};
var allOperators = getUniqueOperators();
var allPlateNos = getUniquePlateNos();
var allVins = getUniqueVins();
var getFilteredList = function () {
var list = recordList;
if (appliedDateStart) {
list = list.filter(function (r) { return r.plateDate >= appliedDateStart; });
}
if (appliedDateEnd) {
list = list.filter(function (r) { return r.plateDate <= appliedDateEnd; });
}
if (appliedOperator) {
list = list.filter(function (r) {
return r.operator && r.operator.indexOf(appliedOperator) >= 0;
});
}
if (appliedPlateNo) {
list = list.filter(function (r) {
return r.plateNo && r.plateNo.indexOf(appliedPlateNo) >= 0;
});
}
if (appliedVin) {
list = list.filter(function (r) {
return r.vin && r.vin.indexOf(appliedVin) >= 0;
});
}
return list;
};
var filteredList = getFilteredList();
var totalItems = filteredList.length;
var totalPages = Math.ceil(totalItems / pageSize) || 1;
var validPage = currentPage > totalPages && totalPages > 0 ? 1 : (currentPage < 1 ? 1 : currentPage);
var startIndex = (validPage - 1) * pageSize;
var endIndex = startIndex + pageSize;
var paginatedList = filteredList.slice(startIndex, endIndex);
var findVehicleByVin = function (vin) {
return mockVehicleList.find(function (v) { return v.frameNo === vin; });
};
var todayStr = function () {
var d = new Date();
var y = d.getFullYear();
var m = (d.getMonth() + 1).toString();
var day = d.getDate().toString();
if (m.length === 1) { m = '0' + m; }
if (day.length === 1) { day = '0' + day; }
return y + '-' + m + '-' + day;
};
var sampleScrapDates = ['2035-12-31', '2030-06-15', '2028-03-20'];
var sampleInspectionExpiries = ['2026-06', '2025-12', '2027-03'];
var getSampleScrapDate = function () { return sampleScrapDates[Math.floor(Math.random() * sampleScrapDates.length)]; };
var getSampleInspectionExpiry = function () { return sampleInspectionExpiries[Math.floor(Math.random() * sampleInspectionExpiries.length)]; };
var processFileAndGetItem = function (file, callback) {
var reader = new FileReader();
reader.onload = function () {
var photoUrl = reader.result;
var mockVin = mockVehicleList[0].frameNo;
var mockPlate = '粤A' + Math.floor(Math.random() * 90000 + 10000).toString();
var vehicle = findVehicleByVin(mockVin);
var item = {
photoUrl: photoUrl,
vin: mockVin,
plateNo: mockPlate,
vehicle: vehicle
};
callback(item);
};
reader.readAsDataURL(file);
};
var simulateOcrAndConfirm = function (items, isMulti) {
setOcrModalVisible(false);
if (isMulti && items.length > 1) {
batchFullListRef.current = items.slice();
setBatchConfirmList(items);
setBatchConfirmIndex(0);
setBatchTotalCount(items.length);
setConfirmData(items[0]);
setConfirmVin(items[0].vin);
setConfirmPlateNo(items[0].plateNo);
setConfirmScrapDate(getSampleScrapDate());
setConfirmInspectionExpiry(getSampleInspectionExpiry());
setConfirmModalVisible(true);
setIsBatchMode(true);
} else if (items.length > 0) {
setConfirmData(items[0]);
setConfirmVin(items[0].vin);
setConfirmPlateNo(items[0].plateNo);
setConfirmScrapDate(getSampleScrapDate());
setConfirmInspectionExpiry(getSampleInspectionExpiry());
setConfirmModalVisible(true);
setIsBatchMode(false);
}
};
var handleUpload = function (e, isBatch) {
var files = e.target.files;
if (!files || files.length === 0) return;
// 从批量上传弹框内「上传车牌」触发:不进入识别/确认页,只在弹框中新增一条识别任务
if (batchUploadFromCardRef.current) {
batchUploadFromCardRef.current = false;
var fileCount = files.length;
var collected = [];
var processed = 0;
var checkDone = function () {
processed = processed + 1;
if (processed === fileCount) {
var now = new Date();
var timeStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + ' ' + String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0');
setBatchTaskList(function (prev) {
var next = [{ id: 'bt' + Date.now(), createTime: timeStr, photoCount: collected.length, progress: 100, items: collected }].concat(prev);
return next.slice(0, 5);
});
}
};
for (var i = 0; i < fileCount; i++) {
(function (idx) {
processFileAndGetItem(files[idx], function (item) {
collected.push(item);
checkDone();
});
})(i);
}
e.target.value = '';
return;
}
setOcrModalVisible(true);
var fileCount = files.length;
var collected = [];
var processed = 0;
var checkDone = function () {
processed = processed + 1;
if (processed === fileCount) {
setTimeout(function () {
simulateOcrAndConfirm(collected, isBatch && collected.length > 1);
}, 1500);
}
};
for (var i = 0; i < fileCount; i++) {
(function (idx) {
processFileAndGetItem(files[idx], function (item) {
collected.push(item);
checkDone();
});
})(i);
}
e.target.value = '';
};
var handleConfirmSubmit = function () {
var vehicle = confirmData && confirmData.vehicle;
var newRecord = {
id: 'r' + Date.now(),
plateDate: todayStr(),
operator: '当前用户',
plateNo: confirmPlateNo,
vin: confirmVin,
vehicleType: vehicle ? vehicle.vehicleType : '轿车',
brand: vehicle ? vehicle.brand : '-',
model: vehicle ? vehicle.model : '-',
photoUrl: confirmData && confirmData.photoUrl ? confirmData.photoUrl : 'https://picsum.photos/300/200?random=' + Date.now()
};
var nextList = recordList.slice();
nextList.unshift(newRecord);
setRecordList(nextList);
message.success('车辆上牌成功');
if (isBatchMode && batchConfirmList.length > 1) {
var nextBatch = batchConfirmList.slice(1);
var nextItem = nextBatch[0];
setBatchConfirmList(nextBatch);
setBatchConfirmIndex(batchConfirmIndex + 1);
if (nextItem) {
setConfirmData(nextItem);
setConfirmVin(nextItem.vin);
setConfirmPlateNo(nextItem.plateNo);
setConfirmScrapDate(getSampleScrapDate());
setConfirmInspectionExpiry(getSampleInspectionExpiry());
} else {
var fullList = batchFullListRef.current;
if (fullList && fullList.length > 0) {
var now = new Date();
var timeStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + ' ' + String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0');
setBatchTaskList(function (prev) {
var next = [{ id: 'bt' + Date.now(), createTime: timeStr, photoCount: fullList.length, progress: 100, items: fullList }].concat(prev);
return next.slice(0, 5);
});
batchFullListRef.current = null;
}
setConfirmModalVisible(false);
setConfirmData(null);
setConfirmVin('');
setConfirmPlateNo('');
setConfirmScrapDate('');
setConfirmInspectionExpiry('');
setBatchConfirmList([]);
setBatchTotalCount(0);
setIsBatchMode(false);
}
} else {
setConfirmModalVisible(false);
setConfirmData(null);
setConfirmVin('');
setConfirmPlateNo('');
setConfirmScrapDate('');
setConfirmInspectionExpiry('');
setBatchConfirmList([]);
setBatchTotalCount(0);
setIsBatchMode(false);
}
};
var handleConfirmCancel = function () {
setConfirmModalVisible(false);
setConfirmData(null);
setConfirmVin('');
setConfirmPlateNo('');
setConfirmScrapDate('');
setConfirmInspectionExpiry('');
setBatchConfirmList([]);
setBatchConfirmIndex(0);
setBatchTotalCount(0);
setIsBatchMode(false);
};
var t = ARCO_TOKEN;
var styles = {
page: { padding: t.spacing24, fontFamily: t.fontFamily, backgroundColor: t.fill, minHeight: '100vh' },
breadcrumb: { marginBottom: t.spacing16, fontSize: t.fontSize14, color: t.neutral6, display: 'flex', alignItems: 'center', justifyContent: 'space-between' },
breadcrumbLeft: { display: 'flex', alignItems: 'center' },
breadcrumbLink: { color: t.link, textDecoration: 'none', marginRight: t.spacing8 },
breadcrumbCurrent: { color: t.neutral8 },
breadcrumbRight: { display: 'flex', alignItems: 'center' },
requirementLink: { color: t.link, textDecoration: 'none', fontSize: t.fontSize14, cursor: 'pointer' },
card: { backgroundColor: t.neutral1, borderRadius: t.radiusLarge, boxShadow: t.shadowLight, marginBottom: t.spacing16, padding: t.spacing16 },
filterRow: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: t.spacing12 },
filterRowRight: { display: 'flex', alignItems: 'center', gap: t.spacing8, marginLeft: 'auto' },
label: { marginRight: t.spacing8, fontSize: t.fontSize14, color: t.neutral8, whiteSpace: 'nowrap' },
input: { padding: '0 10px', height: '32px', width: '180px', borderRadius: '2px', border: '1px solid ' + t.border, fontSize: t.fontSize14, boxSizing: 'border-box' },
btn: { padding: t.spacing8 + ' ' + t.spacing16, borderRadius: t.radiusMedium, cursor: 'pointer', fontSize: t.fontSize14, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '6px', boxSizing: 'border-box' },
btnFixed: { width: '82px', height: '32px', padding: 0, borderRadius: '2px', lineHeight: '1' },
btnIcon: { width: '14px', height: '14px', flexShrink: 0, display: 'block' },
btnFillBlue: { backgroundColor: t.primary, color: t.neutral1, border: 'none' },
btnOutlineBlue: { backgroundColor: t.neutral1, color: t.primary, border: '1px solid ' + t.primary },
btnDefault: { backgroundColor: t.neutral1, color: t.neutral8, border: '1px solid ' + t.border },
btnSize82: { width: '82px', height: '32px', padding: 0, lineHeight: '1', boxSizing: 'border-box' },
toolbar: { display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: t.spacing12, marginBottom: t.spacing16 },
tableWrap: { overflowX: 'auto', backgroundColor: t.neutral1, borderRadius: t.radiusMedium, border: '1px solid ' + t.neutral4 },
table: { width: '100%', borderCollapse: 'separate', borderSpacing: 0, fontSize: t.fontSize14 },
th: { textAlign: 'left', padding: '12px 16px', backgroundColor: t.fillSecondary, borderBottom: '1px solid ' + t.neutral4, fontWeight: 600, color: t.neutral8, fontSize: t.fontSize14, whiteSpace: 'nowrap' },
td: { padding: '12px 16px', borderBottom: '1px solid ' + t.neutral4, color: t.neutral8, fontSize: t.fontSize14 },
pagination: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '16px', borderTop: '1px solid ' + t.neutral4, backgroundColor: t.neutral1 },
paginationLeft: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: t.fontSize14, color: t.neutral7 },
paginationRight: { display: 'flex', alignItems: 'center', gap: '8px' },
paginationSelect: { padding: '4px 8px', height: '28px', borderRadius: '2px', border: '1px solid ' + t.border, fontSize: t.fontSize14, backgroundColor: t.neutral1 },
paginationBtn: { minWidth: '28px', height: '28px', padding: '0 8px', borderRadius: '2px', border: '1px solid ' + t.border, backgroundColor: t.neutral1, color: t.neutral8, cursor: 'pointer', fontSize: t.fontSize14, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' },
paginationBtnActive: { backgroundColor: t.primary, color: t.neutral1, borderColor: t.primary },
paginationBtnDisabled: { opacity: 0.5, cursor: 'not-allowed' },
paginationInput: { width: '50px', height: '28px', padding: '0 8px', borderRadius: '2px', border: '1px solid ' + t.border, fontSize: t.fontSize14, textAlign: 'center' },
actionLink: { color: t.link, cursor: 'pointer', marginRight: t.spacing12, fontSize: t.fontSize14 },
modalMask: { position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.45)', zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center' },
modalBox: { backgroundColor: t.neutral1, borderRadius: t.radiusLarge, maxWidth: '90%', maxHeight: '90%', overflow: 'auto', padding: t.spacing24, minWidth: '500px', position: 'relative' },
modalTitle: { fontSize: t.fontSize16, fontWeight: 600, marginBottom: t.spacing16, color: t.neutral8 },
modalFooter: { marginTop: t.spacing24, display: 'flex', justifyContent: 'flex-end', gap: t.spacing8 },
toast: { position: 'fixed', top: t.spacing24, left: '50%', transform: 'translateX(-50%)', backgroundColor: 'rgba(0,0,0,0.75)', color: t.neutral1, padding: '10px 20px', borderRadius: t.radiusMedium, zIndex: 2000, fontSize: t.fontSize14 },
autocompleteWrap: { position: 'relative', width: '180px', display: 'inline-block' },
autocompletePanel: { position: 'absolute', left: 0, top: '100%', marginTop: '4px', backgroundColor: t.neutral1, borderRadius: t.radiusMedium, border: '1px solid ' + t.border, boxShadow: t.shadowMedium, zIndex: 100, minWidth: '100%', maxHeight: '200px', overflowY: 'auto' },
autocompleteOption: { padding: '8px 12px', fontSize: t.fontSize14, color: t.neutral8, cursor: 'pointer' },
autocompleteOptionHover: { backgroundColor: t.fill },
confirmCard: { display: 'flex', gap: t.spacing24, marginTop: t.spacing16 },
confirmPhoto: { flex: '0 0 300px', height: '200px', borderRadius: t.radiusMedium, overflow: 'hidden', backgroundColor: t.neutral3 },
confirmPhotoImg: { width: '100%', height: '100%', objectFit: 'cover' },
confirmForm: { flex: 1, display: 'flex', flexDirection: 'column', gap: t.spacing16 },
formLabel: { display: 'block', marginBottom: '6px', fontSize: t.fontSize14, color: t.neutral8 },
formInput: { padding: '8px 12px', height: '36px', borderRadius: t.radiusMedium, border: '1px solid ' + t.border, fontSize: t.fontSize14, width: '100%', boxSizing: 'border-box' },
photoViewModal: { maxWidth: '800px', textAlign: 'center' },
photoViewImg: { maxWidth: '100%', maxHeight: '70vh', borderRadius: t.radiusMedium },
modalCloseBtn: { position: 'absolute', right: t.spacing16, top: t.spacing16, width: '24px', height: '24px', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', borderRadius: t.radiusMedium, backgroundColor: 'transparent', border: 'none', color: t.neutral6, fontSize: '18px', lineHeight: '1', padding: 0 },
modalContent: { fontSize: t.fontSize14, color: t.neutral8, lineHeight: '1.6' },
requirementSection: { marginBottom: t.spacing16 },
requirementSectionTitle: { fontSize: t.fontSize16, fontWeight: 600, color: t.neutral8, marginBottom: t.spacing8 },
flowWrap: { marginTop: t.spacing8, marginBottom: t.spacing16 },
flowCol: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 0 },
flowArrow: { width: '2px', height: '20px', backgroundColor: t.neutral5 },
flowNodeOval: { padding: '8px 20px', borderRadius: '20px', border: '1px solid ' + t.neutral5, backgroundColor: t.neutral2, fontSize: t.fontSize14, color: t.neutral8 },
flowNodeRect: { padding: '8px 20px', border: '1px solid ' + t.neutral5, backgroundColor: t.neutral1, fontSize: t.fontSize14, color: t.neutral8 },
flowNodeDiamond: { padding: '10px 16px', border: '1px solid ' + t.neutral5, backgroundColor: t.fillSecondary, fontSize: t.fontSize14, color: t.neutral8, transform: 'rotate(0deg)', width: '140px', textAlign: 'center', boxSizing: 'border-box', clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)' },
flowNodeDiamondWrap: { padding: '8px 16px', border: '1px solid ' + t.neutral5, backgroundColor: t.fillSecondary, fontSize: t.fontSize14, color: t.neutral8, minWidth: '120px', textAlign: 'center' },
flowNodeToast: { padding: '8px 16px', borderRadius: '8px', border: '1px solid ' + t.neutral4, backgroundColor: t.neutral2, fontSize: t.fontSize14, color: t.neutral7 },
flowRow: { display: 'flex', alignItems: 'flex-start', justifyContent: 'center', gap: '24px', flexWrap: 'wrap' },
flowBranch: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 0 },
requirementItem: { marginBottom: t.spacing8, paddingLeft: t.spacing16 },
requirementSubItem: { marginBottom: t.spacing4, paddingLeft: t.spacing16, fontSize: t.fontSize14, color: t.neutral7 },
batchTaskCardHeader: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: t.spacing16 },
batchTaskTable: { width: '100%', borderCollapse: 'collapse', fontSize: t.fontSize14 },
batchTaskTh: { textAlign: 'left', padding: '10px 12px', borderBottom: '1px solid ' + t.neutral4, color: t.neutral7, fontWeight: 500 },
batchTaskTd: { padding: '10px 12px', borderBottom: '1px solid ' + t.neutral4, color: t.neutral8 },
progressWrap: { width: '120px', height: '8px', backgroundColor: t.neutral4, borderRadius: '4px', overflow: 'hidden' },
progressBar: { height: '100%', backgroundColor: t.primary, borderRadius: '4px', transition: 'width 0.2s' },
recognizeLink: { color: t.link, cursor: 'pointer', fontSize: t.fontSize14 },
dateRangeWrap: { position: 'relative', display: 'inline-block' },
dateRangeTrigger: { display: 'flex', alignItems: 'center', height: '32px', padding: '0 12px', border: '1px solid ' + t.border, borderRadius: '2px', backgroundColor: t.neutral1, cursor: 'pointer', minWidth: '280px', boxSizing: 'border-box' },
dateRangeTriggerFocused: { borderColor: t.primary, outline: 'none' },
dateRangeLabel: { display: 'flex', alignItems: 'center', gap: '6px', padding: '0 8px', height: '100%', fontSize: t.fontSize14, color: t.neutral8 },
dateRangeLabelActive: { backgroundColor: 'rgba(22,93,255,0.1)', color: t.primary, borderBottom: '2px solid ' + t.primary },
dateRangeLabelText: { whiteSpace: 'nowrap' },
dateRangeDash: { color: t.neutral5, margin: '0 4px', fontSize: t.fontSize14 },
dateRangeIcon: { marginLeft: 'auto', width: '16px', height: '16px', color: t.neutral6, flexShrink: 0 },
dateRangePanel: { position: 'absolute', left: 0, top: '100%', marginTop: '4px', backgroundColor: t.neutral1, borderRadius: t.radiusMedium, border: '1px solid ' + t.border, boxShadow: t.shadowMedium, zIndex: 100, padding: '16px', display: 'flex', gap: '24px' },
dateRangeCalendar: { width: '280px' },
dateRangeCalendarHeader: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '12px', padding: '0 4px' },
dateRangeCalendarTitle: { fontSize: t.fontSize14, fontWeight: 500, color: t.neutral8 },
dateRangeCalendarNav: { display: 'flex', alignItems: 'center', gap: '4px' },
dateRangeNavBtn: { width: '28px', height: '28px', display: 'flex', alignItems: 'center', justifyContent: 'center', border: 'none', backgroundColor: 'transparent', color: t.neutral6, cursor: 'pointer', borderRadius: t.radiusSmall },
dateRangeNavBtnHover: { color: t.primary, backgroundColor: t.fill },
dateRangeWeekRow: { display: 'flex', marginBottom: '4px' },
dateRangeWeekCell: { width: '36px', height: '28px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '12px', color: t.neutral6 },
dateRangeDayRow: { display: 'flex' },
dateRangeDayCell: { width: '36px', height: '36px', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', fontSize: t.fontSize14, cursor: 'pointer', borderRadius: t.radiusSmall, color: t.neutral8 },
dateRangeDayCellOther: { color: t.neutral5 },
dateRangeDayCellSelected: { color: t.primary },
dateRangeDayCellInRange: { backgroundColor: 'rgba(22,93,255,0.08)', color: t.primary },
dateRangeDayDot: { width: '4px', height: '4px', borderRadius: '50%', backgroundColor: t.primary, marginTop: '2px' }
};
var renderFilterSelect = function (value, setValue, options, placeholder) {
var opts = (options || []).map(function (o) { return React.createElement(Option, { key: o, value: o }, o); });
return React.createElement(Select, {
placeholder: placeholder || '请选择或输入搜索',
style: { width: 180 },
value: value || undefined,
onChange: function (v) { setValue(v || ''); },
showSearch: true,
allowClear: true,
filterOption: function (input, opt) {
var c = opt && opt.children;
return c && String(c).toLowerCase().indexOf((input || '').toLowerCase()) >= 0;
}
}, opts);
};
return React.createElement(
'div',
{ style: styles.page },
React.createElement(
'div',
{ style: styles.breadcrumb },
React.createElement(
'div',
{ style: styles.breadcrumbLeft },
React.createElement('a', { href: '#', style: styles.breadcrumbLink, onClick: function (e) { e.preventDefault(); } }, '运维管理'),
React.createElement('span', { style: { marginRight: '8px' } }, '/'),
React.createElement('a', { href: '#', style: styles.breadcrumbLink, onClick: function (e) { e.preventDefault(); } }, '车辆业务'),
React.createElement('span', { style: { marginRight: '8px' } }, '/'),
React.createElement('span', { style: styles.breadcrumbCurrent }, '上牌管理')
),
React.createElement(
'div',
{ style: styles.breadcrumbRight },
React.createElement('a', { href: '#', style: styles.requirementLink, onClick: function (e) { e.preventDefault(); setShowRequirementModal(true); } }, '查看需求说明')
)
),
React.createElement(
'div',
{ style: styles.card },
React.createElement(
'div',
{ style: styles.filterRow },
React.createElement('span', { style: styles.label }, '上牌日期:'),
React.createElement(DatePicker, {
style: { width: 180 },
format: 'YYYY-MM-DD',
placeholder: '开始日期',
value: filterDateStart && window.moment ? window.moment(filterDateStart, 'YYYY-MM-DD') : null,
onChange: function (d, dateStr) { setFilterDateStart(dateStr || ''); }
}),
React.createElement('span', { style: { color: t.neutral6, margin: '0 4px' } }, '至'),
React.createElement(DatePicker, {
style: { width: 180 },
format: 'YYYY-MM-DD',
placeholder: '结束日期',
value: filterDateEnd && window.moment ? window.moment(filterDateEnd, 'YYYY-MM-DD') : null,
onChange: function (d, dateStr) { setFilterDateEnd(dateStr || ''); }
}),
React.createElement('span', { style: styles.label }, '操作人:'),
renderFilterSelect(filterOperator, setFilterOperator, allOperators, '请选择操作人'),
React.createElement('span', { style: styles.label }, '车牌号:'),
renderFilterSelect(filterPlateNo, setFilterPlateNo, allPlateNos, '请选择车牌号'),
React.createElement('span', { style: styles.label }, '车辆识别代码:'),
renderFilterSelect(filterVin, setFilterVin, allVins, '请选择车辆识别代码'),
React.createElement(
'div',
{ style: styles.filterRowRight },
React.createElement(Button, {
type: 'primary',
onClick: function () {
setAppliedDateStart(filterDateStart);
setAppliedDateEnd(filterDateEnd);
setAppliedOperator(filterOperator);
setAppliedPlateNo(filterPlateNo);
setAppliedVin(filterVin);
setCurrentPage(1);
message.success('查询成功');
}
}, '查询'),
React.createElement(Button, {
onClick: function () {
setFilterDateStart('');
setFilterDateEnd('');
setAppliedDateStart('');
setAppliedDateEnd('');
setFilterOperator('');
setFilterPlateNo('');
setFilterVin('');
setAppliedOperator('');
setAppliedPlateNo('');
setAppliedVin('');
setCurrentPage(1);
}
}, '重置')
)
)
),
React.createElement(
'div',
{ style: styles.card },
React.createElement(
'div',
{ style: styles.toolbar },
React.createElement('input', {
type: 'file',
ref: fileInputRef,
accept: 'image/*',
style: { display: 'none' },
onChange: function (e) { handleUpload(e, false); }
}),
React.createElement('input', {
type: 'file',
ref: batchFileInputRef,
accept: 'image/*',
multiple: true,
style: { display: 'none' },
onChange: function (e) { handleUpload(e, true); }
}),
React.createElement(Button, {
type: 'primary',
onClick: function () { if (fileInputRef.current) fileInputRef.current.click(); }
}, '新增'),
React.createElement(Button, {
onClick: function () { setBatchTaskCardVisible(true); }
}, '批量上传')
),
React.createElement(Table, {
rowKey: 'id',
size: 'small',
columns: [
{ title: '上牌日期', dataIndex: 'plateDate', key: 'plateDate', width: 120 },
{ title: '操作人', dataIndex: 'operator', key: 'operator', width: 100 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 120 },
{ title: '车辆识别代码', dataIndex: 'vin', key: 'vin', width: 140 },
{ title: '车辆类型', dataIndex: 'vehicleType', key: 'vehicleType', width: 100 },
{ title: '品牌', dataIndex: 'brand', key: 'brand', width: 100 },
{ title: '型号', dataIndex: 'model', key: 'model', width: 120 },
{ title: '操作', key: 'action', width: 80, render: function (_, row) { return React.createElement(Button, { type: 'link', size: 'small', onClick: function () { setViewPhotoRecord(row); } }, '查看'); } }
],
dataSource: paginatedList,
pagination: {
current: validPage,
pageSize: pageSize,
total: totalItems,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ['10', '20', '50', '100'],
showTotal: function (total) { return '共 ' + total + ' 条'; },
onChange: function (page, size) {
setCurrentPage(page);
if (size !== pageSize) setPageSize(size);
}
}
})
),
React.createElement(Modal, {
title: '识别中,请勿关闭页面',
visible: ocrModalVisible,
footer: null,
closable: false,
maskClosable: false,
children: React.createElement('div', { style: { padding: '24px 0', textAlign: 'center' } },
React.createElement(Spin, { size: 'large' }),
React.createElement('p', { style: { marginTop: 12, color: t.neutral6 } }, '正在识别行驶证信息...')
)
}),
React.createElement(Modal, {
title: isBatchMode && batchTotalCount > 1 ? '确认上牌信息(' + (batchTotalCount - batchConfirmList.length + 1) + '/' + batchTotalCount + '' : '确认上牌信息',
visible: confirmModalVisible && !!confirmData,
onCancel: handleConfirmCancel,
onOk: handleConfirmSubmit,
okText: '确认',
cancelText: '取消',
width: 560,
children: confirmData ? React.createElement(
'div',
{ style: styles.confirmCard },
React.createElement('div', { style: styles.confirmPhoto },
React.createElement('img', { src: confirmData.photoUrl, alt: '行驶证', style: styles.confirmPhotoImg })
),
React.createElement('div', { style: styles.confirmForm },
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('label', { style: styles.formLabel }, '车辆识别代号'),
React.createElement(Input, {
style: { width: '100%' },
value: confirmVin,
onChange: function (e) { setConfirmVin(e.target.value); }
})
),
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('label', { style: styles.formLabel }, '车牌号'),
React.createElement(Input, {
style: { width: '100%' },
value: confirmPlateNo,
onChange: function (e) { setConfirmPlateNo(e.target.value); }
})
),
React.createElement('div', { style: { marginBottom: 16 } },
React.createElement('label', { style: styles.formLabel }, '强制报废日期'),
React.createElement(Input, {
style: { width: '100%' },
placeholder: 'YYYY-MM-DD',
value: confirmScrapDate,
onChange: function (e) { setConfirmScrapDate(e.target.value); }
})
),
React.createElement('div', null,
React.createElement('label', { style: styles.formLabel }, '检验有效期'),
React.createElement(Input, {
style: { width: '100%' },
placeholder: 'YYYY-MM',
value: confirmInspectionExpiry,
onChange: function (e) { setConfirmInspectionExpiry(e.target.value); }
})
)
)
) : null
}),
React.createElement(Modal, {
title: '行驶证照片',
visible: !!viewPhotoRecord,
footer: React.createElement(Button, { onClick: function () { setViewPhotoRecord(null); } }, '关闭'),
onCancel: function () { setViewPhotoRecord(null); },
width: 640,
children: viewPhotoRecord ? React.createElement('img', { src: viewPhotoRecord.photoUrl, alt: '行驶证', style: Object.assign({}, styles.photoViewImg, { width: '100%' }) }) : null
}),
React.createElement(Modal, {
title: '批量上牌任务',
visible: batchTaskCardVisible,
onCancel: function () { setBatchTaskCardVisible(false); },
footer: React.createElement(Button, { onClick: function () { setBatchTaskCardVisible(false); } }, '关闭'),
width: 560,
children: React.createElement(React.Fragment, null,
React.createElement('div', { style: Object.assign({}, styles.batchTaskCardHeader, { marginBottom: 16 }) },
React.createElement(Button, {
type: 'primary',
onClick: function () {
batchUploadFromCardRef.current = true;
if (batchFileInputRef.current) batchFileInputRef.current.click();
}
}, '批量上传')
),
React.createElement(Table, {
rowKey: 'id',
size: 'small',
columns: [
{ title: '任务时间', dataIndex: 'createTime', key: 'createTime', width: 160 },
{ title: '照片数量', dataIndex: 'photoCount', key: 'photoCount', width: 100, render: function (c) { return c + ' 张'; } },
{ title: '完成进度', key: 'progress', width: 160, render: function (_, task) {
return React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
React.createElement('div', { style: styles.progressWrap },
React.createElement('div', { style: Object.assign({}, styles.progressBar, { width: (task.progress || 0) + '%' }) })
),
React.createElement('span', { style: { fontSize: t.fontSize14, color: t.neutral7, minWidth: 36 } }, (task.progress || 0) + '%')
);
} },
{ title: '操作', key: 'action', width: 80, render: function (_, task) {
return task.progress === 100 && task.items && task.items.length > 0
? React.createElement(Button, { type: 'link', size: 'small', onClick: function () {
setBatchConfirmList(task.items);
setBatchConfirmIndex(0);
setBatchTotalCount(task.items.length);
setConfirmData(task.items[0]);
setConfirmVin(task.items[0].vin);
setConfirmPlateNo(task.items[0].plateNo);
setConfirmScrapDate(getSampleScrapDate());
setConfirmInspectionExpiry(getSampleInspectionExpiry());
setConfirmModalVisible(true);
setIsBatchMode(true);
setBatchTaskCardVisible(false);
} }, '识别')
: React.createElement('span', { style: { color: t.neutral5, fontSize: t.fontSize14 } }, '-');
} }
],
dataSource: batchTaskList.slice(0, 5),
pagination: false
})
)
}),
React.createElement(Modal, {
title: '需求说明',
visible: showRequirementModal,
onCancel: function () { setShowRequirementModal(false); },
footer: React.createElement(Button, { onClick: function () { setShowRequirementModal(false); } }, '关闭'),
width: 720,
children: React.createElement('div', { style: styles.modalContent },
React.createElement('div', { style: Object.assign({}, styles.requirementSection, { marginBottom: t.spacing24 }) },
React.createElement('div', { style: Object.assign({}, styles.requirementSectionTitle, { fontSize: '18px', marginBottom: t.spacing12 }) }, '上牌管理'),
React.createElement('div', { style: Object.assign({}, styles.requirementItem, { marginTop: 0, color: t.neutral7 }) }, '用以识别行驶证正反面识别车架号、车牌号、强制报废日期YYYY-MM-DD、检验有效期YYYY-MM')
),
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '1.面包屑:'),
React.createElement('div', { style: styles.requirementItem }, '运维管理-车辆业务-上牌管理')
),
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '2.筛选:'),
React.createElement('div', { style: styles.requirementSubItem }, '2.1.上牌日期:双日历日期选择器,支持选择开始-结束时间,支持手动修改日期,但检验格式及判断结束日期不得早于开始日期;'),
React.createElement('div', { style: styles.requirementSubItem }, '2.2.操作人:选择器,支持从输入框输入内容模糊搜索,默认提示内容为:请选择操作人;'),
React.createElement('div', { style: styles.requirementSubItem }, '2.3.车牌号:选择器,支持从输入框输入内容模糊搜索,默认提示内容为:请选择车牌号;'),
React.createElement('div', { style: styles.requirementSubItem }, '2.4.车辆识别代码:选择器,支持从输入框输入内容模糊搜索,默认提示内容为:请选择车辆识别代码;')
),
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '3.列表:'),
React.createElement('div', { style: styles.requirementItem }, '列表右侧按钮为新增、批量上传,字段依次为上牌日期、操作人、车牌号、车辆识别代码、车辆类型、品牌、型号、操作;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.上牌日期车辆上牌操作完成日期格式为YYYY-MM-DD'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.操作人:车辆上牌记录操作用户姓名;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.3.车牌号显示上牌车牌号通过新增按钮上传行驶证照片后通过OCR识别技术自动识别出该车辆识别代号对应车牌号确认无误提交后自动反写'),
React.createElement('div', { style: styles.requirementSubItem }, '3.4.车辆识别代码:显示上牌车辆车辆识别代码;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.5.车辆类型:显示该车辆识别代码对应车辆类型;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.6.品牌:显示该车辆识别代码对应品牌;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.7.型号:显示该车辆识别代码对应型号;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.8.操作:行驶证,点击放大预览行驶证照片;'),
React.createElement('div', { style: styles.requirementItem }, '下方增加分页功能,支持选择单页数据条数;')
),
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '4.新增:'),
React.createElement('div', { style: styles.requirementSubItem }, '4.1.点击新增按钮上传行驶证照片附件上传后OCR识别过程中弹出卡片提示识别中请勿关闭页面如果照片识别失败则提示识别失败请重新尝试'),
React.createElement('div', { style: styles.requirementSubItem }, '4.2.上传成功后确认卡片中显示照片、车辆识别代码、车牌号、强制报废日期、检验有效期,可通过二次编辑进行校正;'),
React.createElement('div', { style: styles.requirementSubItem }, '4.3.点击卡片页面底部"确认"按钮确认根据车辆识别代码判断是否存在该车辆如果是则toast提示"上牌成功"并在列表中生成操作如果否则toast提示该车辆不存在。')
),
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '5.批量上传:'),
React.createElement('div', { style: styles.requirementItem }, '5.1.点击批量上牌按钮弹出批量上牌任务卡片再点击右上角上传车牌上传多张行驶证照片附件上传后弹出批量上牌任务卡片卡片中记录最近5条批量上牌任务任务字段为任务时间、照片数量、识别错误、完成进度、操作'),
React.createElement('div', { style: styles.requirementSubItem }, '5.1.1.任务时间上传批量照片的时间精确至分钟格式为YYYY-MM-DD HH:MM'),
React.createElement('div', { style: styles.requirementSubItem }, '5.1.2.照片数量:显示这一批照片总数;'),
React.createElement('div', { style: styles.requirementSubItem }, '5.1.3.识别错误显示识别失败的照片总数hover时气泡卡片显示识别失败的照片名称以;分隔;'),
React.createElement('div', { style: styles.requirementSubItem }, '5.1.4.完成进度显示ocr识别进度条和已完成百分比'),
React.createElement('div', { style: styles.requirementSubItem }, '5.1.5.操作:已完成任务操作栏显示识别,未完成任务操作栏显示-'),
React.createElement('div', { style: styles.requirementItem }, '5.2.识别:点击识别确认卡片中当前张数、显示照片、车辆识别代码、车牌号、强制报废日期、检验有效期,可通过二次编辑进行校正;当前张数显示在确认上牌信息标题右侧,格式为(当前/总计依次操作直到完成所有记录提交完成全部完成后toast提示批量上传成功'),
React.createElement('div', { style: styles.requirementItem }, '5.3.在识别确认卡片中点击确认后将立刻上传该照片,可再次通过点击批量上传拉取上传任务框的方式,自动跳转至最后一条上传记录进行操作;'),
React.createElement('div', { style: styles.requirementItem }, '5.4.批量上传任务中照片全部识别完成后,不再显示识别按钮;'),
React.createElement('div', { style: styles.requirementItem }, '5.5.具体识别流程请参考axure菜单目录中上牌管理下的流程图')
)
)
})
);
};
if (typeof window !== 'undefined') {
window.Component = Component;
function mount() {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', mount);
} else {
setTimeout(mount, 0);
}
}

View File

@@ -0,0 +1,538 @@
// 【重要】必须使用 const Component 作为组件变量名
// 车辆业务 - 交车管理ONEOS运管平台布局参照新增租赁合同
const Component = function () {
var useState = React.useState;
var useCallback = React.useCallback;
var useMemo = React.useMemo;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Card = antd.Card;
var DatePicker = antd.DatePicker;
var Select = antd.Select;
var Button = antd.Button;
var Tabs = antd.Tabs;
var Table = antd.Table;
var Popover = antd.Popover;
var Cascader = antd.Cascader;
var Modal = antd.Modal;
var message = antd.message;
var RangePicker = DatePicker.RangePicker;
var filterState = useState({
contractCode: undefined,
projectName: undefined,
customerName: undefined,
deliveryRegion: undefined,
dateStart: '',
dateEnd: '',
deliveryPerson: undefined
});
var filters = filterState[0];
var setFilters = filterState[1];
var appliedFilterState = useState({
contractCode: undefined,
projectName: undefined,
customerName: undefined,
deliveryRegion: undefined,
dateStart: '',
dateEnd: '',
deliveryPerson: undefined
});
var appliedFilters = appliedFilterState[0];
var setAppliedFilters = appliedFilterState[1];
var activeTabState = useState('pending');
var activeTab = activeTabState[0];
var setActiveTab = activeTabState[1];
var pageState = useState(1);
var pageSizeState = useState(10);
var requirementModalOpen = useState(false);
var setRequirementModalOpen = requirementModalOpen[1];
var requirementDocContent = '交车管理\n\n1.面包屑:\n1.1.运维管理-车辆业务-交车管理\n\n2.筛选:\n2.1.合同编码:选择器,默认为所有合同;提示信息为:请输入或选择合同编码,支持从输入框输入内容进行模糊搜索,下拉显示结果;\n2.2.项目名称:选择器,默认为所有项目;提示信息为:请输入或选择项目名称,支持从输入框输入内容进行模糊搜索,下拉显示结果;\n3.3.客户名称:选择器,默认为所有客户;提示信息为:请输入或选择客户名称,支持从输入框输入内容进行模糊搜索,下拉显示结果;\n3.4.交车区域:地区选择器,支持省-市2级筛选\n3.5.交车时间:日期选择器,默认提示信息为:请选择交车开始时间 请选择交车结束时间单输入框双日历支持时间段选择精确至天格式为YYYY-MM-DD - YYYY-MM-DD\n3.6.交车人:选择器,默认为所有交车人;提示信息为:请输入或选择交车人姓名,支持从输入框输入内容进行模糊搜索,下拉显示结果;\n3.7.查询:点击查询,根据单个或多个筛选条件(且)联动表格进行查询;\n3.8.重置:点击清空查询条件至默认;\n\n3.列表:\n分为两个tab待处理、历史记录\n3.1.待处理:显示以下字段:\n3.1.1.预计交车时间:支持单日及开始-结束日期两种方式格式为YYYY-MM-DD及YYYY-MM-DD至YYYY-MM-DD取自对应交车任务中预计交车时间\n3.1.2.任务发布时间显示交车任务单生成时间格式为YYYY-MM-DD HH:MM\n3.1.3.合同编码:显示租赁/自营合同编码;\n3.1.4.项目名称:显示租赁/自营合同项目名称;\n3.1.5.客户名称:显示租赁/自营合同客户名称;\n3.1.6.交车数量:显示交车数量,重点色显示,点击弹出气泡卡片,列表显示:车辆类型、品牌、型号、车牌号;\n 3.1.6.1.车辆类型:显示车辆类型;\n 3.1.6.2.品牌:显示车辆品牌;\n 3.1.6.3.型号:显示车辆型号;\n 3.1.6.4.车牌号:显示交车车辆车牌号,如果该车还未交车则显示为-\n3.1.7.交车区域:显示交车区域,交车区域来自车辆租赁合同-交车区域,格式为省-市;\n3.1.8.交车地点:显示交车地点,交车地点来自车辆租赁合同-交车地点,显示详细地址;\n3.1.9.操作:查看、交车;\n 3.1.8.1.交车:点击跳转交车单页面;\n\n3.2.历史记录:显示以下字段:\n3.2.1.预计交车时间:支持单日及开始-结束日期两种方式格式为YYYY-MM-DD及YYYY-MM-DD至YYYY-MM-DD取自对应交车任务中预计交车时间\n3.2.2.任务发布时间显示交车任务单生成时间格式为YYYY-MM-DD HH:MM\n3.2.3.交车完成时间显示交车单完成时间格式为YYYY-MM-DD HH:MM\n3.2.4.交车人:显示交车单最终提交用户;\n3.2.5.合同编码:显示租赁/自营合同编码;\n3.2.6.项目名称:显示租赁/自营合同项目名称;\n3.2.7.客户名称:显示租赁/自营合同客户名称;\n3.2.8.交车数量:显示交车数,重点色显示,点击弹出气泡卡片,列表显示:车辆类型、品牌、型号、车牌号、实际交车日期、交车人;\n 3.2.8.1.车辆类型:显示车辆类型;\n 3.2.8.2.品牌:显示车辆品牌;\n 3.2.8.3.型号:显示车辆型号;\n 3.2.8.4.车牌号:显示交车车辆车牌号,如果该车还未交车则显示为-\n 3.2.8.5.实际交车日期显示实际交车日期格式为YYYY-MM-DD如该车还未交车则显示为-\n 3.2.8.6.交车人:显示实际交车人用户姓名,如该车还未还车则显示为-\n3.2.9.交车区域:显示交车区域,交车区域来自车辆租赁合同-交车区域,格式为省-市;\n3.2.10.交车地点:显示交车地点,交车地点来自车辆租赁合同-交车地点,显示详细地址;\n3.2.11.操作:查看;\n 3.2.11.1.查看:点击跳转查看交车单页面;';
// 交车区域:省-市 二级
var regionOptions = [
{ value: 'zhejiang', label: '浙江省', children: [{ value: 'hangzhou', label: '杭州市' }, { value: 'jiaxing', label: '嘉兴市' }, { value: 'ningbo', label: '宁波市' }] },
{ value: 'shanghai', label: '上海市', children: [{ value: 'shanghai', label: '上海市' }] },
{ value: 'guangdong', label: '广东省', children: [{ value: 'guangzhou', label: '广州市' }, { value: 'shenzhen', label: '深圳市' }] }
];
var contractCodeOptions = [
{ value: 'HT-ZL-2025-001', label: 'HT-ZL-2025-001' },
{ value: 'HT-ZL-2025-002', label: 'HT-ZL-2025-002' },
{ value: 'HT-ZL-2025-003', label: 'HT-ZL-2025-003' }
];
var projectNameOptions = [
{ value: 'p1', label: '嘉兴氢能示范项目' },
{ value: 'p2', label: '上海物流租赁项目' },
{ value: 'p3', label: '杭州城配租赁项目' }
];
var customerNameOptions = [
{ value: 'c1', label: '嘉兴某某物流有限公司' },
{ value: 'c2', label: '上海某某运输公司' },
{ value: 'c3', label: '杭州某某租赁有限公司' }
];
var deliveryPersonOptions = [
{ value: '张三', label: '张三' },
{ value: '李四', label: '李四' },
{ value: '王五', label: '王五' }
];
// 待处理 mock10条样例
var pendingListState = useState([
{ id: 'd1', expectedDate: '2025-02-28', taskPublishTime: '2025-02-20 09:00', contractCode: 'HT-ZL-2025-001', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 2, vehicleList: [{ vehicleType: '厢式货车', brand: '东风', model: 'DFH1180', plateNo: '京A12345' }, { vehicleType: '平板货车', brand: '福田', model: 'BJ1180', plateNo: '-' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市南湖区科技大道1号' },
{ id: 'd2', expectedDate: '2025-03-01 至 2025-03-05', taskPublishTime: '2025-02-21 10:30', contractCode: 'HT-ZL-2025-002', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 1, vehicleList: [{ vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', plateNo: '-' }], deliveryRegion: '上海市-上海市', deliveryAddress: '浦东新区张江高科技园区' },
{ id: 'd3', expectedDate: '2025-02-25', taskPublishTime: '2025-02-18 14:00', contractCode: 'HT-ZL-2025-003', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 3, vehicleList: [{ vehicleType: '栏板货车', brand: '重汽', model: 'ZZ1180', plateNo: '浙A10001' }, { vehicleType: '厢式货车', brand: '东风', model: 'DFH1190', plateNo: '-' }, { vehicleType: '平板货车', brand: '福田', model: 'BJ1190', plateNo: '-' }], deliveryRegion: '浙江省-杭州市', deliveryAddress: '余杭区未来科技城' },
{ id: 'd4', expectedDate: '2025-03-08', taskPublishTime: '2025-02-25 08:15', contractCode: 'HT-ZL-2025-004', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, vehicleList: [{ vehicleType: '厢式货车', brand: '重汽', model: 'ZZ1160', plateNo: '-' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市秀洲区洪兴西路288号' },
{ id: 'd5', expectedDate: '2025-03-10 至 2025-03-12', taskPublishTime: '2025-02-26 11:20', contractCode: 'HT-ZL-2025-005', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 2, vehicleList: [{ vehicleType: '平板货车', brand: '福田', model: 'BJ1180', plateNo: '-' }, { vehicleType: '栏板货车', brand: '东风', model: 'DFH1160', plateNo: '-' }], deliveryRegion: '上海市-上海市', deliveryAddress: '闵行区莘庄工业区申富路669号' },
{ id: 'd6', expectedDate: '2025-03-15', taskPublishTime: '2025-03-01 09:30', contractCode: 'HT-ZL-2025-006', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 4, vehicleList: [{ vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', plateNo: '-' }, { vehicleType: '厢式货车', brand: '东风', model: 'DFH1180', plateNo: '-' }, { vehicleType: '平板货车', brand: '福田', model: 'BJ1190', plateNo: '-' }, { vehicleType: '栏板货车', brand: '重汽', model: 'ZZ1180', plateNo: '-' }], deliveryRegion: '浙江省-杭州市', deliveryAddress: '萧山区市心北路108号' },
{ id: 'd7', expectedDate: '2025-03-18', taskPublishTime: '2025-03-03 14:00', contractCode: 'HT-ZL-2025-007', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, vehicleList: [{ vehicleType: '平板货车', brand: '福田', model: 'BJ1180', plateNo: '浙F80088' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市经开区昌盛路1号' },
{ id: 'd8', expectedDate: '2025-03-20 至 2025-03-22', taskPublishTime: '2025-03-05 10:00', contractCode: 'HT-ZL-2025-008', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 3, vehicleList: [{ vehicleType: '厢式货车', brand: '江淮', model: 'HFC1190', plateNo: '-' }, { vehicleType: '栏板货车', brand: '重汽', model: 'ZZ1190', plateNo: '-' }, { vehicleType: '厢式货车', brand: '东风', model: 'DFH1190', plateNo: '-' }], deliveryRegion: '上海市-上海市', deliveryAddress: '宝山区沪太路5008号' },
{ id: 'd9', expectedDate: '2025-03-25', taskPublishTime: '2025-03-08 08:45', contractCode: 'HT-ZL-2025-009', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 2, vehicleList: [{ vehicleType: '栏板货车', brand: '东风', model: 'DFH1160', plateNo: '-' }, { vehicleType: '平板货车', brand: '福田', model: 'BJ1180', plateNo: '浙A20002' }], deliveryRegion: '浙江省-杭州市', deliveryAddress: '滨江区网商路699号' },
{ id: 'd10', expectedDate: '2025-03-28', taskPublishTime: '2025-03-10 16:20', contractCode: 'HT-ZL-2025-010', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, vehicleList: [{ vehicleType: '厢式货车', brand: '重汽', model: 'ZZ1180', plateNo: '-' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市南湖区广益路与由拳路交叉口' }
]);
var pendingList = pendingListState[0];
// 历史记录 mock10条样例含交车完成时间、交车人vehicleList 含实际交车日期、交车人)
var historyListState = useState([
{ id: 'h1', expectedDate: '2025-02-15', taskPublishTime: '2025-02-10 09:00', completeTime: '2025-02-15 14:30', deliveryPerson: '张三', contractCode: 'HT-ZL-2024-001', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 2, vehicleList: [{ vehicleType: '厢式货车', brand: '东风', model: 'DFH1180', plateNo: '京A12345', actualDate: '2025-02-15', deliveryPerson: '张三' }, { vehicleType: '平板货车', brand: '福田', model: 'BJ1180', plateNo: '京C11111', actualDate: '2025-02-15', deliveryPerson: '李四' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市南湖区科技大道1号' },
{ id: 'h2', expectedDate: '2025-02-10 至 2025-02-12', taskPublishTime: '2025-02-05 10:00', completeTime: '2025-02-12 11:00', deliveryPerson: '王五', contractCode: 'HT-ZL-2024-002', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 1, vehicleList: [{ vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', plateNo: '沪A20002', actualDate: '2025-02-11', deliveryPerson: '王五' }], deliveryRegion: '上海市-上海市', deliveryAddress: '浦东新区张江路100号' },
{ id: 'h3', expectedDate: '2025-02-18', taskPublishTime: '2025-02-12 08:30', completeTime: '2025-02-18 15:00', deliveryPerson: '张三', contractCode: 'HT-ZL-2024-003', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 3, vehicleList: [{ vehicleType: '栏板货车', brand: '重汽', model: 'ZZ1180', plateNo: '浙A10001', actualDate: '2025-02-18', deliveryPerson: '张三' }, { vehicleType: '厢式货车', brand: '东风', model: 'DFH1190', plateNo: '浙A10002', actualDate: '2025-02-18', deliveryPerson: '李四' }, { vehicleType: '平板货车', brand: '福田', model: 'BJ1190', plateNo: '浙A10003', actualDate: '2025-02-18', deliveryPerson: '王五' }], deliveryRegion: '浙江省-杭州市', deliveryAddress: '余杭区未来科技城' },
{ id: 'h4', expectedDate: '2025-02-20', taskPublishTime: '2025-02-14 11:00', completeTime: '2025-02-20 10:15', deliveryPerson: '李四', contractCode: 'HT-ZL-2024-004', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, vehicleList: [{ vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', plateNo: '浙F60001', actualDate: '2025-02-20', deliveryPerson: '李四' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市秀洲区洪兴西路288号' },
{ id: 'h5', expectedDate: '2025-02-22 至 2025-02-24', taskPublishTime: '2025-02-16 09:45', completeTime: '2025-02-24 16:30', deliveryPerson: '王五', contractCode: 'HT-ZL-2024-005', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 2, vehicleList: [{ vehicleType: '平板货车', brand: '福田', model: 'BJ1180', plateNo: '沪B30001', actualDate: '2025-02-23', deliveryPerson: '王五' }, { vehicleType: '栏板货车', brand: '东风', model: 'DFH1160', plateNo: '沪B30002', actualDate: '2025-02-24', deliveryPerson: '张三' }], deliveryRegion: '上海市-上海市', deliveryAddress: '闵行区莘庄工业区申富路669号' },
{ id: 'h6', expectedDate: '2025-02-25', taskPublishTime: '2025-02-18 14:20', completeTime: '2025-02-25 11:00', deliveryPerson: '张三', contractCode: 'HT-ZL-2024-006', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 1, vehicleList: [{ vehicleType: '厢式货车', brand: '重汽', model: 'ZZ1160', plateNo: '浙A40001', actualDate: '2025-02-25', deliveryPerson: '张三' }], deliveryRegion: '浙江省-杭州市', deliveryAddress: '萧山区市心北路108号' },
{ id: 'h7', expectedDate: '2025-02-28', taskPublishTime: '2025-02-20 10:10', completeTime: '2025-02-28 14:45', deliveryPerson: '李四', contractCode: 'HT-ZL-2024-007', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 2, vehicleList: [{ vehicleType: '厢式货车', brand: '东风', model: 'DFH1180', plateNo: '浙F70001', actualDate: '2025-02-28', deliveryPerson: '李四' }, { vehicleType: '平板货车', brand: '福田', model: 'BJ1180', plateNo: '浙F70002', actualDate: '2025-02-28', deliveryPerson: '王五' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市经开区昌盛路1号' },
{ id: 'h8', expectedDate: '2025-03-02', taskPublishTime: '2025-02-22 08:00', completeTime: '2025-03-02 09:30', deliveryPerson: '王五', contractCode: 'HT-ZL-2024-008', projectName: '上海物流租赁项目', customerName: '上海某某运输公司', deliveryCount: 1, vehicleList: [{ vehicleType: '栏板货车', brand: '江淮', model: 'HFC1160', plateNo: '沪A50001', actualDate: '2025-03-02', deliveryPerson: '王五' }], deliveryRegion: '上海市-上海市', deliveryAddress: '宝山区沪太路5008号' },
{ id: 'h9', expectedDate: '2025-03-05 至 2025-03-07', taskPublishTime: '2025-02-25 15:30', completeTime: '2025-03-07 13:20', deliveryPerson: '张三', contractCode: 'HT-ZL-2024-009', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', deliveryCount: 2, vehicleList: [{ vehicleType: '厢式货车', brand: '江淮', model: 'HFC1190', plateNo: '浙A60001', actualDate: '2025-03-06', deliveryPerson: '张三' }, { vehicleType: '栏板货车', brand: '重汽', model: 'ZZ1190', plateNo: '浙A60002', actualDate: '2025-03-07', deliveryPerson: '李四' }], deliveryRegion: '浙江省-杭州市', deliveryAddress: '滨江区网商路699号' },
{ id: 'h10', expectedDate: '2025-03-10', taskPublishTime: '2025-03-01 11:00', completeTime: '2025-03-10 10:00', deliveryPerson: '李四', contractCode: 'HT-ZL-2024-010', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', deliveryCount: 1, vehicleList: [{ vehicleType: '平板货车', brand: '福田', model: 'BJ1190', plateNo: '浙F90001', actualDate: '2025-03-10', deliveryPerson: '李四' }], deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴市南湖区广益路与由拳路交叉口' }
]);
var historyList = historyListState[0];
var filteredPending = useMemo(function () {
var list = pendingList.slice();
if (appliedFilters.contractCode) list = list.filter(function (r) { return (r.contractCode || '').indexOf(appliedFilters.contractCode) !== -1; });
if (appliedFilters.projectName) list = list.filter(function (r) { return r.projectName === appliedFilters.projectName; });
if (appliedFilters.customerName) list = list.filter(function (r) { return r.customerName === appliedFilters.customerName; });
if (appliedFilters.deliveryRegion) list = list.filter(function (r) { return (r.deliveryRegion || '').indexOf(appliedFilters.deliveryRegion) !== -1; });
if (appliedFilters.dateStart) list = list.filter(function (r) { var d = (r.expectedDate || '').slice(0, 10); return d >= appliedFilters.dateStart; });
if (appliedFilters.dateEnd) list = list.filter(function (r) { var d = (r.expectedDate || '').slice(0, 10); return d <= appliedFilters.dateEnd; });
return list;
}, [pendingList, appliedFilters]);
var filteredHistory = useMemo(function () {
var list = historyList.slice();
if (appliedFilters.contractCode) list = list.filter(function (r) { return (r.contractCode || '').indexOf(appliedFilters.contractCode) !== -1; });
if (appliedFilters.projectName) list = list.filter(function (r) { return r.projectName === appliedFilters.projectName; });
if (appliedFilters.customerName) list = list.filter(function (r) { return r.customerName === appliedFilters.customerName; });
if (appliedFilters.deliveryRegion) list = list.filter(function (r) { return (r.deliveryRegion || '').indexOf(appliedFilters.deliveryRegion) !== -1; });
if (appliedFilters.dateStart) list = list.filter(function (r) { var d = (r.completeTime || '').slice(0, 10); return d >= appliedFilters.dateStart; });
if (appliedFilters.dateEnd) list = list.filter(function (r) { var d = (r.completeTime || '').slice(0, 10); return d <= appliedFilters.dateEnd; });
if (appliedFilters.deliveryPerson) list = list.filter(function (r) { return (r.deliveryPerson || '').indexOf(appliedFilters.deliveryPerson) !== -1; });
return list;
}, [historyList, appliedFilters]);
var page = pageState[0];
var setPage = pageState[1];
var pageSize = pageSizeState[0];
var setPageSize = pageSizeState[1];
var totalCount = activeTab === 'pending' ? filteredPending.length : filteredHistory.length;
var displayPending = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredPending.slice(start, start + pageSize);
}, [filteredPending, page, pageSize]);
var displayHistory = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredHistory.slice(start, start + pageSize);
}, [filteredHistory, page, pageSize]);
var handleQuery = useCallback(function () {
var regionVal = filters.deliveryRegion;
if (Array.isArray(regionVal) && regionVal.length >= 2) {
var prov = regionOptions.find(function (r) { return r.value === regionVal[0]; });
var city = prov && prov.children && prov.children.find(function (c) { return c.value === regionVal[1]; });
regionVal = prov && city ? prov.label + '-' + city.label : undefined;
} else if (Array.isArray(regionVal) && regionVal.length === 1) {
var p = regionOptions.find(function (r) { return r.value === regionVal[0]; });
regionVal = p ? p.label : undefined;
}
setAppliedFilters({
contractCode: filters.contractCode,
projectName: filters.projectName,
customerName: filters.customerName,
deliveryRegion: regionVal,
dateStart: filters.dateStart,
dateEnd: filters.dateEnd,
deliveryPerson: filters.deliveryPerson
});
setPage(1);
}, [filters]);
var handleReset = useCallback(function () {
var empty = { contractCode: undefined, projectName: undefined, customerName: undefined, deliveryRegion: undefined, dateStart: '', dateEnd: '', deliveryPerson: undefined };
setFilters(empty);
setAppliedFilters(empty);
setPage(1);
}, []);
var handleExport = useCallback(function () {
var rows = activeTab === 'pending' ? filteredPending : filteredHistory;
if (!rows || rows.length === 0) {
message.warning('当前无数据可导出');
return;
}
var escapeCsv = function (v) {
var s = v == null ? '' : String(v);
if (s.indexOf(',') !== -1 || s.indexOf('"') !== -1 || s.indexOf('\n') !== -1) return '"' + s.replace(/"/g, '""') + '"';
return s;
};
var headers;
var rowToCells = function (r) {
if (activeTab === 'pending') {
return [r.expectedDate, r.taskPublishTime, r.contractCode, r.projectName, r.customerName, r.deliveryCount, r.deliveryRegion, r.deliveryAddress];
}
return [r.expectedDate, r.taskPublishTime, r.completeTime, r.deliveryPerson, r.contractCode, r.projectName, r.customerName, r.deliveryCount, r.deliveryRegion, r.deliveryAddress];
};
if (activeTab === 'pending') {
headers = ['预计交车时间', '任务发布时间', '合同编码', '项目名称', '客户名称', '交车数量', '交车区域', '交车地点'];
} else {
headers = ['预计交车时间', '任务发布时间', '交车完成时间', '交车人', '合同编码', '项目名称', '客户名称', '交车数量', '交车区域', '交车地点'];
}
var csv = headers.map(escapeCsv).join(',') + '\n';
rows.forEach(function (r) {
csv += rowToCells(r).map(escapeCsv).join(',') + '\n';
});
var blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = '交车管理_' + (activeTab === 'pending' ? '待处理' : '历史记录') + '_' + new Date().getTime() + '.csv';
a.click();
URL.revokeObjectURL(url);
message.success('导出成功');
}, [activeTab, filteredPending, filteredHistory]);
var dateRangeValue = useMemo(function () {
if (!filters.dateStart && !filters.dateEnd) return null;
try {
if (typeof window !== 'undefined' && window.dayjs && filters.dateStart && filters.dateEnd) {
return [window.dayjs(filters.dateStart), window.dayjs(filters.dateEnd)];
}
} catch (e) {}
return null;
}, [filters.dateStart, filters.dateEnd]);
var onDateRangeChange = useCallback(function (dates, dateStrings) {
setFilters(function (f) {
var g = {}; for (var k in f) g[k] = f[k];
g.dateStart = (dateStrings && dateStrings[0]) || '';
g.dateEnd = (dateStrings && dateStrings[1]) || '';
return g;
});
}, []);
// 交车区域 Cascader 的 value用 appliedFilters 反推或存 value 数组。筛选用字符串比较,表单用 Cascader 选省-市
var deliveryRegionValue = useMemo(function () {
var s = filters.deliveryRegion;
if (!s || typeof s !== 'string') return undefined;
var parts = s.split('-');
if (parts.length < 2) return undefined;
for (var i = 0; i < regionOptions.length; i++) {
var prov = regionOptions[i];
if (prov.label !== parts[0]) continue;
for (var j = 0; j < (prov.children || []).length; j++) {
if (prov.children[j].label === parts[1]) return [prov.value, prov.children[j].value];
}
}
return undefined;
}, [filters.deliveryRegion]);
// 列表列:待处理
var popoverTableStyle = { width: '100%', borderCollapse: 'collapse', fontSize: 12 };
var popoverThStyle = { padding: '6px 8px', textAlign: 'left', borderBottom: '1px solid #f0f0f0', backgroundColor: '#fafafa', fontWeight: 600 };
var popoverTdStyle = { padding: '6px 8px', borderBottom: '1px solid #f0f0f0' };
function renderPendingQuantity(record) {
var list = record.vehicleList || [];
var content = React.createElement('div', { style: { padding: 8, minWidth: 320 } },
React.createElement('div', { style: { marginBottom: 8, fontWeight: 600 } }, '车辆明细'),
React.createElement('table', { style: popoverTableStyle },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: popoverThStyle }, '车辆类型'),
React.createElement('th', { style: popoverThStyle }, '品牌'),
React.createElement('th', { style: popoverThStyle }, '型号'),
React.createElement('th', { style: popoverThStyle }, '车牌号')
)
),
React.createElement('tbody', null,
list.map(function (v, i) {
return React.createElement('tr', { key: i },
React.createElement('td', { style: popoverTdStyle }, v.vehicleType || '-'),
React.createElement('td', { style: popoverTdStyle }, v.brand || '-'),
React.createElement('td', { style: popoverTdStyle }, v.model || '-'),
React.createElement('td', { style: popoverTdStyle }, v.plateNo || '-')
);
})
)
)
);
return React.createElement(Popover, { content: content, title: null },
React.createElement('span', { style: { color: '#1890ff', cursor: 'pointer', fontWeight: 600 } }, record.deliveryCount + ' 辆')
);
}
function renderHistoryQuantity(record) {
var list = record.vehicleList || [];
var content = React.createElement('div', { style: { padding: 8, minWidth: 420 } },
React.createElement('div', { style: { marginBottom: 8, fontWeight: 600 } }, '车辆明细'),
React.createElement('table', { style: popoverTableStyle },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', { style: popoverThStyle }, '车辆类型'),
React.createElement('th', { style: popoverThStyle }, '品牌'),
React.createElement('th', { style: popoverThStyle }, '型号'),
React.createElement('th', { style: popoverThStyle }, '车牌号'),
React.createElement('th', { style: popoverThStyle }, '实际交车日期'),
React.createElement('th', { style: popoverThStyle }, '交车人')
)
),
React.createElement('tbody', null,
list.map(function (v, i) {
return React.createElement('tr', { key: i },
React.createElement('td', { style: popoverTdStyle }, v.vehicleType || '-'),
React.createElement('td', { style: popoverTdStyle }, v.brand || '-'),
React.createElement('td', { style: popoverTdStyle }, v.model || '-'),
React.createElement('td', { style: popoverTdStyle }, v.plateNo || '-'),
React.createElement('td', { style: popoverTdStyle }, v.actualDate || '-'),
React.createElement('td', { style: popoverTdStyle }, v.deliveryPerson || '-')
);
})
)
)
);
return React.createElement(Popover, { content: content, title: null },
React.createElement('span', { style: { color: '#1890ff', cursor: 'pointer', fontWeight: 600 } }, record.deliveryCount + ' 辆')
);
}
var pendingColumns = [
{ title: '预计交车时间', dataIndex: 'expectedDate', key: 'expectedDate', width: 260, ellipsis: true },
{ title: '任务发布时间', dataIndex: 'taskPublishTime', key: 'taskPublishTime', width: 160, ellipsis: true },
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 160, ellipsis: true },
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 160, ellipsis: true },
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 180, ellipsis: true },
{ title: '交车数量', key: 'deliveryCount', width: 100, render: function (_, r) { return renderPendingQuantity(r); } },
{ title: '交车区域', dataIndex: 'deliveryRegion', key: 'deliveryRegion', width: 130, ellipsis: true },
{ title: '交车地点', dataIndex: 'deliveryAddress', key: 'deliveryAddress', width: 220, ellipsis: true },
{ title: '操作', key: 'action', width: 80, fixed: 'right', render: function (_, r) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () { message.info('跳转查看交车单'); } }, '查看');
} }
];
var historyColumns = [
{ title: '预计交车时间', dataIndex: 'expectedDate', key: 'expectedDate', width: 260, ellipsis: true },
{ title: '任务发布时间', dataIndex: 'taskPublishTime', key: 'taskPublishTime', width: 160, ellipsis: true },
{ title: '交车完成时间', dataIndex: 'completeTime', key: 'completeTime', width: 160, ellipsis: true },
{ title: '交车人', dataIndex: 'deliveryPerson', key: 'deliveryPerson', width: 100, ellipsis: true },
{ title: '合同编码', dataIndex: 'contractCode', key: 'contractCode', width: 160, ellipsis: true },
{ title: '项目名称', dataIndex: 'projectName', key: 'projectName', width: 160, ellipsis: true },
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 180, ellipsis: true },
{ title: '交车数量', key: 'deliveryCount', width: 100, render: function (_, r) { return renderHistoryQuantity(r); } },
{ title: '交车区域', dataIndex: 'deliveryRegion', key: 'deliveryRegion', width: 130, ellipsis: true },
{ title: '交车地点', dataIndex: 'deliveryAddress', key: 'deliveryAddress', width: 220, ellipsis: true },
{ title: '操作', key: 'action', width: 80, fixed: 'right', render: function () {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () { message.info('跳转查看交车单页面'); } }, '查看');
} }
];
var tablePagination = useMemo(function () {
return {
current: page,
pageSize: pageSize,
total: totalCount,
showSizeChanger: true,
showTotal: function (t) { return '共 ' + t + ' 条'; },
pageSizeOptions: ['10', '20', '50'],
onChange: function (p, size) { setPage(p); if (size !== pageSize) setPageSize(size); }
};
}, [page, pageSize, totalCount]);
var styles = {
page: { padding: '16px 24px 48px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardBody: { padding: '20px 24px' },
formRow: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '16px 24px', alignItems: 'start' },
formItem: { marginBottom: 4 },
formLabel: { display: 'block', marginBottom: 4, color: '#333' }
};
var breadcrumbItems = [
{ title: '运维管理' },
{ title: '车辆业务' },
{ title: '交车管理' }
];
return React.createElement('div', { style: styles.page },
React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } },
React.createElement(Breadcrumb, { items: breadcrumbItems }),
React.createElement(Button, { type: 'link', onClick: function () { setRequirementModalOpen(true); } }, '查看需求说明')
),
React.createElement(Card, { style: { marginBottom: 16 } },
React.createElement('div', { style: styles.cardBody },
React.createElement('div', { style: styles.formRow },
React.createElement('div', null,
React.createElement('div', { style: styles.formLabel }, '合同编码'),
React.createElement(Select, {
placeholder: '请输入或选择合同编码',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.contractCode,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.contractCode = v; return g; }); },
style: { width: '100%' },
options: contractCodeOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: styles.formLabel }, '项目名称'),
React.createElement(Select, {
placeholder: '请输入或选择项目名称',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.projectName,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.projectName = v; return g; }); },
style: { width: '100%' },
options: projectNameOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: styles.formLabel }, '客户名称'),
React.createElement(Select, {
placeholder: '请输入或选择客户名称',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.customerName,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.customerName = v; return g; }); },
style: { width: '100%' },
options: customerNameOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: styles.formLabel }, '交车区域'),
React.createElement(Cascader, {
options: regionOptions,
placeholder: '请选择省-市',
allowClear: true,
style: { width: '100%' },
value: deliveryRegionValue,
onChange: function (value) {
var s;
if (value && value.length >= 2) {
var prov = regionOptions.find(function (r) { return r.value === value[0]; });
var city = prov && prov.children && prov.children.find(function (c) { return c.value === value[1]; });
s = prov && city ? prov.label + '-' + city.label : undefined;
} else { s = undefined; }
setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.deliveryRegion = s; return g; });
},
displayRender: function (labels) { return labels && labels.length ? labels.join(' / ') : ''; }
})
),
React.createElement('div', null,
React.createElement('div', { style: styles.formLabel }, '交车时间'),
React.createElement(RangePicker, {
style: { width: '100%' },
placeholder: ['请选择交车开始时间', '请选择交车结束时间'],
value: dateRangeValue,
onChange: onDateRangeChange
})
),
React.createElement('div', null,
React.createElement('div', { style: styles.formLabel }, '交车人'),
React.createElement(Select, {
placeholder: '请输入或选择交车人姓名',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.deliveryPerson,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.deliveryPerson = v; return g; }); },
style: { width: '100%' },
options: deliveryPersonOptions
})
)
),
React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 16 } },
React.createElement(Button, { onClick: handleReset }, '重置'),
React.createElement(Button, { type: 'primary', onClick: handleQuery }, '查询')
)
)
),
React.createElement(Card, null,
React.createElement(Tabs, {
activeKey: activeTab,
onChange: function (k) { setActiveTab(k); setPage(1); },
tabBarExtraContent: React.createElement(Button, { onClick: handleExport }, '导出'),
items: [
{
key: 'pending',
label: '待处理',
children: React.createElement(Table, {
columns: pendingColumns,
dataSource: displayPending,
rowKey: 'id',
pagination: tablePagination,
scroll: { x: 1490 },
size: 'middle'
})
},
{
key: 'history',
label: '历史记录',
children: React.createElement(Table, {
columns: historyColumns,
dataSource: displayHistory,
rowKey: 'id',
pagination: tablePagination,
scroll: { x: 1650 },
size: 'middle'
})
}
]
})
),
React.createElement(Modal, {
title: '需求说明',
open: requirementModalOpen[0],
onCancel: function () { setRequirementModalOpen(false); },
footer: React.createElement(Button, { onClick: function () { setRequirementModalOpen(false); } }, '关闭'),
width: 640,
destroyOnClose: true
}, React.createElement('div', { style: { maxHeight: 560, overflowY: 'auto', whiteSpace: 'pre-wrap', lineHeight: 1.6, fontSize: 13 } }, requirementDocContent))
);
};
if (typeof window !== 'undefined') {
window.Component = Component;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
});
} else {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
}

View File

@@ -0,0 +1,481 @@
// 【重要】必须使用 const Component 作为组件变量名
// 后装设备 - 运维管理-车辆业务
var ARCO_TOKEN = {
primary: '#165DFF',
primaryHover: '#4080FF',
danger: '#F53F3F',
success: '#00B42A',
neutral1: '#FFFFFF',
neutral2: '#F7F8FA',
neutral3: '#F2F3F5',
neutral4: '#E5E6EB',
neutral5: '#C9CDD4',
neutral6: '#86909C',
neutral7: '#4E5969',
neutral8: '#1D2129',
border: '#E5E6EB',
fill: '#F2F3F5',
fillSecondary: '#F7F8FA',
shadowLight: '0 1px 2px rgba(0,0,0,0.05)',
radiusMedium: '4px',
radiusLarge: '8px',
spacing8: '8px',
spacing12: '12px',
spacing16: '16px',
spacing24: '24px',
fontSize14: '14px',
fontSize16: '16px',
fontFamily: '-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif',
link: '#165DFF'
};
var DEVICE_TYPES = ['GPS', '尾板', '车身广告', 'G7安全套件', 'G7普通设备', 'G7温控设备', '备胎'];
var MOCK_VEHICLE_OPTIONS = ['粤A12345', '粤A67890', '粤B11111', '粤B22222', '粤C33333', '京A88888'];
var MOCK_LIST = [
{ id: '1', deviceType: 'GPS', plateNo: '粤A12345', supplier: '深圳智联', lastOpType: '安装', createTime: '2025-02-20 10:30', removeTime: '', createOperator: '张明', removeOperator: '' },
{ id: '2', deviceType: '尾板', plateNo: '粤A67890', supplier: '广州机械', lastOpType: '拆除', createTime: '2025-02-01 09:00', removeTime: '2025-02-18 14:20', createOperator: '李强', removeOperator: '王芳' },
{ id: '3', deviceType: '车身广告', plateNo: '粤B11111', supplier: '东莞广告', lastOpType: '安装', createTime: '2025-02-15 09:00', removeTime: '', createOperator: '李强', removeOperator: '' },
{ id: '4', deviceType: 'G7安全套件', plateNo: '粤A12345', supplier: 'G7科技', lastOpType: '安装', createTime: '2025-02-10 16:45', removeTime: '', createOperator: '张明', removeOperator: '' },
{ id: '5', deviceType: '备胎', plateNo: '粤C33333', supplier: '华南轮胎', lastOpType: '拆除', createTime: '2025-01-20 08:00', removeTime: '2025-02-08 11:20', createOperator: '赵六', removeOperator: '赵六' }
];
const Component = function () {
var antd = window.antd;
var Select = antd.Select;
var Button = antd.Button;
var DatePicker = antd.DatePicker;
var Table = antd.Table;
var Modal = antd.Modal;
var Input = antd.Input;
var message = antd.message;
var Option = Select.Option;
var RangePicker = DatePicker.RangePicker;
var Tabs = antd.Tabs;
var _useStateTab = React.useState('installed');
var activeTab = _useStateTab[0];
var setActiveTab = _useStateTab[1];
var _useState = React.useState('');
var filterDeviceType = _useState[0];
var setFilterDeviceType = _useState[1];
var _useState2 = React.useState('');
var filterVehicle = _useState2[0];
var setFilterVehicle = _useState2[1];
var _useState3 = React.useState([]);
var filterDateRange = _useState3[0];
var setFilterDateRange = _useState3[1];
var _useState4 = React.useState({ deviceType: '', vehicle: '', dateStart: '', dateEnd: '' });
var appliedFilter = _useState4[0];
var setAppliedFilter = _useState4[1];
var _useState5 = React.useState(1);
var currentPage = _useState5[0];
var setCurrentPage = _useState5[1];
var _useState6 = React.useState(10);
var pageSize = _useState6[0];
var setPageSize = _useState6[1];
var _useState7 = React.useState(MOCK_LIST);
var dataList = _useState7[0];
var setDataList = _useState7[1];
var _useState8 = React.useState(null);
var viewRecord = _useState8[0];
var setViewRecord = _useState8[1];
var _useState9 = React.useState(null);
var editRecord = _useState9[0];
var setEditRecord = _useState9[1];
var _useState10 = React.useState(null);
var removeConfirmRecord = _useState10[0];
var setRemoveConfirmRecord = _useState10[1];
var _useState11 = React.useState(false);
var addModalVisible = _useState11[0];
var setAddModalVisible = _useState11[1];
var _useState12 = React.useState(false);
var showRequirementModal = _useState12[0];
var setShowRequirementModal = _useState12[1];
var applyBaseFilter = function (list) {
if (appliedFilter.deviceType) {
list = list.filter(function (r) { return r.deviceType === appliedFilter.deviceType; });
}
if (appliedFilter.vehicle) {
list = list.filter(function (r) { return r.plateNo && r.plateNo.indexOf(appliedFilter.vehicle) >= 0; });
}
return list;
};
var installedList = dataList.filter(function (r) { return !r.removeTime || r.removeTime === ''; });
var removedList = dataList.filter(function (r) { return r.removeTime && r.removeTime !== ''; });
var installedFiltered = applyBaseFilter(installedList).filter(function (r) {
if (appliedFilter.dateStart && r.createTime) { if (r.createTime.slice(0, 10) < appliedFilter.dateStart) return false; }
if (appliedFilter.dateEnd && r.createTime) { if (r.createTime.slice(0, 10) > appliedFilter.dateEnd) return false; }
return true;
});
var removedFiltered = applyBaseFilter(removedList).filter(function (r) {
if (appliedFilter.dateStart && r.removeTime) { if (r.removeTime.slice(0, 10) < appliedFilter.dateStart) return false; }
if (appliedFilter.dateEnd && r.removeTime) { if (r.removeTime.slice(0, 10) > appliedFilter.dateEnd) return false; }
return true;
});
var filteredList = activeTab === 'installed' ? installedFiltered : removedFiltered;
var totalItems = filteredList.length;
var totalPages = Math.ceil(totalItems / pageSize) || 1;
var validPage = currentPage > totalPages && totalPages > 0 ? 1 : (currentPage < 1 ? 1 : currentPage);
var startIndex = (validPage - 1) * pageSize;
var paginatedList = filteredList.slice(startIndex, startIndex + pageSize);
var handleQuery = function () {
var dateStart = '';
var dateEnd = '';
if (filterDateRange && filterDateRange.length >= 2 && filterDateRange[0] && filterDateRange[1]) {
if (filterDateRange[0].format) {
dateStart = filterDateRange[0].format('YYYY-MM-DD');
dateEnd = filterDateRange[1].format('YYYY-MM-DD');
} else if (window.dayjs) {
dateStart = window.dayjs(filterDateRange[0]).format('YYYY-MM-DD');
dateEnd = window.dayjs(filterDateRange[1]).format('YYYY-MM-DD');
}
}
setAppliedFilter({
deviceType: filterDeviceType,
vehicle: filterVehicle,
dateStart: dateStart,
dateEnd: dateEnd
});
setCurrentPage(1);
message.success('查询成功');
};
var handleReset = function () {
setFilterDeviceType('');
setFilterVehicle('');
setFilterDateRange([]);
setAppliedFilter({ deviceType: '', vehicle: '', dateStart: '', dateEnd: '' });
setCurrentPage(1);
};
var handleRemoveConfirm = function (row) {
var nowStr = '2025-02-24 15:00';
if (window.dayjs) { nowStr = window.dayjs().format('YYYY-MM-DD HH:mm'); }
setDataList(dataList.map(function (r) {
if (r.id === row.id) {
return { id: r.id, deviceType: r.deviceType, plateNo: r.plateNo, supplier: r.supplier, lastOpType: '拆除', createTime: r.createTime, removeTime: nowStr, createOperator: r.createOperator, removeOperator: '当前用户' };
}
return r;
}));
setRemoveConfirmRecord(null);
message.success('拆除成功');
};
var t = ARCO_TOKEN;
var styles = {
page: { padding: t.spacing24, fontFamily: t.fontFamily, backgroundColor: t.fill, minHeight: '100vh' },
breadcrumb: { marginBottom: t.spacing16, fontSize: t.fontSize14, color: t.neutral6, display: 'flex', alignItems: 'center', justifyContent: 'space-between' },
breadcrumbLeft: { display: 'flex', alignItems: 'center' },
breadcrumbLink: { color: t.link, textDecoration: 'none', marginRight: '8px' },
breadcrumbCurrent: { color: t.neutral8 },
requirementLink: { color: t.link, textDecoration: 'none', fontSize: t.fontSize14, cursor: 'pointer' },
modalContent: { fontSize: t.fontSize14, color: t.neutral8, lineHeight: 1.6 },
requirementSection: { marginBottom: t.spacing16 },
requirementSectionTitle: { fontSize: t.fontSize16, fontWeight: 600, color: t.neutral8, marginBottom: 8 },
requirementItem: { marginBottom: 8, paddingLeft: 16 },
requirementSubItem: { marginBottom: 4, paddingLeft: 16, color: t.neutral7 },
card: { backgroundColor: t.neutral1, borderRadius: t.radiusLarge, boxShadow: t.shadowLight, marginBottom: t.spacing16, padding: t.spacing16 },
filterRow: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: t.spacing12 },
label: { marginRight: t.spacing8, fontSize: t.fontSize14, color: t.neutral8, whiteSpace: 'nowrap' },
filterRight: { marginLeft: 'auto', display: 'flex', gap: t.spacing8 },
toolbar: { display: 'flex', justifyContent: 'flex-end', gap: t.spacing12, marginBottom: t.spacing8 }
};
var deviceTypeOptions = DEVICE_TYPES.map(function (type) {
return React.createElement(Option, { key: type, value: type }, type);
});
var vehicleOptions = MOCK_VEHICLE_OPTIONS.map(function (v) {
return React.createElement(Option, { key: v, value: v }, v);
});
return React.createElement(
'div',
{ style: styles.page },
React.createElement(
'div',
{ style: styles.breadcrumb },
React.createElement('div', { style: styles.breadcrumbLeft },
React.createElement('a', { href: '#', style: styles.breadcrumbLink, onClick: function (e) { e.preventDefault(); } }, '运维管理'),
React.createElement('span', { style: { marginRight: '8px' } }, '/'),
React.createElement('a', { href: '#', style: styles.breadcrumbLink, onClick: function (e) { e.preventDefault(); } }, '车辆业务'),
React.createElement('span', { style: { marginRight: '8px' } }, '/'),
React.createElement('span', { style: styles.breadcrumbCurrent }, '后装设备')
),
React.createElement('a', { href: '#', style: styles.requirementLink, onClick: function (e) { e.preventDefault(); setShowRequirementModal(true); } }, '查看需求说明')
),
React.createElement(
'div',
{ style: styles.card },
React.createElement(
'div',
{ style: styles.filterRow },
React.createElement('span', { style: styles.label }, '设备类型:'),
React.createElement(Select, {
placeholder: '请选择设备类型',
style: { width: 160 },
value: filterDeviceType || undefined,
onChange: function (v) { setFilterDeviceType(v || ''); },
allowClear: true
}, deviceTypeOptions),
React.createElement('span', { style: styles.label }, '使用车辆:'),
React.createElement(Select, {
placeholder: '请选择或输入搜索',
style: { width: 180 },
value: filterVehicle || undefined,
onChange: function (v) { setFilterVehicle(v || ''); },
showSearch: true,
allowClear: true,
filterOption: function (input, opt) {
var c = opt && opt.children;
return c && String(c).toLowerCase().indexOf((input || '').toLowerCase()) >= 0;
}
}, vehicleOptions),
React.createElement('span', { style: styles.label }, '安装时间:'),
React.createElement(RangePicker, {
style: { width: 260 },
format: 'YYYY-MM-DD',
placeholder: ['开始日期', '结束日期'],
value: filterDateRange,
onChange: function (dates) { setFilterDateRange(dates || []); }
}),
React.createElement('div', { style: styles.filterRight },
React.createElement(Button, { type: 'primary', onClick: handleQuery }, '查询'),
React.createElement(Button, { onClick: handleReset }, '重置')
)
)
),
React.createElement(
'div',
{ style: styles.card },
React.createElement(
'div',
{ style: styles.toolbar },
activeTab === 'installed' && React.createElement(Button, { type: 'primary', onClick: function () { message.info('请查看运维管理-车辆业务-后装设备-新增后装设备'); } }, '新增'),
React.createElement(Button, { onClick: function () { message.info('根据筛选条件导出excel'); } }, '导出')
),
React.createElement(Tabs, {
activeKey: activeTab,
onChange: function (key) { setActiveTab(key); setCurrentPage(1); },
items: [
{
key: 'installed',
label: '已安装',
children: React.createElement(Table, {
rowKey: 'id',
size: 'small',
columns: [
{ title: '设备类型', dataIndex: 'deviceType', key: 'deviceType', width: 120 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 120 },
{ title: '供应商', dataIndex: 'supplier', key: 'supplier', width: 120 },
{ title: '安装时间', dataIndex: 'createTime', key: 'createTime', width: 160 },
{ title: '安装人', dataIndex: 'createOperator', key: 'createOperator', width: 100 },
{
title: '操作',
key: 'action',
width: 160,
render: function (_, row) {
return React.createElement(React.Fragment, null,
React.createElement(Button, { type: 'link', size: 'small', onClick: function () { message.info('请查看运维管理-车辆业务-后装设备-查看'); } }, '查看'),
React.createElement(Button, { type: 'link', size: 'small', onClick: function () { message.info('请查看运维管理-车辆业务-后装设备-编辑'); } }, '编辑'),
React.createElement(Button, { type: 'link', size: 'small', danger: true, onClick: function () { setRemoveConfirmRecord(row); } }, '拆除')
);
}
}
],
dataSource: paginatedList,
pagination: {
current: validPage,
pageSize: pageSize,
total: totalItems,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ['10', '20', '50', '100'],
showTotal: function (total) { return '共 ' + total + ' 条'; },
onChange: function (page, size) {
setCurrentPage(page);
if (size !== pageSize) setPageSize(size);
}
}
})
},
{
key: 'removed',
label: '拆除记录',
children: React.createElement(Table, {
rowKey: 'id',
size: 'small',
columns: [
{ title: '设备类型', dataIndex: 'deviceType', key: 'deviceType', width: 120 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 120 },
{ title: '供应商', dataIndex: 'supplier', key: 'supplier', width: 120 },
{ title: '拆除时间', dataIndex: 'removeTime', key: 'removeTime', width: 160 },
{ title: '拆除人', dataIndex: 'removeOperator', key: 'removeOperator', width: 100 },
{
title: '操作',
key: 'action',
width: 80,
render: function (_, row) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () { message.info('请查看运维管理-车辆业务-后装设备-查看'); } }, '查看');
}
}
],
dataSource: paginatedList,
pagination: {
current: validPage,
pageSize: pageSize,
total: totalItems,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ['10', '20', '50', '100'],
showTotal: function (total) { return '共 ' + total + ' 条'; },
onChange: function (page, size) {
setCurrentPage(page);
if (size !== pageSize) setPageSize(size);
}
}
})
}
]
})
),
viewRecord && React.createElement(Modal, {
title: '查看后装设备',
open: !!viewRecord,
onCancel: function () { setViewRecord(null); },
footer: React.createElement(Button, { onClick: function () { setViewRecord(null); } }, '关闭'),
width: 520,
children: viewRecord ? React.createElement('div', { style: { lineHeight: '2' } },
React.createElement('div', null, '设备类型:', viewRecord.deviceType),
React.createElement('div', null, '车牌号:', viewRecord.plateNo),
React.createElement('div', null, '供应商:', viewRecord.supplier),
React.createElement('div', null, '安装时间:', viewRecord.createTime || '-'),
React.createElement('div', null, '安装人:', viewRecord.createOperator || '-'),
React.createElement('div', null, '拆除时间:', viewRecord.removeTime || '-'),
React.createElement('div', null, '拆除人:', viewRecord.removeOperator || '-')
) : null
}),
editRecord && React.createElement(Modal, {
title: '编辑后装设备',
open: !!editRecord,
onCancel: function () { setEditRecord(null); },
onOk: function () {
setEditRecord(null);
message.success('保存成功');
},
okText: '保存',
cancelText: '取消',
width: 520,
children: editRecord ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 16 } },
React.createElement('div', null, React.createElement('span', { style: styles.label }, '设备类型'), React.createElement(Select, { style: { width: '100%' }, value: editRecord.deviceType, options: DEVICE_TYPES.map(function (d) { return { label: d, value: d }; }) })),
React.createElement('div', null, React.createElement('span', { style: styles.label }, '车牌号'), React.createElement(Input, { style: { width: '100%' }, value: editRecord.plateNo, readOnly: true })),
React.createElement('div', null, React.createElement('span', { style: styles.label }, '供应商'), React.createElement(Input, { style: { width: '100%' }, defaultValue: editRecord.supplier }))
) : null
}),
removeConfirmRecord && React.createElement(Modal, {
title: '确认拆除',
open: !!removeConfirmRecord,
onCancel: function () { setRemoveConfirmRecord(null); },
onOk: function () { handleRemoveConfirm(removeConfirmRecord); },
okText: '确认拆除',
cancelText: '取消',
okButtonProps: { danger: true },
children: removeConfirmRecord ? React.createElement('div', null, '确定要拆除该车辆「', removeConfirmRecord.deviceType, '」后装设备吗?') : null
}),
React.createElement(Modal, {
title: '需求说明',
open: showRequirementModal,
onCancel: function () { setShowRequirementModal(false); },
footer: React.createElement(Button, { onClick: function () { setShowRequirementModal(false); } }, '关闭'),
width: 720,
children: React.createElement('div', { style: styles.modalContent },
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '1. 面包屑:'),
React.createElement('div', { style: styles.requirementItem }, '1.1. 运维管理-车辆业务-后装设备')
),
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '2. 筛选:'),
React.createElement('div', { style: styles.requirementItem }, '2.1. 支持通过设备类型、使用车辆、安装日期进行管理,点击查询后,筛选条件与列表内容联动。点击重置会回到默认筛选条件并在列表展示结果:'),
React.createElement('div', { style: styles.requirementSubItem }, '2.1.1. 设备类型选择器包括GPS、尾板、车身广告、G7安全套件、G7普通设备、G7温控设备、备胎'),
React.createElement('div', { style: styles.requirementSubItem }, '2.1.2. 使用车辆:选择器,支持通过输入框对输入内容模糊搜索,并下拉对应选项;'),
React.createElement('div', { style: styles.requirementSubItem }, '2.1.3. 安装时间:日期选择器,支持单输入框内双日历选择开始-结束时间;')
),
React.createElement('div', { style: styles.requirementSection },
React.createElement('div', { style: styles.requirementSectionTitle }, '3. 列表:'),
React.createElement('div', { style: styles.requirementItem }, '列表分为2个tab已安装/拆除记录;'),
React.createElement('div', { style: styles.requirementItem }, '当已安装列表对应车辆存在车身广告/尾板时,在备车时会自动拉取车身广告/尾板为有的状态;'),
React.createElement('div', { style: styles.requirementItem }, '当已安装列表不存在车身广告/尾板时,在备车时车身广告/尾板为无的状态;'),
React.createElement('div', { style: styles.requirementItem }, '如果在备车/交车时手动取消或勾选车身广告尾板,并完成提交,后装设备列表也会新增一条该车辆的车身广告/尾板安装数据;'),
React.createElement('div', { style: styles.requirementSectionTitle }, '3.1. 已安装:'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.1. 列表展示所有后装设备信息,字段依次为:设备类型、车牌号、供应商、安装时间、安装人、操作;列表右上角为新增、导出;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.1.1. 设备类型显示后装设备类型包括GPS、尾板、车身广告、G7安全套件、G7普通设备、G7温控设备、备胎'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.1.2. 车牌号:显示后装设备对应车牌号信息;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.1.3. 供应商:显示后装设备供应商信息;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.1.4. 安装时间显示后装设备安装时间格式为YYYY-MM-DD HH:MM'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.1.5. 安装人:显示后装设备安装用户名称;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.1.1.6. 操作:支持查看、编辑、拆除;'),
React.createElement('div', { style: styles.requirementSectionTitle }, '3.2. 拆除记录:'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.1. 列表展示所有后装设备拆除记录,字段依次为:设备类型、车牌号、供应商、拆除时间、拆除人、操作;列表右上角为新增、导出;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.1.1. 设备类型显示后装设备类型包括GPS、尾板、车身广告、G7安全套件、G7普通设备、G7温控设备、备胎'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.1.2. 车牌号:显示后装设备对应车牌号信息;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.1.3. 供应商:显示后装设备供应商信息;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.1.4. 拆除时间显示后装设备拆除时间格式为YYYY-MM-DD HH:MM'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.1.5. 拆除人:显示后装设备拆除用户名称;'),
React.createElement('div', { style: styles.requirementSubItem }, '3.2.1.6. 操作:支持查看;')
)
)
}),
addModalVisible && React.createElement(Modal, {
title: '新增后装设备',
open: addModalVisible,
onCancel: function () { setAddModalVisible(false); },
onOk: function () {
setDataList([{ id: String(Date.now()), deviceType: 'GPS', plateNo: '粤A12345', supplier: '新供应商', lastOpType: '安装', createTime: '2025-02-24 12:00', removeTime: '', createOperator: '当前用户', removeOperator: '' }].concat(dataList));
setAddModalVisible(false);
message.success('新增成功');
},
okText: '确定',
cancelText: '取消',
width: 520,
children: React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 16 } },
React.createElement('div', null, React.createElement('span', { style: styles.label }, '设备类型'), React.createElement(Select, { style: { width: '100%' }, placeholder: '请选择', options: DEVICE_TYPES.map(function (d) { return { label: d, value: d }; }) })),
React.createElement('div', null, React.createElement('span', { style: styles.label }, '使用车辆'), React.createElement(Select, { style: { width: '100%' }, placeholder: '请选择或搜索', showSearch: true, options: MOCK_VEHICLE_OPTIONS.map(function (v) { return { label: v, value: v }; }) })),
React.createElement('div', null, React.createElement('span', { style: styles.label }, '供应商'), React.createElement(Input, { style: { width: '100%' }, placeholder: '请输入供应商' }))
)
})
);
};
if (typeof window !== 'undefined') {
window.Component = Component;
function mount() {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', mount);
} else {
setTimeout(mount, 0);
}
}

View File

@@ -0,0 +1,652 @@
// 【重要】必须使用 const Component 作为组件变量名
// 备车管理 - 车辆资产管理后台(按 antd 规范)
const Component = function () {
var useState = React.useState;
var useCallback = React.useCallback;
var useMemo = React.useMemo;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Card = antd.Card;
var DatePicker = antd.DatePicker;
var Select = antd.Select;
var Button = antd.Button;
var Tabs = antd.Tabs;
var Table = antd.Table;
var Modal = antd.Modal;
var Steps = antd.Steps;
var Input = antd.Input;
var Radio = antd.Radio;
var Space = antd.Space;
var Row = antd.Row;
var Col = antd.Col;
var message = antd.message;
var RangePicker = DatePicker.RangePicker;
// 当前视图:'list' | 'add'
var viewState = useState('list');
var currentView = viewState[0];
var setCurrentView = viewState[1];
var filterState = useState({
dateStart: '',
dateEnd: '',
operator: undefined,
plateNo: undefined,
vehicleType: undefined,
parkingLot: undefined
});
var filters = filterState[0];
var setFilters = filterState[1];
// 实际参与列表筛选的条件(点击查询后与 filters 同步)
var appliedFilterState = useState({
dateStart: '',
dateEnd: '',
operator: undefined,
plateNo: undefined,
vehicleType: undefined,
parkingLot: undefined
});
var appliedFilters = appliedFilterState[0];
var setAppliedFilters = appliedFilterState[1];
var activeTabState = useState('completed');
var activeTab = activeTabState[0];
var setActiveTab = activeTabState[1];
var defaultInspection = [{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '灯光', checkItem: '尾灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '轮胎', checkItem: '前左胎', result: '正常', treadDepth: '5.2mm', remark: '' }, { checkType: '车身', checkItem: '车身外观', result: '正常', treadDepth: '', remark: '' }];
var completedListState = useState([
{ id: '1', completeDate: '2025-02-10 09:30', operator: '张三', vehicleType: '厢式货车', plateNo: '京A12345', brand: '东风', model: 'DFH1180', vin: 'LGHXCAE28M1234567', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 3, adPhotos: ['https://picsum.photos/200/150?random=1', 'https://picsum.photos/200/150?random=2', 'https://picsum.photos/200/150?random=3'], tailboard: '有', hasTrailer: '有', trailerPlate: '京B67890', flawPhotoCount: 2, flawPhotos: ['https://picsum.photos/200/150?random=4', 'https://picsum.photos/200/150?random=5'], inspectionList: [{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '灯光', checkItem: '尾灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '轮胎', checkItem: '前左胎', result: '正常', treadDepth: '5.2mm', remark: '' }, { checkType: '车身', checkItem: '车身外观', result: '异常', treadDepth: '', remark: '有划痕' }] },
{ id: '2', completeDate: '2025-02-09 10:15', operator: '李四', vehicleType: '平板货车', plateNo: '京C11111', brand: '福田', model: 'BJ1180', vin: 'LGHXCAE28M7654321', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=6'], inspectionList: [{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' }, { checkType: '轮胎', checkItem: '前左胎', result: '异常', treadDepth: '3.1mm', remark: '需更换' }] },
{ id: '3', completeDate: '2025-02-08 11:00', operator: '王五', vehicleType: '厢式货车', plateNo: '京D22222', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M8888888', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=7', 'https://picsum.photos/200/150?random=8'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '4', completeDate: '2025-02-07 13:45', operator: '赵六', vehicleType: '栏板货车', plateNo: '京E33333', brand: '重汽', model: 'ZZ1180', vin: 'LGHXCAE28M7777777', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '有', trailerPlate: '京E33334', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=9'], inspectionList: defaultInspection },
{ id: '5', completeDate: '2025-02-06 08:20', operator: '张三', vehicleType: '平板货车', plateNo: '京A23456', brand: '东风', model: 'DFH1190', vin: 'LGHXCAE28M6666666', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 1, adPhotos: ['https://picsum.photos/200/150?random=10'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '6', completeDate: '2025-02-05 14:30', operator: '李四', vehicleType: '厢式货车', plateNo: '京B34567', brand: '福田', model: 'BJ1190', vin: 'LGHXCAE28M5555555', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 2, flawPhotos: ['https://picsum.photos/200/150?random=11', 'https://picsum.photos/200/150?random=12'], inspectionList: defaultInspection },
{ id: '7', completeDate: '2025-02-04 16:00', operator: '王五', vehicleType: '栏板货车', plateNo: '京C45678', brand: '江淮', model: 'HFC1190', vin: 'LGHXCAE28M4444444', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=13', 'https://picsum.photos/200/150?random=14'], tailboard: '有', hasTrailer: '有', trailerPlate: '京C45679', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '8', completeDate: '2025-02-03 09:00', operator: '赵六', vehicleType: '厢式货车', plateNo: '京D56789', brand: '重汽', model: 'ZZ1190', vin: 'LGHXCAE28M3333333', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=15'], inspectionList: defaultInspection },
{ id: '9', completeDate: '2025-02-02 10:30', operator: '张三', vehicleType: '平板货车', plateNo: '京E67890', brand: '东风', model: 'DFH1200', vin: 'LGHXCAE28M2222222', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 3, adPhotos: ['https://picsum.photos/200/150?random=16', 'https://picsum.photos/200/150?random=17', 'https://picsum.photos/200/150?random=18'], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection },
{ id: '10', completeDate: '2025-02-01 15:45', operator: '李四', vehicleType: '厢式货车', plateNo: '京A78901', brand: '福田', model: 'BJ1200', vin: 'LGHXCAE28M1111111', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '有', hasTrailer: '有', trailerPlate: '京A78902', flawPhotoCount: 0, flawPhotos: [], inspectionList: defaultInspection }
]);
var completedList = completedListState[0];
var setCompletedList = completedListState[1];
var pendingListState = useState([
{ id: 'p1', operateDate: '2025-02-10 14:30', operator: '王五', vehicleType: '厢式货车', plateNo: '京F10001', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M9990001', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=19', 'https://picsum.photos/200/150?random=20'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p2', operateDate: '2025-02-09 09:15', operator: '赵六', vehicleType: '平板货车', plateNo: '京F10002', brand: '重汽', model: 'ZZ1180', vin: 'LGHXCAE28M9990002', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=21'] },
{ id: 'p3', operateDate: '2025-02-08 11:45', operator: '张三', vehicleType: '栏板货车', plateNo: '京F10003', brand: '东风', model: 'DFH1180', vin: 'LGHXCAE28M9990003', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 1, adPhotos: ['https://picsum.photos/200/150?random=22'], tailboard: '有', hasTrailer: '有', trailerPlate: '京F10004', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p4', operateDate: '2025-02-07 08:00', operator: '李四', vehicleType: '厢式货车', plateNo: '京F10005', brand: '福田', model: 'BJ1180', vin: 'LGHXCAE28M9990004', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p5', operateDate: '2025-02-06 13:20', operator: '王五', vehicleType: '厢式货车', plateNo: '京F10006', brand: '江淮', model: 'HFC1190', vin: 'LGHXCAE28M9990005', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 3, adPhotos: ['https://picsum.photos/200/150?random=23', 'https://picsum.photos/200/150?random=24', 'https://picsum.photos/200/150?random=25'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 2, flawPhotos: ['https://picsum.photos/200/150?random=26', 'https://picsum.photos/200/150?random=27'] },
{ id: 'p6', operateDate: '2025-02-05 15:30', operator: '赵六', vehicleType: '平板货车', plateNo: '京F10007', brand: '重汽', model: 'ZZ1190', vin: 'LGHXCAE28M9990006', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '有', trailerPlate: '京F10008', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p7', operateDate: '2025-02-04 10:00', operator: '张三', vehicleType: '厢式货车', plateNo: '京F10009', brand: '东风', model: 'DFH1190', vin: 'LGHXCAE28M9990007', parkingLot: '朝阳停车场', bodyAd: '有', adPhotoCount: 2, adPhotos: ['https://picsum.photos/200/150?random=28', 'https://picsum.photos/200/150?random=29'], tailboard: '有', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p8', operateDate: '2025-02-03 16:45', operator: '李四', vehicleType: '栏板货车', plateNo: '京F10010', brand: '福田', model: 'BJ1190', vin: 'LGHXCAE28M9990008', parkingLot: '海淀停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 1, flawPhotos: ['https://picsum.photos/200/150?random=30'] },
{ id: 'p9', operateDate: '2025-02-02 09:30', operator: '王五', vehicleType: '厢式货车', plateNo: '京F10011', brand: '江淮', model: 'HFC1200', vin: 'LGHXCAE28M9990009', parkingLot: '丰台停车场', bodyAd: '有', adPhotoCount: 1, adPhotos: ['https://picsum.photos/200/150?random=31'], tailboard: '有', hasTrailer: '有', trailerPlate: '京F10012', flawPhotoCount: 0, flawPhotos: [] },
{ id: 'p10', operateDate: '2025-02-01 14:00', operator: '赵六', vehicleType: '平板货车', plateNo: '京F10013', brand: '重汽', model: 'ZZ1200', vin: 'LGHXCAE28M9990010', parkingLot: '西城停车场', bodyAd: '无', adPhotoCount: 0, adPhotos: [], tailboard: '无', hasTrailer: '无', trailerPlate: '', flawPhotoCount: 0, flawPhotos: [] }
]);
var pendingList = pendingListState[0];
var setPendingList = pendingListState[1];
var pageState = useState(1);
var page = pageState[0];
var setPage = pageState[1];
var pageSizeState = useState(10);
var pageSize = pageSizeState[0];
var setPageSize = pageSizeState[1];
var operatorOptions = useMemo(function () { return [{ value: '张三', label: '张三' }, { value: '李四', label: '李四' }, { value: '王五', label: '王五' }, { value: '赵六', label: '赵六' }]; }, []);
var plateOptions = useMemo(function () { return [{ value: '京A12345', label: '京A12345' }, { value: '京C11111', label: '京C11111' }, { value: '京D22222', label: '京D22222' }, { value: '京E33333', label: '京E33333' }]; }, []);
var vehicleTypeOptions = useMemo(function () { return [{ value: '厢式货车', label: '厢式货车' }, { value: '平板货车', label: '平板货车' }, { value: '栏板货车', label: '栏板货车' }]; }, []);
var parkingOptions = useMemo(function () { return [{ value: '朝阳停车场', label: '朝阳停车场' }, { value: '海淀停车场', label: '海淀停车场' }, { value: '丰台停车场', label: '丰台停车场' }, { value: '西城停车场', label: '西城停车场' }]; }, []);
var reqDocOpenState = useState(false);
var photoModalState = useState({ open: false, photos: [], currentIndex: 0 });
var addStepState = useState(1);
var addFormState = useState({
plateNo: '',
vehicleType: '',
brand: '',
vin: '',
bodyAd: '无',
adPhotos: [],
tailboard: '无',
hasTrailer: '',
trailerPlate: '',
flawPhotos: [],
inspectionList: [
{ checkType: '灯光', checkItem: '前大灯', result: '正常', treadDepth: '', remark: '' },
{ checkType: '灯光', checkItem: '尾灯', result: '正常', treadDepth: '', remark: '' },
{ checkType: '轮胎', checkItem: '前左胎', result: '正常', treadDepth: '', remark: '' },
{ checkType: '车身', checkItem: '车身外观', result: '正常', treadDepth: '', remark: '' }
]
});
var filteredCompleted = useMemo(function () {
var list = completedList.slice();
if (appliedFilters.operator) list = list.filter(function (r) { return r.operator.indexOf(appliedFilters.operator) !== -1; });
if (appliedFilters.plateNo) list = list.filter(function (r) { return r.plateNo.indexOf(appliedFilters.plateNo) !== -1; });
if (appliedFilters.vehicleType) list = list.filter(function (r) { return r.vehicleType.indexOf(appliedFilters.vehicleType) !== -1; });
if (appliedFilters.parkingLot) list = list.filter(function (r) { return r.parkingLot.indexOf(appliedFilters.parkingLot) !== -1; });
if (appliedFilters.dateStart) list = list.filter(function (r) { var d = (r.completeDate || '').slice(0, 10); return d >= appliedFilters.dateStart; });
if (appliedFilters.dateEnd) list = list.filter(function (r) { var d = (r.completeDate || '').slice(0, 10); return d <= appliedFilters.dateEnd; });
return list.sort(function (a, b) { return (b.completeDate || '').localeCompare(a.completeDate || ''); });
}, [completedList, appliedFilters]);
var filteredPending = useMemo(function () {
var list = pendingList.slice();
if (appliedFilters.operator) list = list.filter(function (r) { return r.operator.indexOf(appliedFilters.operator) !== -1; });
if (appliedFilters.plateNo) list = list.filter(function (r) { return r.plateNo.indexOf(appliedFilters.plateNo) !== -1; });
if (appliedFilters.vehicleType) list = list.filter(function (r) { return r.vehicleType.indexOf(appliedFilters.vehicleType) !== -1; });
if (appliedFilters.parkingLot) list = list.filter(function (r) { return r.parkingLot.indexOf(appliedFilters.parkingLot) !== -1; });
if (appliedFilters.dateStart) list = list.filter(function (r) { var d = (r.operateDate || '').slice(0, 10); return d >= appliedFilters.dateStart; });
if (appliedFilters.dateEnd) list = list.filter(function (r) { var d = (r.operateDate || '').slice(0, 10); return d <= appliedFilters.dateEnd; });
return list.sort(function (a, b) { return (b.operateDate || '').localeCompare(a.operateDate || ''); });
}, [pendingList, appliedFilters]);
var displayCompleted = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredCompleted.slice(start, start + pageSize);
}, [filteredCompleted, page, pageSize]);
var displayPending = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredPending.slice(start, start + pageSize);
}, [filteredPending, page, pageSize]);
var totalCompleted = filteredCompleted.length;
var totalPending = filteredPending.length;
var totalCount = activeTab === 'completed' ? totalCompleted : totalPending;
var handleQuery = useCallback(function () {
setAppliedFilters({ dateStart: filters.dateStart, dateEnd: filters.dateEnd, operator: filters.operator, plateNo: filters.plateNo, vehicleType: filters.vehicleType, parkingLot: filters.parkingLot });
setPage(1);
}, [filters.dateStart, filters.dateEnd, filters.operator, filters.plateNo, filters.vehicleType, filters.parkingLot]);
var handleReset = useCallback(function () {
var empty = { dateStart: '', dateEnd: '', operator: undefined, plateNo: undefined, vehicleType: undefined, parkingLot: undefined };
setFilters(empty);
setAppliedFilters(empty);
setPage(1);
}, []);
var handleExport = useCallback(function () {
if (activeTab !== 'completed') {
message.warning('请在「已完成」Tab 下导出');
return;
}
var rows = filteredCompleted;
var headers = ['备车时间', '备车人', '车辆类型', '车牌号', '品牌', '型号', '车辆识别代码', '停车场', '车身广告', '广告照片', '尾板', '是否有挂', '挂车牌号', '瑕疵照片'];
var csv = headers.join(',') + '\n';
rows.forEach(function (r) {
csv += [r.completeDate, r.operator, r.vehicleType, r.plateNo, r.brand, r.model, r.vin, r.parkingLot, r.bodyAd, (r.adPhotoCount || 0) + '张', r.tailboard, r.hasTrailer, r.trailerPlate || '', (r.flawPhotoCount || 0) + '张'].join(',') + '\n';
});
var blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = '备车管理导出_' + new Date().getTime() + '.csv';
a.click();
URL.revokeObjectURL(url);
message.success('导出成功');
}, [activeTab, filteredCompleted]);
var openPhotoModal = useCallback(function (photos, index) {
if (!photos || photos.length === 0) return;
photoModalState[1]({ open: true, photos: photos, currentIndex: index || 0 });
}, []);
var addForm = addFormState[0];
var setAddForm = addFormState[1];
var addStep = addStepState[0];
var setAddStep = addStepState[1];
var handleAddSave = useCallback(function () {
var d = new Date();
var pad = function (n) { return String(n).padStart(2, '0'); };
var dateTimeStr = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
var item = {
id: 'p' + Date.now(),
operateDate: dateTimeStr,
operator: '当前用户',
vehicleType: addForm.vehicleType || '厢式货车',
plateNo: addForm.plateNo,
brand: addForm.brand || '-',
model: addForm.model || '-',
vin: addForm.vin,
parkingLot: addForm.parkingLot || '朝阳停车场',
bodyAd: addForm.bodyAd,
adPhotoCount: (addForm.adPhotos && addForm.adPhotos.length) || 0,
adPhotos: addForm.adPhotos || [],
tailboard: addForm.tailboard,
hasTrailer: addForm.trailerPlate ? '有' : '无',
trailerPlate: addForm.trailerPlate || '',
flawPhotoCount: (addForm.flawPhotos && addForm.flawPhotos.length) || 0,
flawPhotos: addForm.flawPhotos || []
};
setPendingList(pendingList.concat([item]));
setCurrentView('list');
setActiveTab('pending');
setAddForm({ plateNo: '', vehicleType: '', brand: '', vin: '', bodyAd: '无', adPhotos: [], tailboard: '无', hasTrailer: '', trailerPlate: '', flawPhotos: [], inspectionList: addForm.inspectionList });
setAddStep(1);
message.success('已保存至待提交列表');
}, [addForm, pendingList]);
var handleAddNext = useCallback(function () {
if (!addForm.plateNo) {
message.warning('请选择车牌号');
return;
}
setAddStep(2);
}, [addForm.plateNo]);
var handleAddSubmit = useCallback(function () {
var d = new Date();
var pad = function (n) { return String(n).padStart(2, '0'); };
var dateTimeStr = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
var item = {
id: String(Date.now()),
completeDate: dateTimeStr,
operator: '当前用户',
vehicleType: addForm.vehicleType || '厢式货车',
plateNo: addForm.plateNo,
brand: addForm.brand || '-',
model: addForm.model || '-',
vin: addForm.vin,
parkingLot: addForm.parkingLot || '朝阳停车场',
bodyAd: addForm.bodyAd,
adPhotoCount: (addForm.adPhotos && addForm.adPhotos.length) || 0,
adPhotos: addForm.adPhotos || [],
tailboard: addForm.tailboard,
hasTrailer: addForm.trailerPlate ? '有' : '无',
trailerPlate: addForm.trailerPlate || '',
flawPhotoCount: (addForm.flawPhotos && addForm.flawPhotos.length) || 0,
flawPhotos: addForm.flawPhotos || [],
inspectionList: addForm.inspectionList || []
};
setCompletedList(completedList.concat([item]));
setCurrentView('list');
setActiveTab('completed');
setAddForm({ plateNo: '', vehicleType: '', brand: '', vin: '', bodyAd: '无', adPhotos: [], tailboard: '无', hasTrailer: '', trailerPlate: '', flawPhotos: [], inspectionList: addForm.inspectionList });
setAddStep(1);
message.success('提交成功');
}, [addForm, completedList]);
var onPlateSelect = useCallback(function (plateNo) {
setAddForm(function (prev) {
var next = {};
for (var k in prev) next[k] = prev[k];
next.plateNo = plateNo;
next.vehicleType = '厢式货车';
next.brand = '东风';
next.vin = 'LGHXCAE28M' + Math.floor(Math.random() * 10000000);
return next;
});
}, []);
var requirementDocContent = '#.面包屑:运维管理-车辆业务-备车管理,支持点击对应模块跳转\n\n#筛选:支持通过备车日期、备车人、车牌号、车辆类型、停车场等方式进行筛选;\n1.备车日期日期选择器点击显示两个日历控件支持选择开始和结束时间时间格式为YYYY-MM-DD;\n2.备车人:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n3.车牌号:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n4.车辆类型:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n5.停车场:选择器,支持从输入框输入内容模糊搜索展示对应选项;\n6.右侧显示查询、重置按钮,点击查询按钮按筛选条件显示列表内容,点击重置清除筛选条件并按默认条件显示列表内容;\n\n#列表:\n列表分为两个tab分别为已完成、待检查已完成列表右侧包含新增、导出按钮,下方增加分页功能,支持选择单页显示数据记录条数;\n1.已完成tab显示完成车辆记录及备车检查两个步骤表单并点击提交的记录\n2.待检查tab显示新增备车时只点击保存但未提交的记录\n3.点击新增按钮,打开新页面进行新增表单页;\n4.导出需全选/多选对应数据记录再点击导出下载csv\n5.列表以区域进行数据权限划分,用户表中对应区域的用户只能查询自己区域的数据;';
// 日期范围变化antd RangePicker 返回 dayjs 或 [string, string] 依项目而定,此处用字符串存)
function onDateRangeChange(dates, dateStrings) {
setFilters(function (f) {
var g = {};
for (var k in f) g[k] = f[k];
g.dateStart = (dateStrings && dateStrings[0]) || '';
g.dateEnd = (dateStrings && dateStrings[1]) || '';
return g;
});
}
var dateRangeValue = useMemo(function () {
if (!filters.dateStart && !filters.dateEnd) return null;
try {
if (typeof window.dayjs === 'function' && filters.dateStart && filters.dateEnd) {
return [window.dayjs(filters.dateStart), window.dayjs(filters.dateEnd)];
}
} catch (e) {}
return null;
}, [filters.dateStart, filters.dateEnd]);
// 已完成表格列(含多选、照片链接、操作列查看按钮,点击不打开新页面)
function getCompletedColumns(openPhoto) {
return [
{ title: '备车时间', dataIndex: 'completeDate', key: 'completeDate', width: 160 },
{ title: '备车人', dataIndex: 'operator', key: 'operator', width: 90 },
{ title: '车辆类型', dataIndex: 'vehicleType', key: 'vehicleType', width: 100 },
{ title: '品牌', dataIndex: 'brand', key: 'brand', width: 80 },
{ title: '型号', dataIndex: 'model', key: 'model', width: 100 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 100 },
{ title: '车辆识别代码', dataIndex: 'vin', key: 'vin', width: 180 },
{ title: '停车场', dataIndex: 'parkingLot', key: 'parkingLot', width: 110 },
{ title: '车身广告', dataIndex: 'bodyAd', key: 'bodyAd', width: 90 },
{ title: '广告照片', key: 'adPhotos', width: 90, render: function (_, r) {
var photos = r.adPhotos && r.adPhotos.length > 0 ? r.adPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '尾板', dataIndex: 'tailboard', key: 'tailboard', width: 70 },
{ title: '是否有挂', dataIndex: 'hasTrailer', key: 'hasTrailer', width: 90 },
{ title: '挂车牌号', dataIndex: 'trailerPlate', key: 'trailerPlate', width: 100, render: function (v) { return v || '-'; } },
{ title: '瑕疵照片', key: 'flawPhotos', width: 90, render: function (_, r) {
var photos = r.flawPhotos && r.flawPhotos.length > 0 ? r.flawPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '操作', key: 'action', width: 80, fixed: 'right', render: function (_, r) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () {} }, '查看');
}}
];
}
function getPendingColumns(openPhoto, onEdit) {
return [
{ title: '创建时间', dataIndex: 'operateDate', key: 'operateDate', width: 160 },
{ title: '备车人', dataIndex: 'operator', key: 'operator', width: 90 },
{ title: '车辆类型', dataIndex: 'vehicleType', key: 'vehicleType', width: 100 },
{ title: '品牌', dataIndex: 'brand', key: 'brand', width: 80 },
{ title: '型号', dataIndex: 'model', key: 'model', width: 100 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 100 },
{ title: '车辆识别代码', dataIndex: 'vin', key: 'vin', width: 180 },
{ title: '停车场', dataIndex: 'parkingLot', key: 'parkingLot', width: 110 },
{ title: '车身广告', dataIndex: 'bodyAd', key: 'bodyAd', width: 90 },
{ title: '广告照片', key: 'adPhotos', width: 90, render: function (_, r) {
var photos = (r.adPhotos && r.adPhotos.length > 0) ? r.adPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '尾板', dataIndex: 'tailboard', key: 'tailboard', width: 70 },
{ title: '是否有挂', dataIndex: 'hasTrailer', key: 'hasTrailer', width: 90 },
{ title: '挂车牌号', dataIndex: 'trailerPlate', key: 'trailerPlate', width: 100, render: function (v) { return v || '-'; } },
{ title: '瑕疵照片', key: 'flawPhotos', width: 90, render: function (_, r) {
var photos = (r.flawPhotos && r.flawPhotos.length > 0) ? r.flawPhotos : [];
return photos.length > 0 ? React.createElement(Button, { type: 'link', size: 'small', onClick: function (e) { if (e) { e.preventDefault(); e.stopPropagation(); } openPhoto(photos, 0); } }, photos.length + '张') : '-';
}},
{ title: '操作', key: 'action', width: 80, fixed: 'right', render: function (_, r) {
return React.createElement(Button, { type: 'link', size: 'small', onClick: function () {
setAddForm(function (prev) {
var n = {};
for (var k in prev) n[k] = prev[k];
n.plateNo = r.plateNo; n.vehicleType = r.vehicleType; n.brand = r.brand; n.vin = r.vin;
n.bodyAd = r.bodyAd; n.adPhotos = r.adPhotos || []; n.tailboard = r.tailboard;
n.trailerPlate = r.trailerPlate || ''; n.flawPhotos = r.flawPhotos || [];
return n;
});
setAddStep(1);
setCurrentView('add');
} }, '编辑');
}}
];
}
var tablePagination = useMemo(function () {
return {
current: page,
pageSize: pageSize,
total: totalCount,
showSizeChanger: true,
showTotal: function (t) { return '共 ' + t + ' 条'; },
pageSizeOptions: ['10', '20', '50'],
onChange: function (p, size) {
setPage(p);
if (size !== pageSize) setPageSize(size);
}
};
}, [page, pageSize, totalCount]);
// —————— 列表页 ——————
function ListView() {
var breadcrumbItems = [
{ title: '运维管理' },
{ title: '车辆业务' },
{ title: '备车管理' }
];
return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } },
React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } },
React.createElement(Breadcrumb, { items: breadcrumbItems }),
React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { reqDocOpenState[1](true); } }, '查看需求说明')
),
React.createElement(Modal, {
title: '需求说明',
open: reqDocOpenState[0],
onCancel: function () { reqDocOpenState[1](false); },
footer: null,
width: 720,
styles: { body: { maxHeight: '70vh', overflow: 'auto', whiteSpace: 'pre-wrap', fontSize: 14 } }
}, requirementDocContent.split('\n').map(function (line, idx) {
var trimmed = line;
if (trimmed.indexOf('#') === 0) {
return React.createElement('div', { key: idx, style: { fontWeight: 'bold', marginTop: idx === 0 ? 0 : 16, marginBottom: 8, paddingBottom: 4, borderBottom: '1px solid #f0f0f0' } }, trimmed.replace(/^#\.?/, '').trim());
}
if (/^\d+\./.test(trimmed)) return React.createElement('div', { key: idx, style: { marginLeft: 12, marginBottom: 4 } }, trimmed);
if (trimmed === '') return React.createElement('div', { key: idx, style: { height: 12 } });
return React.createElement('div', { key: idx, style: { marginBottom: 8 } }, trimmed);
})),
React.createElement(Card, { style: { marginBottom: 16 } },
React.createElement('div', {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
gap: '16px 24px',
alignItems: 'start',
flex: 1,
minWidth: 0
}
},
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '备车日期'),
React.createElement(RangePicker, {
value: dateRangeValue,
onChange: onDateRangeChange,
style: { width: '100%' },
placeholder: ['开始日期', '结束日期']
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '备车人'),
React.createElement(Select, {
placeholder: '请选择备车人',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.operator,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.operator = v; return g; }); },
style: { width: '100%' },
options: operatorOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '车牌号'),
React.createElement(Select, {
placeholder: '请选择车牌号',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.plateNo,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.plateNo = v; return g; }); },
style: { width: '100%' },
options: plateOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '车辆类型'),
React.createElement(Select, {
placeholder: '请选择车辆类型',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.vehicleType,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.vehicleType = v; return g; }); },
style: { width: '100%' },
options: vehicleTypeOptions
})
),
React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 4 } }, '停车场'),
React.createElement(Select, {
placeholder: '请选择停车场',
allowClear: true,
showSearch: true,
optionFilterProp: 'label',
value: filters.parkingLot,
onChange: function (v) { setFilters(function (f) { var g = {}; for (var k in f) g[k] = f[k]; g.parkingLot = v; return g; }); },
style: { width: '100%' },
options: parkingOptions
})
)
),
React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 16 } },
React.createElement(Button, { onClick: handleReset }, '重置'),
React.createElement(Button, { type: 'primary', onClick: handleQuery }, '查询')
)
),
React.createElement(Card, null,
React.createElement(Tabs, {
activeKey: activeTab,
onChange: function (k) { setActiveTab(k); setPage(1); },
tabBarExtraContent: React.createElement('div', { style: { display: 'flex', gap: 8 } },
React.createElement(Button, { type: 'primary', onClick: function () {} }, '新增'),
activeTab === 'completed' ? React.createElement(Button, { onClick: handleExport }, '导出') : null
),
items: [
{
key: 'completed',
label: '已完成',
children: React.createElement(Table, {
columns: getCompletedColumns(openPhotoModal),
dataSource: displayCompleted,
rowKey: 'id',
pagination: tablePagination,
scroll: { x: 1400 },
size: 'middle'
})
},
{
key: 'pending',
label: '待提交',
children: React.createElement(Table, {
columns: getPendingColumns(openPhotoModal),
dataSource: displayPending,
rowKey: 'id',
pagination: tablePagination,
scroll: { x: 1400 },
size: 'middle'
})
}
]
})
),
// 照片预览:全屏遮罩 + 放大图片,点击遮罩关闭
photoModalState[0].open && photoModalState[0].photos && photoModalState[0].photos.length > 0 ? React.createElement('div', {
style: {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.75)',
zIndex: 1000,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer'
},
onClick: function () { photoModalState[1]({ open: false, photos: [], currentIndex: 0 }); }
}, React.createElement('div', {
style: { position: 'relative', display: 'flex', flexDirection: 'column', alignItems: 'center', cursor: 'default', maxWidth: '100%', maxHeight: '100%' },
onClick: function (e) { if (e) e.stopPropagation(); }
},
React.createElement('img', {
src: photoModalState[0].photos[photoModalState[0].currentIndex] || photoModalState[0].photos[0],
alt: '',
style: { maxWidth: '90vw', maxHeight: '85vh', objectFit: 'contain' }
}),
photoModalState[0].photos.length > 1 ? React.createElement('div', { style: { marginTop: 16, display: 'flex', alignItems: 'center', gap: 16 } },
React.createElement(Button, {
disabled: photoModalState[0].currentIndex === 0,
onClick: function (e) { e.stopPropagation(); photoModalState[1]({ open: true, photos: photoModalState[0].photos, currentIndex: Math.max(0, photoModalState[0].currentIndex - 1) }); }
}, '上一张'),
React.createElement('span', { style: { color: '#fff' } }, (photoModalState[0].currentIndex + 1) + ' / ' + photoModalState[0].photos.length),
React.createElement(Button, {
disabled: photoModalState[0].currentIndex >= photoModalState[0].photos.length - 1,
onClick: function (e) { e.stopPropagation(); photoModalState[1]({ open: true, photos: photoModalState[0].photos, currentIndex: Math.min(photoModalState[0].photos.length - 1, photoModalState[0].currentIndex + 1) }); }
}, '下一张')
) : null
)) : null
);
}
// —————— 新增页 ——————
function AddView() {
var form = addFormState[0];
var setForm = addFormState[1];
var step = addStepState[0];
var addBreadcrumbItems = [
{ title: '运维管理' },
{ title: '车辆业务' },
{ title: '备车管理' },
{ title: '新增备车' }
];
return React.createElement('div', { style: { padding: 24, background: '#f5f5f5', minHeight: '100vh' } },
React.createElement(Breadcrumb, { items: addBreadcrumbItems, style: { marginBottom: 16 } }),
React.createElement(Card, null,
React.createElement(Steps, { current: step - 1, style: { marginBottom: 24 }, items: [
{ title: '步骤1 车辆记录' },
{ title: '步骤2 备车检查' }
] }),
step === 1 ? React.createElement(Row, { gutter: [16, 16] },
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车牌号 *'), React.createElement(Select, { placeholder: '请选择车牌号(仅库存车辆)', allowClear: true, showSearch: true, optionFilterProp: 'label', value: form.plateNo || undefined, onChange: onPlateSelect, style: { width: 200 }, options: plateOptions })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车辆类型'), React.createElement(Input, { value: form.vehicleType, readOnly: true, style: { width: 200, background: '#f5f5f5' } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '品牌'), React.createElement(Input, { value: form.brand, readOnly: true, style: { width: 200, background: '#f5f5f5' } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车架号'), React.createElement(Input, { value: form.vin, readOnly: true, style: { width: 200, background: '#f5f5f5' } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '车身广告 *'), React.createElement(Radio.Group, { value: form.bodyAd, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.bodyAd = e.target.value; return n; }); }, options: [{ value: '无', label: '无' }, { value: '有', label: '有' }] })),
form.bodyAd === '有' ? React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '广告照片最多5张'), React.createElement(Space, null, (form.adPhotos || []).slice(0, 5).map(function (url, i) { return React.createElement('img', { key: i, src: url, alt: '', style: { width: 60, height: 60, objectFit: 'cover', borderRadius: 4 } }); }), (form.adPhotos || []).length < 5 ? React.createElement(Button, { onClick: function () { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.adPhotos = (p.adPhotos || []).concat(['https://picsum.photos/200/150?r=' + Date.now()]); return n; }); } }, '上传') : null)) : null,
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '尾板 *'), React.createElement(Radio.Group, { value: form.tailboard, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.tailboard = e.target.value; return n; }); }, options: [{ value: '无', label: '无' }, { value: '有', label: '有' }] })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '挂车牌号(有挂时填写)'), React.createElement(Input, { value: form.trailerPlate, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.trailerPlate = e.target.value; return n; }); }, placeholder: '不填视为无挂', style: { width: 200 } })),
React.createElement(Col, { span: 24 }, React.createElement('span', { style: { color: '#666', marginRight: 8 } }, '瑕疵照片最多5张'), React.createElement(Space, null, (form.flawPhotos || []).slice(0, 5).map(function (url, i) { return React.createElement('img', { key: i, src: url, alt: '', style: { width: 60, height: 60, objectFit: 'cover', borderRadius: 4 } }); }), (form.flawPhotos || []).length < 5 ? React.createElement(Button, { onClick: function () { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.flawPhotos = (p.flawPhotos || []).concat(['https://picsum.photos/200/150?f=' + Date.now()]); return n; }); } }, '上传') : null)),
React.createElement(Col, { span: 24 }, React.createElement(Space, null, React.createElement(Button, { type: 'primary', onClick: handleAddNext }, '下一步'), React.createElement(Button, { onClick: handleAddSave }, '保存'), React.createElement(Button, { onClick: function () { setCurrentView('list'); } }, '取消')))
) : React.createElement('div', null,
React.createElement('div', { style: { marginBottom: 16, fontWeight: 600 } }, '备车检查'),
React.createElement(Table, {
dataSource: form.inspectionList || [],
rowKey: function (_, i) { return i; },
pagination: false,
columns: [
{ title: '检查类型', dataIndex: 'checkType', width: 100 },
{ title: '检查项', dataIndex: 'checkItem', width: 120 },
{ title: '检查项结果', dataIndex: 'result', width: 120, render: function (val, record, i) {
return React.createElement(Select, { value: val, onChange: function (v) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; var list = (p.inspectionList || []).slice(); list[i] = Object.assign({}, list[i], { result: v }); n.inspectionList = list; return n; }); }, style: { width: '100%' }, options: [{ value: '正常', label: '正常' }, { value: '异常', label: '异常' }] });
}},
{ title: '胎纹深度(轮胎时)', key: 'treadDepth', width: 140, render: function (_, record, i) {
if (record.checkItem && record.checkItem.indexOf('胎') !== -1) {
return React.createElement(Input, { value: record.treadDepth, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; var list = (p.inspectionList || []).slice(); list[i] = Object.assign({}, list[i], { treadDepth: e.target.value }); n.inspectionList = list; return n; }); }, placeholder: '胎纹深度' });
}
return '-';
}},
{ title: '备注', dataIndex: 'remark', render: function (val, record, i) {
return React.createElement(Input, { value: val, onChange: function (e) { setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; var list = (p.inspectionList || []).slice(); list[i] = Object.assign({}, list[i], { remark: e.target.value }); n.inspectionList = list; return n; }); }, placeholder: '备注' });
}}
]
}),
React.createElement('div', { style: { marginTop: 16 } }, React.createElement(Space, null, React.createElement(Button, { type: 'primary', onClick: handleAddSubmit }, '提交'), React.createElement(Button, { onClick: handleAddSave }, '保存'), React.createElement(Button, { onClick: function () { setCurrentView('list'); } }, '取消')))
)
)
);
}
return ListView();
};
if (typeof window !== 'undefined') {
window.Component = Component;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
});
} else {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
}

View File

@@ -0,0 +1,143 @@
// 【重要】必须使用 const Component 作为组件变量名
// 新增后装设备 - 运维管理-车辆业务
var ARCO_TOKEN = {
primary: '#165DFF',
primaryHover: '#4080FF',
neutral1: '#FFFFFF',
neutral4: '#E5E6EB',
neutral6: '#86909C',
neutral8: '#1D2129',
border: '#E5E6EB',
fill: '#F2F3F5',
shadowLight: '0 1px 2px rgba(0,0,0,0.05)',
radiusLarge: '8px',
spacing16: '16px',
spacing24: '24px',
fontSize14: '14px',
fontSize16: '16px',
fontFamily: '-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial, sans-serif',
link: '#165DFF'
};
var DEVICE_TYPES = ['GPS', '尾板', '车身广告', 'G7安全套件', 'G7普通设备', 'G7温控设备', '备胎'];
var MOCK_VEHICLE_OPTIONS = ['粤A12345', '粤A67890', '粤B11111', '粤B22222', '粤C33333', '京A88888'];
const Component = function () {
var antd = window.antd;
var Select = antd.Select;
var Button = antd.Button;
var Input = antd.Input;
var message = antd.message;
var Option = Select.Option;
var _useState = React.useState('');
var deviceType = _useState[0];
var setDeviceType = _useState[1];
var _useState2 = React.useState('');
var vehicle = _useState2[0];
var setVehicle = _useState2[1];
var _useState3 = React.useState('');
var supplier = _useState3[0];
var setSupplier = _useState3[1];
var handleSubmit = function () {
message.success('新增成功');
setDeviceType('');
setVehicle('');
setSupplier('');
};
var t = ARCO_TOKEN;
var styles = {
page: { padding: t.spacing24, fontFamily: t.fontFamily, backgroundColor: t.fill, minHeight: '100vh' },
breadcrumb: { marginBottom: t.spacing16, fontSize: t.fontSize14, color: t.neutral6, display: 'flex', alignItems: 'center' },
breadcrumbLink: { color: t.link, textDecoration: 'none', marginRight: '8px' },
breadcrumbCurrent: { color: t.neutral8 },
card: { backgroundColor: t.neutral1, borderRadius: t.radiusLarge, boxShadow: t.shadowLight, marginBottom: t.spacing16, padding: t.spacing24, maxWidth: 560 },
label: { display: 'block', marginBottom: 8, fontSize: t.fontSize14, color: t.neutral8 },
row: { marginBottom: t.spacing16 },
actions: { marginTop: t.spacing24, display: 'flex', gap: 12 }
};
var deviceTypeOptions = DEVICE_TYPES.map(function (type) {
return React.createElement(Option, { key: type, value: type }, type);
});
var vehicleOptions = MOCK_VEHICLE_OPTIONS.map(function (v) {
return React.createElement(Option, { key: v, value: v }, v);
});
return React.createElement(
'div',
{ style: styles.page },
React.createElement(
'div',
{ style: styles.breadcrumb },
React.createElement('a', { href: '#', style: styles.breadcrumbLink, onClick: function (e) { e.preventDefault(); } }, '运维管理'),
React.createElement('span', { style: { marginRight: '8px' } }, '/'),
React.createElement('a', { href: '#', style: styles.breadcrumbLink, onClick: function (e) { e.preventDefault(); } }, '车辆业务'),
React.createElement('span', { style: { marginRight: '8px' } }, '/'),
React.createElement('span', { style: styles.breadcrumbCurrent }, '新增后装设备')
),
React.createElement(
'div',
{ style: styles.card },
React.createElement('div', { style: { fontSize: t.fontSize16, fontWeight: 600, marginBottom: t.spacing24, color: t.neutral8 } }, '新增后装设备'),
React.createElement('div', { style: styles.row },
React.createElement('label', { style: styles.label }, '设备类型'),
React.createElement(Select, {
placeholder: '请选择设备类型',
style: { width: '100%' },
value: deviceType || undefined,
onChange: function (v) { setDeviceType(v || ''); },
allowClear: true
}, deviceTypeOptions)
),
React.createElement('div', { style: styles.row },
React.createElement('label', { style: styles.label }, '使用车辆'),
React.createElement(Select, {
placeholder: '请选择或输入搜索',
style: { width: '100%' },
value: vehicle || undefined,
onChange: function (v) { setVehicle(v || ''); },
showSearch: true,
allowClear: true,
filterOption: function (input, opt) {
var c = opt && opt.children;
return c && String(c).toLowerCase().indexOf((input || '').toLowerCase()) >= 0;
}
}, vehicleOptions)
),
React.createElement('div', { style: styles.row },
React.createElement('label', { style: styles.label }, '供应商'),
React.createElement(Input, {
placeholder: '请输入供应商',
value: supplier,
onChange: function (e) { setSupplier(e.target.value); }
})
),
React.createElement('div', { style: styles.actions },
React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交'),
React.createElement(Button, { onClick: function () { setDeviceType(''); setVehicle(''); setSupplier(''); } }, '重置')
)
)
);
};
if (typeof window !== 'undefined') {
window.Component = Component;
function mount() {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', mount);
} else {
setTimeout(mount, 0);
}
}

View File

@@ -0,0 +1,472 @@
// 【重要】必须使用 const Component 作为组件变量名
// 车辆业务 - 新增备车ONEOS运管平台布局参照新增租赁合同
const Component = function () {
var useState = React.useState;
var useCallback = React.useCallback;
var useMemo = React.useMemo;
var useRef = React.useRef;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Card = antd.Card;
var Select = antd.Select;
var Input = antd.Input;
var Button = antd.Button;
var Switch = antd.Switch;
var Drawer = antd.Drawer;
var Table = antd.Table;
var message = antd.message;
var Modal = antd.Modal;
var Space = antd.Space;
// 车牌管理 mock车牌号及对应车辆信息、后装设备车身广告、尾板
var plateManageList = [
{ plateNo: '京A12345', vehicleType: '厢式货车', brand: '东风', model: 'DFH1180', vin: 'LGHXCAE28M1234567', bodyAd: true, tailboard: true },
{ plateNo: '京C11111', vehicleType: '平板货车', brand: '福田', model: 'BJ1180', vin: 'LGHXCAE28M7654321', bodyAd: false, tailboard: false },
{ plateNo: '京D22222', vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M8888888', bodyAd: true, tailboard: false },
{ plateNo: '京E33333', vehicleType: '栏板货车', brand: '重汽', model: 'ZZ1180', vin: 'LGHXCAE28M7777777', bodyAd: false, tailboard: true },
{ plateNo: '京F10001', vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M9990001', bodyAd: true, tailboard: true }
];
// 备车检查单:类别 -> 检查项目列表
var inspectionCategoryItems = {
'车灯': ['大灯', '转向灯', '小灯', '示廓灯', '刹车灯', '倒车灯', '牌照灯', '防雾灯', '室内灯'],
'仪表盘': ['氢系统指示', '电控系统指示', '数值清晰准确', '故障报警灯'],
'驾驶室': ['点烟器', '车窗升降', '按键开关', '雨刮器', '内后视镜是否正常', '内/外门把手', '安全带', '空调冷暖风', '仪表盘', '门锁功能', '手刹', '车钥匙功能是否正常', '喇叭', '音响功能', '遮阳板', '主副驾座椅', '方向盘', '内饰干净整洁'],
'轮胎': ['前左胎', '前右胎', '后左胎', '后右胎'],
'液位检查': ['冷却液', '制动液', '玻璃水'],
'外观检查': ['车身外观', '漆面', '玻璃'],
'车辆外观': ['整车外观'],
'其他': ['其他检查项'],
'随车工具': ['三角牌', '灭火器', '反光背心'],
'随车证件': ['行驶证', '营运证', '保险单'],
'整车': ['整车状态'],
'燃料电池系统': ['氢系统', '储氢瓶'],
'冷机': ['冷机运行'],
'制动系统': ['制动踏板', '驻车制动']
};
function buildInspectionList() {
var list = [];
var categories = Object.keys(inspectionCategoryItems);
for (var i = 0; i < categories.length; i++) {
var cat = categories[i];
var items = inspectionCategoryItems[cat];
for (var j = 0; j < items.length; j++) {
list.push({ category: cat, checkItem: items[j], checked: true, remark: '' });
}
}
return list;
}
var formState = useState({
plateNo: '',
vehicleType: '',
brand: '',
model: '',
vin: '',
bodyAd: true,
adPhotos: [],
tailboard: false,
trailerPlate: '',
flawPhotos: [],
inspectionList: buildInspectionList()
});
var form = formState[0];
var setForm = formState[1];
var drawerOpenState = useState(false);
var photoPreviewState = useState({ open: false, url: null });
var reqDocOpenState = useState(false);
var adPhotoInputRef = useRef(null);
var flawPhotoInputRef = useRef(null);
var plateOptions = useMemo(function () {
return plateManageList.map(function (p) { return { value: p.plateNo, label: p.plateNo }; });
}, []);
var onPlateSelect = useCallback(function (plateNo) {
var vehicle = plateManageList.find(function (p) { return p.plateNo === plateNo; });
if (!vehicle) return;
setForm(function (prev) {
var next = {};
for (var k in prev) next[k] = prev[k];
next.plateNo = vehicle.plateNo;
next.vehicleType = vehicle.vehicleType || '';
next.brand = vehicle.brand || '';
next.model = vehicle.model || '';
next.vin = vehicle.vin || '';
next.bodyAd = !!vehicle.bodyAd;
next.tailboard = !!vehicle.tailboard;
return next;
});
}, []);
var updateInspection = useCallback(function (index, field, value) {
setForm(function (prev) {
var n = {};
for (var k in prev) n[k] = prev[k];
var list = (prev.inspectionList || []).slice();
var row = list[index] || {};
list[index] = Object.assign({}, row, { [field]: value });
n.inspectionList = list;
return n;
});
}, []);
var addAdPhoto = useCallback(function () {
if ((form.adPhotos || []).length >= 4) { message.warning('最多上传4张'); return; }
if (adPhotoInputRef.current) adPhotoInputRef.current.click();
}, [form.adPhotos]);
var onAdPhotoFileChange = useCallback(function (e) {
var files = e.target.files;
if (!files || files.length === 0) return;
setForm(function (p) {
var current = p.adPhotos || [];
var remain = 4 - current.length;
if (remain <= 0) return p;
var urls = [];
for (var i = 0; i < files.length && urls.length < remain; i++) {
if (files[i].type.indexOf('image') !== -1) urls.push(URL.createObjectURL(files[i]));
}
if (urls.length === 0) return p;
var n = {}; for (var k in p) n[k] = p[k]; n.adPhotos = current.concat(urls); return n;
});
e.target.value = '';
}, []);
var removeAdPhoto = useCallback(function (idx) {
setForm(function (p) {
var n = {};
for (var k in p) n[k] = p[k];
var arr = (p.adPhotos || []).slice();
var url = arr[idx];
if (url && url.indexOf('blob:') === 0) URL.revokeObjectURL(url);
arr.splice(idx, 1);
n.adPhotos = arr;
return n;
});
}, []);
var addFlawPhoto = useCallback(function () {
if ((form.flawPhotos || []).length >= 4) { message.warning('最多上传4张'); return; }
if (flawPhotoInputRef.current) flawPhotoInputRef.current.click();
}, [form.flawPhotos]);
var onFlawPhotoFileChange = useCallback(function (e) {
var files = e.target.files;
if (!files || files.length === 0) return;
setForm(function (p) {
var current = p.flawPhotos || [];
var remain = 4 - current.length;
if (remain <= 0) return p;
var urls = [];
for (var i = 0; i < files.length && urls.length < remain; i++) {
if (files[i].type.indexOf('image') !== -1) urls.push(URL.createObjectURL(files[i]));
}
if (urls.length === 0) return p;
var n = {}; for (var k in p) n[k] = p[k]; n.flawPhotos = current.concat(urls); return n;
});
e.target.value = '';
}, []);
var removeFlawPhoto = useCallback(function (idx) {
setForm(function (p) {
var n = {};
for (var k in p) n[k] = p[k];
var arr = (p.flawPhotos || []).slice();
var url = arr[idx];
if (url && url.indexOf('blob:') === 0) URL.revokeObjectURL(url);
arr.splice(idx, 1);
n.flawPhotos = arr;
return n;
});
}, []);
var handleSubmit = useCallback(function () {
if (!form.plateNo) { message.warning('请选择车牌号'); return; }
message.success('备车成功');
// 保存数据并跳转至备车管理-已完成(实际项目接路由)
if (typeof window !== 'undefined' && window.history) window.history.back();
}, [form.plateNo]);
var handleSave = useCallback(function () {
if (!form.plateNo) { message.warning('请选择车牌号'); return; }
message.success('暂存成功');
// 保存数据并跳转至备车管理-待提交
if (typeof window !== 'undefined' && window.history) window.history.back();
}, [form.plateNo]);
// 布局样式(参照新增租赁合同)
var styles = {
page: { padding: '16px 24px 80px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardBody: { padding: '20px 24px' },
formRow: { display: 'flex', flexWrap: 'wrap', marginBottom: 16 },
formCol: { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8, boxSizing: 'border-box' },
formColFull: { flex: '0 0 100%', marginBottom: 8, boxSizing: 'border-box' },
label: { display: 'block', marginBottom: 6, color: '#333' },
labelRequired: { color: '#ff4d4f', marginRight: 4 },
footer: { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, zIndex: 99 }
};
var FormItem = function (props) {
var colStyle = props.fullWidth ? styles.formColFull : styles.formCol;
return React.createElement('div', { style: colStyle },
React.createElement('label', { style: styles.label },
props.required ? React.createElement('span', { style: styles.labelRequired }, '*') : null,
props.label
),
props.children
);
};
var inspectionList = form.inspectionList || [];
var categoryRowSpans = useMemo(function () {
var list = inspectionList;
var spans = [];
var i = 0;
while (i < list.length) {
var cat = list[i].category;
var start = i;
while (i < list.length && list[i].category === cat) i++;
spans[start] = i - start;
for (var j = start + 1; j < i; j++) spans[j] = 0;
}
return spans;
}, [form.inspectionList]);
var inspectionColumns = [
{
title: '类别',
dataIndex: 'category',
key: 'category',
width: 120,
onCell: function (_, index) { return { rowSpan: categoryRowSpans[index] !== undefined ? categoryRowSpans[index] : 1 }; }
},
{ title: '检查项目', dataIndex: 'checkItem', key: 'checkItem', width: 180 },
{
title: '检查情况',
key: 'checked',
width: 100,
render: function (_, record, index) {
return React.createElement(Switch, {
checked: record.checked !== false,
onChange: function (checked) { updateInspection(index, 'checked', checked); }
});
}
},
{
title: '备注',
dataIndex: 'remark',
key: 'remark',
render: function (val, record, index) {
return React.createElement(Input, {
value: val,
onChange: function (e) { updateInspection(index, 'remark', e.target.value); },
placeholder: '备注'
});
}
}
];
// 方形拍照图标(广告照片与瑕疵共用)
var cameraIconBox = function (onClick) {
return React.createElement('div', {
role: 'button',
tabIndex: 0,
onClick: onClick,
style: { width: 64, height: 64, border: '1px dashed #d9d9d9', borderRadius: 4, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', background: '#fafafa', boxSizing: 'border-box' }
}, React.createElement('svg', { width: 28, height: 28, viewBox: '0 0 24 24', fill: 'none', stroke: '#999', strokeWidth: 2 },
React.createElement('path', { d: 'M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z' }),
React.createElement('circle', { cx: 12, cy: 13, r: 4 })
));
};
var requirementDocContent = '新增备车\n\n1.面包屑:\n1.1.运维管理-车辆业务-备车管理-新增备车\n\n2.表单:\n2.1.车牌号:必选项,选择器,支持从输入框内输入内容进行模糊搜索,默认拉取「车牌管理」中所有「车牌号」;\n2.2.车辆类型:输入框禁用,选择车牌号后自动拉取该车牌号对应「车辆类型」;\n2.3.品牌:输入框禁用,选择车牌号后自动拉取该车牌号对应「品牌」;\n2.4.型号:输入框禁用,选择车牌号后自动拉取该车牌号对应「型号」\n2.5.车辆识别代码:输入框禁用,选择车牌号后自动拉取该车牌号「车辆识别代码」;\n2.6.车身广告:开关,选择车辆后拉取该车辆「后装设备」「车身广告」,如果该车辆有「车身广告」则勾选为开,如果无则勾选为无。同时如果手动进行操作,会同步到「后装设备」「车身广告」中,安装时间以该条备车记录提交成功为准;\n2.7.广告照片图片上传最多支持上传4张图片支持主流照片格式。上传后上传按钮后方横排显示已上传图片缩略图支持点击预览和删除\n2.8.尾板:开关,选择车辆后拉取该车辆「后装设备」「尾板」,如果该车辆有「尾板」则勾选为开,如果无则勾选为无。同时如果手动进行操作,会同步到「后装设备」「尾板」中,安装时间以该条备车记录提交成功为准;\n2.9.是否有挂:输入框,提示信息为:请输入挂车牌号,不输入为无挂;\n2.10.瑕疵图片上传最多支持上传4张图片支持主流照片格式。上传后上传按钮后方横排显示已上传图片缩略图支持点击预览和删除\n2.11.车辆检查:按钮,文字为备车检查单,点击右侧展开抽屉,抽屉内显示列表,字段为类别、检查项目、选择、备注;\n 2.11.1.类别:分为车灯、仪表盘、驾驶室、轮胎、液位检查、外观检查、车辆外观、其他、随车工具、随车证件、整车、燃料电池系统、冷机、制动系统;\n 2.11.2.检查项目:车灯类别对应(大灯、转向灯、小灯、示廓灯、刹车灯、倒车灯、牌照灯、防雾灯、室内灯)、仪表盘对应(氢系统指示、电控系统指示、数值清晰准确、故障报警灯)、驾驶室对应(点烟器、车窗升降、按键开关、雨刮器、内后视镜是否正常、内/外门把手、安全带、空调冷暖风、仪表盘、门锁功能、手刹、车钥匙功能是否正常、喇叭、音响功能、遮阳板、主副驾座椅、方向盘、内饰干净整洁)\n 2.11.3.检查情况:开关,在检查项目每项后方显示,默认为开,可手动进行关闭;\n 2.11.4.备注:输入框;\n2.12.下方为提交和保存;\n 2.12.1.提交点击提交toast提示备车成功同时保存该条数据并跳转至「备车管理」「已完成」\n 2.12.2.保存点击保存toast提示暂存成功同时保存该条数据并跳转至「备车管理」「待提交」';
var breadcrumbNodes = [
React.createElement('span', { key: '1' }, '运维管理'),
React.createElement('span', { key: '2', style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { key: '3' }, '车辆业务'),
React.createElement('span', { key: '4', style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { key: '5' }, '备车管理'),
React.createElement('span', { key: '6', style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { key: '7', style: { color: '#1890ff' } }, '新增备车')
];
return React.createElement('div', { style: styles.page },
React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } },
React.createElement('div', { style: styles.breadcrumb }, breadcrumbNodes),
React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { reqDocOpenState[1](true); } }, '查看需求说明')
),
React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardBody },
React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '车牌号', required: true },
React.createElement(Select, {
placeholder: '请选择车牌号',
style: { width: '100%' },
value: form.plateNo || undefined,
onChange: onPlateSelect,
showSearch: true,
allowClear: true,
optionFilterProp: 'label',
filterOption: function (input, opt) {
return (opt && opt.label && String(opt.label).toLowerCase().indexOf((input || '').toLowerCase()) >= 0);
},
options: plateOptions
})
),
React.createElement(FormItem, { label: '车辆类型' },
React.createElement(Input, { value: form.vehicleType, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '品牌' },
React.createElement(Input, { value: form.brand, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '型号' },
React.createElement(Input, { value: form.model, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '车辆识别代码' },
React.createElement(Input, { value: form.vin, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement('div', { style: styles.formCol, key: 'ph0' }),
React.createElement(FormItem, { label: '车身广告' },
React.createElement(Switch, {
checked: form.bodyAd,
checkedChildren: '开',
unCheckedChildren: '关',
onChange: function (checked) {
setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.bodyAd = checked; return n; });
}
})
),
React.createElement('div', { style: styles.formCol, key: 'ph1' }),
React.createElement('div', { style: styles.formCol, key: 'ph2' }),
React.createElement(FormItem, { label: '尾板' },
React.createElement(Switch, {
checked: form.tailboard,
checkedChildren: '开',
unCheckedChildren: '关',
onChange: function (checked) {
setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.tailboard = checked; return n; });
}
})
),
React.createElement(FormItem, { label: '广告照片', fullWidth: true },
React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
React.createElement('input', { type: 'file', ref: adPhotoInputRef, accept: 'image/*', multiple: true, style: { display: 'none' }, onChange: onAdPhotoFileChange }),
(form.adPhotos || []).length < 4 ? cameraIconBox(addAdPhoto) : null,
(form.adPhotos || []).map(function (url, i) {
return React.createElement('span', { key: i, style: { position: 'relative', display: 'inline-block' } },
React.createElement('img', {
src: url,
alt: '',
style: { width: 64, height: 64, objectFit: 'cover', borderRadius: 4, cursor: 'pointer' },
onClick: function () { photoPreviewState[1]({ open: true, url: url }); }
}),
React.createElement('span', {
style: { position: 'absolute', top: -6, right: -6, width: 20, height: 20, borderRadius: '50%', background: '#ff4d4f', color: '#fff', fontSize: 12, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' },
onClick: function () { removeAdPhoto(i); }
}, '×')
);
})
)
),
React.createElement(FormItem, { label: '是否有挂' },
React.createElement(Input, {
placeholder: '请输入挂车牌号,不输入为无挂',
value: form.trailerPlate,
onChange: function (e) {
setForm(function (p) { var n = {}; for (var k in p) n[k] = p[k]; n.trailerPlate = e.target.value; return n; });
},
style: { width: '100%', maxWidth: 320 }
})
),
React.createElement(FormItem, { label: '瑕疵', fullWidth: true },
React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
React.createElement('input', { type: 'file', ref: flawPhotoInputRef, accept: 'image/*', multiple: true, style: { display: 'none' }, onChange: onFlawPhotoFileChange }),
(form.flawPhotos || []).length < 4 ? cameraIconBox(addFlawPhoto) : null,
(form.flawPhotos || []).map(function (url, i) {
return React.createElement('span', { key: i, style: { position: 'relative', display: 'inline-block' } },
React.createElement('img', {
src: url,
alt: '',
style: { width: 64, height: 64, objectFit: 'cover', borderRadius: 4, cursor: 'pointer' },
onClick: function () { photoPreviewState[1]({ open: true, url: url }); }
}),
React.createElement('span', {
style: { position: 'absolute', top: -6, right: -6, width: 20, height: 20, borderRadius: '50%', background: '#ff4d4f', color: '#fff', fontSize: 12, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' },
onClick: function () { removeFlawPhoto(i); }
}, '×')
);
})
)
),
React.createElement(FormItem, { label: '车辆检查', fullWidth: true },
React.createElement(Button, { type: 'default', onClick: function () { drawerOpenState[1](true); } }, '备车检查单')
)
)
)
),
React.createElement('div', { style: styles.footer },
React.createElement(Button, { type: 'primary', onClick: handleSubmit }, '提交'),
React.createElement(Button, { onClick: handleSave }, '保存'),
React.createElement(Button, { onClick: function () { if (typeof window !== 'undefined' && window.history) window.history.back(); } }, '取消')
),
React.createElement(Drawer, {
title: '备车检查单',
placement: 'right',
width: 640,
open: drawerOpenState[0],
onClose: function () { drawerOpenState[1](false); },
styles: { body: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', paddingBottom: 0 } },
footer: React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: 8 } },
React.createElement(Button, { onClick: function () { drawerOpenState[1](false); } }, '返回'),
React.createElement(Button, { type: 'primary', onClick: function () { drawerOpenState[1](false); message.success('检查单已保存'); } }, '提交')
)
},
React.createElement('div', { style: { flex: 1, minHeight: 0, overflow: 'auto' } },
React.createElement(Table, {
columns: inspectionColumns,
dataSource: form.inspectionList || [],
rowKey: function (_, i) { return i; },
pagination: false,
size: 'small'
})
)
),
React.createElement(Modal, {
title: '需求说明',
open: reqDocOpenState[0],
onCancel: function () { reqDocOpenState[1](false); },
footer: null,
width: 720,
styles: { body: { maxHeight: '70vh', overflow: 'auto', whiteSpace: 'pre-wrap', fontSize: 14, lineHeight: 1.8 } }
}, requirementDocContent),
photoPreviewState[0].open && photoPreviewState[0].url
? React.createElement(Modal, {
title: '预览',
open: true,
footer: null,
onCancel: function () { photoPreviewState[1]({ open: false, url: null }); }
}, React.createElement('img', { src: photoPreviewState[0].url, alt: '', style: { width: '100%' } }))
: null
);
};
if (typeof window !== 'undefined') {
window.Component = Component;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
});
} else {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
}

View File

@@ -0,0 +1,275 @@
// 【重要】必须使用 const Component 作为组件变量名
// 车辆业务 - 查看备车(与新增备车相同布局,全部只读)
const Component = function () {
var useState = React.useState;
var useMemo = React.useMemo;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Card = antd.Card;
var Input = antd.Input;
var Button = antd.Button;
var Drawer = antd.Drawer;
var Table = antd.Table;
var Modal = antd.Modal;
var plateManageList = [
{ plateNo: '京A12345', vehicleType: '厢式货车', brand: '东风', model: 'DFH1180', vin: 'LGHXCAE28M1234567', bodyAd: true, tailboard: true },
{ plateNo: '京C11111', vehicleType: '平板货车', brand: '福田', model: 'BJ1180', vin: 'LGHXCAE28M7654321', bodyAd: false, tailboard: false },
{ plateNo: '京D22222', vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M8888888', bodyAd: true, tailboard: false },
{ plateNo: '京E33333', vehicleType: '栏板货车', brand: '重汽', model: 'ZZ1180', vin: 'LGHXCAE28M7777777', bodyAd: false, tailboard: true },
{ plateNo: '京F10001', vehicleType: '厢式货车', brand: '江淮', model: 'HFC1180', vin: 'LGHXCAE28M9990001', bodyAd: true, tailboard: true }
];
var inspectionCategoryItems = {
'车灯': ['大灯', '转向灯', '小灯', '示廓灯', '刹车灯', '倒车灯', '牌照灯', '防雾灯', '室内灯'],
'仪表盘': ['氢系统指示', '电控系统指示', '数值清晰准确', '故障报警灯'],
'驾驶室': ['点烟器', '车窗升降', '按键开关', '雨刮器', '内后视镜是否正常', '内/外门把手', '安全带', '空调冷暖风', '仪表盘', '门锁功能', '手刹', '车钥匙功能是否正常', '喇叭', '音响功能', '遮阳板', '主副驾座椅', '方向盘', '内饰干净整洁'],
'轮胎': ['前左胎', '前右胎', '后左胎', '后右胎'],
'液位检查': ['冷却液', '制动液', '玻璃水'],
'外观检查': ['车身外观', '漆面', '玻璃'],
'车辆外观': ['整车外观'],
'其他': ['其他检查项'],
'随车工具': ['三角牌', '灭火器', '反光背心'],
'随车证件': ['行驶证', '营运证', '保险单'],
'整车': ['整车状态'],
'燃料电池系统': ['氢系统', '储氢瓶'],
'冷机': ['冷机运行'],
'制动系统': ['制动踏板', '驻车制动']
};
function buildInspectionList() {
var list = [];
var categories = Object.keys(inspectionCategoryItems);
for (var i = 0; i < categories.length; i++) {
var cat = categories[i];
var items = inspectionCategoryItems[cat];
for (var j = 0; j < items.length; j++) {
list.push({ category: cat, checkItem: items[j], checked: true, remark: '' });
}
}
return list;
}
// 只读:一条已填写的备车记录(不可编辑)
var form = useMemo(function () {
return {
plateNo: '京A12345',
vehicleType: '厢式货车',
brand: '东风',
model: 'DFH1180',
vin: 'LGHXCAE28M1234567',
bodyAd: true,
adPhotos: ['https://picsum.photos/200/150?r=1', 'https://picsum.photos/200/150?r=2'],
tailboard: true,
trailerPlate: '京B67890',
flawPhotos: ['https://picsum.photos/200/150?f=1'],
inspectionList: buildInspectionList()
};
}, []);
var drawerOpenState = useState(false);
var photoPreviewState = useState({ open: false, url: null });
var reqDocOpenState = useState(false);
var styles = {
page: { padding: '16px 24px 80px', backgroundColor: '#f5f5f5', minHeight: '100vh', fontSize: 14 },
breadcrumb: { marginBottom: 16, color: '#666' },
breadcrumbSep: { margin: '0 8px', color: '#999' },
card: { backgroundColor: '#fff', borderRadius: 8, marginBottom: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.05)', overflow: 'hidden' },
cardBody: { padding: '20px 24px' },
formRow: { display: 'flex', flexWrap: 'wrap', marginBottom: 16 },
formCol: { flex: '0 0 33.33%', minWidth: 200, paddingRight: 16, marginBottom: 8, boxSizing: 'border-box' },
formColFull: { flex: '0 0 100%', marginBottom: 8, boxSizing: 'border-box' },
label: { display: 'block', marginBottom: 6, color: '#333' },
labelRequired: { color: '#ff4d4f', marginRight: 4 },
footer: { position: 'fixed', bottom: 0, left: 0, right: 0, padding: '12px 24px', backgroundColor: '#fff', borderTop: '1px solid #e8e8e8', display: 'flex', gap: 12, zIndex: 99 }
};
var FormItem = function (props) {
var colStyle = props.fullWidth ? styles.formColFull : styles.formCol;
return React.createElement('div', { style: colStyle },
React.createElement('label', { style: styles.label },
props.required ? React.createElement('span', { style: styles.labelRequired }, '*') : null,
props.label
),
props.children
);
};
var inspectionList = form.inspectionList || [];
var categoryRowSpans = useMemo(function () {
var list = inspectionList;
var spans = [];
var i = 0;
while (i < list.length) {
var cat = list[i].category;
var start = i;
while (i < list.length && list[i].category === cat) i++;
spans[start] = i - start;
for (var j = start + 1; j < i; j++) spans[j] = 0;
}
return spans;
}, [form.inspectionList]);
var inspectionColumns = [
{
title: '类别',
dataIndex: 'category',
key: 'category',
width: 120,
onCell: function (_, index) { return { rowSpan: categoryRowSpans[index] !== undefined ? categoryRowSpans[index] : 1 }; }
},
{ title: '检查项目', dataIndex: 'checkItem', key: 'checkItem', width: 180 },
{
title: '检查情况',
key: 'checked',
width: 100,
render: function (_, record) { return record.checked !== false ? '开' : '关'; }
},
{ title: '备注', dataIndex: 'remark', key: 'remark', render: function (val) { return val || '-'; } }
];
var requirementDocContent = '新增备车\n\n1.面包屑:\n1.1.运维管理-车辆业务-备车管理-新增备车\n\n2.表单:\n2.1.车牌号:必选项,选择器,支持从输入框内输入内容进行模糊搜索,默认拉取「车牌管理」中所有「车牌号」;\n2.2.车辆类型:输入框禁用,选择车牌号后自动拉取该车牌号对应「车辆类型」;\n2.3.品牌:输入框禁用,选择车牌号后自动拉取该车牌号对应「品牌」;\n2.4.型号:输入框禁用,选择车牌号后自动拉取该车牌号对应「型号」\n2.5.车辆识别代码:输入框禁用,选择车牌号后自动拉取该车牌号「车辆识别代码」;\n2.6.车身广告:开关,选择车辆后拉取该车辆「后装设备」「车身广告」,如果该车辆有「车身广告」则勾选为开,如果无则勾选为无。同时如果手动进行操作,会同步到「后装设备」「车身广告」中,安装时间以该条备车记录提交成功为准;\n2.7.广告照片图片上传最多支持上传4张图片支持主流照片格式。上传后上传按钮后方横排显示已上传图片缩略图支持点击预览和删除\n2.8.尾板:开关,选择车辆后拉取该车辆「后装设备」「尾板」,如果该车辆有「尾板」则勾选为开,如果无则勾选为无。同时如果手动进行操作,会同步到「后装设备」「尾板」中,安装时间以该条备车记录提交成功为准;\n2.9.是否有挂:输入框,提示信息为:请输入挂车牌号,不输入为无挂;\n2.10.瑕疵图片上传最多支持上传4张图片支持主流照片格式。上传后上传按钮后方横排显示已上传图片缩略图支持点击预览和删除\n2.11.车辆检查:按钮,文字为备车检查单,点击右侧展开抽屉,抽屉内显示列表,字段为类别、检查项目、选择、备注;\n 2.11.1.类别:分为车灯、仪表盘、驾驶室、轮胎、液位检查、外观检查、车辆外观、其他、随车工具、随车证件、整车、燃料电池系统、冷机、制动系统;\n 2.11.2.检查项目:车灯类别对应(大灯、转向灯、小灯、示廓灯、刹车灯、倒车灯、牌照灯、防雾灯、室内灯)、仪表盘对应(氢系统指示、电控系统指示、数值清晰准确、故障报警灯)、驾驶室对应(点烟器、车窗升降、按键开关、雨刮器、内后视镜是否正常、内/外门把手、安全带、空调冷暖风、仪表盘、门锁功能、手刹、车钥匙功能是否正常、喇叭、音响功能、遮阳板、主副驾座椅、方向盘、内饰干净整洁)\n 2.11.3.检查情况:开关,在检查项目每项后方显示,默认为开,可手动进行关闭;\n 2.11.4.备注:输入框;\n2.12.下方为提交和保存;\n 2.12.1.提交点击提交toast提示备车成功同时保存该条数据并跳转至「备车管理」「已完成」\n 2.12.2.保存点击保存toast提示暂存成功同时保存该条数据并跳转至「备车管理」「待提交」';
var breadcrumbNodes = [
React.createElement('span', { key: '1' }, '运维管理'),
React.createElement('span', { key: '2', style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { key: '3' }, '车辆业务'),
React.createElement('span', { key: '4', style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { key: '5' }, '备车管理'),
React.createElement('span', { key: '6', style: styles.breadcrumbSep }, ' / '),
React.createElement('span', { key: '7', style: { color: '#1890ff' } }, '查看备车')
];
return React.createElement('div', { style: styles.page },
React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 } },
React.createElement('div', { style: styles.breadcrumb }, breadcrumbNodes),
React.createElement(Button, { type: 'link', style: { padding: 0 }, onClick: function () { reqDocOpenState[1](true); } }, '查看需求说明')
),
React.createElement('div', { style: styles.card },
React.createElement('div', { style: styles.cardBody },
React.createElement('div', { style: styles.formRow },
React.createElement(FormItem, { label: '车牌号', required: true },
React.createElement(Input, { value: form.plateNo, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '车辆类型' },
React.createElement(Input, { value: form.vehicleType, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '品牌' },
React.createElement(Input, { value: form.brand, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '型号' },
React.createElement(Input, { value: form.model, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '车辆识别代码' },
React.createElement(Input, { value: form.vin, disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement('div', { style: styles.formCol, key: 'ph0' }),
React.createElement(FormItem, { label: '车身广告' },
React.createElement(Input, { value: form.bodyAd ? '开' : '关', disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement('div', { style: styles.formCol, key: 'ph1' }),
React.createElement('div', { style: styles.formCol, key: 'ph2' }),
React.createElement(FormItem, { label: '尾板' },
React.createElement(Input, { value: form.tailboard ? '开' : '关', disabled: true, style: { width: '100%', background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '广告照片', fullWidth: true },
React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
(form.adPhotos || []).map(function (url, i) {
return React.createElement('img', {
key: i,
src: url,
alt: '',
style: { width: 64, height: 64, objectFit: 'cover', borderRadius: 4, cursor: 'pointer' },
onClick: function () { photoPreviewState[1]({ open: true, url: url }); }
});
}),
(form.adPhotos || []).length === 0 ? React.createElement('span', { style: { color: '#999' } }, '无') : null
)
),
React.createElement(FormItem, { label: '是否有挂' },
React.createElement(Input, { value: form.trailerPlate || '无', disabled: true, style: { width: '100%', maxWidth: 320, background: '#f5f5f5' } })
),
React.createElement(FormItem, { label: '瑕疵', fullWidth: true },
React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
(form.flawPhotos || []).map(function (url, i) {
return React.createElement('img', {
key: i,
src: url,
alt: '',
style: { width: 64, height: 64, objectFit: 'cover', borderRadius: 4, cursor: 'pointer' },
onClick: function () { photoPreviewState[1]({ open: true, url: url }); }
});
}),
(form.flawPhotos || []).length === 0 ? React.createElement('span', { style: { color: '#999' } }, '无') : null
)
),
React.createElement(FormItem, { label: '车辆检查', fullWidth: true },
React.createElement(Button, { type: 'default', onClick: function () { drawerOpenState[1](true); } }, '备车检查单')
)
)
)
),
React.createElement('div', { style: styles.footer },
React.createElement(Button, { onClick: function () { if (typeof window !== 'undefined' && window.history) window.history.back(); } }, '返回')
),
React.createElement(Drawer, {
title: '备车检查单',
placement: 'right',
width: 640,
open: drawerOpenState[0],
onClose: function () { drawerOpenState[1](false); },
styles: { body: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', paddingBottom: 0 } },
footer: React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end' } },
React.createElement(Button, { onClick: function () { drawerOpenState[1](false); } }, '返回')
)
},
React.createElement('div', { style: { flex: 1, minHeight: 0, overflow: 'auto' } },
React.createElement(Table, {
columns: inspectionColumns,
dataSource: form.inspectionList || [],
rowKey: function (_, i) { return i; },
pagination: false,
size: 'small'
})
)
),
React.createElement(Modal, {
title: '需求说明',
open: reqDocOpenState[0],
onCancel: function () { reqDocOpenState[1](false); },
footer: null,
width: 720,
styles: { body: { maxHeight: '70vh', overflow: 'auto', whiteSpace: 'pre-wrap', fontSize: 14, lineHeight: 1.8 } }
}, requirementDocContent),
photoPreviewState[0].open && photoPreviewState[0].url
? React.createElement(Modal, {
title: '预览',
open: true,
footer: null,
onCancel: function () { photoPreviewState[1]({ open: false, url: null }); }
}, React.createElement('img', { src: photoPreviewState[0].url, alt: '', style: { width: '100%' } }))
: null
);
};
if (typeof window !== 'undefined') {
window.Component = Component;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
});
} else {
var rootEl = document.getElementById('root');
if (rootEl && window.ReactDOM && window.React) {
var root = ReactDOM.createRoot(rootEl);
root.render(React.createElement(Component));
}
}
}

File diff suppressed because it is too large Load Diff

176
小程序/App.jsx Normal file
View File

@@ -0,0 +1,176 @@
// 【重要】必须使用 const Component 作为组件变量名
// 集成登录页 + 工作台 于单页面
const Component = function () {
var _React$useState = React.useState("login");
var page = _React$useState[0];
var setPage = _React$useState[1];
// 登录页状态
var _React$useState2 = React.useState("");
var account = _React$useState2[0];
var setAccount = _React$useState2[1];
var _React$useState3 = React.useState("");
var password = _React$useState3[0];
var setPassword = _React$useState3[1];
var _React$useState4 = React.useState(false);
var agreed = _React$useState4[0];
var setAgreed = _React$useState4[1];
// 工作台状态
var _React$useState5 = React.useState(0);
var activeTab = _React$useState5[0];
var setActiveTab = _React$useState5[1];
var todos = [
{ id: 1, title: "审批设备巡检报告", status: "待处理", time: "今天" },
{ id: 2, title: "处理加氢站异常告警", status: "进行中", time: "今天" },
{ id: 3, title: "完成月度资产盘点", status: "待处理", time: "本周" }
];
var stats = [
{ label: "待办任务", value: "8", color: "#07c160" },
{ label: "本周完成", value: "23", color: "#576b95" },
{ label: "告警待处理", value: "2", color: "#fa5151" }
];
var navItems = [
{ key: 0, icon: "\uD83D\uDCCA", text: "工作台" },
{ key: 1, icon: "\uD83D\uDCC4", text: "业务" },
{ key: 2, icon: "\uD83D\uDC64", text: "我的" }
];
var handleLogin = function () {
if (!agreed) {
alert("请先阅读并同意用户服务协议和隐私政策");
return;
}
setPage("workbench");
};
var styles = {
loginPage: {
minHeight: "100vh",
backgroundColor: "#f7f7f7",
padding: "40px 24px 24px",
boxSizing: "border-box",
display: "flex",
flexDirection: "column",
alignItems: "center"
},
logo: { width: "80px", height: "80px", backgroundColor: "#07c160", borderRadius: "16px", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: "20px", color: "#fff", fontSize: "16px", fontWeight: "bold", textAlign: "center", lineHeight: "1.3" },
title: { fontSize: "20px", fontWeight: "600", color: "#333", textAlign: "center", marginBottom: "40px", lineHeight: "1.5", maxWidth: "280px" },
form: { width: "100%", maxWidth: "340px" },
inputGroup: { marginBottom: "16px" },
input: { width: "100%", height: "48px", padding: "0 16px", fontSize: "16px", border: "1px solid #e5e5e5", borderRadius: "8px", backgroundColor: "#fff", boxSizing: "border-box", outline: "none" },
checkboxRow: { display: "flex", alignItems: "center", marginBottom: "24px", cursor: "pointer" },
checkbox: { width: "18px", height: "18px", marginRight: "8px", accentColor: "#07c160", cursor: "pointer" },
agreement: { fontSize: "14px", color: "#666", lineHeight: "1.5" },
link: { color: "#07c160", textDecoration: "none" },
loginBtn: { width: "100%", height: "48px", backgroundColor: "#07c160", color: "#fff", fontSize: "17px", fontWeight: "500", border: "none", borderRadius: "8px", cursor: "pointer", marginBottom: "32px" },
loginBtnDisabled: { width: "100%", height: "48px", backgroundColor: "#b0b0b0", color: "#fff", fontSize: "17px", fontWeight: "500", border: "none", borderRadius: "8px", cursor: "not-allowed", marginBottom: "32px" },
divider: { display: "flex", alignItems: "center", width: "100%", maxWidth: "340px", marginBottom: "24px" },
dividerLine: { flex: 1, height: "1px", backgroundColor: "#e5e5e5" },
dividerText: { padding: "0 16px", fontSize: "14px", color: "#999" },
phoneLogin: { display: "flex", flexDirection: "column", alignItems: "center" },
iconLabel: { fontSize: "14px", color: "#999", marginTop: "8px" },
iconBtn: { width: "48px", height: "48px", borderRadius: "50%", backgroundColor: "#fff", border: "1px solid #e5e5e5", display: "flex", alignItems: "center", justifyContent: "center", cursor: "pointer", fontSize: "24px" },
workbenchPage: { minHeight: "100vh", backgroundColor: "#f7f7f7", paddingBottom: "70px", boxSizing: "border-box" },
header: { backgroundColor: "#fff", padding: "24px 20px", marginBottom: "12px" },
headerTitle: { fontSize: "22px", fontWeight: "600", color: "#333", marginBottom: "4px" },
headerSub: { fontSize: "14px", color: "#999" },
statsRow: { display: "flex", padding: "0 12px 12px", marginBottom: "12px" },
statCard: { flex: 1, backgroundColor: "#fff", borderRadius: "8px", padding: "20px 12px", textAlign: "center", margin: "0 6px" },
statValue: { fontSize: "24px", fontWeight: "600", marginBottom: "8px" },
statLabel: { fontSize: "13px", color: "#999" },
section: { backgroundColor: "#fff", padding: "20px", marginBottom: "12px" },
sectionTitle: { fontSize: "17px", fontWeight: "600", color: "#333", marginBottom: "16px", display: "flex", justifyContent: "space-between", alignItems: "center" },
sectionMore: { fontSize: "14px", color: "#07c160" },
todoItem: { display: "flex", alignItems: "center", padding: "14px 0", borderBottom: "1px solid #f0f0f0" },
todoLeft: { flex: 1 },
todoTitle: { fontSize: "15px", color: "#333", marginBottom: "4px" },
todoMeta: { fontSize: "12px", color: "#999" },
todoStatus: { fontSize: "12px", padding: "4px 10px", borderRadius: "4px", backgroundColor: "#e8f5e9", color: "#07c160" },
todoStatusDoing: { fontSize: "12px", padding: "4px 10px", borderRadius: "4px", backgroundColor: "#fff3e0", color: "#ff9800" },
bottomNav: { position: "fixed", bottom: 0, left: 0, right: 0, height: "60px", backgroundColor: "#fff", display: "flex", borderTop: "1px solid #e5e5e5", boxSizing: "border-box" },
navItem: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", cursor: "pointer" },
navIcon: { fontSize: "24px", marginBottom: "4px" },
navText: { fontSize: "11px", color: "#999" }
};
if (page === "login") {
return React.createElement("div", { style: styles.loginPage },
React.createElement("style", null, "input::placeholder{color:#999;opacity:1;}"),
React.createElement("div", { style: styles.logo }, "羚牛氢能"),
React.createElement("h1", { style: styles.title }, "数字化资产ONE-OS运管平台"),
React.createElement("div", { style: styles.form },
React.createElement("div", { style: styles.inputGroup },
React.createElement("input", { style: styles.input, type: "text", placeholder: "请输入账号信息", value: account, onChange: function (e) { setAccount(e.target.value); } })
),
React.createElement("div", { style: styles.inputGroup },
React.createElement("input", { style: styles.input, type: "password", placeholder: "请输入密码", value: password, onChange: function (e) { setPassword(e.target.value); } })
),
React.createElement("label", { style: styles.checkboxRow },
React.createElement("input", { style: styles.checkbox, type: "checkbox", checked: agreed, onChange: function (e) { setAgreed(e.target.checked); } }),
React.createElement("span", { style: styles.agreement },
"阅读并同意",
React.createElement("a", { href: "#", style: styles.link }, "《用户服务协议》"),
"和",
React.createElement("a", { href: "#", style: styles.link }, "《隐私政策》")
)
),
React.createElement("button", { style: agreed ? styles.loginBtn : styles.loginBtnDisabled, onClick: handleLogin, disabled: !agreed }, "登录")
),
React.createElement("div", { style: styles.divider },
React.createElement("div", { style: styles.dividerLine }),
React.createElement("span", { style: styles.dividerText }, "其他登录方式"),
React.createElement("div", { style: styles.dividerLine })
),
React.createElement("div", { style: styles.phoneLogin },
React.createElement("div", { style: styles.iconBtn, title: "手机号登录" }, "\uD83D\uDCF1"),
React.createElement("span", { style: styles.iconLabel }, "授权登录")
)
);
}
return React.createElement("div", { style: styles.workbenchPage },
React.createElement("div", { style: styles.header },
React.createElement("div", { style: styles.headerTitle }, "工作台"),
React.createElement("div", { style: styles.headerSub }, "欢迎使用 ONE-OS 运管平台")
),
React.createElement("div", { style: styles.statsRow },
stats.map(function (stat, i) {
var valueStyle = { fontSize: "24px", fontWeight: "600", marginBottom: "8px", color: stat.color };
return React.createElement("div", { key: i, style: styles.statCard },
React.createElement("div", { style: valueStyle }, stat.value),
React.createElement("div", { style: styles.statLabel }, stat.label)
);
})
),
React.createElement("div", { style: styles.section },
React.createElement("div", { style: styles.sectionTitle },
React.createElement("span", null, "待办任务"),
React.createElement("span", { style: styles.sectionMore }, "全部")
),
todos.map(function (todo, i) {
var isLast = i === todos.length - 1;
var statusStyle = todo.status === "进行中" ? styles.todoStatusDoing : styles.todoStatus;
var itemStyle = isLast ? { display: "flex", alignItems: "center", padding: "14px 0", borderBottom: "none" } : styles.todoItem;
return React.createElement("div", { key: todo.id, style: itemStyle },
React.createElement("div", { style: styles.todoLeft },
React.createElement("div", { style: styles.todoTitle }, todo.title),
React.createElement("div", { style: styles.todoMeta }, todo.time)
),
React.createElement("span", { style: statusStyle }, todo.status)
);
})
),
React.createElement("div", { style: styles.bottomNav },
navItems.map(function (item) {
var isActive = activeTab === item.key;
var textStyle = isActive ? { fontSize: "11px", color: "#07c160" } : styles.navText;
return React.createElement("div", { key: item.key, style: styles.navItem, onClick: function () { setActiveTab(item.key); } },
React.createElement("div", { style: styles.navIcon }, item.icon),
React.createElement("div", { style: textStyle }, item.text)
);
})
)
);
};

286
小程序/LoginPage.jsx Normal file
View File

@@ -0,0 +1,286 @@
// 【重要】必须使用 const Component 作为组件变量名
const LoginPage = function (props) {
var onLoginSuccess = (props && props.onLoginSuccess) ? props.onLoginSuccess : null;
var _React$useState = React.useState("");
var account = _React$useState[0];
var setAccount = _React$useState[1];
var _React$useState2 = React.useState("");
var password = _React$useState2[0];
var setPassword = _React$useState2[1];
var _React$useState3 = React.useState(false);
var agreed = _React$useState3[0];
var setAgreed = _React$useState3[1];
var handleAccountChange = function (e) {
setAccount(e.target.value);
};
var handlePasswordChange = function (e) {
setPassword(e.target.value);
};
var handleAgreedChange = function (e) {
setAgreed(e.target.checked);
};
var handleLogin = function () {
if (!agreed) {
alert("请先阅读并同意用户服务协议和隐私政策");
return;
}
if (onLoginSuccess) {
onLoginSuccess();
} else {
alert("登录功能演示");
}
};
var styles = {
page: {
minHeight: "100vh",
backgroundColor: "#f7f7f7",
padding: "40px 24px 24px",
boxSizing: "border-box",
display: "flex",
flexDirection: "column",
alignItems: "center"
},
logo: {
width: "80px",
height: "80px",
backgroundColor: "#07c160",
borderRadius: "16px",
display: "flex",
alignItems: "center",
justifyContent: "center",
marginBottom: "20px",
color: "#fff",
fontSize: "16px",
fontWeight: "bold",
textAlign: "center",
lineHeight: "1.3"
},
title: {
fontSize: "20px",
fontWeight: "600",
color: "#333",
textAlign: "center",
marginBottom: "40px",
lineHeight: "1.5",
maxWidth: "280px"
},
form: {
width: "100%",
maxWidth: "340px"
},
inputGroup: {
marginBottom: "16px"
},
input: {
width: "100%",
height: "48px",
padding: "0 16px",
fontSize: "16px",
border: "1px solid #e5e5e5",
borderRadius: "8px",
backgroundColor: "#fff",
boxSizing: "border-box",
outline: "none"
},
inputFocus: {
borderColor: "#07c160"
},
checkboxRow: {
display: "flex",
alignItems: "center",
marginBottom: "24px",
cursor: "pointer"
},
checkbox: {
width: "18px",
height: "18px",
marginRight: "8px",
accentColor: "#07c160",
cursor: "pointer"
},
agreement: {
fontSize: "14px",
color: "#666",
lineHeight: "1.5"
},
link: {
color: "#07c160",
textDecoration: "none"
},
loginBtn: {
width: "100%",
height: "48px",
backgroundColor: "#07c160",
color: "#fff",
fontSize: "17px",
fontWeight: "500",
border: "none",
borderRadius: "8px",
cursor: "pointer",
marginBottom: "32px"
},
loginBtnDisabled: {
width: "100%",
height: "48px",
backgroundColor: "#b0b0b0",
color: "#fff",
fontSize: "17px",
fontWeight: "500",
border: "none",
borderRadius: "8px",
cursor: "not-allowed",
marginBottom: "32px"
},
divider: {
display: "flex",
alignItems: "center",
width: "100%",
maxWidth: "340px",
marginBottom: "24px"
},
dividerLine: {
flex: 1,
height: "1px",
backgroundColor: "#e5e5e5"
},
dividerText: {
padding: "0 16px",
fontSize: "14px",
color: "#999"
},
phoneLogin: {
display: "flex",
flexDirection: "column",
alignItems: "center"
},
iconLabel: {
fontSize: "14px",
color: "#999",
marginTop: "8px"
},
iconBtn: {
width: "48px",
height: "48px",
borderRadius: "50%",
backgroundColor: "#fff",
border: "1px solid #e5e5e5",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
fontSize: "24px"
}
};
return React.createElement(
"div",
{ style: styles.page },
React.createElement("style", null, "input::placeholder{color:#999;opacity:1;}"),
React.createElement(
"div",
{ style: styles.logo },
"羚牛氢能"
),
React.createElement(
"h1",
{ style: styles.title },
"\u6570\u5B57\u5316\u8D44\u4EA7ONE-OS\u8FD0\u7BA1\u5E73\u53F0"
),
React.createElement(
"div",
{ style: styles.form },
React.createElement(
"div",
{ style: styles.inputGroup },
React.createElement("input", {
style: styles.input,
type: "text",
placeholder: "请输入账号信息",
value: account,
onChange: handleAccountChange
})
),
React.createElement(
"div",
{ style: styles.inputGroup },
React.createElement("input", {
style: styles.input,
type: "password",
placeholder: "请输入密码",
value: password,
onChange: handlePasswordChange
})
),
React.createElement(
"label",
{ style: styles.checkboxRow },
React.createElement("input", {
style: styles.checkbox,
type: "checkbox",
checked: agreed,
onChange: handleAgreedChange
}),
React.createElement(
"span",
{ style: styles.agreement },
"阅读并同意",
React.createElement(
"a",
{ href: "#", style: styles.link },
"《用户服务协议》"
),
"和",
React.createElement(
"a",
{ href: "#", style: styles.link },
"《隐私政策》"
)
)
),
React.createElement(
"button",
{
style: agreed ? styles.loginBtn : styles.loginBtnDisabled,
onClick: handleLogin,
disabled: !agreed
},
"\u767B\u5F55"
)
),
React.createElement(
"div",
{ style: styles.divider },
React.createElement("div", { style: styles.dividerLine }),
React.createElement(
"span",
{ style: styles.dividerText },
"\u5176\u4ED6\u767B\u5F55\u65B9\u5F0F"
),
React.createElement("div", { style: styles.dividerLine })
),
React.createElement(
"div",
{ style: styles.phoneLogin },
React.createElement(
"div",
{ style: styles.iconBtn, title: "手机号登录" },
"\uD83D\uDCF1"
),
React.createElement(
"span",
{ style: styles.iconLabel },
"授权登录"
)
)
);
};
// Axhub 要求必须定义 Component 变量
var Component = LoginPage;

232
小程序/WorkbenchPage.jsx Normal file
View File

@@ -0,0 +1,232 @@
const WorkbenchPage = function () {
var _React$useState = React.useState(0);
var activeTab = _React$useState[0];
var setActiveTab = _React$useState[1];
var todos = [
{ id: 1, title: "审批设备巡检报告", status: "待处理", time: "今天" },
{ id: 2, title: "处理加氢站异常告警", status: "进行中", time: "今天" },
{ id: 3, title: "完成月度资产盘点", status: "待处理", time: "本周" }
];
var stats = [
{ label: "待办任务", value: "8", color: "#07c160" },
{ label: "本周完成", value: "23", color: "#576b95" },
{ label: "告警待处理", value: "2", color: "#fa5151" }
];
var navItems = [
{ key: 0, icon: "\uD83D\uDCCA", text: "工作台" },
{ key: 1, icon: "\uD83D\uDCC4", text: "业务" },
{ key: 2, icon: "\uD83D\uDC64", text: "我的" }
];
var handleNavClick = function (key) {
setActiveTab(key);
};
var styles = {
page: {
minHeight: "100vh",
backgroundColor: "#f7f7f7",
paddingBottom: "70px",
boxSizing: "border-box"
},
header: {
backgroundColor: "#fff",
padding: "24px 20px",
marginBottom: "12px"
},
headerTitle: {
fontSize: "22px",
fontWeight: "600",
color: "#333",
marginBottom: "4px"
},
headerSub: {
fontSize: "14px",
color: "#999"
},
statsRow: {
display: "flex",
padding: "0 12px 12px",
marginBottom: "12px"
},
statCard: {
flex: 1,
backgroundColor: "#fff",
borderRadius: "8px",
padding: "20px 12px",
textAlign: "center",
margin: "0 6px"
},
statValue: {
fontSize: "24px",
fontWeight: "600",
marginBottom: "8px"
},
statLabel: {
fontSize: "13px",
color: "#999"
},
section: {
backgroundColor: "#fff",
padding: "20px",
marginBottom: "12px"
},
sectionTitle: {
fontSize: "17px",
fontWeight: "600",
color: "#333",
marginBottom: "16px",
display: "flex",
justifyContent: "space-between",
alignItems: "center"
},
sectionMore: {
fontSize: "14px",
color: "#07c160"
},
todoItem: {
display: "flex",
alignItems: "center",
padding: "14px 0",
borderBottom: "1px solid #f0f0f0"
},
todoItemLast: {
borderBottom: "none"
},
todoLeft: {
flex: 1
},
todoTitle: {
fontSize: "15px",
color: "#333",
marginBottom: "4px"
},
todoMeta: {
fontSize: "12px",
color: "#999"
},
todoStatus: {
fontSize: "12px",
padding: "4px 10px",
borderRadius: "4px",
backgroundColor: "#e8f5e9",
color: "#07c160"
},
todoStatusDoing: {
fontSize: "12px",
padding: "4px 10px",
borderRadius: "4px",
backgroundColor: "#fff3e0",
color: "#ff9800"
},
bottomNav: {
position: "fixed",
bottom: 0,
left: 0,
right: 0,
height: "60px",
backgroundColor: "#fff",
display: "flex",
borderTop: "1px solid #e5e5e5",
boxSizing: "border-box"
},
navItem: {
flex: 1,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
cursor: "pointer"
},
navIcon: {
fontSize: "24px",
marginBottom: "4px"
},
navText: {
fontSize: "11px",
color: "#999"
},
navTextActive: {
color: "#07c160"
}
};
return React.createElement(
"div",
{ style: styles.page },
React.createElement(
"div",
{ style: styles.header },
React.createElement("div", { style: styles.headerTitle }, "工作台"),
React.createElement("div", { style: styles.headerSub }, "欢迎使用 ONE-OS 运管平台")
),
React.createElement(
"div",
{ style: styles.statsRow },
stats.map(function (stat, i) {
var valueStyle = {
fontSize: "24px",
fontWeight: "600",
marginBottom: "8px",
color: stat.color
};
return React.createElement(
"div",
{ key: i, style: styles.statCard },
React.createElement("div", { style: valueStyle }, stat.value),
React.createElement("div", { style: styles.statLabel }, stat.label)
);
})
),
React.createElement(
"div",
{ style: styles.section },
React.createElement(
"div",
{ style: styles.sectionTitle },
React.createElement("span", null, "待办任务"),
React.createElement("span", { style: styles.sectionMore }, "全部")
),
todos.map(function (todo, i) {
var isLast = i === todos.length - 1;
var statusStyle = todo.status === "进行中" ? styles.todoStatusDoing : styles.todoStatus;
var itemStyle = isLast ? { display: "flex", alignItems: "center", padding: "14px 0", borderBottom: "none" } : styles.todoItem;
return React.createElement(
"div",
{ key: todo.id, style: itemStyle },
React.createElement(
"div",
{ style: styles.todoLeft },
React.createElement("div", { style: styles.todoTitle }, todo.title),
React.createElement("div", { style: styles.todoMeta }, todo.time)
),
React.createElement("span", { style: statusStyle }, todo.status)
);
})
),
React.createElement(
"div",
{ style: styles.bottomNav },
navItems.map(function (item) {
var isActive = activeTab === item.key;
var textStyle = isActive ? { fontSize: "11px", color: "#07c160" } : styles.navText;
return React.createElement(
"div",
{
key: item.key,
style: styles.navItem,
onClick: function () { handleNavClick(item.key); }
},
React.createElement("div", { style: styles.navIcon }, item.icon),
React.createElement("div", { style: textStyle }, item.text)
);
})
)
);
};
// Axhub 要求必须定义 Component 变量
var Component = WorkbenchPage;

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ONE-OS运管平台</title>
<link rel="stylesheet" href="https://res.wx.qq.com/t/wx_fed/weui-source/res/2.6.22/weui.min.css">
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel" src="App.jsx"></script>
<script type="text/babel">
var root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(Component));
</script>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>工作台 - 数字化资产ONE-OS运管平台</title>
<link rel="stylesheet" href="https://res.wx.qq.com/t/wx_fed/weui-source/res/2.6.22/weui.min.css">
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel" src="WorkbenchPage.jsx"></script>
<script type="text/babel">
var root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(WorkbenchPage));
</script>
</body>
</html>