feat: add department operations statistics section
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
496
src/App.tsx
496
src/App.tsx
@@ -860,6 +860,502 @@ export default function App() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Department Operations Statistics */}
|
||||
<section className="bg-white rounded-sm border border-gray-100 shadow-sm 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="flex items-center gap-3">
|
||||
<div className="w-1.5 h-6 bg-blue-600 rounded-full"></div>
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-gray-800">部门运营统计</h2>
|
||||
<p className="text-[10px] text-gray-400 font-medium">实时更新部门运营核心指标</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-0 sm:p-2 bg-gray-50/30">
|
||||
{/* Overall Total Summary (Compact) */}
|
||||
<div className="m-2 bg-slate-800 rounded-xl p-3 text-white shadow-lg">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="flex flex-col">
|
||||
<span className="text-[9px] opacity-50 uppercase font-bold tracking-widest mb-0.5">总资产</span>
|
||||
<span className="text-xl font-black">{deptData.reduce((s, d) => s + d.totalAssets, 0)}</span>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-[9px] opacity-50 uppercase font-bold tracking-widest mb-0.5 text-green-400">运营中</span>
|
||||
<span className="text-xl font-black text-green-400">
|
||||
{deptData.reduce((acc, d) => acc + d.operatingCount, 0)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-[9px] opacity-50 uppercase font-bold tracking-widest mb-0.5 text-slate-400">闲置中</span>
|
||||
<span className="text-xl font-black text-slate-400">
|
||||
{deptData.reduce((acc, d) => acc + d.idleCount, 0)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Controls Row: Toggles Left, Filter Right */}
|
||||
<div className="px-2 mb-2 flex items-center justify-between gap-4">
|
||||
<div className="flex bg-gray-200/50 p-1 rounded-lg shadow-inner">
|
||||
<button
|
||||
onClick={() => setDeptViewMode('department')}
|
||||
className={`px-4 py-1.5 text-xs font-bold rounded-md transition-all ${deptViewMode === 'department' ? 'bg-white text-blue-600 shadow-sm' : 'text-gray-500 hover:text-gray-700'}`}
|
||||
>
|
||||
按部门
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setDeptViewMode('manager')}
|
||||
className={`px-4 py-1.5 text-xs font-bold rounded-md transition-all ${deptViewMode === 'manager' ? 'bg-white text-blue-600 shadow-sm' : 'text-gray-500 hover:text-gray-700'}`}
|
||||
>
|
||||
按业务员
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 max-w-[240px]">
|
||||
{deptViewMode === 'manager' && (
|
||||
<div className="relative">
|
||||
<Filter className="absolute left-2.5 top-1/2 -translate-y-1/2 text-gray-400" size={14} />
|
||||
<select
|
||||
value={selectedManager}
|
||||
onChange={(e) => setSelectedManager(e.target.value)}
|
||||
className="w-full pl-9 pr-8 py-1.5 bg-white border border-gray-200 rounded-lg text-xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm appearance-none cursor-pointer font-bold text-gray-700"
|
||||
>
|
||||
<option value="All">所有业务员</option>
|
||||
{allManagersList.map(m => (
|
||||
<option key={m} value={m}>{m}</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown className="absolute right-2.5 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none" size={14} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Table View */}
|
||||
<div className="hidden lg:block overflow-x-auto">
|
||||
<table className="w-full text-left border-collapse min-w-[900px]">
|
||||
<thead>
|
||||
<tr className="bg-gray-100/50 text-[11px] text-gray-500 uppercase tracking-wider border-b border-gray-200">
|
||||
<th className="p-2 font-bold border-r border-gray-100 w-48">{deptViewMode === 'department' ? '部门名称' : '业务员'}</th>
|
||||
{deptViewMode === 'manager' && <th className="p-2 font-bold border-r border-gray-100 w-32">所属部门</th>}
|
||||
{deptViewMode === 'department' && (
|
||||
<>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-24">资产总数</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-24 text-green-500">运营中</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-24 text-gray-400">闲置中</th>
|
||||
</>
|
||||
)}
|
||||
{deptViewMode === 'manager' && (
|
||||
<>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-24">合计资产</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-20">4.5T</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-20">冷链</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-20">18T</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-20">49T</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-20">挂车</th>
|
||||
<th className="p-2 font-bold border-r border-gray-100 text-center w-20">其他</th>
|
||||
</>
|
||||
)}
|
||||
<th className="p-2 font-bold text-center w-16">详情</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-xs">
|
||||
{deptViewMode === 'department' ? (
|
||||
deptData.map((dept) => {
|
||||
const isExpanded = expandedDepts.has(dept.department);
|
||||
return (
|
||||
<React.Fragment key={dept.department}>
|
||||
<tr
|
||||
className={`cursor-pointer transition-all border-b border-gray-100 ${
|
||||
isExpanded ? 'bg-blue-50/50' : 'hover:bg-gray-50'
|
||||
}`}
|
||||
onClick={() => toggleDept(dept.department)}
|
||||
>
|
||||
<td className="p-2 border-r border-gray-100 font-bold text-gray-800">
|
||||
{dept.department}
|
||||
</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center font-black text-gray-800 text-sm">
|
||||
{dept.totalAssets}
|
||||
</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center font-black text-green-500 text-sm">
|
||||
{dept.operatingCount}
|
||||
</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center font-black text-gray-400 text-sm">
|
||||
{dept.idleCount}
|
||||
</td>
|
||||
<td className="p-2 text-center">
|
||||
{isExpanded ? <ChevronDown size={16} className="text-blue-500 inline" /> : <ChevronRight size={16} className="text-gray-300 inline" />}
|
||||
</td>
|
||||
</tr>
|
||||
{isExpanded && (
|
||||
<tr className="bg-gray-50/50">
|
||||
<td colSpan={5} className="p-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2">
|
||||
{dept.managers.map(m => {
|
||||
const isManagerExpanded = expandedManagerDetails.has(m.manager);
|
||||
return (
|
||||
<div key={m.manager} className="bg-white rounded-lg border border-gray-100 shadow-sm overflow-hidden">
|
||||
<div
|
||||
className="p-2 flex justify-between items-center cursor-pointer hover:bg-gray-50 transition-colors"
|
||||
onClick={() => toggleManagerDetails(m.manager)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{isManagerExpanded ? <ChevronDown size={14} className="text-blue-500" /> : <ChevronRight size={14} className="text-gray-300" />}
|
||||
<span className="font-bold text-gray-700 text-xs">{m.manager}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager });
|
||||
}}
|
||||
className="text-[10px] font-bold text-blue-600 bg-blue-50 px-2 py-0.5 rounded hover:bg-blue-100 transition-colors"
|
||||
>
|
||||
合计: {m.total}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{isManagerExpanded && (
|
||||
<div className="p-2 pt-0 border-t border-gray-50 bg-gray-50/30">
|
||||
<div className="grid grid-cols-3 gap-1 mt-2">
|
||||
<div
|
||||
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普货' })}
|
||||
>
|
||||
<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>
|
||||
<div
|
||||
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冷链' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
||||
</div>
|
||||
<div
|
||||
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' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
||||
</div>
|
||||
<div
|
||||
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' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
||||
</div>
|
||||
<div
|
||||
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 })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
||||
</div>
|
||||
<div
|
||||
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: '其他' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
managerStats.map((m) => {
|
||||
const isManagerExpanded = expandedManagerDetails.has(m.manager);
|
||||
return (
|
||||
<React.Fragment key={m.manager}>
|
||||
<tr
|
||||
className="border-b border-gray-100 hover:bg-gray-50 transition-colors cursor-pointer"
|
||||
onClick={() => toggleManagerDetails(m.manager)}
|
||||
>
|
||||
<td className="p-2 border-r border-gray-100 font-bold text-gray-800 flex items-center gap-1">
|
||||
{isManagerExpanded ? <ChevronDown size={12} className="text-blue-400" /> : <ChevronRight size={12} className="text-gray-300" />}
|
||||
{m.manager}
|
||||
</td>
|
||||
<td className="p-2 border-r border-gray-100 text-gray-600">{m.department}</td>
|
||||
<td
|
||||
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) => {
|
||||
e.stopPropagation();
|
||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager });
|
||||
}}
|
||||
>
|
||||
{m.total}
|
||||
</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-400">-</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-400">-</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-400">-</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-400">-</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-400">-</td>
|
||||
<td className="p-2 border-r border-gray-100 text-center text-gray-400">-</td>
|
||||
<td className="p-2 text-center">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager });
|
||||
}}
|
||||
className="text-blue-500 hover:text-blue-700 transition-colors"
|
||||
>
|
||||
<ArrowRightLeft size={14} className="inline" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{isManagerExpanded && (
|
||||
<tr className="bg-gray-50/50 border-b border-gray-100">
|
||||
<td colSpan={10} className="p-0">
|
||||
<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普货' })}>
|
||||
<span className="text-gray-400 uppercase mb-1">4.5T</span>
|
||||
<span className="font-bold text-gray-600">{m.t4_5}</span>
|
||||
</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冷链' })}>
|
||||
<span className="text-gray-400 uppercase mb-1">冷链</span>
|
||||
<span className="font-bold text-gray-600">{m.t4_5c}</span>
|
||||
</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' })}>
|
||||
<span className="text-gray-400 uppercase mb-1">18T</span>
|
||||
<span className="font-bold text-gray-600">{m.t18}</span>
|
||||
</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' })}>
|
||||
<span className="text-gray-400 uppercase mb-1">49T</span>
|
||||
<span className="font-bold text-gray-600">{m.t49}</span>
|
||||
</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 })}>
|
||||
<span className="text-gray-400 uppercase mb-1">挂车</span>
|
||||
<span className="font-bold text-gray-600">{m.trailer}</span>
|
||||
</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: '其他' })}>
|
||||
<span className="text-gray-400 uppercase mb-1">其他</span>
|
||||
<span className="font-bold text-gray-600">{m.other}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Mobile Card View */}
|
||||
<div className="lg:hidden p-2 space-y-2">
|
||||
{deptViewMode === 'department' ? (
|
||||
deptData.map((dept) => {
|
||||
const isExpanded = expandedDepts.has(dept.department);
|
||||
return (
|
||||
<div key={dept.department} className="bg-white rounded-sm border border-gray-100 shadow-sm overflow-hidden">
|
||||
<div
|
||||
className="p-3 cursor-pointer"
|
||||
onClick={() => toggleDept(dept.department)}
|
||||
>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<h3 className="text-sm font-bold text-gray-800">{dept.department}</h3>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<div className="text-center">
|
||||
<div className="text-[8px] text-gray-400 uppercase font-bold mb-0.5">资产</div>
|
||||
<div className="text-xs font-black text-gray-800">{dept.totalAssets}</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-[8px] text-green-500 uppercase font-bold mb-0.5">运营</div>
|
||||
<div className="text-xs font-black text-green-500">{dept.operatingCount}</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-[8px] text-gray-400 uppercase font-bold mb-0.5">闲置</div>
|
||||
<div className="text-xs font-black text-gray-400">{dept.idleCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1 flex justify-center">
|
||||
{isExpanded ? <ChevronDown size={14} className="text-blue-500" /> : <ChevronRight size={14} className="text-gray-300" />}
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded && (
|
||||
<div className="bg-gray-50/50 p-2 border-t border-gray-50 space-y-2">
|
||||
{dept.managers.map(m => {
|
||||
const isManagerExpanded = expandedManagerDetails.has(m.manager);
|
||||
return (
|
||||
<div key={m.manager} className="bg-white rounded border border-gray-100 shadow-sm overflow-hidden">
|
||||
<div
|
||||
className="p-2 flex justify-between items-center cursor-pointer"
|
||||
onClick={() => toggleManagerDetails(m.manager)}
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
{isManagerExpanded ? <ChevronDown size={12} className="text-blue-400" /> : <ChevronRight size={12} className="text-gray-300" />}
|
||||
<span className="text-[11px] font-bold text-gray-700">{m.manager}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager });
|
||||
}}
|
||||
className="text-[10px] font-bold text-blue-600 bg-blue-50 px-2 py-0.5 rounded"
|
||||
>
|
||||
合计: {m.total}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{isManagerExpanded && (
|
||||
<div className="p-2 border-t border-gray-50 bg-gray-50/30 grid grid-cols-3 gap-1">
|
||||
<div
|
||||
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普货' })}
|
||||
>
|
||||
<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>
|
||||
<div
|
||||
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冷链' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
||||
</div>
|
||||
<div
|
||||
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' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
||||
</div>
|
||||
<div
|
||||
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' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
||||
</div>
|
||||
<div
|
||||
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 })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
||||
</div>
|
||||
<div
|
||||
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: '其他' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
managerStats.map((m) => {
|
||||
const isManagerExpanded = expandedManagerDetails.has(m.manager);
|
||||
return (
|
||||
<div key={m.manager} className="bg-white rounded-sm border border-gray-100 shadow-sm overflow-hidden">
|
||||
<div
|
||||
className="p-2 cursor-pointer flex items-center justify-between gap-2"
|
||||
onClick={() => toggleManagerDetails(m.manager)}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-1 min-w-0">
|
||||
{isManagerExpanded ? <ChevronDown size={14} className="text-blue-500" /> : <ChevronRight size={14} className="text-gray-300" />}
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<h3 className="text-sm font-bold text-gray-800 shrink-0">{m.manager}</h3>
|
||||
<span className="text-[11px] text-gray-500 shrink-0">{m.department}</span>
|
||||
<div
|
||||
className="text-[11px] font-bold text-blue-600 whitespace-nowrap"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager });
|
||||
}}
|
||||
>
|
||||
资产: {m.total}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager });
|
||||
}}
|
||||
className="text-blue-500 p-1 hover:bg-blue-50 rounded transition-colors flex-shrink-0"
|
||||
>
|
||||
<ArrowRightLeft size={14} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{isManagerExpanded && (
|
||||
<div className="p-2 border-t border-gray-50 bg-gray-50/30 grid grid-cols-3 gap-1">
|
||||
<div
|
||||
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普货' })}
|
||||
>
|
||||
<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>
|
||||
<div
|
||||
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冷链' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">冷链</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t4_5c}</div>
|
||||
</div>
|
||||
<div
|
||||
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' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">18T</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t18}</div>
|
||||
</div>
|
||||
<div
|
||||
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' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">49T</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.t49}</div>
|
||||
</div>
|
||||
<div
|
||||
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 })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">挂车</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.trailer}</div>
|
||||
</div>
|
||||
<div
|
||||
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: '其他' })}
|
||||
>
|
||||
<div className="text-[8px] text-gray-400 uppercase">其他</div>
|
||||
<div className="text-[10px] font-bold text-gray-600">{m.other}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Plate Number Modal */}
|
||||
<AnimatePresence>
|
||||
{showPlateNumbers && (
|
||||
|
||||
Reference in New Issue
Block a user