import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'; import { Truck, ChevronDown, ChevronRight, Loader2, Filter, ArrowRightLeft, MapPin, } from 'lucide-react'; import { motion, AnimatePresence } from 'motion/react'; import * as XLSX from 'xlsx'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell, LabelList, } from 'recharts'; import type { SummaryData, TypeSummary, VehicleListItem, DeptGroup, RegionGroup, CustomerStats, RegionalInventoryStats } from './types'; import { fetchSummary, fetchByType, fetchVehicleList, fetchWeeklyDetail, fetchDeptStats, fetchRegionStats, fetchCustomerStats, fetchInventoryStats, fetchRegionChart, fetchSubjects, fetchFlowStats, type SubjectOption } from './api'; import type { FlowDetailItem, FlowStatsResponse, FlowType, WeeklyDetailItem } from './api'; import { buildCustomerPieData, buildVehicleModalRequest, deriveCustomerView, deriveDepartmentView, deriveInventoryView, deriveModalVehicleView, formatLocalDateTime, getWeeklyFlowRange, selectFlowDetails, type VehicleModalSelection, } from './model'; import { SearchSelect } from '../../components/SearchSelect'; import { MultiSearchSelect } from '../../components/MultiSearchSelect'; import Blur from '../../components/Blur'; import RotatingFooterHint from '../../components/RotatingFooterHint'; import { ErrorState, LoadingState, PageFrame, SkeletonBlock, SurfaceCard } from '../../components/ui/surface'; import { AssetsHeader } from './components/AssetsHeader'; import { FlowDetailModal } from './components/FlowDetailModal'; import { VehicleDetailModal } from './components/VehicleDetailModal'; import { OverviewView } from './components/OverviewView'; export default function AssetsModule() { const [activeTab, setActiveTab] = useState<'overview' | 'department' | 'region' | 'customer'>('overview'); const [tabReady, setTabReady] = useState(true); const prevTabRef = useRef(activeTab); useEffect(() => { if (prevTabRef.current !== activeTab) { setTabReady(false); prevTabRef.current = activeTab; const id = requestAnimationFrame(() => { setTabReady(true); }); return () => cancelAnimationFrame(id); } }, [activeTab]); const [theme, setTheme] = useState<'soft' | 'minimal' | 'vibrant'>('soft'); // 所属公司(归属主体)筛选 —— 影响全页聚合 const [selectedSubject, setSelectedSubject] = useState(null); const [subjects, setSubjects] = useState([]); const [subjectDropdownOpen, setSubjectDropdownOpen] = useState(false); const [subjectSearch, setSubjectSearch] = useState(''); const subjectDropdownRef = useRef(null); const [expandedModels, setExpandedModels] = useState>(new Set()); const [expandedAssetTypes, setExpandedAssetTypes] = useState>(new Set()); const [showPlateNumbers, setShowPlateNumbers] = useState(null); // Data state const [summary, setSummary] = useState(null); const [processedData, setProcessedData] = useState([]); const [modalVehicles, setModalVehicles] = useState([]); const [modalWeeklyDetail, setModalWeeklyDetail] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [lastUpdate, setLastUpdate] = useState(() => formatLocalDateTime(new Date())); const [modalLoading, setModalLoading] = useState(false); const [flowRange, setFlowRange] = useState(() => getWeeklyFlowRange()); const [flowStats, setFlowStats] = useState(null); const [flowLoading, setFlowLoading] = useState(false); const [flowDailyExpanded, setFlowDailyExpanded] = useState(false); const [selectedFlow, setSelectedFlow] = useState<{ date: string; type: FlowType } | null>(null); // Dept/Region/Customer data const [deptData, setDeptData] = useState([]); const [regionData, setRegionData] = useState([]); const [customerData, setCustomerData] = useState([]); // Dept section state const [deptViewMode, setDeptViewMode] = useState<'department' | 'manager'>('department'); const [expandedDepts, setExpandedDepts] = useState>(new Set()); const [expandedManagerDetails, setExpandedManagerDetails] = useState>(new Set()); const [selectedManager, setSelectedManager] = useState('All'); // Region section state const [expandedRegions, setExpandedRegions] = useState>(new Set()); const [expandedRegionCities, setExpandedRegionCities] = useState>(new Set()); const [regionFilters, setRegionFilters] = useState({ region: '', city: '', customer: '' }); const [isRegionFilterOpen, setIsRegionFilterOpen] = useState(false); const [draftRegionFilters, setDraftRegionFilters] = useState({ region: '', city: '', customer: '' }); // Customer section state const [expandedCustomers, setExpandedCustomers] = useState>(new Set()); const [customerFilters, setCustomerFilters] = useState({ customer: [] as string[], brand: '', department: '', manager: '', region: '' }); const [isCustomerFilterOpen, setIsCustomerFilterOpen] = useState(false); const [draftCustomerFilters, setDraftCustomerFilters] = useState({ customer: [] as string[], brand: '', department: '', manager: '', region: '' }); // Inventory statistics section state const [inventoryData, setInventoryData] = useState([]); const [inventoryTab, setInventoryTab] = useState<'region' | 'model'>('region'); const [expandedInventoryRegions, setExpandedInventoryRegions] = useState>(new Set()); const [expandedInventoryTypes, setExpandedInventoryTypes] = useState>(new Set(['4.5T普货'])); const [inventoryFilters, setInventoryFilters] = useState({ region: '', city: '', brand: '', type: '', model: '' }); const [isInventoryFilterOpen, setIsInventoryFilterOpen] = useState(false); const [draftInventoryFilters, setDraftInventoryFilters] = useState({ region: '', city: '', brand: '', type: '', model: '' }); // Chart view states const [customerChartView, setCustomerChartView] = useState<'region' | 'province'>('region'); const [regionChartView, setRegionChartView] = useState<'region' | 'province'>('region'); const [regionChartData, setRegionChartData] = useState<{ name: string; value: number }[]>([]); // Modal filter state const [modalFilters, setModalFilters] = useState({ plateNumber: '', model: '', brand: '', location: '' }); const [isModalFilterExpanded, setIsModalFilterExpanded] = useState(false); // Reset modal filters when modal opens useEffect(() => { if (showPlateNumbers) { setModalFilters({ plateNumber: '', model: '', brand: '', location: '' }); } }, [showPlateNumbers]); const loadData = useCallback(async () => { try { setLoading(true); setError(null); const [s, byType, dept, region, cust, inv] = await Promise.all([ fetchSummary(selectedSubject), fetchByType(selectedSubject), fetchDeptStats(selectedSubject), fetchRegionStats(undefined, selectedSubject), fetchCustomerStats(selectedSubject), fetchInventoryStats(selectedSubject), ]); setSummary(s); setProcessedData(byType); setDeptData(dept); setRegionData(region); setCustomerData(cust); setInventoryData(inv); setLastUpdate(formatLocalDateTime(new Date())); } catch (e) { setError(e instanceof Error ? e.message : '数据加载失败'); } finally { setLoading(false); } }, [selectedSubject]); useEffect(() => { loadData(); const interval = setInterval(loadData, 60 * 1000); return () => clearInterval(interval); }, [loadData]); useEffect(() => { let cancelled = false; setFlowLoading(true); fetchFlowStats({ start: flowRange.start, end: flowRange.end, subject: selectedSubject }) .then((data) => { if (!cancelled) setFlowStats(data); }) .catch(() => { if (!cancelled) setFlowStats(null); }) .finally(() => { if (!cancelled) setFlowLoading(false); }); return () => { cancelled = true; }; }, [flowRange.start, flowRange.end, selectedSubject]); // 归属公司列表(仅首次加载,公司集合相对稳定) useEffect(() => { fetchSubjects().then(setSubjects).catch(() => setSubjects([])); }, []); // 点击外部关闭归属公司下拉 useEffect(() => { if (!subjectDropdownOpen) return; const handler = (e: MouseEvent) => { if (subjectDropdownRef.current && !subjectDropdownRef.current.contains(e.target as Node)) { setSubjectDropdownOpen(false); } }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [subjectDropdownOpen]); // Re-fetch region data when filters change useEffect(() => { const hasFilter = regionFilters.customer || regionFilters.city || regionFilters.region; if (hasFilter) { fetchRegionStats( { customer: regionFilters.customer || undefined, city: regionFilters.city || undefined, region: regionFilters.region || undefined }, selectedSubject, ).then(setRegionData).catch(() => {}); } else { // No filters: use data from the main loadData cycle fetchRegionStats(undefined, selectedSubject).then(setRegionData).catch(() => {}); } }, [regionFilters, selectedSubject]); // Fetch region chart data when view changes useEffect(() => { fetchRegionChart(regionChartView, regionChartView === 'province' ? 5 : 8, 'realtime', selectedSubject) .then(setRegionChartData) .catch(() => setRegionChartData([])); }, [regionChartView, selectedSubject]); // Load modal vehicles useEffect(() => { if (!showPlateNumbers) { setModalVehicles([]); setModalWeeklyDetail([]); return; } setModalLoading(true); const request = buildVehicleModalRequest(showPlateNumbers, selectedSubject); if (request.kind === 'weekly') { setModalVehicles([]); fetchWeeklyDetail(request.type, request.filters) .then(setModalWeeklyDetail) .catch(() => setModalWeeklyDetail([])) .finally(() => setModalLoading(false)); return; } setModalWeeklyDetail([]); fetchVehicleList(request.params) .then(setModalVehicles) .catch(() => setModalVehicles([])) .finally(() => setModalLoading(false)); }, [showPlateNumbers, selectedSubject]); const allTypesExpanded = processedData.length > 0 && processedData.every((t) => expandedAssetTypes.has(t.type)); const toggleAllAssetTypes = () => { if (allTypesExpanded) { setExpandedAssetTypes(new Set()); } else { setExpandedAssetTypes(new Set(processedData.map((t) => t.type))); } }; const toggleAssetType = (type: string) => { const newSet = new Set(expandedAssetTypes); if (newSet.has(type)) newSet.delete(type); else newSet.add(type); setExpandedAssetTypes(newSet); }; const toggleModel = (model: string) => { const newSet = new Set(expandedModels); if (newSet.has(model)) newSet.delete(model); else newSet.add(model); setExpandedModels(newSet); }; const toggleDept = (dept: string) => { const newSet = new Set(expandedDepts); if (newSet.has(dept)) newSet.delete(dept); else newSet.add(dept); setExpandedDepts(newSet); }; const toggleManagerDetails = (manager: string) => { const newSet = new Set(expandedManagerDetails); if (newSet.has(manager)) newSet.delete(manager); else newSet.add(manager); setExpandedManagerDetails(newSet); }; const toggleRegion = (region: string) => { const newSet = new Set(expandedRegions); if (newSet.has(region)) newSet.delete(region); else newSet.add(region); setExpandedRegions(newSet); }; const toggleRegionCity = (key: string) => { const newSet = new Set(expandedRegionCities); if (newSet.has(key)) newSet.delete(key); else newSet.add(key); setExpandedRegionCities(newSet); }; const toggleCustomer = (customer: string) => { const newSet = new Set(expandedCustomers); if (newSet.has(customer)) newSet.delete(customer); else newSet.add(customer); setExpandedCustomers(newSet); }; const toggleInventoryRegion = (region: string) => { const newSet = new Set(expandedInventoryRegions); if (newSet.has(region)) newSet.delete(region); else newSet.add(region); setExpandedInventoryRegions(newSet); }; const toggleInventoryType = (type: string) => { const newSet = new Set(expandedInventoryTypes); if (newSet.has(type)) newSet.delete(type); else newSet.add(type); setExpandedInventoryTypes(newSet); }; const inventoryTypeFilter = isInventoryFilterOpen ? draftInventoryFilters.type : inventoryFilters.type; const { filtered: filteredInventoryStats, brands: uniqueInventoryBrands, regions: uniqueInventoryRegions, cities: uniqueInventoryCities, types: uniqueInventoryTypes, modelsForType: uniqueInventoryModelsForType, byRegion: inventoryByRegion, byModel: inventoryByModel, } = useMemo( () => deriveInventoryView(inventoryData, inventoryFilters, inventoryTypeFilter), [inventoryData, inventoryFilters, inventoryTypeFilter], ); const { managers: allManagersList, groupedManagers: managersGroupedByDept, managerStats, } = useMemo( () => deriveDepartmentView(deptData, selectedManager), [deptData, selectedManager], ); const { filtered: filteredCustomerStats, brands: uniqueBrands, departments: uniqueDepts, regions: uniqueRegions, cities: uniqueCities, customerNames: uniqueCustomerNames, managersByDepartment: customerManagersGroupedByDept, } = useMemo( () => deriveCustomerView(customerData, deptData, customerFilters), [customerData, deptData, customerFilters], ); const { plates: uniqueModalPlates, models: uniqueModalModels, brands: uniqueModalBrands, locations: uniqueModalLocations, filteredVehicles: filteredModalVehicles, filteredWeeklyDetails: filteredModalWeeklyDetail, } = useMemo( () => deriveModalVehicleView(modalVehicles, modalWeeklyDetail, modalFilters), [modalVehicles, modalWeeklyDetail, modalFilters], ); const selectedFlowDetails = useMemo( () => selectFlowDetails(flowStats, selectedFlow), [flowStats, selectedFlow], ); const exportFlowDetails = useCallback((rows?: FlowDetailItem[], title = '资产流转明细') => { const source = rows ?? flowStats?.details ?? []; if (source.length === 0) return; const table = source.map((item) => ({ 日期: item.date, 类型: item.typeLabel, 车牌: item.plateNumber, 流转时间: item.eventTime || '', 提交时间: item.submitTime || '', 部门: item.department || '', 业务负责人: item.manager || '', 客户: item.customerName || '', })); const ws = XLSX.utils.json_to_sheet(table); ws['!cols'] = [ { wch: 14 }, { wch: 8 }, { wch: 14 }, { wch: 20 }, { wch: 20 }, { wch: 16 }, { wch: 14 }, { wch: 24 }, ]; const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, '明细'); XLSX.writeFile(wb, `${title}-${flowRange.start}-${flowRange.end}.xlsx`); }, [flowRange.end, flowRange.start, flowStats]); const [customerProvinceData, setCustomerProvinceData] = useState<{ name: string; value: number }[]>([]); useEffect(() => { if (customerChartView === 'province') { fetchRegionChart('province', 5, 'vehicle', selectedSubject).then(setCustomerProvinceData).catch(() => setCustomerProvinceData([])); } }, [customerChartView, selectedSubject]); const customerPieData = useMemo( () => buildCustomerPieData(customerData, customerChartView, customerProvinceData), [customerData, customerChartView, customerProvinceData], ); if (loading && !summary) { return (
{[0, 1, 2, 3].map(item => ( ))}
); } if (error && !summary) { return (
); } const SUMMARY = summary!; const operatingRate = SUMMARY.totalAssets > 0 ? SUMMARY.operating.total / SUMMARY.totalAssets * 100 : 0; const inventoryRate = SUMMARY.totalAssets > 0 ? SUMMARY.inventory.total / SUMMARY.totalAssets * 100 : 0; const pendingRate = SUMMARY.totalAssets > 0 ? SUMMARY.pendingDelivery / SUMMARY.totalAssets * 100 : 0; return (
{/* Main Content Area */}
{!tabReady && (
)} {tabReady && activeTab === 'overview' && ( )} {tabReady && activeTab === 'department' && (
{/* Overall Total Summary (Compact) - Moved to Top */}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Operating', source: 'department', title: '部门运营统计' })}> 总运营车辆 {deptData.reduce((s, d) => s + d.totalAssets, 0)}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', attendance: 'active', source: 'department', title: '部门运营统计 - 出勤车辆' })}> 出勤车辆 {deptData.reduce((acc, d) => acc + d.operatingCount, 0)}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', attendance: 'idle', source: 'department', title: '部门运营统计 - 闲置车辆' })}> 闲置车辆 {deptData.reduce((acc, d) => acc + d.idleCount, 0)}
平均出勤 {deptData.length > 0 ? (deptData.reduce((acc, d) => acc + d.attendanceRate, 0) / deptData.length).toFixed(1) : 0}%
*说明:当天里程>0即为出勤。
{/* Controls Row: Toggles Left, Filter Right */}
{deptViewMode === 'manager' && (
)}
{/* Desktop Table View */}
{deptViewMode === 'manager' && } {deptViewMode === 'department' && ( <> )} {deptViewMode === 'manager' && ( <> )} {deptViewMode === 'department' ? ( deptData.map((dept) => { const isExpanded = expandedDepts.has(dept.department); return ( toggleDept(dept.department)} > {isExpanded && ( )} ); }) ) : ( managerStats.map((m) => { const isManagerExpanded = expandedManagerDetails.has(m.manager); return ( toggleManagerDetails(m.manager)} > {isManagerExpanded && ( )} ); }) )}
{deptViewMode === 'department' ? '部门名称' : '业务负责人'}所属部门{deptViewMode === 'department' ? '出勤率' : '合计资产'}总运营车辆 出勤车辆 闲置车辆4.5T 冷链 18T 49T 挂车 其他详情
{dept.department} {dept.attendanceRate}% {isExpanded ? : }
{dept.managers.map(m => { const isManagerExpanded = expandedManagerDetails.has(m.manager); return (
toggleManagerDetails(m.manager)} >
{isManagerExpanded ? : } {m.manager}
{isManagerExpanded && (
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T` })} >
4.5T
{m.t4_5}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T冷链` })} >
冷链
{m.t4_5c}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 18T` })} >
18T
{m.t18}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 49T` })} >
49T
{m.t49}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 挂车` })} >
挂车
{m.trailer}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 其他` })} >
其他
{m.other}
)}
); })}
{isManagerExpanded ? : } {m.manager} {m.department} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 正在运营` }); }} > {m.total} - - - - - -
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T` })}> 4.5T {m.t4_5}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T冷链` })}> 冷链 {m.t4_5c}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 18T` })}> 18T {m.t18}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 49T` })}> 49T {m.t49}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 挂车` })}> 挂车 {m.trailer}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 其他` })}> 其他 {m.other}
{/* Mobile Card View */}
{deptViewMode === 'department' ? ( deptData.map((dept) => { const isExpanded = expandedDepts.has(dept.department); return (
toggleDept(dept.department)} >

{dept.department}

出勤率: {dept.attendanceRate}%
{ e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', department: dept.department, category: 'Operating', source: 'department', title: `部门运营统计 - ${dept.department}` }); }}>
总运营
{dept.totalAssets}
{ e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', department: dept.department, attendance: 'active', source: 'department', title: `部门运营统计 - ${dept.department} - 出勤车辆` }); }}>
出勤
{dept.operatingCount}
{ e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', department: dept.department, attendance: 'idle', source: 'department', title: `部门运营统计 - ${dept.department} - 闲置车辆` }); }}>
闲置
{dept.idleCount}
{isExpanded ? : }
{isExpanded && (
{dept.managers.map(m => { const isManagerExpanded = expandedManagerDetails.has(m.manager); return (
toggleManagerDetails(m.manager)} >
{isManagerExpanded ? : } {m.manager}
{isManagerExpanded && (
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T` })} >
4.5T
{m.t4_5}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T冷链` })} >
冷链
{m.t4_5c}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 18T` })} >
18T
{m.t18}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 49T` })} >
49T
{m.t49}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 挂车` })} >
挂车
{m.trailer}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 其他` })} >
其他
{m.other}
)}
); })}
)}
); }) ) : ( managerStats.map((m) => { const isManagerExpanded = expandedManagerDetails.has(m.manager); return (
toggleManagerDetails(m.manager)} >
{isManagerExpanded ? : }

{m.manager}

{m.department}
{ e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 正在运营` }); }} > 资产: {m.total}
{isManagerExpanded && (
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T` })} >
4.5T
{m.t4_5}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '4.5T', isColdChain: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 4.5T冷链` })} >
冷链
{m.t4_5c}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '18T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 18T` })} >
18T
{m.t18}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '49T', category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 49T` })} >
49T
{m.t49}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: true, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 挂车` })} >
挂车
{m.trailer}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', manager: m.manager, type: '其他车型', isTrailer: false, category: 'Operating', source: 'department', title: `部门运营统计 - ${m.manager} - 其他` })} >
其他
{m.other}
)}
); }) )}
)} {tabReady && activeTab === 'region' && (
{/* Region Distribution Chart */}

区域资产分布概览

{/* Region - Vehicle - Customer Section */}

区域运营统计

*按区域—车型—客户维度统计

{isRegionFilterOpen && ( <>

区域筛选

setDraftRegionFilters(prev => ({ ...prev, customer: v }))} options={uniqueCustomerNames} placeholder="所有客户" className="text-xs py-2 px-2" />
)}
{Object.values(regionFilters).some(v => v !== '') && (
{regionFilters.customer && ( 客户: {regionFilters.customer} )} {regionFilters.region && ( 区域: {regionFilters.region} )} {regionFilters.city && ( 城市: {regionFilters.city} )}
)}
{regionData.map((r) => { const isExpanded = expandedRegions.has(r.region); return ( toggleRegion(r.region)} > {isExpanded && r.cities.map((city) => { const cityKey = `${r.region}-${city.city}`; const isCityExpanded = expandedRegionCities.has(cityKey); return ( toggleRegionCity(cityKey)} > {isCityExpanded && city.typeBreakdown.map(tb => ( ))} ); })} ); })}
区域 / 车型 / 客户 资产总数 运营中 待交车 主要客户
{isExpanded ? : } {r.region}区域 { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: r.region, source: 'region', title: `区域运营统计 - ${r.region}` }); }}>{r.totalAssets} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: r.region, category: 'Operating', source: 'region', title: `区域运营统计 - ${r.region} - 正在运营` }); }}>{r.operatingCount} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: r.region, category: 'Pending', source: 'region', title: `区域运营统计 - ${r.region} - 待交车` }); }}>{r.pendingCount} {r.customers.slice(0, 2).join(', ')}
{isCityExpanded ? : } {city.city} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: city.city, source: 'region', title: `区域运营统计 - ${city.city}` }); }}>{city.totalAssets} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: city.city, category: 'Operating', source: 'region', title: `区域运营统计 - ${city.city} - 正在运营` }); }}>{city.operatingCount} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: city.city, category: 'Pending', source: 'region', title: `区域运营统计 - ${city.city} - 待交车` }); }}>{city.pendingCount} {city.customers.slice(0, 2).join(', ')}
{tb.type} 车型
setShowPlateNumbers({ batch: 'All', model: 'All', location: city.city, vehicleType: tb.type, source: 'region', title: `区域运营统计 - ${city.city} - ${tb.type}` })}>{tb.total} setShowPlateNumbers({ batch: 'All', model: 'All', location: city.city, vehicleType: tb.type, category: 'Operating', source: 'region', title: `区域运营统计 - ${city.city} - ${tb.type} - 正在运营` })}>{tb.operating} { setShowPlateNumbers({ batch: 'All', model: 'All', location: city.city, vehicleType: tb.type, category: 'Pending', source: 'region', title: `区域运营统计 - ${city.city} - ${tb.type} - 待交车` }); }}>{tb.pending} {tb.customers.slice(0, 2).join(', ')}
{/* Mobile View (Region) */}
{regionData.map((r) => { const isExpanded = expandedRegions.has(r.region); return (
toggleRegion(r.region)} >
{isExpanded ? : } {r.region}区域
资产: {r.totalAssets}
{isExpanded && ( <>
setShowPlateNumbers({ batch: 'All', model: 'All', location: r.region, category: 'Operating', source: 'region', title: `区域运营统计 - ${r.region} - 正在运营` })} >
运营中
{r.operatingCount}
setShowPlateNumbers({ batch: 'All', model: 'All', location: r.region, category: 'Pending', source: 'region', title: `区域运营统计 - ${r.region} - 待交车` })} >
待交车
{r.pendingCount}
{r.typeBreakdown.map(tb => (
{tb.type} 车型
setShowPlateNumbers({ batch: 'All', model: 'All', location: r.region, vehicleType: tb.type, category: 'Operating', source: 'region', title: `区域运营统计 - ${r.region} - ${tb.type} - 正在运营` })} > 运:{tb.operating} setShowPlateNumbers({ batch: 'All', model: 'All', location: r.region, vehicleType: tb.type, category: 'Pending', source: 'region', title: `区域运营统计 - ${r.region} - ${tb.type} - 待交车` })} > 待:{tb.pending}
))}
)}
); })}
)} {tabReady && activeTab === 'customer' && (
{/* Customer Operations Statistics Section */}

客户运营统计

*按客户维度统计资产分布

{isCustomerFilterOpen && ( <> {/* Backdrop */}
{/* Popover Content */}

数据筛选

setDraftCustomerFilters(prev => ({ ...prev, customer: v }))} options={uniqueCustomerNames} placeholder="所有客户" className="text-xs py-2 px-2" />
)}
{Object.values(customerFilters).some(v => Array.isArray(v) ? v.length > 0 : v !== '') && (
{customerFilters.customer.length > 0 && ( 客户: {customerFilters.customer.join(', ')} )} {customerFilters.manager && ( 负责人: {customerFilters.manager} )} {customerFilters.brand && ( 品牌: {customerFilters.brand} )} {customerFilters.department && ( 部门: {customerFilters.department} )} {customerFilters.region && ( 区域: {customerFilters.region} )}
)}
{/* Desktop Table View (Customer) */}
{filteredCustomerStats.map((cust) => { const isExpanded = expandedCustomers.has(cust.customer); return ( toggleCustomer(cust.customer)} > {isExpanded && ( )} ); })}
客户名称 所在区域 关联业务负责人 4.5T 4.5T冷链 18T 49T 挂车 其他 合计
{isExpanded ? : } {cust.customer} {cust.region} {cust.manager} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', isColdChain: false, source: 'customer', title: `客户运营统计 - ${cust.customer} - 4.5T` }); }}>{cust.t4_5} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', isColdChain: true, source: 'customer', title: `客户运营统计 - ${cust.customer} - 4.5T冷链` }); }}>{cust.t4_5c} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '18T', source: 'customer', title: `客户运营统计 - ${cust.customer} - 18T` }); }}>{cust.t18} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '49T', source: 'customer', title: `客户运营统计 - ${cust.customer} - 49T` }); }}>{cust.t49} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer', title: `客户运营统计 - ${cust.customer} - 挂车` }); }}>{cust.trailer} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer', title: `客户运营统计 - ${cust.customer} - 其他` }); }}>{cust.other} { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, source: 'customer', title: `客户运营统计 - ${cust.customer}` }); }}>{cust.total}
客户详情
{cust.customer}
主要车型
{cust.t49 > cust.t18 ? '49T 重卡' : (cust.t18 > cust.t4_5c ? '18T 货车' : '4.5T 轻卡')}
业务经理
{cust.manager}
资产占比
{((cust.total / deptData.reduce((s, d) => s + d.totalAssets, 0)) * 100).toFixed(1)}%
{/* Mobile Card View (Customer) */}
{filteredCustomerStats.map((cust) => { const isExpanded = expandedCustomers.has(cust.customer); return (
toggleCustomer(cust.customer)} >
{isExpanded ? : }
{cust.customer} {cust.region}区域
{ e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, source: 'customer', title: `客户运营统计 - ${cust.customer}` }); }} > 合计: {cust.total}
{isExpanded && (
{/* Details Cards for Mobile */}
客户详情
{cust.customer}
主要车型
{cust.t49 > cust.t18 ? '49T 重卡' : (cust.t18 > cust.t4_5c ? '18T 货车' : '4.5T 轻卡')}
业务经理
{cust.manager}
资产占比
{((cust.total / deptData.reduce((s, d) => s + d.totalAssets, 0)) * 100).toFixed(1)}%
车型分布
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', isColdChain: false, source: 'customer', title: `客户运营统计 - ${cust.customer} - 4.5T` })} >
4.5T
{cust.t4_5}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '4.5T', isColdChain: true, source: 'customer', title: `客户运营统计 - ${cust.customer} - 4.5T冷链` })} >
冷链
{cust.t4_5c}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '18T', source: 'customer', title: `客户运营统计 - ${cust.customer} - 18T` })} >
18T
{cust.t18}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '49T', source: 'customer', title: `客户运营统计 - ${cust.customer} - 49T` })} >
49T
{cust.t49}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer', title: `客户运营统计 - ${cust.customer} - 挂车` })} >
挂车
{cust.trailer}
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', customer: cust.customer, type: '其他车型', source: 'customer', title: `客户运营统计 - ${cust.customer} - 其他` })} >
其他
{cust.other}
)}
); })}
)}
); }