fix: replace modal with prototype version, extend /list API fields
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
291
src/App.tsx
291
src/App.tsx
@@ -309,109 +309,84 @@ export default function App() {
|
||||
</div>
|
||||
|
||||
{/* Header Summary - Ultra Compact */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-2 mb-6">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-2 mb-6">
|
||||
{/* Total Assets */}
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2 min-w-0">
|
||||
<div className="w-7 h-7 rounded bg-gray-50 flex-shrink-0 flex items-center justify-center text-gray-400 hidden sm:flex">
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2">
|
||||
<div className="w-7 h-7 rounded bg-gray-50 flex items-center justify-center text-gray-400">
|
||||
<Truck size={14} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-[9px] text-gray-400 font-medium uppercase leading-none mb-0.5 whitespace-nowrap">资产总数</div>
|
||||
<div>
|
||||
<div className="text-[9px] text-gray-400 font-medium uppercase leading-none mb-0.5">资产总数</div>
|
||||
<div className="text-base font-bold text-gray-800 leading-none">{SUMMARY.totalAssets.toLocaleString()}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Operating */}
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2 min-w-0">
|
||||
<div className="w-7 h-7 rounded bg-blue-50 flex-shrink-0 flex items-center justify-center text-blue-500 hidden sm:flex">
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2">
|
||||
<div className="w-7 h-7 rounded bg-blue-50 flex items-center justify-center text-blue-500">
|
||||
<Activity size={14} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-[9px] text-gray-400 font-medium uppercase leading-none mb-0.5 whitespace-nowrap">总运营</div>
|
||||
<div className="text-base font-bold text-blue-600 leading-none">{SUMMARY.operating.total}</div>
|
||||
<div className="text-[8px] text-gray-400 leading-none mt-0.5 whitespace-nowrap">
|
||||
自营{SUMMARY.operating.self} 租赁{SUMMARY.operating.leased}
|
||||
<div>
|
||||
<div className="text-[9px] text-gray-400 font-medium uppercase leading-none mb-0.5">总运营</div>
|
||||
<div className="flex items-baseline gap-1">
|
||||
<span className="text-base font-bold text-blue-600 leading-none">{SUMMARY.operating.total}</span>
|
||||
<span className="text-[8px] text-gray-400 leading-none">自{SUMMARY.operating.self} 租{SUMMARY.operating.leased}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Inventory */}
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2 min-w-0">
|
||||
<div className="w-7 h-7 rounded bg-gray-50 flex-shrink-0 flex items-center justify-center text-gray-500 hidden sm:flex">
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2">
|
||||
<div className="w-7 h-7 rounded bg-gray-50 flex items-center justify-center text-gray-500">
|
||||
<Warehouse size={14} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-[9px] text-gray-400 font-medium uppercase leading-none mb-0.5 whitespace-nowrap">总库存</div>
|
||||
<div className="text-base font-bold text-gray-800 leading-none">{SUMMARY.inventory.total}</div>
|
||||
<div className="text-[8px] text-gray-400 leading-none mt-0.5 whitespace-nowrap">
|
||||
库存{SUMMARY.inventory.inStock} 异动{SUMMARY.inventory.abnormal}
|
||||
<div>
|
||||
<div className="text-[9px] text-gray-400 font-medium uppercase leading-none mb-0.5">总库存</div>
|
||||
<div className="flex items-baseline gap-1">
|
||||
<span className="text-base font-bold text-gray-800 leading-none">{SUMMARY.inventory.total}</span>
|
||||
<span className="text-[8px] text-gray-400 leading-none">库{SUMMARY.inventory.inStock} 异{SUMMARY.inventory.abnormal}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pending */}
|
||||
<div
|
||||
className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2 min-w-0 cursor-pointer hover:bg-blue-50 transition-colors"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending' })}
|
||||
>
|
||||
<div className="w-7 h-7 rounded bg-blue-50 flex-shrink-0 flex items-center justify-center text-blue-500 hidden sm:flex">
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2 cursor-pointer hover:bg-blue-50 transition-colors"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending' })}>
|
||||
<div className="w-7 h-7 rounded bg-blue-50 flex items-center justify-center text-blue-500">
|
||||
<PlusCircle size={14} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-[9px] text-blue-500 font-bold uppercase leading-none mb-0.5 whitespace-nowrap">待交车</div>
|
||||
<div>
|
||||
<div className="text-[9px] text-blue-500 font-bold uppercase leading-none mb-0.5">待交车</div>
|
||||
<div className="text-base font-bold text-blue-600 leading-none">{SUMMARY.pendingDelivery}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* New */}
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2 min-w-0">
|
||||
<div className="w-7 h-7 rounded bg-green-50 flex-shrink-0 flex items-center justify-center text-green-500 hidden sm:flex">
|
||||
<PlusCircle size={14} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-[9px] text-green-500 font-bold uppercase leading-none mb-0.5 whitespace-nowrap">本周新增</div>
|
||||
<div className="text-base font-bold text-green-600 leading-none">{SUMMARY.weeklyNew}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Removed */}
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm flex items-center gap-2 min-w-0">
|
||||
<div className="w-7 h-7 rounded bg-red-50 flex-shrink-0 flex items-center justify-center text-red-500 hidden sm:flex">
|
||||
<MinusCircle size={14} />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-[9px] text-red-500 font-bold uppercase leading-none mb-0.5 whitespace-nowrap">本周移除</div>
|
||||
<div className="text-base font-bold text-red-600 leading-none">{SUMMARY.weeklyRemoved}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dynamics */}
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm col-span-2 md:col-span-1">
|
||||
<div className="bg-white p-2 rounded-sm border border-gray-100 shadow-sm col-span-2">
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<div className="text-[9px] text-gray-400 font-bold uppercase tracking-tight">本周动态</div>
|
||||
<div className="text-[7px] text-gray-300 font-normal italic">上周六-本周五</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-center gap-1">
|
||||
<div
|
||||
className="flex-1 flex flex-col items-center cursor-pointer hover:bg-blue-50 py-1 rounded transition-all group"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Delivered' })}
|
||||
>
|
||||
<div className="flex-1 flex flex-col items-center cursor-pointer hover:bg-green-50 py-1 rounded transition-all group">
|
||||
<span className="text-xs font-bold text-gray-800 group-hover:text-green-600">{SUMMARY.weeklyNew}</span>
|
||||
<span className="text-[8px] text-green-500/80 font-bold mt-0.5">新增</span>
|
||||
</div>
|
||||
<div className="w-[1px] h-3 bg-gray-100"></div>
|
||||
<div className="flex-1 flex flex-col items-center cursor-pointer hover:bg-blue-50 py-1 rounded transition-all group"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Delivered' })}>
|
||||
<span className="text-xs font-bold text-gray-800 group-hover:text-blue-600">{SUMMARY.weeklyDelivered}</span>
|
||||
<span className="text-[8px] text-blue-500/80 font-bold mt-0.5">交车</span>
|
||||
</div>
|
||||
<div className="w-[1px] h-3 bg-gray-100"></div>
|
||||
<div
|
||||
className="flex-1 flex flex-col items-center cursor-pointer hover:bg-orange-50 py-1 rounded transition-all group"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Returned' })}
|
||||
>
|
||||
<div className="flex-1 flex flex-col items-center cursor-pointer hover:bg-orange-50 py-1 rounded transition-all group"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Returned' })}>
|
||||
<span className="text-xs font-bold text-gray-800 group-hover:text-orange-600">{SUMMARY.weeklyReturned}</span>
|
||||
<span className="text-[8px] text-orange-500/80 font-bold mt-0.5">还车</span>
|
||||
</div>
|
||||
<div className="w-[1px] h-3 bg-gray-100"></div>
|
||||
<div
|
||||
className="flex-1 flex flex-col items-center cursor-pointer hover:bg-purple-50 py-1 rounded transition-all group"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Replaced' })}
|
||||
>
|
||||
<div className="flex-1 flex flex-col items-center cursor-pointer hover:bg-purple-50 py-1 rounded transition-all group"
|
||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Replaced' })}>
|
||||
<span className="text-xs font-bold text-gray-800 group-hover:text-purple-600">{SUMMARY.weeklyReplaced}</span>
|
||||
<span className="text-[8px] text-purple-500/80 font-bold mt-0.5">替换</span>
|
||||
</div>
|
||||
@@ -2023,85 +1998,161 @@ export default function App() {
|
||||
</section>
|
||||
|
||||
|
||||
{/* Plate Number Modal */}
|
||||
{/* Vehicle Detail Modal */}
|
||||
<AnimatePresence>
|
||||
{showPlateNumbers && (
|
||||
<div className="fixed inset-0 bg-black/20 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||||
<div className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||||
<motion.div
|
||||
initial={{ scale: 0.9, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
className="bg-white rounded-lg shadow-xl w-full max-w-md overflow-hidden"
|
||||
initial={{ scale: 0.9, opacity: 0, y: 20 }}
|
||||
animate={{ scale: 1, opacity: 1, y: 0 }}
|
||||
className={`bg-white rounded-xl shadow-2xl w-full max-w-[95vw] ${showPlateNumbers.source === 'customer' ? 'lg:max-w-6xl' : 'lg:max-w-4xl'} overflow-hidden flex flex-col max-h-[85vh] sm:max-h-[90vh] min-h-[40vh]`}
|
||||
>
|
||||
<div className="p-4 border-b border-gray-100 flex justify-between items-center bg-blue-600 text-white">
|
||||
<div className="p-4 border-b border-gray-100 flex justify-between items-center bg-slate-800 text-white shrink-0">
|
||||
<div>
|
||||
<h3 className="font-bold text-sm">
|
||||
{showPlateNumbers.vehicleType || (showPlateNumbers.model !== 'All' ? showPlateNumbers.model : '全量')} - 车牌明细
|
||||
<h3 className="font-bold text-base flex items-center gap-2">
|
||||
<Truck size={18} className="text-blue-400" />
|
||||
{showPlateNumbers.manager ? `${showPlateNumbers.manager} 的${showPlateNumbers.type || ''}车辆` :
|
||||
showPlateNumbers.customer ? `${showPlateNumbers.customer} 的${showPlateNumbers.type || ''}车辆` :
|
||||
showPlateNumbers.batch === 'All' ? '全量批次' : `${showPlateNumbers.batch} 批次`} - 运营明细
|
||||
</h3>
|
||||
<p className="text-[10px] opacity-80">
|
||||
{showPlateNumbers.vehicleType ? (showPlateNumbers.model === 'All' ? '全量型号' : showPlateNumbers.model) : (showPlateNumbers.batch === 'All' ? '' : showPlateNumbers.batch)} |{' '}
|
||||
{!showPlateNumbers.category
|
||||
? '全部车辆'
|
||||
: showPlateNumbers.category === 'Inventory'
|
||||
? (showPlateNumbers.location === 'All' ? '库存' : `${showPlateNumbers.location}库存`)
|
||||
: showPlateNumbers.category === 'Operating'
|
||||
? '在运营'
|
||||
: showPlateNumbers.category === 'Pending'
|
||||
? '待交车'
|
||||
: showPlateNumbers.category === 'Delivered'
|
||||
? '本周已交车'
|
||||
: showPlateNumbers.category === 'Returned'
|
||||
? '已还车'
|
||||
: '已替换'}
|
||||
<p className="text-[10px] opacity-60 mt-0.5">
|
||||
{showPlateNumbers.model === 'All' ? '全量型号' : showPlateNumbers.model} |
|
||||
{showPlateNumbers.category === 'Pending' ? '待交车' :
|
||||
showPlateNumbers.category === 'Delivered' ? '本周已交车' :
|
||||
showPlateNumbers.category === 'Returned' ? '已还车' :
|
||||
showPlateNumbers.category === 'Replaced' ? '已替换' :
|
||||
showPlateNumbers.category === 'Inventory' ? `${showPlateNumbers.location}库存` :
|
||||
showPlateNumbers.category === 'Operating' ? '正在运营' : '全部状态'}
|
||||
</p>
|
||||
</div>
|
||||
<button onClick={() => setShowPlateNumbers(null)} className="hover:bg-white/20 p-1 rounded">
|
||||
<PlusCircle className="rotate-45" size={20} />
|
||||
<button onClick={() => setShowPlateNumbers(null)} className="hover:bg-white/10 p-2 rounded-full transition-colors">
|
||||
<PlusCircle className="rotate-45" size={24} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-4 max-h-[400px] overflow-y-auto">
|
||||
|
||||
<div className="flex-1 overflow-auto p-0 sm:p-4 bg-gray-50 min-h-0 overscroll-contain">
|
||||
{modalLoading ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Loader2 className="animate-spin text-blue-500" size={24} />
|
||||
<div className="flex items-center justify-center py-16">
|
||||
<Loader2 className="animate-spin text-blue-500" size={32} />
|
||||
</div>
|
||||
) : modalWeeklyDetail.length > 0 ? (
|
||||
<div className="space-y-1.5">
|
||||
{modalWeeklyDetail.map((v, i) => (
|
||||
<div key={`${v.truck_id}-${i}`} className="flex items-center justify-between bg-gray-50 px-3 py-2 rounded border border-gray-100">
|
||||
<span className="font-mono text-[11px] sm:text-xs font-bold text-gray-700">{v.plate_number}</span>
|
||||
<div className="flex items-center gap-2 text-[10px] text-gray-400">
|
||||
{v.customer_name && <span>{v.customer_name}</span>}
|
||||
{v.handover_date && <span>{v.handover_date}</span>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : modalVehicles.length > 0 ? (
|
||||
<div className="space-y-1.5">
|
||||
{modalVehicles.map((v) => (
|
||||
<div
|
||||
key={v.id}
|
||||
className="flex items-center justify-between bg-gray-50 px-3 py-2 rounded border border-gray-100"
|
||||
>
|
||||
<span className="font-mono text-[11px] sm:text-xs font-bold text-gray-700">{v.plateNumber}</span>
|
||||
{(v.province || v.city) && (
|
||||
<span className="text-[10px] text-gray-400 ml-2 shrink-0">
|
||||
{[v.province, v.city].filter(Boolean).join(' ')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden w-full">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-slate-700 text-white text-[10px] uppercase tracking-wider">
|
||||
<th className="p-2 font-semibold border-r border-slate-600 text-center">车牌</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 text-center">客户名称</th>
|
||||
<th className="p-2 font-semibold text-center">日期</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-[11px]">
|
||||
{modalWeeklyDetail.map((v, i) => (
|
||||
<tr key={`${v.truck_id}-${i}`} className={`border-b border-gray-100 hover:bg-blue-50/50 transition-colors ${i % 2 === 0 ? 'bg-white' : 'bg-gray-50/30'}`}>
|
||||
<td className="p-2 border-r border-gray-100 font-mono font-bold text-blue-700 text-center">{v.plate_number}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600 text-center">{v.customer_name || '—'}</td>
|
||||
<td className="p-2 text-gray-500 text-center">{v.handover_date || '—'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-8 text-gray-400 text-sm">暂无数据</div>
|
||||
<div className="bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden w-full">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-slate-700 text-white text-[10px] uppercase tracking-wider">
|
||||
{showPlateNumbers.source === 'customer' ? (
|
||||
<>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 sticky left-0 bg-slate-700 z-10 w-10 text-center">月</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-24">业务部门</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-24">业务负责人</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-16">品牌</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-16">车型</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-48">资产归属</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-48">客户名称</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-24">车牌</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-16 text-center">状态</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-24 text-center">提车时间</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-24 text-center">合同到期时间</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-24">运营区域</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 w-20 text-center">离到期</th>
|
||||
<th className="p-2 font-semibold w-48">签约公司</th>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 text-center">车牌</th>
|
||||
{showPlateNumbers.source !== 'asset' && (
|
||||
<th className="p-2 font-semibold border-r border-slate-600 text-center">客户名称</th>
|
||||
)}
|
||||
<th className="p-2 font-semibold border-r border-slate-600 text-center">品牌</th>
|
||||
<th className="p-2 font-semibold border-r border-slate-600 text-center">车型</th>
|
||||
<th className="p-2 font-semibold text-center">所在地</th>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-[11px]">
|
||||
{modalVehicles.map((v, idx) => (
|
||||
<tr key={v.id} className={`border-b border-gray-100 hover:bg-blue-50/50 transition-colors ${idx % 2 === 0 ? 'bg-white' : 'bg-gray-50/30'}`}>
|
||||
{showPlateNumbers.source === 'customer' ? (
|
||||
<>
|
||||
<td className="p-2 border-r border-gray-100 text-center sticky left-0 bg-inherit z-10 font-bold text-gray-400">{'—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600">{v.departmentName || '—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 font-medium text-gray-700">{v.customerManager || '—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600">{v.brandLabel || '—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600">{v.type}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-500 text-[10px] leading-tight">{v.subjectOrg || '—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 font-bold text-gray-800">{v.customerName || '—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 font-mono font-bold text-blue-700">{v.plateNumber}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center">
|
||||
<span className={`px-1.5 py-0.5 rounded-full text-[9px] font-bold ${
|
||||
v.status === 'Operating' ? 'bg-green-100 text-green-700' :
|
||||
v.status === 'Inventory' ? 'bg-blue-100 text-blue-700' : 'bg-red-100 text-red-700'
|
||||
}`}>
|
||||
{v.status === 'Operating' ? '在租' : v.status === 'Inventory' ? '库存' : '异常'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500">{'—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500">{'—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600">{v.location}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center font-bold text-orange-600">{'—'}</td>
|
||||
<td className="p-2 text-gray-500 text-[10px] leading-tight">{v.orgName || '—'}</td>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<td className="p-2 border-r border-gray-100 font-mono font-bold text-blue-700 text-center">{v.plateNumber}</td>
|
||||
{showPlateNumbers.source !== 'asset' && (
|
||||
<td className="p-2 border-r border-gray-100 font-bold text-gray-800 text-center">{v.customerName || '—'}</td>
|
||||
)}
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600 text-center">{v.brandLabel || '—'}</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600 text-center">{v.type}</td>
|
||||
<td className="p-2 text-gray-600 text-center">{v.location}</td>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
{modalVehicles.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={showPlateNumbers.source === 'customer' ? 14 : (showPlateNumbers.source === 'asset' ? 4 : 5)} className="p-8 text-center text-gray-400 italic">
|
||||
暂无符合条件的车辆数据
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-3 bg-gray-50 border-t border-gray-100 flex justify-between items-center">
|
||||
<span className="text-[10px] text-gray-400">共 {modalWeeklyDetail.length > 0 ? modalWeeklyDetail.length : modalVehicles.length} 辆</span>
|
||||
|
||||
<div className="p-4 bg-white border-t border-gray-100 flex justify-between items-center shrink-0">
|
||||
<div className="text-xs text-gray-500">
|
||||
共计 <span className="font-bold text-blue-600">{modalWeeklyDetail.length > 0 ? modalWeeklyDetail.length : modalVehicles.length}</span> 台车辆
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowPlateNumbers(null)}
|
||||
className="px-4 py-1.5 bg-white border border-gray-200 rounded text-xs font-medium hover:bg-gray-100"
|
||||
className="px-6 py-2 bg-slate-800 text-white rounded-lg text-xs font-bold hover:bg-slate-700 transition-colors shadow-sm"
|
||||
>
|
||||
关闭
|
||||
确认并关闭
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -642,7 +642,7 @@ app.get('/inventory-analysis', async (c) => {
|
||||
// GET /api/vehicles/dept-stats — department & manager breakdown
|
||||
app.get('/dept-stats', async (c) => {
|
||||
const vehicles = await getVehicles();
|
||||
const withManager = vehicles.filter((v) => v.customerManager);
|
||||
const withManager = vehicles.filter((v) => v.customerManager && v.status === 'Operating');
|
||||
|
||||
const deptMap = new Map<string, Map<string, Vehicle[]>>();
|
||||
for (const v of withManager) {
|
||||
@@ -805,6 +805,10 @@ app.get('/list', async (c) => {
|
||||
contractNo: v.contractNo,
|
||||
customerName: v.customerName,
|
||||
subjectOrg: v.subjectOrg,
|
||||
departmentName: v.departmentName,
|
||||
customerManager: v.customerManager,
|
||||
brandLabel: v.brandLabel,
|
||||
orgName: v.orgName,
|
||||
})),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -108,6 +108,10 @@ export interface VehicleListItem {
|
||||
contractNo: string | null;
|
||||
customerName: string | null;
|
||||
subjectOrg: string | null;
|
||||
departmentName: string | null;
|
||||
customerManager: string | null;
|
||||
brandLabel: string | null;
|
||||
orgName: string | null;
|
||||
}
|
||||
|
||||
export interface ManagerStats {
|
||||
|
||||
Reference in New Issue
Block a user