// 【重要】必须使用 const Component 作为组件变量名 // 小程序端 - 登录 + 待办任务页 · 配色青绿 #16D1A1 / #00BFA5 const Component = function () { var useState = React.useState; var h = React.createElement; var antd = window.antd || {}; var App = antd.App || React.Fragment; var message = antd.message || { info: function () {}, success: function () {}, error: function () {} }; var COLOR_PRIMARY = '#16D1A1'; var COLOR_PRIMARY_DEEP = '#00BFA5'; var COLOR_TEXT = '#1D2129'; var COLOR_MUTED = '#86909C'; var COLOR_LINE = '#E5E6EB'; var COLOR_BG = '#FFFFFF'; var COLOR_INPUT_BG = '#F2F4F7'; var COLOR_PAGE_BG = '#F2F3F5'; var FONT_FAMILY = '-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", STHeiti, Tahoma, sans-serif'; var routeState = useState('login'); // login | todo var route = routeState[0]; var setRoute = routeState[1]; var accountState = useState(''); var account = accountState[0]; var setAccount = accountState[1]; var passwordState = useState(''); var password = passwordState[0]; var setPassword = passwordState[1]; var agreeState = useState(false); var agree = agreeState[0]; var setAgree = agreeState[1]; var submittingState = useState(false); var submitting = submittingState[0]; var setSubmitting = submittingState[1]; var tabState = useState('todo'); // todo | biz | map | mine var mainTab = tabState[0]; var setMainTab = tabState[1]; var bizNavState = useState('menu'); // menu | vehicleList | vehicleDetail var bizNav = bizNavState[0]; var setBizNav = bizNavState[1]; var vehicleSearchState = useState(''); var vehicleSearch = vehicleSearchState[0]; var setVehicleSearch = vehicleSearchState[1]; var filterDrawerOpenState = useState(false); var filterDrawerOpen = filterDrawerOpenState[0]; var setFilterDrawerOpen = filterDrawerOpenState[1]; var vehicleFilterAppliedState = useState({ status: '全部', province: '全部', city: '全部' }); var vehicleFilterApplied = vehicleFilterAppliedState[0]; var setVehicleFilterApplied = vehicleFilterAppliedState[1]; var vehicleFilterDraftState = useState({ status: '全部', province: '全部', city: '全部' }); var vehicleFilterDraft = vehicleFilterDraftState[0]; var setVehicleFilterDraft = vehicleFilterDraftState[1]; var selectedVehicleState = useState(null); var selectedVehicle = selectedVehicleState[0]; var setSelectedVehicle = selectedVehicleState[1]; var vehicleDetailTabState = useState('basic'); // basic | spec | cert var vehicleDetailTab = vehicleDetailTabState[0]; var setVehicleDetailTab = vehicleDetailTabState[1]; function gotoTodoPage() { setRoute('todo'); setMainTab('todo'); } function handleLogin() { if (submitting) return; if (!account || !password) { message.info('请输入用户名和密码'); return; } if (!agree) { message.info('请先阅读并同意相关协议'); return; } setSubmitting(true); setTimeout(function () { setSubmitting(false); message.success('登录成功'); gotoTodoPage(); }, 450); } function handlePhoneAuthLogin() { if (!agree) { message.info('请先阅读并同意相关协议'); return; } gotoTodoPage(); } function renderCapsuleCompact() { return h( 'div', { style: { width: 88, height: 32, borderRadius: 16, border: '1px solid ' + COLOR_LINE, background: 'rgba(255,255,255,0.96)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 10px', boxSizing: 'border-box', flexShrink: 0 } }, h('div', { style: { width: 4, height: 4, borderRadius: 2, background: COLOR_MUTED, opacity: 0.75 } }), h('div', { style: { width: 4, height: 4, borderRadius: 2, background: COLOR_MUTED, opacity: 0.75 } }), h('div', { style: { width: 4, height: 4, borderRadius: 2, background: COLOR_MUTED, opacity: 0.75 } }), h('div', { style: { width: 10, height: 10, borderRadius: 5, border: '2px solid ' + COLOR_MUTED, opacity: 0.8 } }) ); } function renderCapsule() { return h( 'div', { style: { position: 'absolute', top: 10, right: 12, width: 88, height: 32, borderRadius: 16, border: '1px solid ' + COLOR_LINE, background: 'rgba(255,255,255,0.9)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 10px', boxSizing: 'border-box', zIndex: 5 } }, h('div', { style: { width: 4, height: 4, borderRadius: 2, background: COLOR_MUTED, opacity: 0.75 } }), h('div', { style: { width: 4, height: 4, borderRadius: 2, background: COLOR_MUTED, opacity: 0.75 } }), h('div', { style: { width: 4, height: 4, borderRadius: 2, background: COLOR_MUTED, opacity: 0.75 } }), h('div', { style: { width: 10, height: 10, borderRadius: 5, border: '2px solid ' + COLOR_MUTED, opacity: 0.8 } }) ); } function renderBrandLogo() { return h( 'div', { style: { display: 'flex', justifyContent: 'center', marginBottom: 32, flexShrink: 0 } }, h( 'div', { style: { width: 80, height: 80, borderRadius: 40, background: COLOR_PRIMARY, boxShadow: '0 14px 36px rgba(22,209,161,0.38)', display: 'flex', alignItems: 'center', justifyContent: 'center' }, 'aria-hidden': true }, h( 'svg', { width: 44, height: 44, viewBox: '0 0 64 64', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, h('circle', { cx: 32, cy: 28, r: 16, stroke: '#FFFFFF', strokeWidth: 2.6 }), h('circle', { cx: 32, cy: 28, r: 5, fill: '#FFFFFF' }), h('path', { d: 'M12 44 Q32 54 52 44', stroke: '#FFFFFF', strokeWidth: 2.6, strokeLinecap: 'round' }) ) ) ); } function renderIconUser() { var ink = COLOR_PRIMARY; return h( 'svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', 'aria-hidden': true }, h('circle', { cx: 12, cy: 8, r: 3.5, stroke: ink, strokeWidth: 1.7 }), h('path', { d: 'M6.5 20v-1c0-2.2 2.46-4 5.5-4s5.5 1.8 5.5 4v1', stroke: ink, strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round' }) ); } function renderIconLock() { var ink = COLOR_PRIMARY; return h( 'svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', 'aria-hidden': true }, h('path', { d: 'M7 11V8a5 5 0 0 1 10 0v3', stroke: ink, strokeWidth: 1.7, strokeLinecap: 'round' }), h('rect', { x: 5, y: 11, width: 14, height: 10, rx: 2, stroke: ink, strokeWidth: 1.7 }), h('circle', { cx: 12, cy: 15.5, r: 1.2, fill: ink }) ); } function pillInputStyle(extra) { var base = { display: 'flex', alignItems: 'center', gap: 12, background: COLOR_INPUT_BG, borderRadius: 999, paddingLeft: 16, paddingRight: 16, minHeight: 52, boxSizing: 'border-box', boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.04)' }; if (!extra) return base; for (var k in extra) { if (Object.prototype.hasOwnProperty.call(extra, k)) base[k] = extra[k]; } return base; } var MOCK_TODO_TASKS = [ { id: 't1', taskName: '交车任务', project: '徐云霆测试项目8', customer: '徐云霆55', place: '羚牛氢能中心', time: '2026-04-28 00:00:00' }, { id: 't2', taskName: '交车任务', project: '徐云霆测试项目9', customer: '徐云霆55', place: '羚牛氢能中心', time: '2026-04-29 09:30:00' } ]; var VEHICLE_FILTER_STATUS = ['全部', '租赁', '自营', '可运营', '待运营', '退出运营']; var VEHICLE_FILTER_PROVINCES = ['全部', '江苏省', '浙江省', '广东省', '河北省', '福建省']; /** 省份 → 下属城市(筛选「城市」选项随「省份」联动) */ var PROVINCE_CITY_MAP = { 江苏省: ['苏州市', '南京市', '无锡市'], 浙江省: ['杭州市', '宁波市', '温州市'], 广东省: ['深圳市', '广州市', '东莞市'], 河北省: ['石家庄市', '唐山市'], 福建省: ['福州市', '厦门市', '泉州市'] }; function getCityFilterOptionsByProvince(province) { if (province === '全部' || !province) { var seen = {}; var list = ['全部']; Object.keys(PROVINCE_CITY_MAP).forEach(function (p) { PROVINCE_CITY_MAP[p].forEach(function (c) { if (!seen[c]) { seen[c] = true; list.push(c); } }); }); return list; } return ['全部'].concat(PROVINCE_CITY_MAP[province] ? PROVINCE_CITY_MAP[province].slice() : []); } function normalizeFilterDraft(draft) { var cities = getCityFilterOptionsByProvince(draft.province); var city = draft.city; if (cities.indexOf(city) === -1) city = '全部'; return { status: draft.status, province: draft.province, city: city }; } var MOCK_VEHICLES = (function () { var statuses = ['租赁', '自营', '可运营', '待运营', '退出运营', '租赁', '自营', '可运营', '待运营', '退出运营']; var provinces = ['江苏省', '浙江省', '广东省', '河北省', '福建省']; var plates = [ '浙F08833F', '苏A9H1234', '粤B66D888', '浙A12345F', '冀A99999F', '闽D01234F', '苏E88888F', '粤S77777F', '浙C66666F', '冀B55555F' ]; var vehicleTypes = [ '重型半挂牵引车', '重型半挂牵引车', '重型仓栅式货车', '重型半挂牵引车', '重型半挂牵引车', '重型仓栅式货车', '重型半挂牵引车', '重型仓栅式货车', '重型半挂牵引车', '重型半挂牵引车' ]; var brands = ['飞驰', '飞驰', '羚牛', '飞驰', '飞驰', '羚牛', '飞驰', '羚牛', '飞驰', '飞驰']; var models = [ '49吨牵引车头', '49吨牵引车头', '31吨载货车', '49吨牵引车头', '49吨牵引车头', '31吨载货车', '49吨牵引车头', '31吨载货车', '49吨牵引车头', '49吨牵引车头' ]; var arr = []; for (var i = 1; i <= 10; i++) { var pr = provinces[(i - 1) % provinces.length]; var cs = PROVINCE_CITY_MAP[pr]; var city = cs[(i - 1) % cs.length]; arr.push({ id: 'veh-' + i, plate: plates[i - 1], status: statuses[i - 1], province: pr, city: city, vehicleType: vehicleTypes[i - 1], brand: brands[i - 1], model: models[i - 1] }); } return arr; })(); function iconTruck() { var c = COLOR_PRIMARY; return h( 'svg', { width: 22, height: 22, viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, h('path', { d: 'M2 17h13V7H8L6 17', stroke: c, strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round' }), h('path', { d: 'M15 17h8l2-6h-8v6zm0-6v2h6', stroke: c, strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round' }), h('circle', { cx: 7.5, cy: 18.5, r: 1.8, fill: c }), h('circle', { cx: 18.5, cy: 18.5, r: 1.8, fill: c }), h('circle', { cx: 7.5, cy: 18.5, r: 0.8, fill: '#FFFFFF' }), h('circle', { cx: 18.5, cy: 18.5, r: 0.8, fill: '#FFFFFF' }) ); } function kvRow(label, value) { return h( 'div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12, paddingTop: 8, paddingBottom: 8, borderTop: '1px solid ' + COLOR_LINE, fontSize: 14, lineHeight: 1.45 } }, h('span', { style: { color: COLOR_MUTED, flexShrink: 0 } }, label), h( 'span', { style: { color: COLOR_TEXT, textAlign: 'right', wordBreak: 'break-all', fontWeight: 500 } }, value ) ); } function renderTaskCard(task) { return h( 'div', { key: task.id, style: { background: COLOR_BG, borderRadius: 12, padding: '14px 16px', marginBottom: 12, boxShadow: '0 1px 4px rgba(0,0,0,0.06)' } }, h( 'div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, marginBottom: 4 } }, h( 'div', { style: { display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 } }, iconTruck(), h( 'span', { style: { fontSize: 16, fontWeight: 700, color: COLOR_TEXT } }, task.taskName ) ), h( 'button', { type: 'button', onClick: function () { message.info('去处理:可跳转任务详情'); }, style: { border: 'none', background: 'transparent', color: COLOR_PRIMARY, fontSize: 15, fontWeight: 600, padding: '4px 0', cursor: 'pointer', flexShrink: 0 } }, '去处理' ) ), kvRow('项目名称', task.project), kvRow('客户名称', task.customer), kvRow('交车地点', task.place), kvRow('交车时间', task.time) ); } function renderBellWithBadge(count) { return h( 'button', { type: 'button', 'aria-label': '通知', onClick: function () { message.info('通知占位'); }, style: { border: 'none', background: 'transparent', padding: 4, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'flex-start', justifySelf: 'start' } }, h( 'div', { style: { position: 'relative', width: 28, height: 28 } }, h( 'svg', { width: 26, height: 26, viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, h('path', { d: 'M12 21a2 2 0 002-2H10a2 2 0 002 2zm7-9a6 6 0 10-12 0c0 6-3 6.5-3 7h18c0-.5-3-1-3-7z', stroke: COLOR_TEXT, strokeWidth: 1.5, strokeLinejoin: 'round' }) ), h( 'span', { style: { position: 'absolute', top: -4, right: -10, minWidth: 18, height: 18, borderRadius: 9, background: COLOR_PRIMARY, color: '#FFFFFF', fontSize: 10, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 5px', boxSizing: 'border-box' } }, String(count || 99) ) ) ); } function bizBadge() { return h( 'span', { style: { position: 'absolute', top: -6, right: -8, minWidth: 18, height: 18, borderRadius: 9, background: COLOR_PRIMARY, color: '#FFFFFF', fontSize: 10, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 5px', boxSizing: 'border-box' } }, '99' ); } function bizMenuCell(spec) { var label = typeof spec === 'string' ? spec : spec.label; var badge = typeof spec === 'object' ? spec.badge : false; var bizEntry = typeof spec === 'object' ? spec.bizEntry : ''; return h( 'button', { key: label, type: 'button', onClick: function () { if (bizEntry === 'vehicleList') { setVehicleSearch(''); setBizNav('vehicleList'); return; } message.info(label + ':功能入口占位'); }, style: { border: 'none', background: 'transparent', padding: '8px 4px', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, width: '100%', boxSizing: 'border-box' } }, h( 'div', { style: { position: 'relative', width: 52, height: 52, borderRadius: 14, background: '#EEEEEE', boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.04)' } }, badge ? bizBadge() : null ), h( 'span', { style: { fontSize: 12, color: COLOR_TEXT, lineHeight: 1.35, textAlign: 'center', maxWidth: '100%', wordBreak: 'break-all' } }, label ) ); } function bizGrid(rows) { return rows.map(function (row, ri) { return h( 'div', { key: 'row-' + ri, style: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', columnGap: 6, rowGap: 4, marginBottom: ri < rows.length - 1 ? 6 : 0 } }, row.map(function (cell) { return bizMenuCell(cell); }) ); }); } function sectionTitle(text) { return h( 'div', { style: { fontSize: 13, color: COLOR_MUTED, marginBottom: 8, paddingLeft: 4, fontWeight: 500, textAlign: 'left' } }, text ); } function whiteCard(children) { return h( 'div', { style: { background: COLOR_BG, borderRadius: 12, padding: '14px 10px', boxShadow: '0 1px 4px rgba(0,0,0,0.06)', marginBottom: 14 } }, children ); } function getFilteredVehicles() { return MOCK_VEHICLES.filter(function (v) { var st = vehicleFilterApplied.status; if (st !== '全部' && v.status !== st) { return false; } if (st === '全部' && v.status === '退出运营') { return false; } if (vehicleFilterApplied.province !== '全部' && v.province !== vehicleFilterApplied.province) { return false; } if (vehicleFilterApplied.city !== '全部' && v.city !== vehicleFilterApplied.city) { return false; } if (vehicleSearch.trim()) { if (v.plate.indexOf(vehicleSearch.trim()) === -1) return false; } return true; }); } function openVehicleFilterDrawer() { setVehicleFilterDraft( normalizeFilterDraft({ status: vehicleFilterApplied.status, province: vehicleFilterApplied.province, city: vehicleFilterApplied.city }) ); setFilterDrawerOpen(true); } function detailLine(label, value, withTopBorder) { return h( 'div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12, padding: '12px 0', borderTop: withTopBorder ? '1px solid ' + COLOR_LINE : 'none', fontSize: 14 } }, h('span', { style: { color: COLOR_MUTED, flexShrink: 0 } }, label), h( 'span', { style: { color: COLOR_TEXT, textAlign: 'right', fontWeight: 500, wordBreak: 'break-all' } }, value ) ); } function renderSubNavHeader(title, onBack) { return h( 'div', { style: { position: 'sticky', top: 0, zIndex: 20, background: COLOR_PAGE_BG, paddingTop: 'calc(8px + env(safe-area-inset-top, 0px))', paddingBottom: 10, paddingLeft: 8, paddingRight: 8 } }, h( 'div', { style: { display: 'grid', gridTemplateColumns: '40px minmax(0, 1fr) 88px', alignItems: 'center', minHeight: 44, columnGap: 4 } }, h( 'button', { type: 'button', onClick: onBack, 'aria-label': '返回', style: { border: 'none', background: 'transparent', padding: 8, cursor: 'pointer', color: COLOR_TEXT, fontSize: 20, lineHeight: 1, justifySelf: 'start' } }, '‹' ), h( 'h1', { style: { margin: 0, fontSize: 17, fontWeight: 700, color: COLOR_TEXT, textAlign: 'center' } }, title ), h('div', { style: { justifySelf: 'end' } }, renderCapsuleCompact()) ) ); } function iconFilterFunnel() { return h( 'svg', { width: 22, height: 22, viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, h('path', { d: 'M5 4h14l-5.5 7.2V18l-3 1.2v-8L5 4z', stroke: COLOR_MUTED, strokeWidth: 1.5, strokeLinejoin: 'round' }) ); } function iconChevronRight() { return h( 'svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, h('path', { d: 'M9 6l6 6-6 6', stroke: '#C9CDD4', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' }) ); } function vehicleStatusBadgeEl(status) { var bg; var fg; if (status === '退出运营') { bg = '#E8EAED'; fg = '#86909C'; } else if (status === '待运营') { bg = '#FFF7E6'; fg = '#D48806'; } else { bg = 'rgba(22,209,161,0.16)'; fg = COLOR_PRIMARY; } return h( 'span', { style: { flexShrink: 0, padding: '3px 10px', borderRadius: 999, fontSize: 11, fontWeight: 600, lineHeight: 1.2, background: bg, color: fg } }, status ); } function vehicleListMetaRow(label, value) { return h( 'div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 10, paddingTop: 4, paddingBottom: 4, fontSize: 13, lineHeight: 1.45 } }, h('span', { style: { color: COLOR_MUTED, flexShrink: 0 } }, label), h( 'span', { style: { color: COLOR_TEXT, fontWeight: 500, textAlign: 'right', wordBreak: 'break-all' } }, value ) ); } function vehicleListCard(v) { return h( 'button', { key: v.id, type: 'button', onClick: function () { setSelectedVehicle(v); setVehicleDetailTab('basic'); setBizNav('vehicleDetail'); }, style: { width: '100%', display: 'flex', alignItems: 'stretch', flexDirection: 'row', gap: 4, border: 'none', borderRadius: 10, background: COLOR_BG, padding: '14px 10px 14px 14px', marginBottom: 10, cursor: 'pointer', boxShadow: '0 1px 3px rgba(0,0,0,0.06)', textAlign: 'left', boxSizing: 'border-box' } }, h( 'div', { style: { flex: 1, minWidth: 0 } }, h( 'div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 } }, h( 'span', { style: { fontSize: 17, fontWeight: 700, color: COLOR_TEXT } }, v.plate ), vehicleStatusBadgeEl(v.status) ), h('div', { style: { height: 1, background: COLOR_LINE, margin: '12px 0 6px' } }), h( 'div', null, vehicleListMetaRow('车辆类型', v.vehicleType || '—'), vehicleListMetaRow('品牌', v.brand || '—'), vehicleListMetaRow('型号', v.model || '—') ) ), h( 'div', { style: { display: 'flex', alignItems: 'center', alignSelf: 'stretch', paddingLeft: 2, flexShrink: 0 } }, iconChevronRight() ) ); } function filterTag(label, active, onSelect) { return h( 'button', { type: 'button', key: label, onClick: onSelect, style: { border: '1px solid ' + (active ? COLOR_PRIMARY : COLOR_LINE), background: active ? 'rgba(22,209,161,0.1)' : COLOR_BG, color: active ? COLOR_PRIMARY : COLOR_TEXT, borderRadius: 6, padding: '10px 8px', fontSize: 13, cursor: 'pointer', textAlign: 'center', lineHeight: 1.3 } }, label ); } function filterSection(title, options, field) { var cur = vehicleFilterDraft[field]; return h( 'div', { key: field, style: { marginBottom: 20 } }, h( 'div', { style: { fontSize: 13, color: COLOR_MUTED, marginBottom: 10 } }, title ), h( 'div', { style: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 } }, options.map(function (opt) { return filterTag(opt, cur === opt, function () { var next = Object.assign({}, vehicleFilterDraft); next[field] = opt; setVehicleFilterDraft(next); }); }) ) ); } function filterProvinceSection() { var cur = vehicleFilterDraft.province; return h( 'div', { key: 'province', style: { marginBottom: 20 } }, h( 'div', { style: { fontSize: 13, color: COLOR_MUTED, marginBottom: 10 } }, '车辆运营省份' ), h( 'div', { style: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 } }, VEHICLE_FILTER_PROVINCES.map(function (opt) { return filterTag(opt, cur === opt, function () { setVehicleFilterDraft( normalizeFilterDraft({ status: vehicleFilterDraft.status, province: opt, city: '全部' }) ); }); }) ) ); } function filterCitySectionDynamic() { var opts = getCityFilterOptionsByProvince(vehicleFilterDraft.province); var raw = vehicleFilterDraft.city; var cur = opts.indexOf(raw) >= 0 ? raw : '全部'; return h( 'div', { key: 'city', style: { marginBottom: 20 } }, h( 'div', { style: { fontSize: 13, color: COLOR_MUTED, marginBottom: 10 } }, '车辆运营城市' ), h( 'div', { style: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 } }, opts.map(function (opt) { return filterTag(opt, cur === opt, function () { var next = Object.assign({}, vehicleFilterDraft); next.city = opt; setVehicleFilterDraft(normalizeFilterDraft(next)); }); }) ) ); } function renderVehicleFilterDrawer() { if (!filterDrawerOpen) return null; return h( 'div', { style: { position: 'fixed', inset: 0, zIndex: 200, display: 'flex', justifyContent: 'flex-end' } }, h('div', { style: { flex: 1, background: 'rgba(0,0,0,0.45)', minWidth: 0 }, onClick: function () { setFilterDrawerOpen(false); } }), h( 'div', { style: { width: 'min(86vw, 340px)', height: '100%', background: COLOR_BG, display: 'flex', flexDirection: 'column', boxShadow: '-4px 0 16px rgba(0,0,0,0.12)', boxSizing: 'border-box' }, onClick: function (e) { e.stopPropagation(); } }, h( 'div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '16px 14px 12px', borderBottom: '1px solid ' + COLOR_LINE, flexShrink: 0 } }, h('span', { style: { fontSize: 17, fontWeight: 700, color: COLOR_TEXT } }, '筛选'), h( 'button', { type: 'button', onClick: function () { setFilterDrawerOpen(false); }, style: { border: 'none', background: 'transparent', fontSize: 22, color: COLOR_MUTED, padding: 6, cursor: 'pointer', lineHeight: 1 } }, '—' ) ), h( 'div', { style: { flex: 1, overflowY: 'auto', padding: '16px 14px', WebkitOverflowScrolling: 'touch' } }, filterSection('车辆运营状态', VEHICLE_FILTER_STATUS, 'status'), filterProvinceSection(), filterCitySectionDynamic() ), h( 'div', { style: { display: 'flex', gap: 10, padding: '12px 14px calc(12px + env(safe-area-inset-bottom, 0px))', borderTop: '1px solid ' + COLOR_LINE, flexShrink: 0 } }, h( 'button', { type: 'button', onClick: function () { setVehicleFilterDraft({ status: '全部', province: '全部', city: '全部' }); }, style: { flex: 1, height: 46, borderRadius: 8, border: 'none', background: '#ECEFF2', color: COLOR_TEXT, fontSize: 16, fontWeight: 600, cursor: 'pointer' } }, '重置' ), h( 'button', { type: 'button', onClick: function () { setVehicleFilterApplied(normalizeFilterDraft(vehicleFilterDraft)); setFilterDrawerOpen(false); }, style: { flex: 1, height: 46, borderRadius: 8, border: 'none', background: COLOR_PRIMARY, color: '#FFFFFF', fontSize: 16, fontWeight: 600, cursor: 'pointer' } }, '确定' ) ) ) ); } function renderVehicleListPage() { var list = getFilteredVehicles(); var count = list.length; return h( 'div', { style: { minHeight: '100dvh', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', background: COLOR_PAGE_BG, fontFamily: FONT_FAMILY, color: COLOR_TEXT, position: 'relative' } }, renderSubNavHeader('车辆管理', function () { setBizNav('menu'); }), h( 'div', { style: { padding: '10px 14px 8px', display: 'flex', alignItems: 'center', gap: 10 } }, h( 'div', { style: { flex: 1, display: 'flex', alignItems: 'center', background: COLOR_BG, borderRadius: 22, paddingLeft: 14, paddingRight: 14, minHeight: 42, boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.06)' } }, h('input', { value: vehicleSearch, onChange: function (e) { setVehicleSearch((e.target && e.target.value) || ''); }, placeholder: '请输入车牌号', 'aria-label': '车牌号搜索', style: { flex: 1, minWidth: 0, border: 'none', outline: 'none', fontSize: 15, background: 'transparent', color: COLOR_TEXT } }) ), h( 'button', { type: 'button', onClick: openVehicleFilterDrawer, 'aria-label': '筛选', style: { border: 'none', background: COLOR_BG, width: 42, height: 42, borderRadius: 22, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 1px 4px rgba(0,0,0,0.06)', flexShrink: 0 } }, iconFilterFunnel() ) ), h( 'div', { style: { display: 'flex', justifyContent: 'space-between', padding: '4px 14px 12px', fontSize: 14, color: COLOR_TEXT } }, h('span', { style: { color: COLOR_MUTED } }, '全国'), h('span', { style: { fontWeight: 500 } }, '车辆数:' + count) ), h( 'div', { style: { flex: 1, overflowY: 'auto', paddingLeft: 14, paddingRight: 14, paddingBottom: 16, WebkitOverflowScrolling: 'touch' } }, list.map(function (v) { return vehicleListCard(v); }) ), renderVehicleFilterDrawer() ); } function photoPlaceholder() { return h( 'div', { style: { height: 120, borderRadius: 8, background: '#F7F8FA', border: '1px dashed ' + COLOR_LINE, display: 'flex', alignItems: 'center', justifyContent: 'center', color: COLOR_MUTED, fontSize: 14, marginTop: 8 } }, 'PHOTO' ); } function renderVehicleDetailPage() { if (!selectedVehicle) { return h('div', { style: { minHeight: 100 } }); } var v = selectedVehicle; var vt = vehicleDetailTab; var basicBlock = h( 'div', null, h( 'div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 } }, h('span', { style: { fontSize: 18, fontWeight: 700 } }, v.plate), vehicleStatusBadgeEl(v.status) ), h( 'div', { style: { background: COLOR_BG, borderRadius: 10, overflow: 'hidden', paddingLeft: 14, paddingRight: 14 } }, detailLine('运营城市', v.province + ' ' + v.city, false), detailLine('停车区域', v.province + ' ' + v.city, true), detailLine('车辆类型', v.vehicleType || '氢能厢式车', true), detailLine('品牌', v.brand || '羚牛', true), detailLine('型号', v.model || 'LN-H2-01', true), detailLine('车辆识别代码', 'LNVIN' + v.id + 'XXXXX', true), detailLine('合同编号', 'HT-2026-' + v.id.slice(-3), true), detailLine('客户名称', '示例客户', true), detailLine('出厂年份', '2024', true), detailLine('行驶公里数', '12345.67 KM', true), detailLine('业务部门', '华东业务部', true), detailLine('业务负责人', '张三', true), detailLine('登记所有权', '羚牛氢能科技有限公司', true) ) ); var specBlock = h( 'div', null, h( 'div', { style: { fontSize: 15, fontWeight: 700, marginBottom: 8, color: COLOR_TEXT } }, '型号参数' ), h( 'div', { style: { background: COLOR_BG, borderRadius: 10, paddingLeft: 14, paddingRight: 14 } }, detailLine('车辆类型', v.vehicleType || '氢能厢式车', false), detailLine('品牌', v.brand || '羚牛', true), detailLine('型号', v.model || 'LN-H2-01', true), detailLine('燃料种类', '氢', true), detailLine('车牌颜色', '绿牌', true), detailLine('整车尺寸', '长×宽×高(mm)', true) ), h('div', { style: { height: 12 } }), h( 'div', { style: { fontSize: 15, fontWeight: 700, marginBottom: 8 } }, '轮胎情况' ), h( 'div', { style: { background: COLOR_BG, borderRadius: 10, padding: '0 14px' } }, detailLine('轮胎数量', '6', false), detailLine('轮胎规格', '12R22.5', true) ), h('div', { style: { height: 12 } }), h( 'div', { style: { fontSize: 15, fontWeight: 700, marginBottom: 8 } }, '电气系统' ), h( 'div', { style: { background: COLOR_BG, borderRadius: 10, padding: '0 14px' } }, detailLine('电池类型', 'LFP', false), detailLine('电池厂家', '某某动力', true), detailLine('电量', '150 kWh', true), detailLine('续航', '300 KM', true) ), h('div', { style: { height: 12 } }), h( 'div', { style: { fontSize: 15, fontWeight: 700, marginBottom: 8 } }, '供氢系统' ), h( 'div', { style: { background: COLOR_BG, borderRadius: 10, padding: '0 14px' } }, detailLine('气瓶容积', '320 L', false), detailLine('仪表盘', '35 MPa', true), detailLine('续航里程', '800 KM', true), detailLine('厂家', '某某氢能', true) ) ); var certBlock = h( 'div', null, h( 'div', { style: { fontSize: 15, fontWeight: 700, marginBottom: 8 } }, '证照信息' ), h('div', { style: { color: COLOR_MUTED, fontSize: 13, marginBottom: 4 } }, '行驶证'), photoPlaceholder(), h('div', { style: { color: COLOR_MUTED, fontSize: 13, marginTop: 12, marginBottom: 4 } }, '营运证'), photoPlaceholder(), h('div', { style: { color: COLOR_MUTED, fontSize: 13, marginTop: 12, marginBottom: 4 } }, '加氢证'), photoPlaceholder(), photoPlaceholder(), h('div', { style: { height: 16 } }), h( 'div', { style: { background: COLOR_BG, borderRadius: 10, padding: '0 14px', marginTop: 8 } }, detailLine('商业险', '到期日期:2027-01-15', false), detailLine('超赔险', '到期日期:2027-01-15', true) ) ); var body = vt === 'basic' ? basicBlock : vt === 'spec' ? specBlock : certBlock; return h( 'div', { style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column', background: COLOR_PAGE_BG, fontFamily: FONT_FAMILY, color: COLOR_TEXT } }, renderSubNavHeader('车辆详情', function () { setBizNav('vehicleList'); }), h( 'div', { style: { display: 'flex', justifyContent: 'space-around', background: COLOR_BG, borderBottom: '1px solid ' + COLOR_LINE, padding: '0 8px', flexShrink: 0 } }, ['basic', 'spec', 'cert'].map(function (key) { var labels = { basic: '基本信息', spec: '型号参数', cert: '证照及保险' }; var active = vehicleDetailTab === key; return h( 'button', { key: key, type: 'button', onClick: function () { setVehicleDetailTab(key); }, style: { flex: 1, border: 'none', background: 'transparent', padding: '12px 6px', fontSize: 15, fontWeight: active ? 700 : 400, color: active ? COLOR_PRIMARY : COLOR_MUTED, borderBottom: active ? '3px solid ' + COLOR_PRIMARY : '3px solid transparent', marginBottom: -1, cursor: 'pointer' } }, labels[key] ); }) ), h( 'div', { style: { flex: 1, overflowY: 'auto', padding: '12px 14px calc(20px + env(safe-area-inset-bottom, 0px))', WebkitOverflowScrolling: 'touch' } }, body ) ); } function renderBusinessMenu() { var opsRows = [ [{ label: '车辆管理', bizEntry: 'vehicleList' }, { label: '备车' }, { label: '交车', badge: true }], [{ label: '还车' }, { label: '替换车' }, { label: '异动' }], [{ label: '调拨', badge: true }, { label: '年审', badge: true }, { label: '故障' }], [{ label: '司机安全培训' }] ]; var dataRows = [ [{ label: '车辆统计' }, { label: '氢费统计' }, { label: '氢量汇总' }], [{ label: '电量汇总' }, { label: '里程查询' }, { label: '里程考核' }] ]; return h( 'div', { style: { flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch', paddingLeft: 16, paddingRight: 16, paddingBottom: 16, boxSizing: 'border-box' } }, h('div', { style: { height: 4 } }), h('div', null, sectionTitle('运维管理'), whiteCard(bizGrid(opsRows))), h( 'div', null, sectionTitle('审批管理'), whiteCard( h('div', { style: { maxWidth: 120 } }, bizMenuCell({ label: '审核中心', badge: true })) ) ), h('div', null, sectionTitle('数据可视化'), whiteCard(bizGrid(dataRows))) ); } function renderMainHeader() { var titles = { todo: '待办', biz: '业务', map: '地图', mine: '我的' }; var title = titles[mainTab] || '羚牛氢能'; return h( 'div', { style: { position: 'sticky', top: 0, zIndex: 10, background: COLOR_PAGE_BG, paddingTop: 'calc(8px + env(safe-area-inset-top, 0px))', paddingBottom: 10, paddingLeft: 16, paddingRight: 16 } }, h( 'div', { style: { display: 'grid', gridTemplateColumns: '42px minmax(0, 1fr) 76px', alignItems: 'center', minHeight: 44, columnGap: 6 } }, mainTab === 'biz' ? renderBellWithBadge(99) : h('div', { 'aria-hidden': true, style: { width: 42, flexShrink: 0 } }), h( 'h1', { style: { margin: 0, fontSize: 18, fontWeight: 700, color: COLOR_TEXT, textAlign: 'center' } }, title ), h( 'div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 10 } }, h( 'button', { type: 'button', 'aria-label': '更多', onClick: function () { message.info('更多菜单占位'); }, style: { border: 'none', background: 'transparent', padding: 6, cursor: 'pointer', color: COLOR_TEXT, fontSize: 18, lineHeight: 1 } }, '⋯' ), h( 'button', { type: 'button', 'aria-label': '关闭', onClick: function () { setRoute('login'); }, style: { width: 26, height: 26, borderRadius: 13, border: '1.5px solid ' + COLOR_LINE, background: COLOR_BG, padding: 0, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, color: COLOR_MUTED, flexShrink: 0 } }, '○' ) ) ) ); } function renderTodoHeader() { return renderMainHeader(); } function renderBottomTabs() { var items = [ { key: 'todo', label: '待办', active: mainTab === 'todo' }, { key: 'biz', label: '业务', active: mainTab === 'biz' }, { key: 'map', label: '地图', active: mainTab === 'map' }, { key: 'mine', label: '我的', active: mainTab === 'mine' } ]; return h( 'div', { style: { flexShrink: 0, display: 'flex', alignItems: 'stretch', justifyContent: 'space-around', background: COLOR_BG, borderTop: '1px solid ' + COLOR_LINE, paddingTop: 6, paddingBottom: 'calc(8px + env(safe-area-inset-bottom, 0px))', paddingLeft: 4, paddingRight: 4 } }, items.map(function (it) { var active = it.active; var color = active ? COLOR_PRIMARY : COLOR_MUTED; return h( 'button', { key: it.key, type: 'button', onClick: function () { var k = it.key; if (k !== 'biz') { setBizNav('menu'); } setMainTab(k); }, style: { flex: 1, border: 'none', background: 'transparent', padding: '6px 4px', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, color: color, fontSize: 11, fontWeight: active ? 600 : 400 } }, h( 'div', { style: { width: 26, height: 26, borderRadius: 6, border: active ? '2px solid ' + COLOR_PRIMARY : '2px solid transparent', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14 } }, it.key === 'todo' ? '□' : it.key === 'biz' ? '◧' : it.key === 'map' ? '⌖' : '☺' ), it.label ); }) ); } function renderTabBody() { if (mainTab === 'biz') { return renderBusinessMenu(); } if (mainTab !== 'todo') { var titles = { map: '地图', mine: '我的' }; return h( 'div', { style: { flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', color: COLOR_MUTED, fontSize: 15, padding: 24 } }, titles[mainTab] + '(占位)' ); } return h( 'div', { style: { flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch', padding: '0 16px 16px' } }, h( 'div', { style: { fontSize: 16, fontWeight: 700, color: COLOR_TEXT, marginBottom: 12, textAlign: 'left' } }, '待办任务' ), MOCK_TODO_TASKS.map(function (t) { return renderTaskCard(t); }) ); } function renderTodoApp() { if (route === 'todo' && mainTab === 'biz' && bizNav === 'vehicleList') { return renderVehicleListPage(); } if (route === 'todo' && mainTab === 'biz' && bizNav === 'vehicleDetail') { return renderVehicleDetailPage(); } return h( 'div', { style: { minHeight: '100dvh', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', background: COLOR_PAGE_BG, fontFamily: FONT_FAMILY, color: COLOR_TEXT } }, renderTodoHeader(), renderTabBody(), renderBottomTabs() ); } function renderLogin() { var canSubmit = !!account && !!password && !!agree && !submitting; return h( 'div', { style: { minHeight: '100dvh', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', background: COLOR_BG, fontFamily: FONT_FAMILY, position: 'relative', overflowY: 'auto', paddingLeft: 24, paddingRight: 24, paddingBottom: 'calc(20px + env(safe-area-inset-bottom, 0px))', paddingTop: 'calc(12px + env(safe-area-inset-top, 0px))' } }, renderCapsule(), h( 'div', { style: { flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', maxWidth: 400, width: '100%', marginLeft: 'auto', marginRight: 'auto', paddingTop: 'max(36px, 7vh)' } }, renderBrandLogo(), h( 'div', { style: pillInputStyle({ marginBottom: 16 }) }, renderIconUser(), h('input', { value: account, onChange: function (e) { setAccount((e && e.target && e.target.value) || ''); }, placeholder: '请输入用户名', autoComplete: 'username', 'aria-label': '用户名', style: { flex: 1, minWidth: 0, border: 'none', outline: 'none', fontSize: 15, color: COLOR_TEXT, background: 'transparent', padding: '14px 0', lineHeight: 1.4 } }) ), h( 'div', { style: pillInputStyle() }, renderIconLock(), h('input', { value: password, type: 'password', onChange: function (e) { setPassword((e && e.target && e.target.value) || ''); }, placeholder: '请输入密码', autoComplete: 'current-password', 'aria-label': '密码', style: { flex: 1, minWidth: 0, border: 'none', outline: 'none', fontSize: 15, color: COLOR_TEXT, background: 'transparent', padding: '14px 0', lineHeight: 1.4 } }) ), h( 'div', { style: { display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 18, fontSize: 13, color: COLOR_TEXT, lineHeight: 1.5, userSelect: 'none' } }, h( 'button', { type: 'button', onClick: function () { setAgree(!agree); }, 'aria-checked': agree, role: 'checkbox', style: { width: 18, height: 18, borderRadius: 9, border: '1.5px solid ' + (agree ? COLOR_PRIMARY : COLOR_LINE), background: agree ? COLOR_PRIMARY : '#FFFFFF', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', padding: 0, cursor: 'pointer', flexShrink: 0, marginTop: 2, boxSizing: 'border-box' } }, agree ? h('div', { style: { width: 5, height: 5, borderRadius: 2.5, background: '#FFFFFF' } }) : null ), h( 'div', { style: { flex: 1 } }, '我同意', h( 'button', { type: 'button', onClick: function () { message.info('用户协议占位'); }, style: { border: 'none', background: 'transparent', padding: 0, color: COLOR_PRIMARY, fontSize: 13, fontWeight: 600, cursor: 'pointer', verticalAlign: 'baseline' } }, '《用户协议》' ), '和', h( 'button', { type: 'button', onClick: function () { message.info('隐私政策占位'); }, style: { border: 'none', background: 'transparent', padding: 0, color: COLOR_PRIMARY, fontSize: 13, fontWeight: 600, cursor: 'pointer' } }, '《隐私政策》' ), '规定' ) ), h( 'button', { type: 'button', onClick: handleLogin, disabled: !canSubmit, style: { width: '100%', height: 52, borderRadius: 26, border: 'none', marginTop: 28, background: canSubmit ? 'linear-gradient(180deg, ' + COLOR_PRIMARY + ' 0%, ' + COLOR_PRIMARY_DEEP + ' 100%)' : '#D0D5DD', color: '#FFFFFF', fontSize: 17, fontWeight: 700, boxShadow: canSubmit ? '0 10px 28px rgba(22,209,161,0.36)' : 'none', cursor: canSubmit ? 'pointer' : 'not-allowed', opacity: submitting ? 0.92 : 1 } }, submitting ? '登录中…' : '立即登录' ), h( 'div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', marginTop: 20, fontSize: 14 } }, h( 'button', { type: 'button', onClick: handlePhoneAuthLogin, 'aria-label': '手机号授权登录', style: { border: 'none', background: 'transparent', padding: 0, color: COLOR_PRIMARY, cursor: 'pointer', fontSize: 14, fontWeight: 600 } }, '手机号授权登录' ) ), h('div', { style: { flexShrink: 0, minHeight: 'max(28px, 4vh)' } }) ) ); } return h(App, null, route === 'login' ? renderLogin() : renderTodoApp()); };