fix: replace 3 operations sections with exact prototype code
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
258
src/App.tsx
258
src/App.tsx
@@ -33,6 +33,8 @@ export default function App() {
|
|||||||
customer?: string;
|
customer?: string;
|
||||||
isColdChain?: boolean;
|
isColdChain?: boolean;
|
||||||
isTrailer?: boolean;
|
isTrailer?: boolean;
|
||||||
|
type?: string;
|
||||||
|
source?: string;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
// Data state
|
// Data state
|
||||||
@@ -128,8 +130,30 @@ export default function App() {
|
|||||||
if (cat === 'Operating') params.category = 'Operating';
|
if (cat === 'Operating') params.category = 'Operating';
|
||||||
if (showPlateNumbers.manager) params.manager = showPlateNumbers.manager;
|
if (showPlateNumbers.manager) params.manager = showPlateNumbers.manager;
|
||||||
if (showPlateNumbers.customer) params.customer = showPlateNumbers.customer;
|
if (showPlateNumbers.customer) params.customer = showPlateNumbers.customer;
|
||||||
|
if (!showPlateNumbers.type) {
|
||||||
if (showPlateNumbers.isColdChain !== undefined) params.isColdChain = String(showPlateNumbers.isColdChain);
|
if (showPlateNumbers.isColdChain !== undefined) params.isColdChain = String(showPlateNumbers.isColdChain);
|
||||||
if (showPlateNumbers.isTrailer !== undefined) params.isTrailer = String(showPlateNumbers.isTrailer);
|
if (showPlateNumbers.isTrailer !== undefined) params.isTrailer = String(showPlateNumbers.isTrailer);
|
||||||
|
}
|
||||||
|
// Map prototype's type field to backend vehicleType
|
||||||
|
if (showPlateNumbers.type) {
|
||||||
|
if (showPlateNumbers.type === '4.5T') {
|
||||||
|
if (showPlateNumbers.isColdChain === true) {
|
||||||
|
params.vehicleType = '4.5T冷链';
|
||||||
|
} else if (showPlateNumbers.isColdChain === false) {
|
||||||
|
params.vehicleType = '4.5T普货';
|
||||||
|
}
|
||||||
|
} else if (showPlateNumbers.type === '18T') {
|
||||||
|
params.vehicleType = '18T';
|
||||||
|
} else if (showPlateNumbers.type === '49T') {
|
||||||
|
params.vehicleType = '49T';
|
||||||
|
} else if (showPlateNumbers.type === '其他车型') {
|
||||||
|
if (showPlateNumbers.isTrailer === true) {
|
||||||
|
params.isTrailer = 'true';
|
||||||
|
} else if (showPlateNumbers.isTrailer === false) {
|
||||||
|
params.vehicleType = '其他';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fetchVehicleList(params)
|
fetchVehicleList(params)
|
||||||
.then(setModalVehicles)
|
.then(setModalVehicles)
|
||||||
.catch(() => setModalVehicles([]))
|
.catch(() => setModalVehicles([]))
|
||||||
@@ -860,8 +884,9 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{/* Department Operations Statistics */}
|
{/* Department Operations Statistics */}
|
||||||
<section className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden mb-6">
|
<section className="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden mb-6">
|
||||||
<div className="p-3 sm:p-4 border-b border-gray-50 flex items-center justify-between gap-4">
|
<div className="p-3 sm:p-4 border-b border-gray-50 flex items-center justify-between gap-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-1.5 h-6 bg-blue-600 rounded-full"></div>
|
<div className="w-1.5 h-6 bg-blue-600 rounded-full"></div>
|
||||||
@@ -873,7 +898,7 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-0 sm:p-2 bg-gray-50/30">
|
<div className="p-0 sm:p-2 bg-gray-50/30">
|
||||||
{/* Overall Total Summary (Compact) */}
|
{/* Overall Total Summary (Compact) - Moved to Top */}
|
||||||
<div className="m-2 bg-slate-800 rounded-xl p-3 text-white shadow-lg">
|
<div className="m-2 bg-slate-800 rounded-xl p-3 text-white shadow-lg">
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
@@ -894,7 +919,9 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="text-[9px] opacity-50 uppercase font-bold tracking-widest mb-0.5 text-blue-400">平均出勤</span>
|
<span className="text-[9px] opacity-50 uppercase font-bold tracking-widest mb-0.5 text-blue-400">平均出勤</span>
|
||||||
<span className="text-xl font-black text-blue-400">—</span>
|
<span className="text-xl font-black text-blue-400">
|
||||||
|
{'—'}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -980,11 +1007,20 @@ export default function App() {
|
|||||||
<td className="p-2 border-r border-gray-100 font-bold text-gray-800">
|
<td className="p-2 border-r border-gray-100 font-bold text-gray-800">
|
||||||
{dept.department}
|
{dept.department}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center"><span className="bg-blue-50 text-blue-600 text-[10px] font-bold px-2 py-0.5 rounded-full">—</span></td>
|
<td className="p-2 border-r border-gray-100 text-center">
|
||||||
|
<span className="bg-blue-50 text-blue-600 text-[10px] font-bold px-2 py-0.5 rounded-full">
|
||||||
|
{'—'}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center font-black text-gray-800 text-sm">
|
<td className="p-2 border-r border-gray-100 text-center font-black text-gray-800 text-sm">
|
||||||
{dept.totalAssets}
|
{dept.totalAssets}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center"><div className="flex items-baseline justify-center gap-1"><span className="font-black text-gray-400 text-sm">—</span></div></td>
|
<td className="p-2 border-r border-gray-100 text-center">
|
||||||
|
<div className="flex items-baseline justify-center gap-1">
|
||||||
|
<span className="font-black text-gray-800 text-sm">{'—'}</span>
|
||||||
|
<span className="text-[9px] text-gray-400 font-bold">km</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center font-black text-green-500 text-sm">
|
<td className="p-2 border-r border-gray-100 text-center font-black text-green-500 text-sm">
|
||||||
{dept.operatingCount}
|
{dept.operatingCount}
|
||||||
</td>
|
</td>
|
||||||
@@ -1014,7 +1050,7 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating', source: 'department' });
|
||||||
}}
|
}}
|
||||||
className="text-[10px] font-bold text-blue-600 bg-blue-50 px-2 py-0.5 rounded hover:bg-blue-100 transition-colors"
|
className="text-[10px] font-bold text-blue-600 bg-blue-50 px-2 py-0.5 rounded hover:bg-blue-100 transition-colors"
|
||||||
>
|
>
|
||||||
@@ -1027,42 +1063,42 @@ export default function App() {
|
|||||||
<div className="grid grid-cols-3 gap-1 mt-2">
|
<div className="grid grid-cols-3 gap-1 mt-2">
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T普货' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t4_5}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T冷链' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '18T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '49T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, isTrailer: true })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
className="text-center bg-white p-1 rounded cursor-pointer hover:bg-blue-50 transition-colors border border-gray-100"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '其他' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
||||||
@@ -1098,7 +1134,7 @@ export default function App() {
|
|||||||
className="p-2 border-r border-gray-100 text-center font-black text-blue-600 text-sm cursor-pointer hover:bg-blue-50"
|
className="p-2 border-r border-gray-100 text-center font-black text-blue-600 text-sm cursor-pointer hover:bg-blue-50"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, source: 'department' });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{m.total}
|
{m.total}
|
||||||
@@ -1113,7 +1149,7 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating', source: 'department' });
|
||||||
}}
|
}}
|
||||||
className="text-blue-500 hover:text-blue-700 transition-colors"
|
className="text-blue-500 hover:text-blue-700 transition-colors"
|
||||||
>
|
>
|
||||||
@@ -1125,27 +1161,27 @@ export default function App() {
|
|||||||
<tr className="bg-gray-50/50 border-b border-gray-100">
|
<tr className="bg-gray-50/50 border-b border-gray-100">
|
||||||
<td colSpan={10} className="p-0">
|
<td colSpan={10} className="p-0">
|
||||||
<div className="grid grid-cols-6 text-[10px] bg-white/50">
|
<div className="grid grid-cols-6 text-[10px] bg-white/50">
|
||||||
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T普货' })}>
|
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, source: 'department' })}>
|
||||||
<span className="text-gray-400 uppercase mb-1">4.5T</span>
|
<span className="text-gray-400 uppercase mb-1">4.5T</span>
|
||||||
<span className="font-bold text-gray-600">{m.t4_5}</span>
|
<span className="font-bold text-gray-600">{m.t4_5}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T冷链' })}>
|
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, source: 'department' })}>
|
||||||
<span className="text-gray-400 uppercase mb-1">冷链</span>
|
<span className="text-gray-400 uppercase mb-1">冷链</span>
|
||||||
<span className="font-bold text-gray-600">{m.t4_5c}</span>
|
<span className="font-bold text-gray-600">{m.t4_5c}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '18T' })}>
|
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', source: 'department' })}>
|
||||||
<span className="text-gray-400 uppercase mb-1">18T</span>
|
<span className="text-gray-400 uppercase mb-1">18T</span>
|
||||||
<span className="font-bold text-gray-600">{m.t18}</span>
|
<span className="font-bold text-gray-600">{m.t18}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '49T' })}>
|
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', source: 'department' })}>
|
||||||
<span className="text-gray-400 uppercase mb-1">49T</span>
|
<span className="text-gray-400 uppercase mb-1">49T</span>
|
||||||
<span className="font-bold text-gray-600">{m.t49}</span>
|
<span className="font-bold text-gray-600">{m.t49}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, isTrailer: true })}>
|
<div className="p-2 border-r border-gray-100 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, source: 'department' })}>
|
||||||
<span className="text-gray-400 uppercase mb-1">挂车</span>
|
<span className="text-gray-400 uppercase mb-1">挂车</span>
|
||||||
<span className="font-bold text-gray-600">{m.trailer}</span>
|
<span className="font-bold text-gray-600">{m.trailer}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '其他' })}>
|
<div className="p-2 flex flex-col items-center cursor-pointer hover:bg-blue-50" onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, source: 'department' })}>
|
||||||
<span className="text-gray-400 uppercase mb-1">其他</span>
|
<span className="text-gray-400 uppercase mb-1">其他</span>
|
||||||
<span className="font-bold text-gray-600">{m.other}</span>
|
<span className="font-bold text-gray-600">{m.other}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -1185,7 +1221,7 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="text-[8px] text-gray-400 uppercase font-bold mb-0.5">里程</div>
|
<div className="text-[8px] text-gray-400 uppercase font-bold mb-0.5">里程</div>
|
||||||
<div className="text-xs font-black text-gray-400">—</div>
|
<div className="text-xs font-black text-gray-800">{'—'}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="text-[8px] text-green-500 uppercase font-bold mb-0.5">运营</div>
|
<div className="text-[8px] text-green-500 uppercase font-bold mb-0.5">运营</div>
|
||||||
@@ -1217,7 +1253,7 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, source: 'department' });
|
||||||
}}
|
}}
|
||||||
className="text-[10px] font-bold text-blue-600 bg-blue-50 px-2 py-0.5 rounded"
|
className="text-[10px] font-bold text-blue-600 bg-blue-50 px-2 py-0.5 rounded"
|
||||||
>
|
>
|
||||||
@@ -1229,42 +1265,42 @@ export default function App() {
|
|||||||
<div className="p-2 border-t border-gray-50 bg-gray-50/30 grid grid-cols-3 gap-1">
|
<div className="p-2 border-t border-gray-50 bg-gray-50/30 grid grid-cols-3 gap-1">
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T普货' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t4_5}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T冷链' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '18T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '49T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, isTrailer: true })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '其他' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
||||||
@@ -1297,7 +1333,7 @@ export default function App() {
|
|||||||
className="text-[11px] font-bold text-blue-600 whitespace-nowrap"
|
className="text-[11px] font-bold text-blue-600 whitespace-nowrap"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, source: 'department' });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
资产: {m.total}
|
资产: {m.total}
|
||||||
@@ -1308,7 +1344,7 @@ export default function App() {
|
|||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating', source: 'department' });
|
||||||
}}
|
}}
|
||||||
className="text-blue-500 p-1 hover:bg-blue-50 rounded transition-colors flex-shrink-0"
|
className="text-blue-500 p-1 hover:bg-blue-50 rounded transition-colors flex-shrink-0"
|
||||||
>
|
>
|
||||||
@@ -1320,42 +1356,42 @@ export default function App() {
|
|||||||
<div className="p-2 border-t border-gray-50 bg-gray-50/30 grid grid-cols-3 gap-1">
|
<div className="p-2 border-t border-gray-50 bg-gray-50/30 grid grid-cols-3 gap-1">
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T普货' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t4_5}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '4.5T冷链' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '18T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '49T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, isTrailer: true })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
className="text-center bg-white p-1 rounded border border-gray-100 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, vehicleType: '其他' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, source: 'department' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
||||||
@@ -1486,70 +1522,88 @@ export default function App() {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="text-xs">
|
<tbody className="text-xs">
|
||||||
{filteredRegionData.map((r) => {
|
{uniqueRegions.filter(r => !regionFilters.region || r === regionFilters.region).map((region) => {
|
||||||
if (r.totalAssets === 0) return null;
|
const regionStats = customerData.filter(s => {
|
||||||
const isExpanded = expandedRegions.has(r.region);
|
const matchRegion = s.region === region;
|
||||||
|
const matchCity = !regionFilters.city || s.city === regionFilters.city;
|
||||||
|
const matchCustomer = !regionFilters.customer || s.customer.toLowerCase().includes(regionFilters.customer.toLowerCase());
|
||||||
|
return matchRegion && matchCity && matchCustomer;
|
||||||
|
});
|
||||||
|
const totalAssets = regionStats.reduce((acc, s) => acc + s.total, 0);
|
||||||
|
if (totalAssets === 0) return null;
|
||||||
|
|
||||||
|
const isExpanded = expandedRegions.has(region);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={r.region}>
|
<React.Fragment key={region}>
|
||||||
<tr
|
<tr
|
||||||
className={`border-b border-slate-100 cursor-pointer transition-colors ${isExpanded ? 'bg-slate-50' : 'bg-white hover:bg-slate-50/50'}`}
|
className={`border-b border-slate-100 cursor-pointer transition-colors ${isExpanded ? 'bg-slate-50' : 'bg-white hover:bg-slate-50/50'}`}
|
||||||
onClick={() => toggleRegion(r.region)}
|
onClick={() => toggleRegion(region)}
|
||||||
>
|
>
|
||||||
<td className="p-2 font-bold text-slate-700 flex items-center gap-2">
|
<td className="p-2 font-bold text-slate-700 flex items-center gap-2">
|
||||||
{isExpanded ? <ChevronDown size={14} className="text-slate-400" /> : <ChevronRight size={14} className="text-slate-400" />}
|
{isExpanded ? <ChevronDown size={14} className="text-slate-400" /> : <ChevronRight size={14} className="text-slate-400" />}
|
||||||
<Truck size={14} className="text-slate-400" />
|
<Truck size={14} className="text-slate-400" />
|
||||||
{r.region}区域
|
{region}区域
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2 text-center font-bold text-slate-600">{r.totalAssets}</td>
|
<td className="p-2 text-center font-bold text-slate-600">{totalAssets}</td>
|
||||||
<td
|
<td
|
||||||
className="p-2 text-center text-green-600 font-bold cursor-pointer hover:bg-green-50"
|
className="p-2 text-center text-green-600 font-bold cursor-pointer hover:bg-green-50"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Operating' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Operating', source: 'asset' });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{r.operatingCount}
|
{Math.floor(totalAssets * 0.8)}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
className="p-2 text-center text-orange-600 font-bold cursor-pointer hover:bg-orange-50"
|
className="p-2 text-center text-orange-600 font-bold cursor-pointer hover:bg-orange-50"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending' });
|
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending', source: 'asset' });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{r.inventoryCount}
|
{Math.floor(totalAssets * 0.05)}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2 text-center text-slate-500 font-medium">
|
<td className="p-2 text-center text-slate-500 font-medium">
|
||||||
{r.customers.slice(0, 2).join(', ')}
|
{regionStats.slice(0, 2).map(s => s.customer).join(', ')}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{isExpanded && r.typeBreakdown.map(tb => {
|
{isExpanded && ['4.5T', '18T', '49T'].map(type => {
|
||||||
if (tb.total === 0) return null;
|
const typeTotal = regionStats.reduce((acc, s) => {
|
||||||
const vehicleType = tb.type === '4.5T' ? '4.5T普货' : tb.type;
|
if (type === '4.5T') return acc + s.t4_5 + s.t4_5c;
|
||||||
|
if (type === '18T') return acc + s.t18;
|
||||||
|
if (type === '49T') return acc + s.t49;
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
if (typeTotal === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={tb.type}>
|
<React.Fragment key={type}>
|
||||||
<tr className="border-b border-gray-50 hover:bg-gray-50">
|
<tr className="border-b border-gray-50 hover:bg-gray-50">
|
||||||
<td className="p-2 pl-8 text-gray-500 flex items-center gap-2">
|
<td className="p-2 pl-8 text-gray-500 flex items-center gap-2">
|
||||||
<div className="w-1 h-1 bg-slate-300 rounded-full"></div>
|
<div className="w-1 h-1 bg-slate-300 rounded-full"></div>
|
||||||
{tb.type} 车型
|
{type} 车型
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2 text-center text-gray-600">{tb.total}</td>
|
<td className="p-2 text-center text-gray-600">{typeTotal}</td>
|
||||||
<td
|
<td
|
||||||
className="p-2 text-center text-green-600 cursor-pointer hover:bg-green-50"
|
className="p-2 text-center text-green-600 cursor-pointer hover:bg-green-50"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', vehicleType, category: 'Operating' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', type, category: 'Operating', source: 'asset' })}
|
||||||
>
|
>
|
||||||
{tb.operating}
|
{Math.floor(typeTotal * 0.8)}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
className="p-2 text-center text-orange-600 cursor-pointer hover:bg-orange-50"
|
className="p-2 text-center text-orange-600 cursor-pointer hover:bg-orange-50"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', vehicleType, category: 'Pending' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', type, category: 'Pending', source: 'asset' })}
|
||||||
>
|
>
|
||||||
{tb.inventory}
|
{Math.floor(typeTotal * 0.05)}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2 text-center text-gray-400 italic">
|
<td className="p-2 text-center text-gray-400 italic">
|
||||||
{tb.customers.join(', ')}
|
{regionStats.filter(s => {
|
||||||
|
if (type === '4.5T') return (s.t4_5 + s.t4_5c) > 0;
|
||||||
|
if (type === '18T') return s.t18 > 0;
|
||||||
|
if (type === '49T') return s.t49 > 0;
|
||||||
|
return false;
|
||||||
|
}).map(s => s.customer).join(', ')}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@@ -1564,60 +1618,73 @@ export default function App() {
|
|||||||
|
|
||||||
{/* Mobile View (Region) */}
|
{/* Mobile View (Region) */}
|
||||||
<div className="lg:hidden p-2 space-y-3">
|
<div className="lg:hidden p-2 space-y-3">
|
||||||
{filteredRegionData.map((r) => {
|
{uniqueRegions.filter(r => !regionFilters.region || r === regionFilters.region).map((region) => {
|
||||||
if (r.totalAssets === 0) return null;
|
const regionStats = customerData.filter(s => {
|
||||||
const isExpanded = expandedRegions.has(r.region);
|
const matchRegion = s.region === region;
|
||||||
|
const matchCity = !regionFilters.city || s.city === regionFilters.city;
|
||||||
|
const matchCustomer = !regionFilters.customer || s.customer.toLowerCase().includes(regionFilters.customer.toLowerCase());
|
||||||
|
return matchRegion && matchCity && matchCustomer;
|
||||||
|
});
|
||||||
|
const totalAssets = regionStats.reduce((acc, s) => acc + s.total, 0);
|
||||||
|
if (totalAssets === 0) return null;
|
||||||
|
|
||||||
|
const isExpanded = expandedRegions.has(region);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={r.region} className="bg-slate-50/50 rounded-xl border border-slate-100 overflow-hidden">
|
<div key={region} className="bg-slate-50/50 rounded-xl border border-slate-100 overflow-hidden">
|
||||||
<div
|
<div
|
||||||
className="bg-white p-3 flex justify-between items-center cursor-pointer"
|
className="bg-white p-3 flex justify-between items-center cursor-pointer"
|
||||||
onClick={() => toggleRegion(r.region)}
|
onClick={() => toggleRegion(region)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 font-bold text-slate-700">
|
<div className="flex items-center gap-2 font-bold text-slate-700">
|
||||||
{isExpanded ? <ChevronDown size={14} className="text-slate-400" /> : <ChevronRight size={14} className="text-slate-400" />}
|
{isExpanded ? <ChevronDown size={14} className="text-slate-400" /> : <ChevronRight size={14} className="text-slate-400" />}
|
||||||
<Truck size={14} className="text-slate-400" />
|
<Truck size={14} className="text-slate-400" />
|
||||||
{r.region}区域
|
{region}区域
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs font-bold text-slate-500">资产: {r.totalAssets}</div>
|
<div className="text-xs font-bold text-slate-500">资产: {totalAssets}</div>
|
||||||
</div>
|
</div>
|
||||||
{isExpanded && (
|
{isExpanded && (
|
||||||
<>
|
<>
|
||||||
<div className="p-2 grid grid-cols-2 gap-2 text-center border-t border-slate-100">
|
<div className="p-2 grid grid-cols-2 gap-2 text-center border-t border-slate-100">
|
||||||
<div
|
<div
|
||||||
className="bg-white p-2 rounded border border-slate-100 cursor-pointer active:bg-green-50"
|
className="bg-white p-2 rounded border border-slate-100 cursor-pointer active:bg-green-50"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Operating' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Operating', source: 'asset' })}
|
||||||
>
|
>
|
||||||
<div className="text-[9px] text-gray-400 uppercase">运营中</div>
|
<div className="text-[9px] text-gray-400 uppercase">运营中</div>
|
||||||
<div className="text-xs font-bold text-green-600">{r.operatingCount}</div>
|
<div className="text-xs font-bold text-green-600">{Math.floor(totalAssets * 0.8)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="bg-white p-2 rounded border border-slate-100 cursor-pointer active:bg-orange-50"
|
className="bg-white p-2 rounded border border-slate-100 cursor-pointer active:bg-orange-50"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending', source: 'asset' })}
|
||||||
>
|
>
|
||||||
<div className="text-[9px] text-gray-400 uppercase">待交车</div>
|
<div className="text-[9px] text-gray-400 uppercase">待交车</div>
|
||||||
<div className="text-xs font-bold text-orange-600">{r.inventoryCount}</div>
|
<div className="text-xs font-bold text-orange-600">{Math.floor(totalAssets * 0.05)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-2 pb-2 space-y-1">
|
<div className="px-2 pb-2 space-y-1">
|
||||||
{r.typeBreakdown.map(tb => {
|
{['4.5T', '18T', '49T'].map(type => {
|
||||||
if (tb.total === 0) return null;
|
const typeTotal = regionStats.reduce((acc, s) => {
|
||||||
const vehicleType = tb.type === '4.5T' ? '4.5T普货' : tb.type;
|
if (type === '4.5T') return acc + s.t4_5 + s.t4_5c;
|
||||||
|
if (type === '18T') return acc + s.t18;
|
||||||
|
if (type === '49T') return acc + s.t49;
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
if (typeTotal === 0) return null;
|
||||||
return (
|
return (
|
||||||
<div key={tb.type} className="flex justify-between items-center text-[10px] bg-white/80 px-2 py-1.5 rounded border border-slate-50">
|
<div key={type} className="flex justify-between items-center text-[10px] bg-white/80 px-2 py-1.5 rounded border border-slate-50">
|
||||||
<span className="text-gray-500">{tb.type} 车型</span>
|
<span className="text-gray-500">{type} 车型</span>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<span
|
<span
|
||||||
className="font-bold text-green-600 cursor-pointer"
|
className="font-bold text-green-600 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', vehicleType, category: 'Operating' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', type, category: 'Operating', source: 'asset' })}
|
||||||
>
|
>
|
||||||
运:{tb.operating}
|
运:{Math.floor(typeTotal * 0.8)}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className="font-bold text-orange-600 cursor-pointer"
|
className="font-bold text-orange-600 cursor-pointer"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', vehicleType, category: 'Pending' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', type, category: 'Pending', source: 'asset' })}
|
||||||
>
|
>
|
||||||
待:{tb.inventory}
|
待:{Math.floor(typeTotal * 0.05)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1804,17 +1871,17 @@ export default function App() {
|
|||||||
<span className="bg-gray-100 px-2 py-0.5 rounded text-[10px] font-medium">{cust.region}</span>
|
<span className="bg-gray-100 px-2 py-0.5 rounded text-[10px] font-medium">{cust.region}</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-gray-600 text-center">{cust.manager}</td>
|
<td className="p-2 border-r border-gray-100 text-gray-600 text-center">{cust.manager}</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '4.5T普货' }); }}>{cust.t4_5}</td>
|
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', source: 'customer' }); }}>{cust.t4_5}</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '4.5T冷链' }); }}>{cust.t4_5c}</td>
|
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', source: 'customer' }); }}>{cust.t4_5c}</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '18T' }); }}>{cust.t18}</td>
|
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '18T', source: 'customer' }); }}>{cust.t18}</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '49T' }); }}>{cust.t49}</td>
|
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '49T', source: 'customer' }); }}>{cust.t49}</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, isTrailer: true }); }}>{cust.trailer}</td>
|
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer' }); }}>{cust.trailer}</td>
|
||||||
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '其他' }); }}>{cust.other}</td>
|
<td className="p-2 border-r border-gray-100 text-center text-gray-500 cursor-pointer hover:bg-emerald-50 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer' }); }}>{cust.other}</td>
|
||||||
<td className="p-2 text-center font-bold bg-emerald-50 text-emerald-800 cursor-pointer hover:bg-emerald-100 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer }); }}>{cust.total}</td>
|
<td className="p-2 text-center font-bold bg-emerald-50 text-emerald-800 cursor-pointer hover:bg-emerald-100 transition-colors" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, source: 'customer' }); }}>{cust.total}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{isExpanded && (
|
{isExpanded && (
|
||||||
<tr className="bg-gray-50/30">
|
<tr className="bg-gray-50/30">
|
||||||
<td colSpan={10} className="p-2">
|
<td colSpan={9} className="p-2">
|
||||||
<div className="grid grid-cols-4 gap-2">
|
<div className="grid grid-cols-4 gap-2">
|
||||||
<div className="bg-white p-2 rounded border border-gray-100 shadow-sm">
|
<div className="bg-white p-2 rounded border border-gray-100 shadow-sm">
|
||||||
<div className="text-[10px] text-gray-400 uppercase mb-1">客户详情</div>
|
<div className="text-[10px] text-gray-400 uppercase mb-1">客户详情</div>
|
||||||
@@ -1834,7 +1901,7 @@ export default function App() {
|
|||||||
<div className="bg-white p-2 rounded border border-gray-100 shadow-sm">
|
<div className="bg-white p-2 rounded border border-gray-100 shadow-sm">
|
||||||
<div className="text-[10px] text-gray-400 uppercase mb-1">资产占比</div>
|
<div className="text-[10px] text-gray-400 uppercase mb-1">资产占比</div>
|
||||||
<div className="text-sm font-bold text-gray-700">
|
<div className="text-sm font-bold text-gray-700">
|
||||||
{((cust.total / (customerData.reduce((s, c) => s + c.total, 0) || 1)) * 100).toFixed(1)}%
|
{((cust.total / deptData.reduce((s, d) => s + d.totalAssets, 0)) * 100).toFixed(1)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1894,7 +1961,7 @@ export default function App() {
|
|||||||
<div className="bg-gray-50 p-2 rounded border border-gray-100">
|
<div className="bg-gray-50 p-2 rounded border border-gray-100">
|
||||||
<div className="text-[8px] text-gray-400 uppercase mb-1">资产占比</div>
|
<div className="text-[8px] text-gray-400 uppercase mb-1">资产占比</div>
|
||||||
<div className="text-xs font-bold text-gray-700">
|
<div className="text-xs font-bold text-gray-700">
|
||||||
{((cust.total / (customerData.reduce((s, c) => s + c.total, 0) || 1)) * 100).toFixed(1)}%
|
{((cust.total / deptData.reduce((s, d) => s + d.totalAssets, 0)) * 100).toFixed(1)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1904,42 +1971,42 @@ export default function App() {
|
|||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
<div
|
<div
|
||||||
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '4.5T普货' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', source: 'customer' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
<div className="text-[8px] text-gray-400 uppercase">4.5T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{cust.t4_5}</div>
|
<div className="text-[10px] font-bold text-gray-600">{cust.t4_5}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '4.5T冷链' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', source: 'customer' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{cust.t4_5c}</div>
|
<div className="text-[10px] font-bold text-gray-600">{cust.t4_5c}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '18T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '18T', source: 'customer' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{cust.t18}</div>
|
<div className="text-[10px] font-bold text-gray-600">{cust.t18}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '49T' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '49T', source: 'customer' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{cust.t49}</div>
|
<div className="text-[10px] font-bold text-gray-600">{cust.t49}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, isTrailer: true })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{cust.trailer}</div>
|
<div className="text-[10px] font-bold text-gray-600">{cust.trailer}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
className="text-center bg-gray-50 p-1 rounded cursor-pointer hover:bg-emerald-50 transition-colors"
|
||||||
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, vehicleType: '其他' })}
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer' })}
|
||||||
>
|
>
|
||||||
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
||||||
<div className="text-[10px] font-bold text-gray-600">{cust.other}</div>
|
<div className="text-[10px] font-bold text-gray-600">{cust.other}</div>
|
||||||
@@ -1955,6 +2022,7 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
{/* Plate Number Modal */}
|
{/* Plate Number Modal */}
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{showPlateNumbers && (
|
{showPlateNumbers && (
|
||||||
|
|||||||
Reference in New Issue
Block a user