// 【重要】必须使用 const Component 作为组件变量名 // 车辆业务 - 交车管理(ONEOS运管平台,布局参照新增租赁合同) var DV_KPI_STYLE = '' + '.dv-kpi-stats-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-bottom:16px;}' + '@media (max-width:768px){.dv-kpi-stats-row{grid-template-columns:repeat(1,minmax(0,1fr));}}' + '.lc-alert-card{display:flex;align-items:flex-start;gap:12px;padding:14px 30px 14px 16px;border-radius:12px;border:1px solid #e2e8f0;background:#fff;position:relative;overflow:hidden;min-width:0;}' + '.lc-alert-card-main{flex:1;min-width:0;}' + '.lc-alert-card-icon{flex-shrink:0;width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;}' + '.lc-alert-card-val{font-size:26px;font-weight:800;line-height:1.1;color:#0f172a;font-variant-numeric:tabular-nums;}' + '.lc-alert-card-title{font-size:13px;font-weight:600;color:#334155;margin-top:2px;}' + '.lc-alert-card-tip-anchor{position:absolute;top:8px;right:8px;z-index:2;line-height:0;}' + '.lc-alert-card-tip{width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:#94a3b8;background:rgba(255,255,255,.92);border:1px solid #e2e8f0;cursor:help;line-height:0;}' + '.lc-alert-card-tip:hover{color:#64748b;border-color:#cbd5e1;background:#fff;}' + '.lc-alert-card--total{background:linear-gradient(135deg,#f8fafc 0%,#fff 100%);}' + '.lc-alert-card--total .lc-alert-card-icon{background:#e2e8f0;color:#475569;}' + '.lc-alert-card--progress{background:linear-gradient(135deg,#fff7ed 0%,#fff 55%);border-color:#fed7aa;}' + '.lc-alert-card--progress .lc-alert-card-icon{background:#ffedd5;color:#ea580c;}' + '.lc-alert-card--progress .lc-alert-card-val{color:#c2410c;}' + '.lc-alert-card--completed{background:linear-gradient(135deg,#ecfdf5 0%,#fff 55%);border-color:#bbf7d0;}' + '.lc-alert-card--completed .lc-alert-card-icon{background:#d1fae5;color:#059669;}' + '.lc-alert-card--completed .lc-alert-card-val{color:#047857;}' + '.lc-alert-card-clickable{cursor:pointer;transition:box-shadow .2s ease,border-color .2s ease,transform .2s ease;}' + '.lc-alert-card-clickable:hover{box-shadow:0 4px 14px rgba(15,23,42,.08);}' + '.lc-alert-card-active{box-shadow:0 0 0 2px rgba(22,93,255,.2)!important;border-color:#165dff!important;}' + '.lc-multi-plate-pop{width:320px;padding:4px 2px;}' + '.lc-multi-plate-pop-hint{font-size:12px;color:#64748b;margin-bottom:8px;line-height:1.5;}' + '.lc-multi-plate-pop-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:10px;}' + '.lc-multi-plate-trigger{cursor:pointer;}' + '.lc-multi-plate-trigger .ant-input{cursor:pointer;}'; var DV_KPI_ICONS = { total: React.createElement('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('rect', { x: 3, y: 3, width: 7, height: 7 }), React.createElement('rect', { x: 14, y: 3, width: 7, height: 7 }), React.createElement('rect', { x: 14, y: 14, width: 7, height: 7 }), React.createElement('rect', { x: 3, y: 14, width: 7, height: 7 })), progress: React.createElement('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('circle', { cx: 12, cy: 12, r: 10 }), React.createElement('polyline', { points: '12 6 12 12 16 14' })), completed: React.createElement('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('path', { d: 'M22 11.08V12a10 10 0 1 1-5.93-9.14' }), React.createElement('polyline', { points: '22 4 12 14.01 9 11.01' })) }; var DV_KPI_TIP_SVG = React.createElement('svg', { width: 12, height: 12, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2.2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('circle', { cx: 12, cy: 12, r: 10 }), React.createElement('line', { x1: 12, y1: 16, x2: 12, y2: 12 }), React.createElement('line', { x1: 12, y1: 8, x2: 12.01, y2: 8 })); function formatDeliveryRegion(region) { if (!region || region === '-') return '-'; var r = String(region).trim(); if (r.indexOf('-') === -1) { var m = r.match(/^(.+?(?:省|市|自治区|特别行政区))(.+)$/); if (m && m[2]) r = m[1] + '-' + m[2]; } return r; } function parseDeliveryRegionParts(region) { if (!region || region === '-') return { province: '', city: '', raw: '' }; var r = String(region).trim(); var idx = r.indexOf('-'); if (idx >= 0) { return { province: r.slice(0, idx).trim(), city: r.slice(idx + 1).trim(), raw: r }; } if (r.indexOf('省') >= 0) return { province: r, city: '', raw: r }; if (r.indexOf('市') >= 0) return { province: '', city: r, raw: r }; return { province: r, city: '', raw: r }; } function regionCityMatch(cityA, cityB) { if (!cityA || !cityB) return false; return cityA === cityB || cityA.indexOf(cityB) >= 0 || cityB.indexOf(cityA) >= 0; } /** 运维人员区域权限是否覆盖目标区域(省-市) */ function matchRegionPermission(permissions, targetRegion) { var target = parseDeliveryRegionParts(formatDeliveryRegion(targetRegion)); if (!target.province && !target.city) return true; var perms = permissions || []; for (var i = 0; i < perms.length; i++) { var perm = String(perms[i] || '').trim(); if (!perm) continue; if (perm.indexOf('-') >= 0) { var scoped = parseDeliveryRegionParts(perm); if (scoped.province && target.province && scoped.province !== target.province) continue; if (scoped.city) { if (regionCityMatch(target.city, scoped.city)) return true; continue; } if (scoped.province && scoped.province === target.province) return true; continue; } if (perm.indexOf('省') >= 0) { if (target.province === perm) return true; continue; } if (regionCityMatch(target.city, perm)) return true; } return false; } var DV_RESERVE_VEHICLE_STATUS_READY = '已备车'; function getOperatorRegionPermissions() { if (typeof window !== 'undefined' && window.DV_MOCK_OPERATOR_REGION_PERMISSIONS && window.DV_MOCK_OPERATOR_REGION_PERMISSIONS.length) { return window.DV_MOCK_OPERATOR_REGION_PERMISSIONS.slice(); } return ['浙江省-嘉兴市']; } function filterRowsByOperatorRegion(rows) { var perms = getOperatorRegionPermissions(); return (rows || []).filter(function (row) { return matchRegionPermission(perms, row.deliveryRegion); }); } function filterSelectableReserveVehicles(vehicles, operatorPermissions) { var perms = operatorPermissions || getOperatorRegionPermissions(); return (vehicles || []).filter(function (vehicle) { if ((vehicle.vehicleStatus || '') !== DV_RESERVE_VEHICLE_STATUS_READY) return false; return matchRegionPermission(perms, vehicle.parkingRegion); }); } function isDeliverySignedStatus(status) { return status === '客户已签章' || status === '已签章'; } function isDeliveryPendingCustomerSignStatus(status) { return status === '待客户签章'; } /** 待客户签章 / 客户已签章 使用统一 Tag 样式 */ var DV_CUSTOMER_SIGN_STATUS_BG = '#2563eb'; function isCustomerSignRelatedStatus(status) { return isDeliveryPendingCustomerSignStatus(status) || isDeliverySignedStatus(status); } function getAuthorizedListFromRecord(record) { var list = record && record.authorizedList; if (!Array.isArray(list)) return []; return list.filter(function (a) { return a && ((a.name && String(a.name).trim()) || (a.phone && String(a.phone).trim())); }); } function buildCustomerSignPendingPopoverContent(record) { var list = getAuthorizedListFromRecord(record); var boxStyle = { minWidth: 168, fontSize: 13, lineHeight: 1.65 }; var labelStyle = { color: '#64748b' }; var valStyle = { color: '#334155', fontWeight: 600 }; if (!list.length) { return React.createElement('div', { style: boxStyle }, React.createElement('div', null, React.createElement('span', { style: labelStyle }, '授权人姓名:'), React.createElement('span', { style: valStyle }, '-') ), React.createElement('div', { style: { marginTop: 4 } }, React.createElement('span', { style: labelStyle }, '授权人手机号:'), React.createElement('span', { style: valStyle }, '-') ) ); } var children = []; list.forEach(function (item, idx) { if (idx > 0) { children.push(React.createElement('div', { key: 'sep-' + idx, style: { borderTop: '1px solid #f1f5f9', margin: '8px 0' } })); } children.push( React.createElement('div', { key: 'name-' + idx }, React.createElement('span', { style: labelStyle }, '授权人姓名:'), React.createElement('span', { style: valStyle }, (item.name && String(item.name).trim()) || '-') ), React.createElement('div', { key: 'phone-' + idx, style: { marginTop: 4 } }, React.createElement('span', { style: labelStyle }, '授权人手机号:'), React.createElement('span', { style: valStyle }, (item.phone && String(item.phone).trim()) || '-') ) ); }); return React.createElement('div', { style: boxStyle }, children); } function buildDeliverySignFileName(record) { var plate = (record.plateNo && String(record.plateNo).trim()) ? String(record.plateNo).trim() : '车牌待选'; var orderId = record.orderId != null ? String(record.orderId) : 'unknown'; var vehicleKey = record.vehicleKey != null ? String(record.vehicleKey) : ''; return '交车签章文件_' + orderId + (vehicleKey ? '_' + vehicleKey : '') + '_' + plate + '.pdf'; } function buildDeliverySignFileContent(record) { var plate = (record.plateNo && String(record.plateNo).trim()) ? String(record.plateNo).trim() : '车牌待选'; return [ '交车签章文件(原型 Mock,联调后对接 E 签宝签章 PDF)', '', '合同编号:' + (record.contractCode || '-'), '项目名称:' + (record.projectName || '-'), '客户名称:' + (record.customerName || '-'), '车牌号:' + plate, '品牌型号:' + (record.brand || '-') + ' / ' + (record.model || '-'), '交车人:' + (record.deliveryPerson || '-'), '完成交车时间:' + (record.deliveryTime || '-'), '签章状态:客户已签章', '', '生成时间:' + new Date().toLocaleString('zh-CN', { hour12: false }) ].join('\n'); } function escapeSignHtml(text) { return String(text == null ? '-' : text) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function buildDeliverySignPreviewHtml(record) { var filename = buildDeliverySignFileName(record); var plate = (record.plateNo && String(record.plateNo).trim()) ? String(record.plateNo).trim() : '车牌待选'; var rows = [ ['文件名称', filename], ['合同编号', record.contractCode || '-'], ['项目名称', record.projectName || '-'], ['客户名称', record.customerName || '-'], ['车牌号', plate], ['品牌型号', (record.brand || '-') + ' / ' + (record.model || '-')], ['交车人', record.deliveryPerson || '-'], ['完成交车时间', record.deliveryTime || '-'], ['签章状态', '客户已签章'], ['签章方', record.customerName || '-'], ['预览时间', new Date().toLocaleString('zh-CN', { hour12: false })] ]; var bodyRows = rows.map(function (row) { return '' + escapeSignHtml(row[0]) + '' + escapeSignHtml(row[1]) + ''; }).join(''); return '' + '' + escapeSignHtml(filename) + '' + '
E签宝签章文件' + '

' + escapeSignHtml(filename) + '

