// 【重要】必须使用 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)
'
+ '
'
+ '
本页为原型预览占位,联调后将展示 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));
}
}
}