ci/woodpecker/push/woodpecker Pipeline failed
Use operations signing times and delivery completion statuses; include replacement deliveries in delivery totals with range drilldowns and exports. Separate abnormal vehicles from inventory, add a date range picker, and enable CI for feature/asset-statistics.
130 lines
9.6 KiB
TypeScript
130 lines
9.6 KiB
TypeScript
import { ChevronDown, ChevronRight } from 'lucide-react';
|
|
import { AnimatePresence, motion } from 'motion/react';
|
|
import type { AssetSummarySectionProps } from './types';
|
|
|
|
export function AssetSummaryMobileCards({
|
|
processedData,
|
|
theme,
|
|
expandedAssetTypes,
|
|
toggleAssetType,
|
|
expandedModels,
|
|
toggleModel,
|
|
setVehicleSelection: setShowPlateNumbers,
|
|
}: AssetSummarySectionProps) {
|
|
return (
|
|
<div className="lg:hidden p-4 space-y-4">
|
|
{processedData.map((typeGroup) => (
|
|
<div key={typeGroup.type} className="space-y-3">
|
|
<div
|
|
className={`px-3 py-2 rounded flex justify-between items-center shadow-sm cursor-pointer transition-all ${
|
|
theme === 'vibrant' ? 'bg-blue-600 text-white active:bg-blue-700' :
|
|
theme === 'minimal' ? 'bg-white border-l-4 border-blue-500 text-gray-800 active:bg-gray-50' :
|
|
'bg-blue-50 border border-blue-100 text-blue-700 active:bg-blue-100'
|
|
}`}
|
|
onClick={() => toggleAssetType(typeGroup.type)}
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
{expandedAssetTypes.has(typeGroup.type) ?
|
|
<ChevronDown size={16} className={theme === 'vibrant' ? 'text-white' : 'text-blue-500'} /> :
|
|
<ChevronRight size={16} className={theme === 'vibrant' ? 'text-white/70' : 'text-blue-300'} />
|
|
}
|
|
<span className="text-xs font-bold">{typeGroup.type}</span>
|
|
</div>
|
|
<div className={`flex gap-3 text-[9px] font-normal ${theme === 'vibrant' ? 'opacity-90' : 'text-gray-500'}`}>
|
|
<span>资产 <span className={theme === 'vibrant' ? 'font-bold' : 'font-bold text-gray-700'}>{typeGroup.totalAssets}</span></span>
|
|
<span>库存 <span className={theme === 'vibrant' ? 'font-bold' : 'font-bold text-blue-600'}>{typeGroup.totalInventory}</span></span>
|
|
<span>异动 <span className="font-bold">{typeGroup.totalAbnormal}</span></span>
|
|
<span>运营 <span className={theme === 'vibrant' ? 'font-bold' : 'font-bold text-green-600'}>{typeGroup.totalOperating}</span></span>
|
|
</div>
|
|
</div>
|
|
|
|
<AnimatePresence>
|
|
{expandedAssetTypes.has(typeGroup.type) && (
|
|
<motion.div
|
|
initial={{ height: 0, opacity: 0 }}
|
|
animate={{ height: 'auto', opacity: 1 }}
|
|
exit={{ height: 0, opacity: 0 }}
|
|
className="space-y-3 overflow-hidden"
|
|
>
|
|
{typeGroup.models.map((model) => (
|
|
<div key={model.model} className="bg-white rounded-lg border border-gray-100 shadow-sm overflow-hidden">
|
|
<div
|
|
className="p-3 flex justify-between items-center cursor-pointer active:bg-gray-50"
|
|
onClick={() => toggleModel(model.model)}
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
{expandedModels.has(model.model) ? <ChevronDown size={14} className="text-blue-500" /> : <ChevronRight size={14} className="text-gray-300" />}
|
|
<span className="text-xs font-bold text-gray-700">{model.model}</span>
|
|
</div>
|
|
<div className="flex flex-wrap justify-end gap-2">
|
|
<span className="text-[10px] bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded font-bold cursor-pointer active:bg-blue-100" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', source: 'asset', title: model.model }); }}>资产 {model.total}</span>
|
|
<span className="text-[10px] bg-orange-50 text-orange-600 px-1.5 py-0.5 rounded font-bold cursor-pointer active:bg-orange-100" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Inventory', source: 'asset', title: `${model.model} - 库存` }); }}>库存 {model.inventory}</span>
|
|
<button type="button" className="text-[10px] bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded font-bold" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Abnormal', source: 'asset', title: `${model.model} - 异动` }); }}>异动 {model.abnormal}</button>
|
|
<span className="text-[10px] bg-green-50 text-green-600 px-1.5 py-0.5 rounded font-bold cursor-pointer active:bg-green-100" onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Operating', source: 'asset', title: `${model.model} - 在运营` }); }}>运营 {model.operating}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{expandedModels.has(model.model) && (
|
|
<div className="px-3 pb-3 pt-1 border-t border-gray-50 bg-gray-50/30">
|
|
<div className="grid grid-cols-2 gap-y-3 gap-x-4 mt-2">
|
|
<div className="flex justify-between items-center cursor-pointer hover:bg-gray-100 p-1 rounded transition-colors"
|
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Inventory', source: 'asset', title: `${model.model} - 库存` })}>
|
|
<span className="text-[10px] text-gray-400">总库存</span>
|
|
<span className="text-xs font-bold text-blue-600">{model.inventory}</span>
|
|
</div>
|
|
<div className="flex justify-between items-center cursor-pointer hover:bg-gray-100 p-1 rounded transition-colors"
|
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Pending', source: 'asset', title: `${model.model} - 待交车` })}>
|
|
<span className="text-[10px] text-gray-400">待交车</span>
|
|
<span className="text-xs font-bold text-gray-600">{model.pending}</span>
|
|
</div>
|
|
<div className="col-span-2 grid grid-cols-5 gap-1 py-2 border-y border-gray-100">
|
|
{['嘉兴', '广东', '北京', '新疆', '其他'].map(reg => (
|
|
<div key={reg} className="text-center">
|
|
<div className="text-[8px] text-gray-400 mb-0.5">{reg === '嘉兴' ? '浙' : reg === '广东' ? '粤' : reg === '北京' ? '京' : reg === '新疆' ? '新' : '其'}</div>
|
|
{model.inventoryRegions[reg] > 0 ? (
|
|
<button
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
setShowPlateNumbers({ batch: 'All', model: model.model, location: reg, category: 'Inventory', source: 'asset', title: `${model.model} - ${reg} 库存` });
|
|
}}
|
|
className="text-[10px] font-bold text-blue-500 hover:underline"
|
|
>
|
|
{model.inventoryRegions[reg]}
|
|
</button>
|
|
) : (
|
|
<div className="text-[10px] font-bold text-gray-300">-</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="col-span-2 grid grid-cols-3 gap-2 pt-1">
|
|
<div className="bg-blue-50/50 p-2 rounded flex flex-col items-center cursor-pointer hover:bg-blue-100/50 transition-colors"
|
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Delivered', source: 'asset', title: `${model.model} - 本周交车` })}>
|
|
<span className="text-[8px] text-gray-400 mb-1">本周已交车</span>
|
|
<span className="text-xs font-bold text-blue-600">{model.weeklyDelivered}</span>
|
|
</div>
|
|
<div className="bg-orange-50/50 p-2 rounded flex flex-col items-center cursor-pointer hover:bg-orange-100/50 transition-colors"
|
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Returned', source: 'asset', title: `${model.model} - 本周还车` })}>
|
|
<span className="text-[8px] text-gray-400 mb-1">已还车</span>
|
|
<span className="text-xs font-bold text-orange-600">{model.weeklyReturned}</span>
|
|
</div>
|
|
<div className="bg-purple-50/50 p-2 rounded flex flex-col items-center cursor-pointer hover:bg-purple-100/50 transition-colors"
|
|
onClick={() => setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Replaced', source: 'asset', title: `${model.model} - 本周替换` })}>
|
|
<span className="text-[8px] text-gray-400 mb-1">已替换</span>
|
|
<span className="text-xs font-bold text-purple-600">{model.weeklyReplaced}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|