数字化资产 ONEOS · 交车管理 · 签章文件预览(原型 Mock)
' + '
' + bodyRows + '
' + '
本页为原型预览占位,联调后将展示 E 签宝返回的真实签章 PDF 或在线预览地址。
' + '
'; } function previewDeliverySignFile(record) { if (!record || !isDeliverySignedStatus(record.deliveryStatus || record.status)) return; if (typeof window === 'undefined') return; var html = buildDeliverySignPreviewHtml(record); var blob = new Blob([html], { type: 'text/html;charset=utf-8' }); var url = URL.createObjectURL(blob); var opened = window.open(url, '_blank', 'noopener,noreferrer'); if (!opened) { URL.revokeObjectURL(url); if (typeof message !== 'undefined' && message.warning) message.warning('请允许浏览器弹出窗口以预览签章文件'); return; } if (typeof message !== 'undefined' && message.success) message.success('已在新页面打开签章文件预览'); setTimeout(function () { URL.revokeObjectURL(url); }, 120000); } function downloadDeliverySignFile(record) { if (!record || !isDeliverySignedStatus(record.deliveryStatus || record.status)) return; var filename = buildDeliverySignFileName(record); var content = buildDeliverySignFileContent(record); var blob = new Blob([content], { type: 'application/octet-stream' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); if (typeof message !== 'undefined' && message.success) message.success('已开始下载签章文件'); } // 查看交车单:禁用输入框/选择器可读性增强(背景更淡、文字纯黑) var DV_VIEW_READONLY_CTRL_CSS = '' + '.dv-edit-drawer-view .ant-input[disabled],' + '.dv-edit-drawer-view textarea.ant-input[disabled]{' + 'color:#000!important;-webkit-text-fill-color:#000!important;' + 'background-color:#fafafa!important;border-color:#e5e7eb!important;' + 'cursor:default!important;opacity:1!important;' + '}' + '.dv-edit-drawer-view .ant-input-affix-wrapper-disabled,' + '.dv-edit-drawer-view .ant-input-affix-wrapper[disabled]{' + 'color:#000!important;background-color:#fafafa!important;' + 'border-color:#e5e7eb!important;cursor:default!important;opacity:1!important;' + '}' + '.dv-edit-drawer-view .ant-input-affix-wrapper-disabled input[disabled],' + '.dv-edit-drawer-view .ant-input-affix-wrapper[disabled] input[disabled]{' + 'color:#000!important;-webkit-text-fill-color:#000!important;' + 'background-color:transparent!important;cursor:default!important;' + '}' + '.dv-edit-drawer-view .ant-input-affix-wrapper-disabled .ant-input-suffix,' + '.dv-edit-drawer-view .ant-input-affix-wrapper[disabled] .ant-input-suffix{' + 'color:rgba(0,0,0,.65)!important;' + '}' + '.dv-edit-drawer-view .ant-select-disabled.ant-select .ant-select-selector{' + 'color:#000!important;background-color:#fafafa!important;' + 'border-color:#e5e7eb!important;cursor:default!important;opacity:1!important;' + '}' + '.dv-edit-drawer-view .ant-select-disabled .ant-select-selection-item,' + '.dv-edit-drawer-view .ant-select-disabled .ant-select-selection-placeholder{' + 'color:#000!important;' + '}'; // 使用方式:window.DeliveryEditDrawer(props) function DeliveryEditDrawer(props) { var useState = React.useState; var useMemo = React.useMemo; var useCallback = React.useCallback; var useRef = React.useRef; var useEffect = React.useEffect; var open = props.open; var record = props.record; var onClose = props.onClose; var onSave = props.onSave; var onSubmit = props.onSubmit; var readOnly = props.readOnly === true || props.mode === 'view'; var antd = window.antd; var Drawer = antd.Drawer; var Button = antd.Button; var Input = antd.Input; var Select = antd.Select; var Switch = antd.Switch; var Modal = antd.Modal; var Table = antd.Table; var Tag = antd.Tag; var Popover = antd.Popover; var message = antd.message; function RequiredLabel(text) { return React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: 4 } }, React.createElement('span', { style: { color: '#ef4444', fontWeight: 600 } }, '*'), React.createElement('span', null, text) ); } function isEmpty(v) { return v === null || v === undefined || String(v).trim() === ''; } function filterOption(input, option) { var label = (option && (option.label || option.children)) || ''; return String(label).toLowerCase().indexOf(String(input || '').toLowerCase()) >= 0; } function fileToDataUrl(file, cb) { try { var reader = new FileReader(); reader.onload = function (e) { cb(null, (e && e.target && e.target.result) || ''); }; reader.onerror = function () { cb(new Error('read error')); }; reader.readAsDataURL(file); } catch (e) { cb(e); } } var reserveVehicles = useMemo(function () { return [ { plateNo: '浙F80088', vehicleStatus: DV_RESERVE_VEHICLE_STATUS_READY, parkingRegion: '浙江省-嘉兴市', parkingLot: '嘉兴港区氢能停车场', vehicleType: '厢式车', brand: '福田', model: 'BJ1180', vin: 'LJNAU1A2XK7654321', hasAd: false, adPhoto: [], bigWordPhoto: [], hasTailboard: false }, { plateNo: '浙F88601', vehicleStatus: DV_RESERVE_VEHICLE_STATUS_READY, parkingRegion: '浙江省-嘉兴市', parkingLot: '平湖指定停车场', vehicleType: '4.5吨冷链车', brand: '现代', model: '帕力安牌4.5吨冷链车', vin: 'LNBSCPKB8RR123888', hasAd: false, adPhoto: [], bigWordPhoto: [], hasTailboard: true }, { plateNo: '浙A10088', vehicleStatus: DV_RESERVE_VEHICLE_STATUS_READY, parkingRegion: '浙江省-杭州市', parkingLot: '未来科技城地下停车场', vehicleType: '城配货车', brand: '福田', model: 'BJ1190', vin: 'LJNAU1A2XK8888001', hasAd: true, adPhoto: [{ uid: 'ad-hz', name: '广告照片.jpg', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=Ad-HZ' }], bigWordPhoto: [], hasTailboard: false }, { plateNo: '粤AGP4598', vehicleStatus: DV_RESERVE_VEHICLE_STATUS_READY, parkingRegion: '广东省-广州市', parkingLot: '广州南沙物流园停车场', vehicleType: '4.5吨冷链车', brand: '现代', model: '帕力安牌4.5吨冷链车', vin: 'LNBSCPKB9RR223402', hasAd: false, adPhoto: [], bigWordPhoto: [], hasTailboard: false }, { plateNo: '川A99999', vehicleStatus: DV_RESERVE_VEHICLE_STATUS_READY, parkingRegion: '四川省-成都市', parkingLot: '成都龙泉驿停车场', vehicleType: '4.5吨冷链车', brand: '现代', model: '帕力安牌4.5吨冷链车', vin: 'LNBSCPKB9RR223999', hasAd: false, adPhoto: [], bigWordPhoto: [], hasTailboard: false }, { plateNo: '京A12345', vehicleStatus: '备车中', parkingRegion: '浙江省-嘉兴市', parkingLot: '嘉兴测试停车场', vehicleType: '牵引车', brand: '东风', model: 'DFH1180', vin: 'LJNAU1A2XK1234567', hasAd: true, adPhoto: [{ uid: 'ad1', name: '广告照片.jpg', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=Ad' }], bigWordPhoto: [{ uid: 'bw1', name: '放大字.jpg', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=BigWord' }], hasTailboard: true }, { plateNo: '沪A30003', vehicleStatus: DV_RESERVE_VEHICLE_STATUS_READY, parkingRegion: '上海市-上海市', parkingLot: '浦东停车场', vehicleType: '厢式车', brand: '重汽', model: 'HOWO-T5G', vin: 'LJNAU1A2XK9999000', hasAd: true, adPhoto: [{ uid: 'ad2', name: '广告2.jpg', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=Ad2' }], bigWordPhoto: [{ uid: 'bw2', name: '放大字2.jpg', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=BW2' }], hasTailboard: true } ]; }, []); var plateOptions = useMemo(function () { return filterSelectableReserveVehicles(reserveVehicles, getOperatorRegionPermissions()).map(function (v) { return { value: v.plateNo, label: v.plateNo + ' · ' + (v.parkingLot || formatDeliveryRegion(v.parkingRegion)) }; }); }, [reserveVehicles]); var vehicleByPlate = useMemo(function () { var map = {}; reserveVehicles.forEach(function (v) { map[v.plateNo] = v; }); return map; }, [reserveVehicles]); function isPlatePendingInForm(plateNo) { if (plateNo == null || plateNo === undefined) return true; var s = String(plateNo).trim(); return s === '' || s === '-'; } function displayDisabledField(v) { var s = v == null || v === undefined ? '' : String(v).trim(); return s || '-'; } function displayFormVin(plateNo, vin) { if (isPlatePendingInForm(plateNo)) return '-'; return displayDisabledField(vin); } function syncVehicleInfoFromReserveRecord(reserveRecord, deliveryRec, plate) { // 备车记录 → 交车单「车辆信息」同步(驾驶培训字段不参与同步,见 buildInitialForm / handlePlateChange) var hasPlate = plate && !isPlatePendingInForm(plate); return { vehicleType: (reserveRecord && reserveRecord.vehicleType) || (deliveryRec && deliveryRec.vehicleType) || '', brand: (reserveRecord && reserveRecord.brand) || (deliveryRec && deliveryRec.brand) || '', model: (reserveRecord && reserveRecord.model) || (deliveryRec && deliveryRec.model) || '', vin: hasPlate ? ((reserveRecord && reserveRecord.vin) || (deliveryRec && deliveryRec.vin) || '') : '', hasAd: !!(reserveRecord && reserveRecord.hasAd), adPhoto: (reserveRecord && reserveRecord.adPhoto) ? reserveRecord.adPhoto.slice() : [], bigWordPhoto: (reserveRecord && reserveRecord.bigWordPhoto) ? reserveRecord.bigWordPhoto.slice() : [], hasTailboard: reserveRecord ? !!reserveRecord.hasTailboard : false, spareTirePhoto: (reserveRecord && reserveRecord.spareTirePhoto) ? reserveRecord.spareTirePhoto.slice() : [], spareTireDepth: (reserveRecord && reserveRecord.spareTireDepth) || '' }; } function buildInitialForm(rec) { var plate = (rec && rec.plateNo && String(rec.plateNo).trim()) || undefined; var reserveRecord = plate ? vehicleByPlate[plate] : null; if (!reserveRecord && rec && rec.brand && plate) { reserveRecord = { plateNo: plate, vehicleType: rec.vehicleType || '', brand: rec.brand || '', model: rec.model || '', vin: rec.vin || '', hasAd: false, adPhoto: [], bigWordPhoto: [], hasTailboard: false }; } var synced = syncVehicleInfoFromReserveRecord(reserveRecord, rec, plate); return Object.assign({ plateNo: plate, trainingRecognized: false, driverLicenses: [], driverFrontPhoto: [], mileageKm: rec && rec.deliveryMileage != null ? String(rec.deliveryMileage) : '', batteryPct: rec && rec.deliveryElec != null ? String(rec.deliveryElec) : '', hydrogenAmount: rec && rec.deliveryH2 != null ? String(rec.deliveryH2) : '', hydrogenUnit: (rec && rec.deliveryH2Unit === 'MPa') ? 'MPa' : '%', serviceFee: '' }, synced); } var formState = useState(buildInitialForm(null)); var form = formState[0]; var setForm = formState[1]; var activeSectionState = useState('basic'); var activeSection = activeSectionState[0]; var setActiveSection = activeSectionState[1]; var submittingState = useState(false); var submitting = submittingState[0]; var setSubmitting = submittingState[1]; var previewState = useState({ open: false, url: '', title: '', gallery: [], index: 0 }); var ocrModalState = useState({ open: false, photoUrl: '', depth: '6.50' }); var trainingInputRef = useRef(null); useEffect(function () { if (open && record) { var initial = buildInitialForm(record); var nextPhotos = createEmptyPhotos(); if (readOnly && record.deliveryStatus && record.deliveryStatus !== '未开始' && record.deliveryStatus !== '已保存') { initial = Object.assign({}, initial, buildDriverInfoFromPickupCode(), buildViewFormPhotoExtras()); nextPhotos = buildViewDeliveryPhotos(); } setForm(initial); setActiveSection('basic'); setSubmitting(false); setPhotos(nextPhotos); setInspectionList(buildInspectionList()); } }, [open, record && record.id, readOnly]); function updateForm(patch) { setForm(function (p) { return Object.assign({}, p, patch); }); } function handlePlateChange(v) { if (!v) { updateForm({ plateNo: undefined, vehicleType: '', brand: '', model: '', vin: '', hasAd: false, adPhoto: [], bigWordPhoto: [], hasTailboard: false, spareTirePhoto: [], spareTireDepth: '', trainingRecognized: false, driverLicenses: [], driverFrontPhoto: [] }); return; } var reserveRecord = vehicleByPlate[v]; updateForm(Object.assign({ plateNo: v, trainingRecognized: false, driverLicenses: [], driverFrontPhoto: [] }, syncVehicleInfoFromReserveRecord(reserveRecord, null, v))); } function makeThumb(url, onPreview, onRemove) { return React.createElement('div', { style: { width: 72, height: 72, borderRadius: 8, border: '1px solid #e2e8f0', overflow: 'hidden', position: 'relative', background: '#f8fafc' } }, React.createElement('img', { src: url, style: { width: '100%', height: '100%', objectFit: 'cover', cursor: 'pointer' }, onClick: onPreview }), onRemove ? React.createElement('button', { type: 'button', 'aria-label': '删除图片', style: { position: 'absolute', right: 4, top: 4, width: 22, height: 22, borderRadius: 999, border: 'none', background: 'rgba(15,23,42,.65)', color: '#fff', cursor: 'pointer', fontSize: 12, lineHeight: '22px', padding: 0 }, onClick: function (e) { e.stopPropagation(); onRemove(); } }, '×') : null ); } function mockViewPhoto(uid, name) { return [{ uid: uid, name: name + '.jpg', url: 'https://dummyimage.com/640x360/e2e8f0/475569&text=' + encodeURIComponent(name) }]; } function mockDeliveryPhotoItem(uid, seed, slotLabel) { return { uid: uid, name: slotLabel + '.jpg', url: 'https://picsum.photos/seed/dv-' + seed + '/960/540' }; } function mockDeliveryPhotoSlot(uid, seed, slotLabel) { return [mockDeliveryPhotoItem(uid, seed, slotLabel)]; } function mockDeliveryPhotoList(items) { return items.map(function (it) { return mockDeliveryPhotoItem(it.uid, it.seed, it.label); }); } function buildDeliveryPhotoGallery(photoData) { var list = []; var slotGroups = [ { key: 'vehicle', label: '车辆' }, { key: 'chassis', label: '底盘' }, { key: 'tire', label: '轮胎' } ]; slotGroups.forEach(function (group) { var groupMap = (photoData && photoData[group.key]) || {}; Object.keys(groupMap).forEach(function (slotLabel) { (groupMap[slotLabel] || []).forEach(function (file) { list.push({ uid: file.uid, url: file.url, name: file.name, title: group.label + ' · ' + slotLabel }); }); }); }); ['defect', 'other'].forEach(function (groupKey) { var groupLabel = groupKey === 'defect' ? '瑕疵' : '其他'; ((photoData && photoData[groupKey]) || []).forEach(function (file, idx) { var files = (photoData && photoData[groupKey]) || []; list.push({ uid: file.uid, url: file.url, name: file.name, title: files.length > 1 ? groupLabel + ' · ' + (file.name || (groupLabel + (idx + 1))) : groupLabel + ' · ' + (file.name || groupLabel) }); }); }); return list; } function closePhotoPreview() { previewState[1]({ open: false, url: '', title: '', gallery: [], index: 0 }); } function openPhotoPreview(options) { var gallery = (options && options.gallery) || []; var index = 0; if (gallery.length && options && options.uid) { for (var i = 0; i < gallery.length; i++) { if (gallery[i].uid === options.uid) { index = i; break; } } } var current = gallery.length ? gallery[index] : { url: options.url, title: options.title }; previewState[1]({ open: true, url: current.url, title: current.title || (options && options.title) || '预览', gallery: gallery, index: index }); } function shiftPhotoPreview(step) { previewState[1](function (prev) { var gallery = prev.gallery || []; if (gallery.length <= 1) return prev; var nextIndex = prev.index + step; if (nextIndex < 0) nextIndex = gallery.length - 1; if (nextIndex >= gallery.length) nextIndex = 0; var item = gallery[nextIndex]; return Object.assign({}, prev, { index: nextIndex, url: item.url, title: item.title }); }); } function buildViewFormPhotoExtras() { return { spareTirePhoto: mockViewPhoto('sp1', '备胎照片'), spareTireDepth: '6.50' }; } function buildViewDeliveryPhotos() { return { vehicle: { '仪表盘': mockDeliveryPhotoSlot('v1', 'vehicle-dash', '仪表盘'), '车辆正前': mockDeliveryPhotoSlot('v2', 'vehicle-front', '车辆正前'), '车辆左前方': mockDeliveryPhotoSlot('v3', 'vehicle-left-front', '车辆左前方'), '车辆左后方': mockDeliveryPhotoSlot('v4', 'vehicle-left-rear', '车辆左后方'), '车辆右前方': mockDeliveryPhotoSlot('v5', 'vehicle-right-front', '车辆右前方'), '车辆右后方': mockDeliveryPhotoSlot('v6', 'vehicle-right-rear', '车辆右后方') }, chassis: { '正前方位底部': mockDeliveryPhotoSlot('c1', 'chassis-front', '正前方位底部'), '左侧前方底部': mockDeliveryPhotoSlot('c2', 'chassis-left-front', '左侧前方底部'), '左侧后方底部': mockDeliveryPhotoSlot('c3', 'chassis-left-rear', '左侧后方底部'), '正后方位底部': mockDeliveryPhotoSlot('c4', 'chassis-rear', '正后方位底部'), '右侧前方底部': mockDeliveryPhotoSlot('c5', 'chassis-right-front', '右侧前方底部'), '右侧后方底部': mockDeliveryPhotoSlot('c6', 'chassis-right-rear', '右侧后方底部') }, tire: { '左前': mockDeliveryPhotoSlot('t1', 'tire-left-front', '左前'), '右前': mockDeliveryPhotoSlot('t2', 'tire-right-front', '右前'), '左后内': mockDeliveryPhotoSlot('t3', 'tire-left-rear-in', '左后内'), '左后外': mockDeliveryPhotoSlot('t4', 'tire-left-rear-out', '左后外'), '右后内': mockDeliveryPhotoSlot('t5', 'tire-right-rear-in', '右后内'), '右后外': mockDeliveryPhotoSlot('t6', 'tire-right-rear-out', '右后外') }, defect: mockDeliveryPhotoList([ { uid: 'd1', seed: 'defect-scratch', label: '瑕疵-刮擦' }, { uid: 'd2', seed: 'defect-dent', label: '瑕疵-凹陷' }, { uid: 'd3', seed: 'defect-paint', label: '瑕疵-漆面' } ]), other: mockDeliveryPhotoList([ { uid: 'o1', seed: 'other-tools', label: '其他-随车工具' }, { uid: 'o2', seed: 'other-cargo', label: '其他-车厢物品' } ]) }; } function ReadonlyPhotoBox(boxProps) { var label = boxProps.label; var value = boxProps.value || []; var gallery = boxProps.gallery; return React.createElement('div', null, label ? React.createElement('div', { style: { fontSize: 13, color: '#475569', marginBottom: 8, fontWeight: 500 } }, label) : null, value.length > 0 ? React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' } }, value.map(function (f) { return React.createElement('div', { key: f.uid }, makeThumb(f.url, function () { openPhotoPreview({ gallery: gallery && gallery.length ? gallery : null, uid: f.uid, url: f.url, title: (gallery && gallery.length) ? ((gallery.filter(function (g) { return g.uid === f.uid; })[0] || {}).title || f.name || label || '预览') : (f.name || label || '预览') }); }) ); }) ) : React.createElement('span', { style: { fontSize: 13, color: '#94a3b8' } }, '-') ); } function UploadBox(uploadProps) { var label = uploadProps.label; var value = uploadProps.value || []; var unlimited = !!uploadProps.unlimited; var max = unlimited ? Infinity : (uploadProps.max || 1); var onChange = uploadProps.onChange; var disabled = !!uploadProps.disabled; function handlePick(e) { if (disabled) return; var f = e && e.target && e.target.files && e.target.files[0]; if (!f) return; fileToDataUrl(f, function (err, url) { if (err) { message.error('上传失败'); return; } var next = value.slice(); next.push({ uid: String(Date.now()), name: f.name || 'image', url: url }); if (!unlimited && next.length > max) next = next.slice(next.length - max); onChange && onChange(next); }); e.target.value = ''; } return React.createElement('div', null, label ? React.createElement('div', { style: { fontSize: 13, color: '#475569', marginBottom: 8, fontWeight: 500 } }, label) : null, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' } }, value.map(function (f) { return React.createElement('div', { key: f.uid }, makeThumb(f.url, function () { previewState[1]({ open: true, url: f.url, title: f.name }); }, disabled ? null : function () { onChange && onChange(value.filter(function (x) { return x.uid !== f.uid; })); }) ); }), (!disabled && (unlimited || value.length < max)) ? React.createElement('label', { style: { width: 72, height: 72, borderRadius: 8, border: '1px dashed #cbd5e1', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', color: '#64748b', cursor: 'pointer', fontSize: 20, lineHeight: 1, background: '#fff', transition: 'border-color .2s' } }, React.createElement('input', { type: 'file', accept: 'image/*', style: { display: 'none' }, onChange: handlePick }), React.createElement('span', { style: { fontSize: 22, lineHeight: 1, marginBottom: 2 } }, '+'), React.createElement('span', { style: { fontSize: 12 } }, '上传') ) : null ), uploadProps.tip ? React.createElement('div', { style: { marginTop: 6, fontSize: 12, color: '#94a3b8', lineHeight: 1.5 } }, uploadProps.tip) : null ); } var EDIT_PHOTO_UPLOAD_HINT = '照片上传说明:jpg、jpeg、png、gif、webp 格式,单张不超过 5MB,支持预览与删除(适用于本页所有照片上传项)'; function createEmptyPhotos() { return { vehicle: { '仪表盘': [], '车辆正前': [], '车辆左前方': [], '车辆左后方': [], '车辆右前方': [], '车辆右后方': [] }, chassis: { '正前方位底部': [], '左侧前方底部': [], '左侧后方底部': [], '正后方位底部': [], '右侧前方底部': [], '右侧后方底部': [] }, tire: { '左前': [], '右前': [], '左后内': [], '左后外': [], '右后内': [], '右后外': [] }, defect: [], other: [] }; } function updatePhotoSlot(groupKey, slotKey, list) { setPhotos(function (p) { var n = Object.assign({}, p); if (slotKey) { n[groupKey] = Object.assign({}, p[groupKey] || {}); n[groupKey][slotKey] = list; } else { n[groupKey] = list; } return n; }); } function PhotoModuleTitle(title, required) { return React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10, fontSize: 14, fontWeight: 700, color: '#0f172a' } }, React.createElement('span', { style: { width: 3, height: 14, borderRadius: 2, background: '#2563eb', flexShrink: 0 } }), (required && !readOnly) ? RequiredLabel(title) : title ); } function PhotoGridColumn(title, items, required, previewGallery) { return React.createElement('div', { style: { marginBottom: 20, minWidth: 0 } }, PhotoModuleTitle(title, required), React.createElement('div', { style: { border: '1px solid #e2e8f0', borderRadius: 10, padding: 12, background: '#fafbfc' } }, React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 12 } }, items.map(function (it) { return React.createElement('div', { key: it.key }, readOnly ? ReadonlyPhotoBox({ label: it.label, value: it.value, gallery: previewGallery }) : UploadBox({ label: required ? RequiredLabel(it.label) : it.label, value: it.value, max: 1, disabled: readOnly, onChange: it.onChange }) ); }) ) ) ); } function PhotoGridSimple(title, value, onChange, previewGallery) { return React.createElement('div', { style: { marginBottom: 20, minWidth: 0 } }, PhotoModuleTitle(title, false), React.createElement('div', { style: { border: '1px solid #e2e8f0', borderRadius: 10, padding: 12, background: '#fafbfc' } }, readOnly ? ReadonlyPhotoBox({ value: value, gallery: previewGallery }) : UploadBox({ value: value, unlimited: true, disabled: readOnly, onChange: onChange }) ) ); } function buildPhotoGridItems(groupKey) { var group = photos[groupKey] || {}; return Object.keys(group).map(function (k) { return { key: groupKey + '-' + k, label: k, value: group[k] || [], onChange: function (l) { updatePhotoSlot(groupKey, k, l); } }; }); } function FormItem(itemProps) { return React.createElement('div', { style: { marginBottom: 16, minWidth: 0 } }, React.createElement('div', { style: { fontSize: 13, color: '#475569', marginBottom: 6, fontWeight: 500 } }, itemProps.required ? RequiredLabel(itemProps.label) : itemProps.label ), itemProps.children ); } var inspectionCategoryItems = { '车灯': ['大灯', '转向灯', '小灯', '示廓灯', '刹车灯', '倒车灯', '牌照灯', '防雾灯', '室内灯'], '仪表盘': ['氢系统指示', '电控系统指示', '数值清晰准确', '故障报警灯'], '驾驶室': ['点烟器', '车窗升降', '按键开关', '雨刮器', '内后视镜是否正常', '内/外门把手', '安全带', '空调冷暖风', '仪表盘', '门锁功能', '手刹', '车钥匙功能是否正常', '喇叭', '音响功能', '遮阳板', '主副驾座椅', '方向盘', '内饰干净整洁'], '轮胎': ['前左胎', '前右胎', '后左胎', '后右胎', '备胎'], '液位检查': ['冷却液', '制动液', '玻璃水'], '外观检查': ['车身外观', '漆面', '玻璃'], '车辆外观': ['整车外观'], '其他': ['其他检查项'], '随车工具': ['三角牌', '灭火器', '反光背心'], '随车证件': ['行驶证', '营运证', '保险单'], '整车': ['整车状态'], '燃料电池系统': ['氢系统', '储氢瓶'], '冷机': ['冷机运行'], '制动系统': ['制动踏板', '驻车制动'] }; function buildInspectionList() { var list = []; var categories = Object.keys(inspectionCategoryItems); for (var ci = 0; ci < categories.length; ci++) { var cat = categories[ci]; var items = inspectionCategoryItems[cat] || []; for (var ji = 0; ji < items.length; ji++) { var it = items[ji]; var isTire = cat === '轮胎'; list.push({ key: 'ins-' + ci + '-' + ji, category: cat, item: it, checked: true, treadDepth: isTire ? '6.5' : '', remark: '' }); } } return list; } var inspectionListState = useState(buildInspectionList); var inspectionList = inspectionListState[0]; var setInspectionList = inspectionListState[1]; var inspectionListRef = useRef(null); inspectionListRef.current = inspectionList; function updateInspectionRow(key, patch) { setInspectionList(function (prev) { return (prev || []).map(function (r) { if (r.key !== key) return r; return Object.assign({}, r, patch); }); }); } var inspectionColumns = useMemo(function () { return [ { title: '类别', dataIndex: 'category', key: 'category', width: 120, render: function (text, record, index) { var rows = inspectionListRef.current || []; var cat = record && record.category; if (!cat) return { children: text, props: { rowSpan: 1 } }; var isFirst = true; for (var i = index - 1; i >= 0; i--) { if (!rows[i] || rows[i].category !== cat) break; isFirst = false; break; } if (!isFirst) return { children: null, props: { rowSpan: 0 } }; var span = 1; for (var j = index + 1; j < rows.length; j++) { if (!rows[j] || rows[j].category !== cat) break; span++; } return { children: text, props: { rowSpan: span } }; } }, { title: '检查项目', dataIndex: 'item', key: 'item', width: 180 }, { title: '检查情况', dataIndex: 'checked', key: 'checked', width: 160, render: function (_, insRecord) { var isTire = insRecord && insRecord.category === '轮胎'; return isTire ? React.createElement(Input, { value: insRecord.treadDepth, placeholder: '请输入胎纹深度', addonAfter: 'mm', disabled: readOnly, onChange: function (e) { updateInspectionRow(insRecord.key, { treadDepth: e.target.value }); } }) : React.createElement(Switch, { checked: !!insRecord.checked, disabled: readOnly, onChange: function (v) { updateInspectionRow(insRecord.key, { checked: !!v }); } }); } }, { title: '备注', dataIndex: 'remark', key: 'remark', render: function (_, insRecord) { return React.createElement(Input, { value: insRecord.remark, placeholder: '请输入', disabled: readOnly, onChange: function (e) { updateInspectionRow(insRecord.key, { remark: e.target.value }); } }); } } ]; }, [readOnly]); var photoState = useState(createEmptyPhotos); var photos = photoState[0]; var setPhotos = photoState[1]; var showSignFileSection = readOnly && record && isDeliverySignedStatus(record.deliveryStatus || record.status); var signFileName = showSignFileSection ? buildDeliverySignFileName(record) : ''; var sectionNav = [ { key: 'basic', label: '交车车辆' }, { key: 'equip', label: '车辆信息' }, { key: 'metrics', label: '交车数据' }, { key: 'inspection', label: '交车检查单' }, { key: 'photos', label: '交车照片' } ]; if (showSignFileSection) { sectionNav.push({ key: 'esign', label: 'E签宝签章' }); } var SECTION_SCROLL_MARGIN = 12; function scrollToSection(key) { setActiveSection(key); var el = document.getElementById('dv-edit-section-' + key); if (el && el.scrollIntoView) el.scrollIntoView({ behavior: 'smooth', block: 'start' }); } function SectionCard(cardProps) { return React.createElement('div', { id: cardProps.id, style: { scrollMarginTop: SECTION_SCROLL_MARGIN, marginBottom: 16, background: '#fff', borderRadius: 12, border: '1px solid #e2e8f0', boxShadow: '0 1px 2px rgba(15,23,42,.04)', overflow: 'hidden' } }, React.createElement('div', { style: { padding: '14px 16px', borderBottom: '1px solid #f1f5f9', fontSize: 14, fontWeight: 700, color: '#0f172a', display: 'flex', alignItems: 'center', gap: 8 } }, React.createElement('span', { style: { width: 3, height: 14, borderRadius: 2, background: '#2563eb', flexShrink: 0 } }), cardProps.title ), React.createElement('div', { style: { padding: '16px 16px 8px' } }, cardProps.children) ); } function validateSubmit() { if (isEmpty(form.plateNo)) return '请选择车牌号'; if (form.hasAd) { if (!form.adPhoto.length) return '请上传广告照片'; if (!form.bigWordPhoto.length) return '请上传放大字照片'; } if (!form.trainingRecognized) return '请上传司机提车码并完成识别'; if (isEmpty(form.mileageKm)) return '请填写交车里程'; if (isEmpty(form.batteryPct)) return '请填写交车电量'; if (isEmpty(form.hydrogenAmount)) return '请填写交车氢量'; var requiredPhotoGroups = [ { key: 'vehicle', label: '车辆' }, { key: 'chassis', label: '底盘' }, { key: 'tire', label: '轮胎' } ]; for (var pi = 0; pi < requiredPhotoGroups.length; pi++) { var pg = requiredPhotoGroups[pi]; var groupMap = photos && photos[pg.key]; var keys = groupMap ? Object.keys(groupMap) : []; for (var ki = 0; ki < keys.length; ki++) { var pk = keys[ki]; if (!(groupMap[pk] && groupMap[pk].length)) return '请上传' + pg.label + '照片:' + pk; } } return ''; } function buildPatchFromForm() { return { plateNo: form.plateNo || '', vehicleType: form.vehicleType, brand: form.brand, model: form.model, vin: form.vin, deliveryMileage: form.mileageKm === '' ? null : Number(form.mileageKm), deliveryElec: form.batteryPct === '' ? null : Number(form.batteryPct), deliveryH2: form.hydrogenAmount === '' ? null : Number(form.hydrogenAmount), deliveryH2Unit: form.hydrogenUnit, deliveryStatus: '已保存' }; } function handleSaveClick() { onSave && onSave(buildPatchFromForm()); message.success('已保存'); } function handleSubmitClick() { var err = validateSubmit(); if (err) { message.error(err); return; } Modal.confirm({ title: '确认交车', content: '请确认信息填写无误,点击确认完成该车辆交车。', okText: '确认', cancelText: '取消', onOk: function () { setSubmitting(true); setTimeout(function () { setSubmitting(false); onSubmit && onSubmit(buildPatchFromForm()); message.success('交车成功'); onClose && onClose(); }, 400); } }); } function isInvalidPickupCodeFile(file) { var name = ((file && file.name) || '').toLowerCase(); return name.indexOf('invalid') >= 0 || name.indexOf('无效') >= 0; } function buildDriverInfoFromPickupCode() { return { trainingRecognized: true, driverFrontPhoto: [{ uid: 'front', name: '司机正面照', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=Driver-Front' }], driverLicenses: [ { uid: 'id1', name: '身份证(正面)', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=ID-F' }, { uid: 'id2', name: '身份证(反面)', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=ID-B' }, { uid: 'dl', name: '驾驶证', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=DL' }, { uid: 'qc', name: '从业资格证', url: 'https://dummyimage.com/600x400/e2e8f0/475569&text=QC' } ] }; } function handleTrainingPick(e) { var f = e && e.target && e.target.files && e.target.files[0]; if (!f) return; var pickedFile = f; setTimeout(function () { if (isInvalidPickupCodeFile(pickedFile)) { updateForm({ trainingRecognized: false, driverFrontPhoto: [], driverLicenses: [] }); message.error('提车码无效,请重新选择'); return; } updateForm(buildDriverInfoFromPickupCode()); message.success('提车码识别成功,已加载司机证照'); }, 500); e.target.value = ''; } function openPickupCodePicker() { trainingInputRef.current && trainingInputRef.current.click(); } if (!open) return null; var drawerTitle = readOnly ? '查看交车单' : '编辑交车单'; var summaryLabelWidth = 80; function renderSummaryField(labelText, valueText) { return React.createElement('div', { style: { display: 'flex', alignItems: 'flex-start', gap: 6, minWidth: 0 } }, React.createElement('span', { style: { color: '#94a3b8', flexShrink: 0, width: summaryLabelWidth, textAlign: 'left' } }, labelText), React.createElement('span', { style: { color: '#334155', flex: 1, minWidth: 0, textAlign: 'left', wordBreak: 'break-all', lineHeight: 1.5 } }, valueText) ); } var summaryCard = record ? React.createElement('div', { style: { marginBottom: 16, padding: '12px 14px', borderRadius: 10, background: 'linear-gradient(135deg,#f8fafc 0%,#fff 100%)', border: '1px solid #e2e8f0', fontSize: 13 } }, React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center', marginBottom: 10, paddingBottom: 10, borderBottom: '1px solid #f1f5f9' } }, React.createElement(Tag, { style: { margin: 0, border: 'none', background: '#eff6ff', color: '#2563eb', fontWeight: 600 } }, record.customerName || '-'), React.createElement('span', { style: { color: '#475569' } }, record.contractCode || '-'), (function () { var status = record.deliveryStatus || '未开始'; var signed = isDeliverySignedStatus(status); var pendingSign = isDeliveryPendingCustomerSignStatus(status); var signRelated = isCustomerSignRelatedStatus(status); var tag = React.createElement(Tag, { style: { margin: 0, border: 'none', background: signRelated ? DV_CUSTOMER_SIGN_STATUS_BG : '#f1f5f9', color: signRelated ? '#fff' : '#475569', fontWeight: signRelated ? 600 : 400 }, title: signed ? '点击下载签章文件' : undefined, role: signed ? 'button' : undefined, tabIndex: signed ? 0 : undefined, onClick: signed ? function (e) { e.stopPropagation(); downloadDeliverySignFile(record); } : undefined, onKeyDown: signed ? function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); downloadDeliverySignFile(record); } } : undefined }, status); if (pendingSign) { return React.createElement(Popover, { content: buildCustomerSignPendingPopoverContent(record), trigger: 'hover', placement: 'topLeft', mouseEnterDelay: 0.15, mouseLeaveDelay: 0.1, destroyTooltipOnHide: true }, tag); } return tag; })() ), React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(2,minmax(0,1fr))', gap: '8px 16px' } }, renderSummaryField('项目:', record.projectName || '-'), renderSummaryField('交车地点:', formatDeliveryRegion(record.deliveryRegion)), renderSummaryField('品牌型号:', (record.brand || '-') + ' / ' + (record.model || '-')), renderSummaryField('任务来源:', record.taskSource || '-') ) ) : null; var sectionNavEl = React.createElement('nav', { 'aria-label': '交车单分节导航', style: { width: 108, flexShrink: 0, position: 'sticky', top: 0, alignSelf: 'flex-start', paddingTop: 4, zIndex: 2 } }, React.createElement('div', { style: { fontSize: 12, color: '#94a3b8', fontWeight: 600, marginBottom: 8, paddingLeft: 12, letterSpacing: '.02em' } }, '目录'), sectionNav.map(function (s) { var active = activeSection === s.key; return React.createElement('button', { key: s.key, type: 'button', onClick: function () { scrollToSection(s.key); }, style: { display: 'block', width: '100%', textAlign: 'left', border: 'none', cursor: 'pointer', padding: '9px 12px', borderRadius: 8, fontSize: 13, lineHeight: 1.4, fontWeight: active ? 600 : 500, background: active ? '#eff6ff' : 'transparent', color: active ? '#2563eb' : '#64748b', borderLeft: active ? '3px solid #2563eb' : '3px solid transparent', marginBottom: 2, transition: 'background .2s,color .2s' } }, s.label); }) ); var sectionBasic = React.createElement(SectionCard, { id: 'dv-edit-section-basic', title: '交车车辆' }, React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(2,minmax(0,1fr))', gap: '0 16px' } }, React.createElement(FormItem, { label: '车牌号', required: !readOnly }, React.createElement(Select, { value: form.plateNo, options: plateOptions, showSearch: true, filterOption: filterOption, placeholder: '请选择已备车车辆(按区域权限过滤)', allowClear: !readOnly, disabled: readOnly, style: { width: '100%' }, onChange: handlePlateChange }) ), React.createElement(FormItem, { label: '车辆类型' }, React.createElement(Input, { value: displayDisabledField(form.vehicleType), disabled: true })), React.createElement(FormItem, { label: '品牌' }, React.createElement(Input, { value: displayDisabledField(form.brand), disabled: true })), React.createElement(FormItem, { label: '型号' }, React.createElement(Input, { value: displayDisabledField(form.model), disabled: true })), React.createElement(FormItem, { label: '车辆识别代码' }, React.createElement(Input, { value: displayFormVin(form.plateNo, form.vin), disabled: true })) ) ); var sectionEquip = React.createElement(SectionCard, { id: 'dv-edit-section-equip', title: '车辆信息' }, !readOnly ? React.createElement('div', { style: { marginBottom: 12, fontSize: 12, color: '#94a3b8', lineHeight: 1.6 } }, EDIT_PHOTO_UPLOAD_HINT) : null, React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0 16px', marginBottom: form.hasAd ? 8 : 0 } }, React.createElement(FormItem, { label: '车身广告及放大字', required: !readOnly }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 10 } }, React.createElement(Switch, { checked: !!form.hasAd, disabled: readOnly, onChange: function (v) { updateForm({ hasAd: !!v }); } }), React.createElement('span', { style: { fontSize: 13, color: '#64748b' } }, form.hasAd ? '有车身广告' : '无车身广告') ) ), React.createElement(FormItem, { label: '尾板', required: !readOnly }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 10 } }, React.createElement(Switch, { checked: !!form.hasTailboard, disabled: readOnly, onChange: function (v) { updateForm({ hasTailboard: !!v }); } }), React.createElement('span', { style: { fontSize: 13, color: '#64748b' } }, form.hasTailboard ? '有尾板' : '无尾板') ) ) ), form.hasAd ? React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginBottom: 8 } }, readOnly ? React.createElement(React.Fragment, null, React.createElement(ReadonlyPhotoBox, { label: '广告照片', value: form.adPhoto }), React.createElement(ReadonlyPhotoBox, { label: '放大字照片', value: form.bigWordPhoto }) ) : React.createElement(React.Fragment, null, React.createElement(UploadBox, { label: RequiredLabel('广告照片'), value: form.adPhoto, max: 1, disabled: readOnly, onChange: function (l) { updateForm({ adPhoto: l }); } }), React.createElement(UploadBox, { label: RequiredLabel('放大字照片'), value: form.bigWordPhoto, max: 1, disabled: readOnly, onChange: function (l) { updateForm({ bigWordPhoto: l }); } }) ) ) : null, React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 } }, readOnly ? React.createElement(ReadonlyPhotoBox, { label: '备胎照片', value: form.spareTirePhoto }) : React.createElement(UploadBox, { label: '备胎照片', value: form.spareTirePhoto, max: 1, disabled: readOnly, onChange: function (l) { updateForm({ spareTirePhoto: l }); if (!readOnly && l && l.length) ocrModalState[1]({ open: true, photoUrl: l[0].url, depth: '6.50' }); } }), React.createElement(FormItem, { label: '备胎胎纹深度' }, React.createElement(Input, { value: form.spareTireDepth, placeholder: readOnly ? undefined : '请输入', addonAfter: 'mm', disabled: readOnly, onChange: function (e) { updateForm({ spareTireDepth: e.target.value }); } }) ) ), React.createElement(FormItem, { label: '驾驶培训', required: !readOnly }, form.trainingRecognized ? React.createElement('div', null, readOnly ? React.createElement('span', { style: { color: '#16a34a', fontWeight: 600, fontSize: 13 } }, '已完成视频培训') : React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' } }, React.createElement('span', { style: { color: '#16a34a', fontWeight: 600, fontSize: 13 } }, '已完成视频培训'), React.createElement(Button, { type: 'link', size: 'small', style: { padding: 0, height: 'auto' }, onClick: openPickupCodePicker }, '重新选择提车码') ), !readOnly ? React.createElement('div', { style: { marginTop: 8, fontSize: 12, color: '#64748b', lineHeight: 1.5 } }, '已根据提车码内绑定的司机信息,自动加载司机证照等照片') : null, form.driverFrontPhoto && form.driverFrontPhoto.length ? React.createElement('div', { style: { marginTop: 12 } }, React.createElement('div', { style: { fontSize: 13, color: '#475569', marginBottom: 8, fontWeight: 500 } }, '司机正面照'), makeThumb(form.driverFrontPhoto[0].url, function () { previewState[1]({ open: true, url: form.driverFrontPhoto[0].url, title: '司机正面照' }); }) ) : null ) : (readOnly ? React.createElement('span', { style: { fontSize: 13, color: '#94a3b8' } }, '-') : React.createElement(React.Fragment, null, React.createElement('input', { type: 'file', ref: trainingInputRef, accept: 'image/*', style: { display: 'none' }, onChange: handleTrainingPick }), React.createElement(Button, { onClick: openPickupCodePicker }, '上传司机提车码'), React.createElement('div', { style: { marginTop: 8, fontSize: 12, color: '#94a3b8', lineHeight: 1.5 } }, '上传后将自动识别提车码内绑定的司机信息,并展示司机证照等照片') )) ), form.driverLicenses && form.driverLicenses.length ? React.createElement(FormItem, { label: '司机证照' }, React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(4,minmax(0,1fr))', gap: 12 } }, form.driverLicenses.map(function (f) { return React.createElement('div', { key: f.uid }, makeThumb(f.url, function () { previewState[1]({ open: true, url: f.url, title: f.name }); }), React.createElement('div', { style: { marginTop: 4, fontSize: 12, color: '#64748b', textAlign: 'center' } }, f.name) ); }) ) ) : null ); var sectionInspection = React.createElement(SectionCard, { id: 'dv-edit-section-inspection', title: '交车检查单' }, React.createElement(Table, { rowKey: 'key', size: 'small', pagination: false, bordered: true, dataSource: inspectionList, columns: inspectionColumns, scroll: { x: 640 } }) ); var sectionMetrics = React.createElement(SectionCard, { id: 'dv-edit-section-metrics', title: '交车数据' }, React.createElement('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(2,minmax(0,1fr))', gap: '0 16px' } }, React.createElement(FormItem, { label: '交车里程', required: !readOnly }, React.createElement(Input, { value: form.mileageKm, placeholder: '请输入', addonAfter: 'km', disabled: readOnly, onChange: function (e) { updateForm({ mileageKm: e.target.value }); } }) ), React.createElement(FormItem, { label: '交车电量', required: !readOnly }, React.createElement(Input, { value: form.batteryPct, placeholder: '请输入', addonAfter: '%', disabled: readOnly, onChange: function (e) { updateForm({ batteryPct: e.target.value }); } }) ), React.createElement(FormItem, { label: '交车氢量', required: !readOnly }, React.createElement(Input, { value: form.hydrogenAmount, placeholder: '请输入', addonAfter: form.hydrogenUnit, disabled: readOnly, onChange: function (e) { updateForm({ hydrogenAmount: e.target.value }); } }) ), React.createElement(FormItem, { label: '送车服务费' }, React.createElement(Input, { value: form.serviceFee, placeholder: '选填', addonAfter: '元', disabled: readOnly, onChange: function (e) { updateForm({ serviceFee: e.target.value }); } }) ) ) ); var deliveryPhotoGallery = readOnly ? buildDeliveryPhotoGallery(photos) : []; var sectionPhotos = React.createElement(SectionCard, { id: 'dv-edit-section-photos', title: '交车照片' }, !readOnly ? React.createElement('div', { style: { marginBottom: 12, fontSize: 12, color: '#94a3b8', lineHeight: 1.6 } }, EDIT_PHOTO_UPLOAD_HINT) : null, PhotoGridColumn('车辆', buildPhotoGridItems('vehicle'), !readOnly, deliveryPhotoGallery), PhotoGridColumn('底盘', buildPhotoGridItems('chassis'), !readOnly, deliveryPhotoGallery), PhotoGridColumn('轮胎', buildPhotoGridItems('tire'), !readOnly, deliveryPhotoGallery), PhotoGridSimple('瑕疵', photos.defect || [], function (l) { updatePhotoSlot('defect', null, l); }, deliveryPhotoGallery), PhotoGridSimple('其他', photos.other || [], function (l) { updatePhotoSlot('other', null, l); }, deliveryPhotoGallery) ); var sectionEsign = showSignFileSection ? React.createElement(SectionCard, { id: 'dv-edit-section-esign', title: 'E签宝签章文件' }, React.createElement('div', { style: { display: 'flex', alignItems: 'flex-start', gap: 14, padding: '12px 14px', borderRadius: 10, border: '1px solid #e2e8f0', background: 'linear-gradient(135deg,#f8fafc 0%,#fff 100%)' } }, React.createElement('div', { style: { width: 44, height: 44, borderRadius: 10, background: '#fee2e2', color: '#dc2626', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 700, flexShrink: 0 } }, 'PDF'), React.createElement('div', { style: { flex: 1, minWidth: 0 } }, React.createElement('div', { style: { fontSize: 14, fontWeight: 600, color: '#0f172a', wordBreak: 'break-all' } }, signFileName), React.createElement('div', { style: { marginTop: 6, fontSize: 12, color: '#64748b', lineHeight: 1.6 } }, React.createElement('div', null, '签章时间:', record.deliveryTime || '-'), React.createElement('div', null, '签章方:', record.customerName || '-') ) ), React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, flexShrink: 0 } }, React.createElement(Button, { size: 'small', onClick: function () { previewDeliverySignFile(record); } }, '预览'), React.createElement(Button, { type: 'primary', size: 'small', onClick: function () { downloadDeliverySignFile(record); } }, '下载') ) ) ) : null; return React.createElement(React.Fragment, null, readOnly ? React.createElement('style', null, DV_VIEW_READONLY_CTRL_CSS) : null, React.createElement(Drawer, { open: open, onClose: onClose, width: Math.min(960, typeof window !== 'undefined' ? window.innerWidth - 24 : 960), title: drawerTitle, destroyOnClose: true, styles: { body: { padding: '16px 20px 88px', background: '#f8fafc' }, footer: { borderTop: '1px solid #e2e8f0', padding: '12px 20px' } }, footer: readOnly ? React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end' } }, React.createElement(Button, { onClick: onClose }, '关闭') ) : React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', gap: 10 } }, React.createElement(Button, { onClick: onClose, disabled: submitting }, '取消'), React.createElement(Button, { onClick: handleSaveClick, disabled: submitting }, '保存'), React.createElement(Button, { type: 'primary', loading: submitting, onClick: handleSubmitClick }, '提交') ) }, React.createElement('div', { className: readOnly ? 'dv-edit-drawer-view' : undefined }, summaryCard, React.createElement('div', { style: { display: 'flex', gap: 16, alignItems: 'flex-start' } }, sectionNavEl, React.createElement('div', { style: { flex: 1, minWidth: 0 } }, sectionBasic, sectionEquip, sectionMetrics, sectionInspection, sectionPhotos, sectionEsign ) ) ) ), React.createElement(Modal, { open: !!previewState[0].open, title: previewState[0].title || '预览', footer: null, onCancel: closePhotoPreview, width: 920, styles: { body: { padding: '12px 20px 20px' } } }, previewState[0].url ? React.createElement('div', null, React.createElement('div', { style: { textAlign: 'center', background: '#0f172a', borderRadius: 10, padding: 12 } }, React.createElement('img', { src: previewState[0].url, alt: previewState[0].title, style: { width: '100%', maxHeight: '72vh', objectFit: 'contain' } }) ), previewState[0].gallery && previewState[0].gallery.length > 1 ? React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginTop: 16 } }, React.createElement(Button, { onClick: function () { shiftPhotoPreview(-1); } }, '上一张'), React.createElement('span', { style: { fontSize: 13, color: '#64748b', fontVariantNumeric: 'tabular-nums' } }, String(previewState[0].index + 1) + ' / ' + previewState[0].gallery.length ), React.createElement(Button, { type: 'primary', onClick: function () { shiftPhotoPreview(1); } }, '下一张') ) : null ) : null ), React.createElement(Modal, { open: !!ocrModalState[0].open, title: '备胎识别', onCancel: function () { ocrModalState[1](Object.assign({}, ocrModalState[0], { open: false })); }, onOk: function () { updateForm({ spareTireDepth: ocrModalState[0].depth }); ocrModalState[1](Object.assign({}, ocrModalState[0], { open: false })); message.success('已反写胎纹深度'); }, okText: '确认', cancelText: '取消' }, React.createElement(Input, { value: ocrModalState[0].depth, addonAfter: 'mm', onChange: function (e) { ocrModalState[1](Object.assign({}, ocrModalState[0], { depth: e.target.value })); } }) ) ); } if (typeof window !== 'undefined') { window.DeliveryEditDrawer = DeliveryEditDrawer; } var DV_REQ_SCROLL_STYLE = { fontSize: 13, color: '#334155', lineHeight: 1.75, maxHeight: '68vh', overflowY: 'auto', paddingRight: 4 }; var DV_REQ_TH_STYLE = { border: '1px solid #e2e8f0', padding: '8px 10px', textAlign: 'left', background: '#f8fafc', fontWeight: 600 }; var DV_REQ_TD_STYLE = { border: '1px solid #e2e8f0', padding: '8px 10px', verticalAlign: 'top' }; function dvReqTitle(text) { return React.createElement('p', { style: { margin: '0 0 8px', fontWeight: 700, color: '#0f172a', fontSize: 14 } }, text); } function dvReqSubtitle(text) { return React.createElement('p', { style: { margin: '14px 0 6px', fontWeight: 600, color: '#334155' } }, text); } function dvReqHint(text) { return React.createElement('p', { style: { margin: '4px 0 8px', color: '#64748b', fontSize: 12 } }, text); } function dvReqStrong(label, text) { return React.createElement(React.Fragment, null, React.createElement('strong', null, label), text); } function dvReqUl(items) { return React.createElement('ul', { style: { paddingLeft: 20, margin: '6px 0 14px' } }, items.map(function (item, idx) { return React.createElement('li', { key: idx, style: { marginBottom: 4 } }, item); }) ); } function dvReqOl(items) { return React.createElement('ol', { style: { paddingLeft: 20, margin: '6px 0 14px' } }, items.map(function (item, idx) { return React.createElement('li', { key: idx, style: { marginBottom: 4 } }, item); }) ); } function dvReqTable(headers, rows) { return React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 12, margin: '8px 0 14px' } }, React.createElement('thead', null, React.createElement('tr', null, headers.map(function (h, i) { return React.createElement('th', { key: i, style: DV_REQ_TH_STYLE }, h); }) ) ), React.createElement('tbody', null, rows.map(function (row, ri) { return React.createElement('tr', { key: ri }, row.map(function (cell, ci) { return React.createElement('td', { key: ci, style: DV_REQ_TD_STYLE }, cell); }) ); }) ) ); } function renderDeliveryRequirementPrdTab(Alert) { return React.createElement('div', { style: DV_REQ_SCROLL_STYLE }, React.createElement(Alert, { type: 'info', showIcon: true, style: { marginBottom: 14, borderRadius: 10 }, message: '模块定位', description: '交车管理面向运维人员,按「单车一行」跟进交车任务进度。运维在列表抽屉内完成交车单录入与提交;客户被授权人通过 E 签宝完成签章后,交车流程完结。本文从产品经理视角描述业务规则与页面行为,不涉及表结构、接口字段及实现细节。' }), dvReqTitle('一、业务对象说明'), dvReqUl([ dvReqStrong('交车任务:', '一次交车业务单元,通常对应一份车辆租赁合同或替换车场景,可包含多台车。'), dvReqStrong('交车单(单车):', '交车任务下某一台车的交车记录,列表以「一车一行」展示。'), dvReqStrong('运维交车:', '运维人员现场验车、拍照、录入里程/电量/氢量等,保存或提交交车单。'), dvReqStrong('客户签章:', '运维提交后,客户侧被授权人在 E 签宝完成电子签章,状态由「待客户签章」变为「客户已签章」。'), dvReqStrong('被授权人:', '取自关联租赁合同的被授权人信息;本模块只读展示姓名与手机号,供运维跟进签章。') ]), dvReqTitle('二、页面结构'), dvReqUl([ '面包屑:运维管理 / 车辆业务 / 交车管理', '右上角「查看需求说明」:打开本说明文档', '页面自上而下:筛选区 → KPI 统计卡片 → 列表区(含导出)' ]), dvReqTitle('三、数据统计(KPI 卡片)'), dvReqHint('三张可点击卡片替代原 Tab,统计范围均为「当前筛选条件命中后的全部车辆行」,不受分页影响。'), dvReqTable( ['卡片', '统计口径', '默认'], [ ['全部交车任务', '进行中 + 已完成', '—'], ['进行中的交车任务', '交车状态为「未开始」「已保存」「待客户签章」', React.createElement('strong', null, '默认选中')], ['已完成的交车任务', '交车状态为「客户已签章」', '—'] ] ), dvReqUl([ '卡片右上角问号:悬停展示指标说明', '点击卡片切换列表数据,选中卡片高亮' ]), dvReqTitle('四、筛选区'), dvReqSubtitle('4.1 通用规则'), dvReqUl([ '默认展示首行 4 项;点击「展开」显示全部 16 项,「收起」恢复默认', '多条件之间为「且」关系;修改筛选项后须点击「搜索」才生效', '「重置」清空全部筛选并恢复默认' ]), dvReqSubtitle('4.2 车辆批量筛选(第一项)'), dvReqHint('交互体验与「保险采购 · 比价单选车」一致。'), dvReqOl([ '点击输入框弹出批量录入面板,支持车牌号、车辆识别代码(VIN)', '每行一条;可从 Excel 等批量复制粘贴;同一行内亦可用逗号、顿号、分号分隔', '面板内「确定」仅保存录入内容;须再点筛选区「搜索」后列表才刷新', '面板内「清空」或触发器一键清除:立即清除该条件并刷新列表', '已生效时触发器展示「已选 N 辆车」', dvReqStrong('匹配规则:', '命中任一输入值即展示(OR);车牌/VIN 均支持精确或包含匹配') ]), dvReqSubtitle('4.3 其余筛选项'), dvReqUl([ '合同编号、项目名称、客户名称:可搜索下拉', '交车区域:省-市二级联动', '完成交车时间:日期段,精确至天', '交车人、车辆识别代码、车辆类型、品牌、型号', '业务部门、业务负责人、任务来源、业务类型、是否延期', dvReqStrong('说明:', '「车辆」批量筛选与「车辆识别代码」单项筛选可同时使用,结果为且关系') ]), dvReqTitle('五、列表(一车一行)'), dvReqSubtitle('5.1 数据粒度'), dvReqUl([ '一个交车任务含多车时,按车辆拆分为独立行展示', '列表数据范围受运维人员区域权限约束(详见第十二节)' ]), dvReqSubtitle('5.2 列说明'), dvReqTable( ['列', '展示与交互'], [ ['车辆信息', '三行:车牌号、品牌-型号、VIN;车牌未选时橙色「车牌待选」,VIN 显示 -;点击车牌号打开查看抽屉'], ['合同信息', '客户名称 + 业务类型 Tag、合同编号(可跳转)、项目名称(可跳转)'], ['业务负责人', '业务部门、业务负责人(两行)'], ['任务来源', '实心 Tag;来源为「替换车」时悬停展示 旧车 → 新车'], ['交车地点', '第一行交车区域(省-市),第二行停车场(车牌待选时显示 -)'], ['交车状态', '详见第六节'], ['完成交车时间', '单行展示'], ['交车人', '单行展示'], ['是否归还', '未交车显示 -;已交车未还车显示「未归还」;已还车显示「已归还」且悬停展示还车时间、还车人'], ['交车记录', '交车里程(km)、交车氢量(%或MPa)、交车电量(%) 三行合并'], ['创建时间 / 创建人', '交车任务维度字段'], ['操作', '「查看」始终可用;「编辑」仅「未开始」「已保存」时展示'] ] ), dvReqSubtitle('5.3 其他规则'), dvReqUl([ '合同信息列宽支持拖拽调整', '分页:默认 10 条/页,可选 10 / 20 / 50' ]), dvReqTitle('六、交车状态与客户签章'), dvReqSubtitle('6.1 状态定义'), dvReqTable( ['状态', '含义', 'KPI 归属'], [ ['未开始', '交车单尚未保存有效数据', '进行中'], ['已保存', '运维已保存但未正式提交', '进行中'], ['待客户签章', '运维已提交,等待客户被授权人 E 签宝签章', '进行中'], ['客户已签章', '客户被授权人已完成签章,流程完结', '已完成'] ] ), dvReqSubtitle('6.2 Tag 视觉与交互规则'), dvReqUl([ dvReqStrong('统一视觉:', '「待客户签章」与「客户已签章」使用相同 Tag 样式(蓝色实心),不做颜色或下划线区分'), dvReqStrong('待客户签章:', '悬停 Popover 展示租赁合同被授权人姓名、手机号;多人逐条展示;无数据显示 -'), dvReqStrong('客户已签章:', '点击 Tag 下载 E 签宝签章文件;文件名建议含交车单标识、车辆序号、车牌号'), '抽屉摘要卡中的状态 Tag 遵循与列表相同的视觉与交互规则' ]), dvReqSubtitle('6.3 被授权人数据来源'), dvReqUl([ '取自交车任务关联的车辆租赁合同「被授权人信息」', '交车管理侧只读展示,不在本模块维护被授权人', '已提交/已签章交车单以提交当时合同快照为准(具体以业务归档规则为准)' ]), dvReqTitle('七、交车状态流转'), React.createElement('div', { style: { padding: '10px 14px', background: '#f8fafc', borderRadius: 8, border: '1px solid #e2e8f0', margin: '8px 0 14px', fontSize: 13, fontWeight: 600, color: '#334155' } }, '未开始 → 已保存(保存)→ 待客户签章(提交)→ 客户已签章(客户 E 签宝完成)' ), dvReqUl([ '仅「未开始」「已保存」可编辑;任意状态均可查看' ]), dvReqTitle('八、编辑交车单(抽屉)'), dvReqSubtitle('8.1 入口与布局'), dvReqUl([ '入口:列表操作列「编辑」(仅未开始/已保存)', '顶部摘要卡:客户名称、合同编号、交车状态、项目、交车地点、品牌型号、任务来源', '左侧目录锚点:交车车辆 · 车辆信息 · 交车数据 · 交车检查单 · 交车照片', '底部操作:取消、保存、提交' ]), dvReqSubtitle('8.2 交车车辆'), dvReqUl([ '车牌号(必填):可搜索选择停车场内「已备车」车辆(详见第十二节)', '车牌待选时 VIN 显示 -;车辆类型/品牌/型号/VIN 只读,随车牌联动' ]), dvReqSubtitle('8.3 车辆信息'), dvReqHint('备车数据同步 — 打开抽屉或选择车牌后自动同步,页面不单独提示。'), dvReqUl([ '同步:车身广告及照片、尾板、备胎照片/胎纹深度、车辆基础信息', '不同步:驾驶培训相关(提车码、司机证照等),须在交车环节单独上传识别', '车身广告开关与备车「后装设备-车身广告」双向同步', '车身广告及放大字(开关必填;开启后各 1 张照片必填)', '尾板(开关必填);备胎照片/胎纹深度(选填,支持 OCR)', '驾驶培训(必填):上传提车码 → 识别成功后加载司机证照;失败提示重新选择' ]), dvReqSubtitle('8.4 交车数据'), dvReqUl([ '交车里程(必填,km)、交车电量(必填,%)、交车氢量(必填,% 或 MPa)', '送车服务费(选填,元)', dvReqStrong('里程自动取值:', '优先车机当前里程 → 其次最近一次异动/调拨/还车结束里程 → 均不可用则手工录入') ]), dvReqSubtitle('8.5 交车检查单'), dvReqUl([ '列:类别(同类合并)、检查项目、检查情况、备注', '覆盖车灯、仪表盘、驾驶室、轮胎、液位、外观、随车工具/证件、燃料电池、冷机、制动等' ]), dvReqSubtitle('8.6 交车照片'), dvReqUl([ '分模块:车辆、底盘、轮胎、瑕疵、其他', '车辆/底盘/轮胎各 6 个必传点位;瑕疵、其他不限张数', '单张:jpg/jpeg/png/gif/webp,不超过 5MB;支持预览、删除' ]), dvReqSubtitle('8.7 保存与提交校验'), dvReqTable( ['业务动作', '须满足的条件'], [ [React.createElement('strong', null, '保存'), React.createElement('ul', { style: { margin: 0, paddingLeft: 18 } }, React.createElement('li', null, '通过当前已填字段校验'), React.createElement('li', null, '状态变为「已保存」,抽屉不关闭') )], [React.createElement('strong', null, '提交'), React.createElement('ul', { style: { margin: 0, paddingLeft: 18 } }, React.createElement('li', null, '车牌已选择'), React.createElement('li', null, '车身广告(若开启)及放大字照片已上传'), React.createElement('li', null, '提车码识别成功,驾驶培训证照齐全'), React.createElement('li', null, '交车里程、电量、氢量已填写'), React.createElement('li', null, '车辆/底盘/轮胎全部必传照片点已上传'), React.createElement('li', null, '二次确认后状态变为「待客户签章」,写入完成交车时间/交车人,关闭抽屉') )] ] ), dvReqTitle('九、查看交车单(抽屉)'), dvReqUl([ '入口:列表点击车牌号,或操作列「查看」', '布局与编辑页一致;全部只读,底部仅「关闭」', '「客户已签章」时额外展示「E签宝签章文件」卡片:文件名、签章时间、签章方;支持预览与下载', '已提交交车单展示完整交车照片;驾驶培训区展示状态与证照图片' ]), dvReqTitle('十、导出'), dvReqUl([ '范围:当前 KPI 卡片选中项 + 全部筛选条件(含车辆批量筛选)下的全部命中行,不受分页限制', '导出列与业务导出样表一致;交车里程、氢量、电量为独立三列(非列表合并列)', '列表区展示当前 KPI 名称及导出范围说明' ]), dvReqTitle('十一、指标单位约定'), dvReqUl([ '交车里程:km', '交车电量:%', '交车氢量:% 或 MPa(按车辆/合同配置)', '列表「交车记录」合并展示;导出仍为三列' ]), dvReqTitle('十二、区域权限与车牌选择'), dvReqSubtitle('12.1 交车任务可见范围'), dvReqUl([ '以交车单「交车区域」(省-市)为任务所属区域', '运维人员须具备该区域或其上级区域权限,方可查看并执行', '示例:交车区域「浙江省-嘉兴市」→ 具备「浙江省」或「嘉兴市」权限可见;仅「杭州市」权限不可见', '无权限时整条交车任务(含其下所有车辆行)均不可见' ]), dvReqSubtitle('12.2 停车场车牌可选范围'), dvReqUl([ '下拉仅展示车辆状态为「已备车」的车辆', '在「已备车」前提下,停车场区域须落在当前运维权限覆盖范围内', '省级权限:可选该省各停车场内已备车车辆;市级权限:仅可选该市', '下拉建议展示:车牌号 + 停车场名称' ]), dvReqTitle('十三、关联模块与数据依赖'), dvReqTable( ['关联模块', '提供的数据 / 能力'], [ ['车辆租赁合同', '合同编号、客户、项目、交车区域/地点、被授权人信息'], ['备车管理', '已备车车辆、车身广告、备胎等同步数据'], ['提车码 / 司机培训', '驾驶培训识别与证照数据'], ['E 签宝', '客户签章状态与签章文件'], ['合同管理', '列表点击合同编号/项目名称跳转详情'], ['替换车', '任务来源为「替换车」时展示旧车 → 新车对照'] ] ) ); } function renderDeliveryRequirementManualTab(Alert, Table) { return React.createElement('div', { style: Object.assign({}, DV_REQ_SCROLL_STYLE, { maxHeight: '62vh' }) }, React.createElement(Alert, { type: 'success', showIcon: true, style: { marginBottom: 14, borderRadius: 10 }, message: '交车全流程(简版)', description: '选车 → 录入交车数据 → 拍照 → 保存/提交 → 跟进客户签章。运维侧以「提交」为节点,客户签章在 E 签宝侧完成。' }), React.createElement(Table, { size: 'small', pagination: false, bordered: true, style: { marginBottom: 14 }, columns: [ { title: '步骤', dataIndex: 'step', width: 56 }, { title: '操作', dataIndex: 'action' }, { title: '要点', dataIndex: 'tip', width: 220 } ], dataSource: [ { key: '1', step: '①', action: '筛选定位车辆', tip: 'KPI 卡片切换进行中/已完成;车辆批量筛选粘贴车牌' }, { key: '2', step: '②', action: '编辑交车单', tip: '仅「未开始/已保存」可编辑;选择已备车车牌' }, { key: '3', step: '③', action: '填写车辆信息', tip: '广告/尾板/备胎;上传提车码完成驾驶培训' }, { key: '4', step: '④', action: '录入交车数据', tip: '里程/电量/氢量必填;里程可自动带入后修改' }, { key: '5', step: '⑤', action: '完成检查单与拍照', tip: '检查单逐项确认;车辆/底盘/轮胎 18 点位必传' }, { key: '6', step: '⑥', action: '保存或提交', tip: '保存→已保存;提交→待客户签章' }, { key: '7', step: '⑦', action: '跟进客户签章', tip: '悬停「待客户签章」查看被授权人联系方式' }, { key: '8', step: '⑧', action: '签章完成', tip: '状态变「客户已签章」;点击 Tag 下载签章文件' } ] }), dvReqTitle('提交前自查'), dvReqUl([ '车牌已从「已备车」列表中选择', '提车码识别成功,司机证照已加载', '交车里程、电量、氢量均已填写', '车辆 / 底盘 / 轮胎全部必传照片点已上传', '车身广告若开启,广告图与放大字图均已上传' ]), dvReqTitle('常见情况'), dvReqUl([ '车牌待选:VIN 不展示,交车地点停车场行显示 -', '待客户签章:运维不可再编辑,可悬停查看被授权人手机号跟进', '客户已签章:归入 KPI「已完成」,可下载签章 PDF', '替换车任务:任务来源列悬停可查看旧车 → 新车对照', '导出:与当前 KPI + 筛选条件一致,不受分页限制' ]) ); } function createDeliveryRequirementModalItems(antd) { var Alert = antd.Alert; var Table = antd.Table; return [ { key: 'prd', label: '需求说明', children: renderDeliveryRequirementPrdTab(Alert) }, { key: 'manual', label: '操作手册', children: renderDeliveryRequirementManualTab(Alert, Table) } ]; } 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 DatePicker = antd.DatePicker; var Select = antd.Select; var Button = antd.Button; var Table = antd.Table; var Cascader = antd.Cascader; var Tag = antd.Tag; var Tooltip = antd.Tooltip; var Popover = antd.Popover; var Modal = antd.Modal; var Tabs = antd.Tabs; var message = antd.message; var Input = antd.Input; var RangePicker = DatePicker.RangePicker; function parseMultiPlates(text) { var raw = (text || '').trim(); if (!raw) return []; var lines = raw.split(/\r?\n/).map(function (line) { return line.trim(); }).filter(Boolean); var expanded = []; lines.forEach(function (line) { if (/[,,、;;]/.test(line)) { line.split(/[,,、;;]+/).forEach(function (s) { var t = s.trim(); if (t) expanded.push(t); }); } else { expanded.push(line); } }); var seen = {}; var out = []; expanded.forEach(function (s) { var key = s.toUpperCase(); if (!seen[key]) { seen[key] = true; out.push(key); } }); return out; } function rowMatchesVehicleFilter(row, vehicleText) { var tokens = parseMultiPlates(vehicleText); if (!tokens.length) return true; var plateRaw = (row.plateNo || '').trim(); var plate = (!plateRaw || plateRaw === '-') ? '' : plateRaw.toUpperCase(); var vin = (row.vin || '').trim().toUpperCase(); for (var i = 0; i < tokens.length; i++) { var token = tokens[i]; if (plate && (plate === token || plate.indexOf(token) !== -1)) return true; if (vin && (vin === token || vin.indexOf(token) !== -1)) return true; } return false; } function createEmptyFilters() { return { contractCode: undefined, projectName: undefined, customerName: undefined, deliveryRegion: undefined, dateStart: '', dateEnd: '', deliveryPerson: undefined, plateNos: '', vin: undefined, vehicleType: undefined, brand: undefined, model: undefined, businessDept: undefined, businessOwner: undefined, taskSource: undefined, bizType: undefined, isDelayed: undefined }; } function patchFilters(prev, patch) { var next = {}; var k; for (k in prev) next[k] = prev[k]; for (k in patch) next[k] = patch[k]; return next; } var filterState = useState(createEmptyFilters); var filters = filterState[0]; var setFilters = filterState[1]; var appliedFilterState = useState(createEmptyFilters); var appliedFilters = appliedFilterState[0]; var setAppliedFilters = appliedFilterState[1]; var filterExpandedState = useState(false); var filterExpanded = filterExpandedState[0]; var setFilterExpanded = filterExpandedState[1]; var multiPlateOpenState = useState(false); var multiPlateOpen = multiPlateOpenState[0]; var setMultiPlateOpen = multiPlateOpenState[1]; var multiPlateDraftState = useState(''); var multiPlateDraft = multiPlateDraftState[0]; var setMultiPlateDraft = multiPlateDraftState[1]; /** total | inProgress | completed */ var kpiFilterState = useState('inProgress'); var kpiFilter = kpiFilterState[0]; var setKpiFilter = kpiFilterState[1]; var pageState = useState(1); var pageSizeState = useState(10); var colWidthsState = useState({ contractInfo: 240 }); var colWidths = colWidthsState[0]; var setColWidths = colWidthsState[1]; var requirementModalOpen = useState(false); var setRequirementModalOpen = requirementModalOpen[1]; var requirementModalItems = useMemo(function () { return createDeliveryRequirementModalItems(antd); }, []); // 交车区域:省-市 二级 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: 'LNZLHT', label: 'LNZLHT' }, { value: 'HT-ZL-2024', label: 'HT-ZL-2024' }, { value: 'HT-ZL-2025', label: 'HT-ZL-2025' } ]; var projectNameOptions = [ { value: 'p1', label: '桐乡韵达租赁4.5T*10' }, { value: 'p2', label: '洛安供应链-租赁帕力安4.5T*30' }, { value: 'p3', label: '嘉兴氢能示范项目' }, { value: 'p4', label: '杭州城配租赁项目' } ]; var customerNameOptions = [ { value: 'c1', label: '桐乡市丰韵快递有限责任公司' }, { value: 'c2', label: '武汉洛安供应链有限公司' }, { value: 'c3', label: '嘉兴某某物流有限公司' }, { value: 'c4', label: '杭州某某租赁有限公司' } ]; var deliveryPersonOptions = [ { value: '张三', label: '张三' }, { value: '李四', label: '李四' }, { value: '王五', label: '王五' }, { value: '魏山', label: '魏山' }, { value: '何苗苗', label: '何苗苗' } ]; var taskSourceOptions = [ { value: '替换车', label: '替换车' }, { value: '交车任务', label: '交车任务' } ]; var bizTypeOptions = [ { value: '租赁', label: '租赁' }, { value: '自营', label: '自营' } ]; var isDelayedOptions = [ { value: 'yes', label: '是' }, { value: 'no', label: '否' } ]; var DV_ORDER_KEY = 'oneos_delivery_order_id'; var DV_VEHICLE_KEY = 'oneos_delivery_vehicle_key'; var DV_NAV_KEY = 'oneos_delivery_navigate_target'; var DV_CONTRACT_CODE_KEY = 'oneos_contract_code'; var DV_LIST_LINK_STYLE = { color: '#165dff', cursor: 'pointer' }; /** 交车状态:进行中=未开始/已保存/待客户签章;历史=客户已签章(运维+客户 E 签宝均完成) */ var DELIVERY_STATUS_HISTORY = '客户已签章'; var DELIVERY_STATUS_IN_PROGRESS = ['未开始', '已保存', '待客户签章']; function isDeliveryHistoryStatus(status) { return status === DELIVERY_STATUS_HISTORY || status === '已签章'; } function isDeliveryInProgressStatus(status) { return DELIVERY_STATUS_IN_PROGRESS.indexOf(status || '未开始') >= 0; } /** 运维侧已完成交车提交(待签章或已签章)视为车辆已交车 */ function isVehicleDelivered(status) { return status === '待客户签章' || isDeliveryHistoryStatus(status); } function canEditDeliveryRow(record) { var s = record.deliveryStatus; return s === '未开始' || s === '已保存'; } // 交车任务(一单多车);列表按车辆拆分为独立行,表头对齐导出样表 var deliveryOrdersState = useState([ { id: 'o1', expectedDate: '2025-02-28 至 2025-03-05', contractCode: 'LNZLHT 20260104001', projectName: '桐乡韵达租赁4.5T*10', customerName: '桐乡市丰韵快递有限责任公司', businessDept: '业务二部', businessOwner: '刘念念', taskSource: '替换车', replaceOldPlate: '浙A88601F', bizType: '租赁', deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '平湖指定停车场', createTime: '2026-06-04 11:28', createBy: '赵小峰', authorizedList: [{ name: '周授权', phone: '13805731234', idCard: '330402199001011234' }], vehicleList: [ { vehicleKey: 1, seq: 1, vehicleType: '4.5吨冷链车', brand: '现代', model: '帕力安牌4.5吨冷链车', vin: 'LNBSCPKB8RR123401', replaceOldPlate: '浙A88601F', plateNo: '', deliveryTime: '', deliveryPerson: '', deliveryStatus: '未开始', deliveryMileage: null, deliveryH2: null, deliveryElec: null }, { vehicleKey: 2, seq: 2, vehicleType: '4.5吨冷链车', brand: '现代', model: '帕力安牌4.5吨冷链车', vin: 'LNBSCPKB8RR123402', replaceOldPlate: '浙A88602F', plateNo: '', deliveryTime: '', deliveryPerson: '', deliveryStatus: '未开始', deliveryMileage: null, deliveryH2: null, deliveryElec: null } ] }, { id: 'o2', expectedDate: '2025-03-01', contractCode: 'LNZLHT2026040301-042', projectName: '洛安供应链-租赁帕力安4.5T*30', customerName: '武汉洛安供应链有限公司', businessDept: '业务三部', businessOwner: '金可鹏', taskSource: '交车任务', bizType: '租赁', deliveryRegion: '四川省-成都市', deliveryAddress: '成都龙泉驿停车场', createTime: '2026-05-31 14:07', createBy: '何苗苗', authorizedList: [{ name: '陈明', phone: '13800138088', idCard: '420102199002022345' }], vehicleList: [ { vehicleKey: 1, seq: 1, vehicleType: '4.5吨冷链车', brand: '现代', model: '帕力安牌4.5吨冷链车', vin: 'LNBSCPKB9RR223401', plateNo: '粤AGP9827', deliveryTime: '2026-06-03 18:20', deliveryPerson: '魏山', deliveryStatus: '待客户签章', deliveryMileage: 48202, deliveryH2: 19, deliveryH2Unit: '%', deliveryElec: 82 }, { vehicleKey: 2, seq: 2, vehicleType: '4.5吨冷链车', brand: '现代', model: '帕力安牌4.5吨冷链车', vin: 'LNBSCPKB9RR223402', plateNo: '粤AGP4598', deliveryTime: '2026-06-02 11:00', deliveryPerson: '魏山', deliveryStatus: '已保存', deliveryMileage: null, deliveryH2: null, deliveryElec: null } ] }, { id: 'o3', expectedDate: '2025-03-08', contractCode: 'LNZLHT2025042201', projectName: '炽瑞-租赁现代4.5T', customerName: '东莞沙田炽瑞物流有限公司', businessDept: '业务三部', businessOwner: '金可鹏', taskSource: '替换车', replaceOldPlate: '粤B58888F', bizType: '租赁', deliveryRegion: '广东省-广州市', deliveryAddress: '广州南沙物流园停车场', createTime: '2026-05-28 20:30', createBy: '童军林', authorizedList: [{ name: '黄签章', phone: '13600136066', idCard: '441900199003033456' }], vehicleList: [ { vehicleKey: 1, seq: 1, vehicleType: '4.5吨货车', brand: '现代', model: '4.5吨货车', vin: 'LNBSCPKB7RR323401', replaceOldPlate: '粤B58888F', plateNo: '', deliveryTime: '', deliveryPerson: '', deliveryStatus: '未开始', deliveryMileage: null, deliveryH2: null, deliveryElec: null } ] }, { id: 'o4', expectedDate: '2024-11-15', contractCode: 'LNZLHT2024111401', projectName: '聚德11月新增苏龙18T*2', customerName: '沈阳聚德物流有限公司', businessDept: '业务三部', businessOwner: '金可鹏', taskSource: '交车任务', bizType: '租赁', deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '嘉兴港区氢能停车场', createTime: '2024-11-15 15:05', createBy: '何苗苗', authorizedList: [ { name: '李签章', phone: '13900139099', idCard: '210102199004044567' }, { name: '王签章', phone: '13700137077', idCard: '210103199005055678' } ], vehicleList: [ { vehicleKey: 1, seq: 1, vehicleType: '18吨双飞翼货车', brand: '苏龙', model: '海格牌18吨双飞翼货车', vin: 'LKLG7C4E4NA774701', plateNo: '浙F80088', deliveryTime: '2026-06-02 16:00', deliveryPerson: '魏山', deliveryStatus: '待客户签章', deliveryMileage: 46200, deliveryH2: 21, deliveryH2Unit: '%', deliveryElec: 80 }, { vehicleKey: 2, seq: 2, vehicleType: '18吨双飞翼货车', brand: '苏龙', model: '海格牌18吨双飞翼货车', vin: 'LKLG7C4E4NA774702', plateNo: '沪A03802F', deliveryTime: '2025-11-20 09:30', deliveryPerson: '何苗苗', deliveryStatus: '已保存', deliveryMileage: null, deliveryH2: null, deliveryElec: null } ] }, { id: 'o5', expectedDate: '2025-02-15', contractCode: 'HT-ZL-2024-001', projectName: '嘉兴氢能示范项目', customerName: '嘉兴某某物流有限公司', businessDept: '业务一部', businessOwner: '张经理', taskSource: '交车任务', bizType: '租赁', deliveryRegion: '浙江省-嘉兴市', deliveryAddress: '南湖科技大道停车场', createTime: '2025-02-10 09:00', createBy: '系统', authorizedList: [{ name: '张授权', phone: '13500135055', idCard: '330402199006066789' }], vehicleList: [ { vehicleKey: 1, seq: 1, vehicleType: '厢式货车', brand: '东风', model: 'DFH1180', vin: 'LKLG7C4E4NA774759', plateNo: '京A12345', deliveryTime: '2025-02-15 10:30', deliveryPerson: '张三', deliveryStatus: '客户已签章', deliveryMileage: 12580, deliveryH2: 35, deliveryH2Unit: 'MPa', deliveryElec: 45, vehicleReturned: true, returnTime: '2025-08-20 11:30', returnPerson: '王五' }, { vehicleKey: 2, seq: 2, vehicleType: '厢式货车', brand: '福田', model: 'BJ1180', vin: 'LKLG7C4E4NA774760', plateNo: '京C11111', deliveryTime: '2025-02-15 14:00', deliveryPerson: '李四', deliveryStatus: '客户已签章', deliveryMileage: 13200, deliveryH2: 68, deliveryH2Unit: '%', deliveryElec: 38, vehicleReturned: false } ] }, { id: 'o6', expectedDate: '2025-02-18', contractCode: 'HT-ZL-2024-003', projectName: '杭州城配租赁项目', customerName: '杭州某某租赁有限公司', businessDept: '业务二部', businessOwner: '李经理', taskSource: '交车任务', bizType: '租赁', deliveryRegion: '浙江省-杭州市', deliveryAddress: '未来科技城地下停车场', createTime: '2025-02-12 08:30', createBy: '李四', authorizedList: [{ name: '赵授权', phone: '13300133033', idCard: '330106199007077890' }], vehicleList: [ { vehicleKey: 1, seq: 1, vehicleType: '城配货车', brand: '重汽', model: 'ZZ1180', vin: 'LKLG7C4E4NA774801', plateNo: '浙A10001', deliveryTime: '2025-02-18 09:15', deliveryPerson: '张三', deliveryStatus: '客户已签章', deliveryMileage: 9800, deliveryH2: 10.8, deliveryH2Unit: '%', deliveryElec: 52, vehicleReturned: true, returnTime: '2026-05-12 09:20', returnPerson: '张三' }, { vehicleKey: 2, seq: 2, vehicleType: '城配货车', brand: '东风', model: 'DFH1190', vin: 'LKLG7C4E4NA774802', plateNo: '浙A10002', deliveryTime: '2025-02-18 11:40', deliveryPerson: '李四', deliveryStatus: '客户已签章', deliveryMileage: 10120, deliveryH2: 9.6, deliveryH2Unit: '%', deliveryElec: 48, vehicleReturned: false }, { vehicleKey: 3, seq: 3, vehicleType: '城配货车', brand: '福田', model: 'BJ1190', vin: 'LKLG7C4E4NA774803', plateNo: '浙A10003', deliveryTime: '2025-02-18 16:20', deliveryPerson: '王五', deliveryStatus: '客户已签章', deliveryMileage: 11500, deliveryH2: 32, deliveryH2Unit: 'MPa', deliveryElec: 55, vehicleReturned: false } ] } ]); var deliveryOrders = deliveryOrdersState[0]; var setDeliveryOrders = deliveryOrdersState[1]; var editDrawerState = useState({ open: false, record: null, mode: 'edit' }); var editDrawer = editDrawerState[0]; var setEditDrawer = editDrawerState[1]; function resolveVehicleReturnedFields(deliveryStatus, v) { if (!isVehicleDelivered(deliveryStatus || '未开始')) { return { vehicleReturned: false, returnTime: '', returnPerson: '' }; } if (!isDeliveryHistoryStatus(deliveryStatus || '未开始')) { return { vehicleReturned: false, returnTime: '', returnPerson: '' }; } return { vehicleReturned: v.vehicleReturned === true || !!(v.returnTime && String(v.returnTime).trim()), returnTime: v.returnTime || '', returnPerson: (v.returnPerson && v.returnPerson !== '-') ? String(v.returnPerson).trim() : '' }; } function expandOrdersToVehicleRows(orders) { var rows = []; (orders || []).forEach(function (order) { (order.vehicleList || []).forEach(function (v, idx) { var vk = v.vehicleKey != null ? v.vehicleKey : idx + 1; var deliveryStatus = v.deliveryStatus || '未开始'; var returnFields = resolveVehicleReturnedFields(deliveryStatus, v); rows.push({ id: order.id + '_v' + vk, orderId: order.id, vehicleKey: vk, seq: v.seq != null ? v.seq : idx + 1, deliveryTime: v.deliveryTime || v.actualDate || '', deliveryPerson: (v.deliveryPerson && v.deliveryPerson !== '-') ? v.deliveryPerson : '', plateNo: (v.plateNo && v.plateNo !== '-') ? String(v.plateNo).trim() : '', vin: (v.plateNo && v.plateNo !== '-' && String(v.plateNo).trim()) ? (v.vin || '') : '', vehicleType: v.vehicleType || '', brand: v.brand || '', model: v.model || '', contractCode: order.contractCode, customerName: order.customerName, projectName: order.projectName, businessDept: order.businessDept || '-', businessOwner: order.businessOwner || '-', taskSource: order.taskSource || '-', replaceOldPlate: (v.replaceOldPlate || order.replaceOldPlate || '').trim(), bizType: order.bizType || '-', deliveryRegion: order.deliveryRegion || '-', deliveryAddress: order.deliveryAddress || '-', deliveryStatus: deliveryStatus, deliveryMileage: v.deliveryMileage, deliveryH2: v.deliveryH2, deliveryH2Unit: v.deliveryH2Unit === 'MPa' ? 'MPa' : '%', deliveryElec: v.deliveryElec, createTime: order.createTime, createBy: order.createBy, expectedDate: order.expectedDate, authorizedList: Array.isArray(order.authorizedList) ? order.authorizedList.slice() : [], vehicleReturned: returnFields.vehicleReturned, returnTime: returnFields.returnTime, returnPerson: returnFields.returnPerson }); }); }); return rows; } function formatDeliveryMileage(v) { if (v === null || v === undefined || v === '') return '-'; return String(v) + ' km'; } function formatDeliveryH2(v, unit) { if (v === null || v === undefined || v === '') return '-'; var u = unit === 'MPa' ? 'MPa' : '%'; return String(v) + ' ' + u; } function formatDeliveryElec(v) { if (v === null || v === undefined || v === '') return '-'; return String(v) + ' %'; } function renderDeliveryRecordCell(record) { return React.createElement('div', null, React.createElement('div', { style: cellLineSubStyle }, '里程 ', formatDeliveryMileage(record.deliveryMileage)), React.createElement('div', { style: cellLineSubStyle }, '氢量 ', formatDeliveryH2(record.deliveryH2, record.deliveryH2Unit)), React.createElement('div', { style: cellLineSubStyle }, '电量 ', formatDeliveryElec(record.deliveryElec)) ); } function rowDateKey(row) { var t = row.deliveryTime || ''; if (t && t.length >= 10) return t.slice(0, 10); return (row.createTime || '').slice(0, 10); } function parseExpectedEndDate(expectedDate) { if (!expectedDate) return ''; var s = String(expectedDate).trim(); if (s.indexOf('至') >= 0) { var seg = s.split('至'); return (seg[seg.length - 1] || '').trim().slice(0, 10); } return s.slice(0, 10); } function computeRowDelayed(row) { if (isDeliveryHistoryStatus(row.deliveryStatus)) return false; var end = parseExpectedEndDate(row.expectedDate); if (!end) return false; return end < '2026-06-01'; } function filterSelectOption(input, option) { var label = (option && (option.label || option.children)) || ''; return String(label).toLowerCase().indexOf(String(input || '').toLowerCase()) >= 0; } function filterVehicleRows(rows) { var list = rows.slice(); var f = appliedFilters; if (f.contractCode) { var cc = (contractCodeOptions.find(function (o) { return o.value === f.contractCode; }) || {}).label || f.contractCode; list = list.filter(function (r) { return (r.contractCode || '').indexOf(cc) !== -1; }); } if (f.projectName) { var projLabel = (projectNameOptions.find(function (o) { return o.value === f.projectName; }) || {}).label; if (projLabel) list = list.filter(function (r) { return r.projectName === projLabel; }); } if (f.customerName) { var custLabel = (customerNameOptions.find(function (o) { return o.value === f.customerName; }) || {}).label; if (custLabel) list = list.filter(function (r) { return r.customerName === custLabel; }); } if (f.deliveryRegion) list = list.filter(function (r) { return (r.deliveryRegion || '').indexOf(f.deliveryRegion) !== -1; }); if (f.dateStart) list = list.filter(function (r) { return rowDateKey(r) >= f.dateStart; }); if (f.dateEnd) list = list.filter(function (r) { return rowDateKey(r) <= f.dateEnd; }); if (f.deliveryPerson) list = list.filter(function (r) { return (r.deliveryPerson || '').indexOf(f.deliveryPerson) !== -1; }); if (parseMultiPlates(f.plateNos).length) { list = list.filter(function (r) { return rowMatchesVehicleFilter(r, f.plateNos); }); } if (f.vin) list = list.filter(function (r) { return (r.vin || '').indexOf(f.vin) !== -1; }); if (f.vehicleType) list = list.filter(function (r) { return r.vehicleType === f.vehicleType; }); if (f.brand) list = list.filter(function (r) { return r.brand === f.brand; }); if (f.model) list = list.filter(function (r) { return r.model === f.model; }); if (f.businessDept) list = list.filter(function (r) { return (r.businessDept || '').indexOf(f.businessDept) !== -1; }); if (f.businessOwner) list = list.filter(function (r) { return (r.businessOwner || '').indexOf(f.businessOwner) !== -1; }); if (f.taskSource) list = list.filter(function (r) { return r.taskSource === f.taskSource; }); if (f.bizType) list = list.filter(function (r) { return r.bizType === f.bizType; }); if (f.isDelayed === 'yes') list = list.filter(function (r) { return computeRowDelayed(r); }); if (f.isDelayed === 'no') list = list.filter(function (r) { return !computeRowDelayed(r); }); return list; } var allVehicleRows = useMemo(function () { return expandOrdersToVehicleRows(deliveryOrders); }, [deliveryOrders]); var operatorVisibleRows = useMemo(function () { return filterRowsByOperatorRegion(allVehicleRows); }, [allVehicleRows]); function buildSelectOptions(values) { var seen = {}; var opts = []; (values || []).forEach(function (v) { var s = v == null ? '' : String(v).trim(); if (!s || seen[s]) return; seen[s] = true; opts.push({ value: s, label: s }); }); opts.sort(function (a, b) { return a.label.localeCompare(b.label, 'zh-CN'); }); return opts; } var dynamicFilterOptions = useMemo(function () { var vins = []; var vehicleTypes = []; var brands = []; var models = []; var depts = []; var owners = []; operatorVisibleRows.forEach(function (r) { if (r.vin) vins.push(r.vin); if (r.vehicleType) vehicleTypes.push(r.vehicleType); if (r.brand) brands.push(r.brand); if (r.model) models.push(r.model); if (r.businessDept && r.businessDept !== '-') depts.push(r.businessDept); if (r.businessOwner && r.businessOwner !== '-') owners.push(r.businessOwner); }); return { vinOptions: buildSelectOptions(vins), vehicleTypeOptions: buildSelectOptions(vehicleTypes), brandOptions: buildSelectOptions(brands), modelOptions: buildSelectOptions(models), businessDeptOptions: buildSelectOptions(depts), businessOwnerOptions: buildSelectOptions(owners) }; }, [operatorVisibleRows]); var filteredBySearch = useMemo(function () { return filterVehicleRows(operatorVisibleRows); }, [operatorVisibleRows, appliedFilters]); var kpiStats = useMemo(function () { var inProgress = 0; var completed = 0; filteredBySearch.forEach(function (r) { if (isDeliveryHistoryStatus(r.deliveryStatus)) completed++; else if (isDeliveryInProgressStatus(r.deliveryStatus)) inProgress++; }); return { total: filteredBySearch.length, inProgress: inProgress, completed: completed }; }, [filteredBySearch]); function matchKpiFilter(row, filterKey) { if (filterKey === 'total') return true; if (filterKey === 'inProgress') return isDeliveryInProgressStatus(row.deliveryStatus); if (filterKey === 'completed') return isDeliveryHistoryStatus(row.deliveryStatus); return true; } var filteredList = useMemo(function () { return filteredBySearch.filter(function (r) { return matchKpiFilter(r, kpiFilter); }); }, [filteredBySearch, kpiFilter]); function patchVehicleInOrder(orderId, vehicleKey, patch) { setDeliveryOrders(function (orders) { return orders.map(function (order) { if (order.id !== orderId) return order; return Object.assign({}, order, { vehicleList: (order.vehicleList || []).map(function (v) { var vk = v.vehicleKey != null ? v.vehicleKey : v.seq; if (vk !== vehicleKey) return v; return Object.assign({}, v, patch); }) }); }); }); } var openEditDrawer = useCallback(function (record) { setEditDrawer({ open: true, record: record, mode: 'edit' }); }, []); var openViewDrawer = useCallback(function (record) { setEditDrawer({ open: true, record: record, mode: 'view' }); }, []); var closeEditDrawer = useCallback(function () { setEditDrawer({ open: false, record: null, mode: 'edit' }); }, []); var handleEditSave = useCallback(function (patch) { var rec = editDrawer.record; if (!rec) return; patchVehicleInOrder(rec.orderId, rec.vehicleKey, Object.assign({}, patch, { deliveryStatus: '已保存' })); }, [editDrawer.record]); var handleEditSubmit = useCallback(function (patch) { var rec = editDrawer.record; if (!rec) return; patchVehicleInOrder(rec.orderId, rec.vehicleKey, Object.assign({}, patch, { deliveryStatus: '待客户签章', deliveryTime: patch.deliveryTime || '2026-06-04 10:00', deliveryPerson: patch.deliveryPerson || '魏山' })); closeEditDrawer(); }, [editDrawer.record, closeEditDrawer]); var navigateToContractDetail = useCallback(function (record) { try { sessionStorage.setItem(DV_CONTRACT_CODE_KEY, record.contractCode || ''); sessionStorage.setItem(DV_ORDER_KEY, record.orderId || ''); } catch (e) {} message.info('跳转 合同管理-该合同详情页(合同编号 ' + (record.contractCode || '-') + ')'); }, []); var navigateDelivery = useCallback(function (record, target) { try { sessionStorage.setItem(DV_ORDER_KEY, record.orderId || ''); sessionStorage.setItem(DV_VEHICLE_KEY, String(record.vehicleKey != null ? record.vehicleKey : '')); sessionStorage.setItem(DV_NAV_KEY, target || 'order'); } catch (e) {} var pageMap = { order: '交车管理-交车单', edit: '交车管理-交车单-编辑', view: '交车管理-交车单-查看' }; message.info('跳转 ' + (pageMap[target] || target) + '(交车单 ' + record.orderId + ' · 车辆 ' + record.plateNo + ')'); }, []); var page = pageState[0]; var setPage = pageState[1]; var pageSize = pageSizeState[0]; var setPageSize = pageSizeState[1]; var handleKpiCardClick = useCallback(function (key) { setKpiFilter(key); setPage(1); }, []); var totalCount = filteredList.length; var displayList = useMemo(function () { var start = (page - 1) * pageSize; return filteredList.slice(start, start + pageSize); }, [filteredList, page, pageSize]); var kpiExportLabelMap = { total: '全部交车任务', inProgress: '进行中的交车任务', completed: '已完成的交车任务' }; function normalizeRegionFilter(regionVal) { 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]; }); return prov && city ? prov.label + '-' + city.label : undefined; } if (Array.isArray(regionVal) && regionVal.length === 1) { var pOnly = regionOptions.find(function (r) { return r.value === regionVal[0]; }); return pOnly ? pOnly.label : undefined; } return regionVal; } var appliedMultiVehicles = useMemo(function () { return parseMultiPlates(appliedFilters.plateNos); }, [appliedFilters.plateNos]); var vehicleFilterTriggerText = appliedMultiVehicles.length ? ('已选 ' + appliedMultiVehicles.length + ' 辆车') : ''; var handleMultiPlateOpenChange = useCallback(function (open) { setMultiPlateOpen(open); if (open) setMultiPlateDraft(filters.plateNos || ''); }, [filters.plateNos]); var handleMultiPlateClear = useCallback(function () { setMultiPlateDraft(''); setMultiPlateOpen(false); var next = patchFilters(filters, { plateNos: '' }); setFilters(next); setAppliedFilters(patchFilters(next, {})); setPage(1); }, [filters]); var handleMultiPlateApply = useCallback(function () { var trimmed = multiPlateDraft.trim(); setFilters(function (f) { return patchFilters(f, { plateNos: trimmed }); }); setMultiPlateOpen(false); }, [multiPlateDraft]); var handleQuery = useCallback(function () { var plateText = (multiPlateDraft.trim() || (filters.plateNos || '')).trim(); var next = patchFilters(filters, { deliveryRegion: normalizeRegionFilter(filters.deliveryRegion), plateNos: plateText }); setFilters(next); setAppliedFilters(patchFilters(next, {})); setMultiPlateDraft(plateText); setMultiPlateOpen(false); setPage(1); var tokens = parseMultiPlates(plateText); if (tokens.length) { message.success('已按 ' + tokens.length + ' 辆车筛选'); } }, [filters, multiPlateDraft]); var handleReset = useCallback(function () { var empty = createEmptyFilters(); setFilters(empty); setAppliedFilters(empty); setMultiPlateDraft(''); setMultiPlateOpen(false); setPage(1); }, []); var getExportRowsByKpi = useCallback(function (filterKey) { return filteredBySearch.filter(function (r) { return matchKpiFilter(r, filterKey); }); }, [filteredBySearch]); var handleExport = useCallback(function () { var tabLabel = kpiExportLabelMap[kpiFilter] || '交车任务'; var rows = getExportRowsByKpi(kpiFilter); if (!rows || rows.length === 0) { message.warning('当前「' + tabLabel + '」无数据可导出'); 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) { return [formatCompletedDeliveryTimeExport(r.deliveryTime), r.deliveryPerson || '-', displayPlateNo(r.plateNo), r.brand || '-', r.model || '-', r.contractCode, r.customerName, r.projectName, r.businessDept, r.businessOwner, r.taskSource, r.bizType, r.deliveryRegion, r.deliveryAddress, r.deliveryStatus, formatDeliveryMileage(r.deliveryMileage), formatDeliveryH2(r.deliveryH2, r.deliveryH2Unit), formatDeliveryElec(r.deliveryElec), r.createTime, r.createBy]; }; 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 = '交车管理_' + tabLabel + '_' + new Date().getTime() + '.csv'; a.click(); URL.revokeObjectURL(url); message.success('已导出「' + tabLabel + '」共 ' + rows.length + ' 条(含当前筛选条件)'); }, [kpiFilter, getExportRowsByKpi]); 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 solidTagBaseStyle = { margin: 0, border: 'none', fontWeight: 600, color: '#fff', lineHeight: '20px', flexShrink: 0, flexGrow: 0 }; function renderSolidTag(text, bgColor) { if (!text || text === '-') return '-'; return React.createElement(Tag, { style: Object.assign({}, solidTagBaseStyle, { backgroundColor: bgColor || '#64748b' }) }, text); } function renderDeliveryStatus(status, record) { var bg = '#8c8c8c'; if (isCustomerSignRelatedStatus(status)) bg = DV_CUSTOMER_SIGN_STATUS_BG; else if (status === '已保存') bg = '#ea580c'; else if (status === '未开始') bg = '#64748b'; var signed = isDeliverySignedStatus(status); var pendingSign = isDeliveryPendingCustomerSignStatus(status); var style = Object.assign({}, solidTagBaseStyle, { backgroundColor: bg || '#64748b' }); var tag = React.createElement(Tag, { style: style, title: signed ? '点击下载签章文件' : undefined, role: signed ? 'button' : undefined, tabIndex: signed ? 0 : undefined, onClick: signed ? function (e) { e.stopPropagation(); downloadDeliverySignFile(record); } : undefined, onKeyDown: signed ? function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); downloadDeliverySignFile(record); } } : undefined }, status); if (pendingSign) { return React.createElement(Popover, { content: buildCustomerSignPendingPopoverContent(record), trigger: 'hover', placement: 'topLeft', mouseEnterDelay: 0.15, mouseLeaveDelay: 0.1, destroyTooltipOnHide: true }, tag); } return tag; } function renderBizTypeTag(bizType) { if (!bizType || bizType === '-') return null; var bg = '#64748b'; if (bizType === '租赁') bg = '#2563eb'; else if (bizType === '自营') bg = '#7c3aed'; return React.createElement(Tag, { style: Object.assign({}, solidTagBaseStyle, { backgroundColor: bg, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', textAlign: 'center', alignSelf: 'center', minWidth: 44, height: 22, padding: '0 10px', boxSizing: 'border-box' }) }, bizType); } function renderTaskSourceTag(text, bgColor) { return React.createElement(Tag, { style: Object.assign({}, solidTagBaseStyle, { backgroundColor: bgColor, cursor: 'default' }) }, text); } var handleColumnResizeStart = useCallback(function (colKey, e) { e.preventDefault(); e.stopPropagation(); var startX = e.clientX; var startW = colWidths[colKey] || 240; function onMove(ev) { var nextW = Math.max(140, Math.min(560, startW + ev.clientX - startX)); setColWidths(function (prev) { var next = {}; for (var k in prev) next[k] = prev[k]; next[colKey] = nextW; return next; }); } function onUp() { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); } document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp); }, [colWidths]); function renderResizableTitle(title, colKey) { return React.createElement('div', { style: { position: 'relative', paddingRight: 10, userSelect: 'none' } }, title, React.createElement('span', { role: 'separator', 'aria-orientation': 'vertical', title: '拖动调整列宽', style: { position: 'absolute', right: 0, top: 0, bottom: 0, width: 8, cursor: 'col-resize', zIndex: 1 }, onMouseDown: function (ev) { handleColumnResizeStart(colKey, ev); } }) ); } function renderContractInfoCell(record) { var customerName = record.customerName || '-'; var showTip = customerName !== '-'; var contractCode = record.contractCode || '-'; var projectName = record.projectName || '-'; return React.createElement('div', { style: { minWidth: 0, width: '100%' } }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', flexWrap: 'nowrap', gap: 6, minWidth: 0, width: '100%', lineHeight: 1.45 } }, React.createElement(Tooltip, { title: showTip ? customerName : null, placement: 'topLeft' }, React.createElement('span', { style: { flex: '1 1 auto', minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: '#333', display: 'block' } }, customerName) ), React.createElement('span', { style: { flexShrink: 0, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' } }, renderBizTypeTag(record.bizType)) ), contractCode !== '-' ? React.createElement('div', { style: Object.assign({}, cellLineSubStyle, DV_LIST_LINK_STYLE, { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }), role: 'button', tabIndex: 0, onClick: function () { navigateToContractDetail(record); }, onKeyDown: function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); navigateToContractDetail(record); } } }, contractCode) : React.createElement('div', { style: cellLineSubStyle }, '-'), projectName !== '-' ? React.createElement('div', { style: Object.assign({}, cellLineSubStyle, DV_LIST_LINK_STYLE, { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }), role: 'button', tabIndex: 0, onClick: function () { navigateToContractDetail(record); }, onKeyDown: function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); navigateToContractDetail(record); } } }, projectName) : React.createElement('div', { style: Object.assign({}, cellLineSubStyle, { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }) }, '-') ); } function renderDeliveryPlaceCell(record) { var regionText = '交车区域:' + formatDeliveryRegion(record.deliveryRegion); var parkingText = isPlatePending(record.plateNo) ? '-' : (record.deliveryAddress || '-'); return renderCellLines(regionText, [parkingText]); } function parseCompletedDeliveryTime(raw) { if (!raw || String(raw).trim() === '' || raw === '-') return { date: '-', time: '-' }; var s = String(raw).trim(); if (s.indexOf(' ') >= 0) { var parts = s.split(/\s+/); var datePart = parts[0] || '-'; var timePart = parts[1] || '-'; if (timePart.length >= 5) timePart = timePart.slice(0, 5); return { date: datePart, time: timePart }; } return { date: s, time: '-' }; } function renderCompletedDeliveryTimeCell(record) { var parsed = parseCompletedDeliveryTime(record.deliveryTime); return renderCellLines(parsed.date, [parsed.time]); } function renderTaskCreateTimeCell(record) { var parsed = parseCompletedDeliveryTime(record.createTime); if (parsed.date === '-' && parsed.time === '-') return '-'; if (parsed.time === '-') return parsed.date; return parsed.date + ' ' + parsed.time; } function renderTaskCreateByCell(createBy) { if (createBy == null || createBy === undefined) return '-'; var name = String(createBy).trim(); return name === '' || name === '-' ? '-' : name; } function isVehicleReturned(record) { if (!record || !isVehicleDelivered(record.deliveryStatus) || !isDeliveryHistoryStatus(record.deliveryStatus)) return false; return record.vehicleReturned === true; } function renderVehicleReturnedCell(record) { if (!record || !isVehicleDelivered(record.deliveryStatus)) { return '-'; } if (!isVehicleReturned(record)) { return React.createElement('span', { style: { color: '#64748b' } }, '未归还'); } var label = React.createElement('span', { style: { color: '#16a34a', fontWeight: 600, cursor: 'default', borderBottom: '1px dashed #86efac' } }, '已归还'); return React.createElement(Popover, { content: renderReturnVehiclePopoverContent(record), trigger: 'hover', placement: 'topLeft', mouseEnterDelay: 0.15, mouseLeaveDelay: 0.1, destroyTooltipOnHide: true }, label); } function formatReturnTimeDisplay(raw) { var parsed = parseCompletedDeliveryTime(raw); if (parsed.date === '-' && parsed.time === '-') return '-'; if (parsed.time === '-') return parsed.date; return parsed.date + ' ' + parsed.time; } function renderReturnVehiclePopoverContent(record) { return React.createElement('div', { style: { minWidth: 168, fontSize: 13, lineHeight: 1.65 } }, React.createElement('div', null, React.createElement('span', { style: { color: '#64748b' } }, '还车时间:'), React.createElement('span', { style: { color: '#334155', fontWeight: 600 } }, formatReturnTimeDisplay(record.returnTime)) ), React.createElement('div', { style: { marginTop: 4 } }, React.createElement('span', { style: { color: '#64748b' } }, '还车人:'), React.createElement('span', { style: { color: '#334155', fontWeight: 600 } }, record.returnPerson || '-') ) ); } function formatCompletedDeliveryTimeExport(raw) { var parsed = parseCompletedDeliveryTime(raw); if (parsed.date === '-' && parsed.time === '-') return '-'; if (parsed.time === '-') return parsed.date; return parsed.date + ' ' + parsed.time; } var cellLineMainStyle = { lineHeight: 1.45, color: '#333', wordBreak: 'break-all' }; var cellLineSubStyle = { lineHeight: 1.4, fontSize: 12, color: '#8c8c8c', marginTop: 2, wordBreak: 'break-all' }; function renderCellLines(mainText, subLines) { var subs = subLines || []; return React.createElement('div', null, React.createElement('div', { style: cellLineMainStyle }, mainText || '-'), subs.map(function (line, i) { return React.createElement('div', { key: i, style: cellLineSubStyle }, line || '-'); }) ); } function isPlatePending(plateNo) { if (plateNo == null || plateNo === undefined) return true; var s = String(plateNo).trim(); return s === '' || s === '-'; } function displayPlateNo(plateNo) { return isPlatePending(plateNo) ? '车牌待选' : String(plateNo).trim(); } function displayBrandModel(brand, model) { var b = brand && brand !== '-' ? String(brand).trim() : ''; var m = model && model !== '-' ? String(model).trim() : ''; if (b && m) return b + '-' + m; if (b) return b; if (m) return m; return '-'; } function displayVin(vin, plateNo) { if (plateNo != null && isPlatePending(plateNo)) return '-'; var s = vin == null || vin === undefined ? '' : String(vin).trim(); return s || '-'; } function displayReplaceOldPlate(plate) { var s = plate == null ? '' : String(plate).trim(); return s || '-'; } function renderReplaceVehiclePopoverContent(record) { var oldPlate = displayReplaceOldPlate(record.replaceOldPlate); var newPlate = displayPlateNo(record.plateNo); return React.createElement('div', { style: { minWidth: 168, fontSize: 13, lineHeight: 1.5 } }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } }, React.createElement('span', { style: { color: '#64748b' } }, '旧车'), React.createElement('span', { style: { fontWeight: 600, color: '#334155' } }, oldPlate), React.createElement('span', { style: { color: '#94a3b8', fontWeight: 600 } }, '→'), React.createElement('span', { style: { color: '#64748b' } }, '新车'), React.createElement('span', { style: { fontWeight: 600, color: isPlatePending(record.plateNo) ? '#d48806' : '#334155' } }, newPlate) ) ); } function renderTaskSourceCell(value, record) { if (value === '替换车') { return React.createElement(Popover, { content: renderReplaceVehiclePopoverContent(record), trigger: 'hover', placement: 'topLeft', mouseEnterDelay: 0.15, mouseLeaveDelay: 0.1, destroyTooltipOnHide: true }, renderTaskSourceTag('替换车', '#ea580c')); } if (value === '交车任务') return renderTaskSourceTag('交车任务', '#2563eb'); return value || '-'; } function renderVehicleInfoCell(record) { var pending = isPlatePending(record.plateNo); var plateStyle = Object.assign({}, cellLineMainStyle, { cursor: 'pointer' }, pending ? { color: '#d48806', fontWeight: 500 } : { color: '#165dff' }); return React.createElement('div', null, React.createElement('div', { style: plateStyle, role: 'button', tabIndex: 0, onClick: function () { openViewDrawer(record); }, onKeyDown: function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openViewDrawer(record); } } }, displayPlateNo(record.plateNo)), React.createElement('div', { style: cellLineSubStyle }, displayBrandModel(record.brand, record.model)), React.createElement('div', { style: cellLineSubStyle }, displayVin(record.vin, record.plateNo)) ); } // 列表列(按车辆一行;待处理/历史记录列顺序一致) var colDeliveryTime = { title: '完成交车时间', key: 'completedDeliveryTime', width: 118, render: function (_, r) { return renderCompletedDeliveryTimeCell(r); } }; var colDeliveryPerson = { title: '交车人', dataIndex: 'deliveryPerson', key: 'deliveryPerson', width: 80, render: function (v) { return v || '-'; } }; var colDeliveryStatus = { title: '交车状态', dataIndex: 'deliveryStatus', key: 'deliveryStatus', width: 108, render: function (v, r) { return renderDeliveryStatus(v, r); } }; var sharedListColumns = useMemo(function () { return [ { title: '车辆信息', key: 'vehicleInfo', width: 188, render: function (_, r) { return renderVehicleInfoCell(r); } }, { title: renderResizableTitle('合同信息', 'contractInfo'), key: 'contractInfo', width: colWidths.contractInfo, render: function (_, r) { return renderContractInfoCell(r); } }, { title: '业务负责人', key: 'businessInfo', width: 120, render: function (_, r) { return renderCellLines(r.businessDept, [r.businessOwner]); } }, { title: '任务来源', dataIndex: 'taskSource', key: 'taskSource', width: 92, ellipsis: true, render: function (v, r) { return renderTaskSourceCell(v, r); } }, { title: '交车地点', key: 'deliveryPlace', width: 168, render: function (_, r) { return renderDeliveryPlaceCell(r); } }, colDeliveryStatus, colDeliveryTime, colDeliveryPerson, { title: '是否归还', key: 'vehicleReturned', width: 88, render: function (_, r) { return renderVehicleReturnedCell(r); } }, { title: '交车记录', key: 'deliveryRecord', width: 118, render: function (_, r) { return renderDeliveryRecordCell(r); } }, { title: '交车任务创建时间', key: 'taskCreateTime', width: 150, ellipsis: true, render: function (_, r) { return renderTaskCreateTimeCell(r); } }, { title: '交车任务创建人', dataIndex: 'createBy', key: 'taskCreateBy', width: 108, ellipsis: true, render: function (v) { return renderTaskCreateByCell(v); } } ]; }, [colWidths.contractInfo, handleColumnResizeStart, navigateToContractDetail]); var listColumns = useMemo(function () { return sharedListColumns.concat([ { title: '操作', key: 'action', width: 96, fixed: 'right', render: function (_, r) { var nodes = [ React.createElement(Button, { key: 'view', type: 'link', size: 'small', onClick: function () { openViewDrawer(r); } }, '查看') ]; if (canEditDeliveryRow(r)) { nodes.push(React.createElement(Button, { key: 'edit', type: 'link', size: 'small', onClick: function () { openEditDrawer(r); } }, '编辑')); } return React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 2, flexWrap: 'nowrap' } }, nodes); } } ]); }, [sharedListColumns, openEditDrawer, openViewDrawer]); var kpiCards = useMemo(function () { return [ { key: 'total', type: 'total', title: '全部交车任务', desc: '当前筛选条件下的全部交车任务(含进行中与已完成)', val: kpiStats.total, icon: DV_KPI_ICONS.total }, { key: 'inProgress', type: 'progress', title: '进行中的交车任务', desc: '交车状态为「未开始」「已保存」「待客户签章」的任务(客户未完成最终签章)', val: kpiStats.inProgress, icon: DV_KPI_ICONS.progress }, { key: 'completed', type: 'completed', title: '已完成的交车任务', desc: '客户已完成最终签章步骤的所有交车任务(状态为「客户已签章」)', val: kpiStats.completed, icon: DV_KPI_ICONS.completed } ]; }, [kpiStats]); function renderKpiCard(card) { var active = kpiFilter === card.key; return React.createElement('div', { key: card.key, role: 'button', tabIndex: 0, className: 'lc-alert-card lc-alert-card--' + card.type + ' lc-alert-card-clickable' + (active ? ' lc-alert-card-active' : ''), onClick: function () { handleKpiCardClick(card.key); }, onKeyDown: function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleKpiCardClick(card.key); } } }, React.createElement('div', { className: 'lc-alert-card-tip-anchor' }, React.createElement(Tooltip, { title: card.desc, placement: 'topRight', overlayStyle: { maxWidth: 360 } }, React.createElement('span', { className: 'lc-alert-card-tip', role: 'img', 'aria-label': card.title + '说明', onClick: function (e) { e.stopPropagation(); }, onMouseDown: function (e) { e.stopPropagation(); } }, DV_KPI_TIP_SVG) ) ), React.createElement('div', { className: 'lc-alert-card-icon' }, card.icon), React.createElement('div', { className: 'lc-alert-card-main' }, React.createElement('div', { className: 'lc-alert-card-val' }, card.val), React.createElement('div', { className: 'lc-alert-card-title' }, card.title) ) ); } 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 filterLabelStyle = { display: 'block', marginBottom: 4, color: '#333', fontSize: 14 }; var filterControlStyle = { width: '100%' }; var filterItemStyle = { minWidth: 0 }; 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' }, filterGrid: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: '16px 24px', alignItems: 'start' }, filterActions: { display: 'flex', justifyContent: 'flex-end', alignItems: 'center', gap: 8, marginTop: 16, paddingTop: 16, borderTop: '1px solid #f1f5f9' } }; var filterItems = [ React.createElement('div', { key: 'plateNos', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '车辆'), React.createElement(Popover, { open: multiPlateOpen, onOpenChange: handleMultiPlateOpenChange, trigger: 'click', placement: 'bottomLeft', overlayClassName: 'lc-multi-plate-popover', content: React.createElement('div', { className: 'lc-multi-plate-pop' }, React.createElement('div', { className: 'lc-multi-plate-pop-hint' }, '支持多辆车车牌号、车辆识别代码,每行一条;可从 Excel 等批量复制粘贴,点击「确定」后于筛选区点击「搜索」生效。' ), React.createElement(Input.TextArea, { value: multiPlateDraft, onChange: function (e) { setMultiPlateDraft(e.target.value); }, placeholder: '浙F80088\n粤AGP4598\nLNBSCPKB9RR223402', autoSize: { minRows: 5, maxRows: 10 }, style: { borderRadius: 8, fontFamily: 'monospace', fontSize: 13 } }), React.createElement('div', { className: 'lc-multi-plate-pop-actions' }, React.createElement(Button, { size: 'small', onClick: handleMultiPlateClear }, '清空'), React.createElement(Button, { size: 'small', type: 'primary', onClick: handleMultiPlateApply }, '确定') ) ) }, React.createElement(Input, { className: 'lc-multi-plate-trigger', readOnly: true, allowClear: !!vehicleFilterTriggerText, placeholder: '支持多辆车车牌号、车辆识别代码,每行一条', value: vehicleFilterTriggerText, onClick: function () { setMultiPlateOpen(true); }, onClear: function (e) { if (e && e.stopPropagation) e.stopPropagation(); handleMultiPlateClear(); }, style: Object.assign({ borderRadius: 8 }, filterControlStyle), suffix: React.createElement('svg', { width: 14, height: 14, viewBox: '0 0 24 24', fill: 'none', stroke: '#94a3b8', strokeWidth: 2, style: { pointerEvents: 'none' } }, React.createElement('polyline', { points: '6 9 12 15 18 9' })) }) ) ), React.createElement('div', { key: 'contractCode', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '合同编号'), React.createElement(Select, { placeholder: '请输入或选择合同编号', allowClear: true, showSearch: true, optionFilterProp: 'label', style: filterControlStyle, value: filters.contractCode, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { contractCode: v }); }); }, options: contractCodeOptions }) ), React.createElement('div', { key: 'projectName', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '项目名称'), React.createElement(Select, { placeholder: '请输入或选择项目名称', allowClear: true, showSearch: true, optionFilterProp: 'label', style: filterControlStyle, value: filters.projectName, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { projectName: v }); }); }, options: projectNameOptions }) ), React.createElement('div', { key: 'customerName', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '客户名称'), React.createElement(Select, { placeholder: '请输入或选择客户名称', allowClear: true, showSearch: true, optionFilterProp: 'label', style: filterControlStyle, value: filters.customerName, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { customerName: v }); }); }, options: customerNameOptions }) ), React.createElement('div', { key: 'deliveryRegion', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '交车区域'), React.createElement(Cascader, { options: regionOptions, placeholder: '请选择省-市', allowClear: true, style: filterControlStyle, 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) { return patchFilters(f, { deliveryRegion: s }); }); }, displayRender: function (labels) { return labels && labels.length ? labels.join(' / ') : ''; } }) ), React.createElement('div', { key: 'completedTime', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '完成交车时间'), React.createElement(RangePicker, { style: filterControlStyle, placeholder: ['请选择开始时间', '请选择结束时间'], value: dateRangeValue, onChange: onDateRangeChange }) ), React.createElement('div', { key: 'deliveryPerson', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '交车人'), React.createElement(Select, { placeholder: '请输入或选择交车人', allowClear: true, showSearch: true, optionFilterProp: 'label', style: filterControlStyle, value: filters.deliveryPerson, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { deliveryPerson: v }); }); }, options: deliveryPersonOptions }) ), React.createElement('div', { key: 'vin', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '车辆识别代码'), React.createElement(Select, { placeholder: '请输入或选择车辆识别代码', allowClear: true, showSearch: true, style: filterControlStyle, value: filters.vin, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { vin: v }); }); }, options: dynamicFilterOptions.vinOptions, filterOption: filterSelectOption }) ), React.createElement('div', { key: 'vehicleType', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '车辆类型'), React.createElement(Select, { placeholder: '请选择车辆类型', allowClear: true, showSearch: true, style: filterControlStyle, value: filters.vehicleType, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { vehicleType: v }); }); }, options: dynamicFilterOptions.vehicleTypeOptions, filterOption: filterSelectOption }) ), React.createElement('div', { key: 'brand', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '品牌'), React.createElement(Select, { placeholder: '请选择品牌', allowClear: true, showSearch: true, style: filterControlStyle, value: filters.brand, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { brand: v }); }); }, options: dynamicFilterOptions.brandOptions, filterOption: filterSelectOption }) ), React.createElement('div', { key: 'model', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '型号'), React.createElement(Select, { placeholder: '请选择或输入型号', allowClear: true, showSearch: true, style: filterControlStyle, value: filters.model, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { model: v }); }); }, options: dynamicFilterOptions.modelOptions, filterOption: filterSelectOption }) ), React.createElement('div', { key: 'businessDept', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '业务部门'), React.createElement(Select, { placeholder: '请输入或选择业务部门', allowClear: true, showSearch: true, style: filterControlStyle, value: filters.businessDept, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { businessDept: v }); }); }, options: dynamicFilterOptions.businessDeptOptions, filterOption: filterSelectOption }) ), React.createElement('div', { key: 'businessOwner', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '业务负责人'), React.createElement(Select, { placeholder: '请输入或选择业务负责人', allowClear: true, showSearch: true, style: filterControlStyle, value: filters.businessOwner, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { businessOwner: v }); }); }, options: dynamicFilterOptions.businessOwnerOptions, filterOption: filterSelectOption }) ), React.createElement('div', { key: 'taskSource', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '任务来源'), React.createElement(Select, { placeholder: '请选择任务来源', allowClear: true, style: filterControlStyle, value: filters.taskSource, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { taskSource: v }); }); }, options: taskSourceOptions }) ), React.createElement('div', { key: 'bizType', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '业务类型'), React.createElement(Select, { placeholder: '请选择业务类型', allowClear: true, style: filterControlStyle, value: filters.bizType, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { bizType: v }); }); }, options: bizTypeOptions }) ), React.createElement('div', { key: 'isDelayed', style: filterItemStyle }, React.createElement('div', { style: filterLabelStyle }, '是否延期'), React.createElement(Select, { placeholder: '请选择是否延期', allowClear: true, style: filterControlStyle, value: filters.isDelayed, onChange: function (v) { setFilters(function (f) { return patchFilters(f, { isDelayed: v }); }); }, options: isDelayedOptions }) ) ]; var filterVisibleCount = filterExpanded ? filterItems.length : 4; var filterNodes = []; var fi; for (fi = 0; fi < filterVisibleCount && fi < filterItems.length; fi++) { filterNodes.push(filterItems[fi]); } var breadcrumbItems = [ { title: '运维管理' }, { title: '车辆业务' }, { title: '交车管理' } ]; return React.createElement('div', { style: styles.page }, React.createElement('style', null, DV_KPI_STYLE), React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 } }, React.createElement(Breadcrumb, { items: breadcrumbItems }), React.createElement(Button, { type: 'default', style: { borderRadius: 8, border: '1px solid #cbd5e1', fontWeight: 600, color: '#475569' }, onClick: function () { setRequirementModalOpen(true); } }, '查看需求说明') ), React.createElement(Card, { style: { marginBottom: 16 } }, React.createElement('div', { style: styles.cardBody }, React.createElement('div', { style: styles.filterGrid }, filterNodes), React.createElement('div', { style: styles.filterActions }, React.createElement(Button, { onClick: handleReset }, '重置'), React.createElement(Button, { type: 'primary', onClick: handleQuery }, '搜索'), React.createElement(Button, { type: 'link', size: 'small', onClick: function () { setFilterExpanded(!filterExpanded); }, style: { display: 'inline-flex', alignItems: 'center', gap: 4, padding: '0 4px' } }, filterExpanded ? '收起' : '展开', React.createElement('svg', { width: 12, height: 12, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round', style: { transform: filterExpanded ? 'rotate(180deg)' : 'none', transition: 'transform 0.2s ease' } }, React.createElement('polyline', { points: '6 9 12 15 18 9' })) ) ) ) ), React.createElement(Card, null, React.createElement('div', { style: styles.cardBody }, React.createElement('div', { className: 'dv-kpi-stats-row' }, kpiCards.map(renderKpiCard)), React.createElement('div', { style: { display: 'flex', justifyContent: 'flex-end', alignItems: 'center', marginBottom: 12, flexWrap: 'wrap', gap: 12 } }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } }, React.createElement('span', { style: { fontSize: 13, color: '#64748b' } }, '当前标签:', React.createElement('span', { style: { color: '#334155', fontWeight: 600 } }, kpiExportLabelMap[kpiFilter] || '-'), ' · 导出与列表一致(含筛选,全部命中行)' ), React.createElement(Button, { onClick: handleExport }, '导出') ) ), React.createElement(Table, { columns: listColumns, dataSource: displayList, rowKey: 'id', pagination: tablePagination, tableLayout: 'fixed', scroll: { x: 1760 }, size: 'middle' }) ) ), React.createElement(Modal, { title: '交车管理 — 说明文档', open: requirementModalOpen[0], onCancel: function () { setRequirementModalOpen(false); }, footer: null, width: 880, centered: true, destroyOnClose: true }, React.createElement(Tabs, { defaultActiveKey: 'prd', size: 'small', items: requirementModalItems })), React.createElement(DeliveryEditDrawer, { open: editDrawer.open, record: editDrawer.record, mode: editDrawer.mode, onClose: closeEditDrawer, onSave: handleEditSave, onSubmit: handleEditSubmit }) ); }; 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)); } } }