perf: 实时监控性能优化
- 后端:车辆关联信息缓存5分钟、两库并行查询、支持服务端 筛选/排序/分页(默认返回100条) - 前端:筛选和排序参数传给后端,不再加载全量数据 - 筛选选项(部门/客户/车牌)仅首次加载获取 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -106,14 +106,43 @@ export default function MonitoringView() {
|
||||
const [filterRegionCode, setFilterRegionCode] = useState('All');
|
||||
const [filterMileageRange, setFilterMileageRange] = useState({ min: '', max: '' });
|
||||
|
||||
const [allVehicles, setAllVehicles] = useState<MonitoringVehicle[]>([]);
|
||||
const [filteredVehicles, setFilteredVehicles] = useState<MonitoringVehicle[]>([]);
|
||||
const [totalCount, setTotalCount] = useState(0);
|
||||
const [departments, setDepartments] = useState<string[]>([]);
|
||||
const [plateNumbers, setPlateNumbers] = useState<string[]>([]);
|
||||
const [projects, setProjects] = useState<string[]>([]);
|
||||
|
||||
// 加载筛选选项(仅首次,用轻量请求)
|
||||
useEffect(() => {
|
||||
const load = () => fetchMonitoring().then(d => setAllVehicles(d.vehicles)).catch(() => {});
|
||||
fetchMonitoring({ limit: 2000 }).then(d => {
|
||||
const depts = Array.from(new Set(d.vehicles.map(v => v.department).filter(Boolean))) as string[];
|
||||
const plates = Array.from(new Set(d.vehicles.map(v => v.plate).filter(Boolean)));
|
||||
const custs = Array.from(new Set(d.vehicles.map(v => v.customer).filter(Boolean))) as string[];
|
||||
setDepartments(depts);
|
||||
setPlateNumbers(plates);
|
||||
setProjects(custs);
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
// 加载数据(带服务端筛选/排序/分页)
|
||||
useEffect(() => {
|
||||
const load = () => {
|
||||
fetchMonitoring({
|
||||
sortBy,
|
||||
sortOrder,
|
||||
limit: 100,
|
||||
search: searchTerm || undefined,
|
||||
dept: filterDept !== 'All' ? filterDept : undefined,
|
||||
customer: filterProject !== 'All' ? filterProject : undefined,
|
||||
}).then(d => {
|
||||
setFilteredVehicles(d.vehicles);
|
||||
setTotalCount(d.total);
|
||||
}).catch(() => {});
|
||||
};
|
||||
load();
|
||||
const interval = setInterval(load, 60000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
}, [sortBy, sortOrder, searchTerm, filterDept, filterProject]);
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
if (!isFullscreen) {
|
||||
@@ -129,34 +158,6 @@ export default function MonitoringView() {
|
||||
setIsFullscreen(!isFullscreen);
|
||||
};
|
||||
|
||||
const filteredVehicles = useMemo(() => {
|
||||
return allVehicles.filter(v => {
|
||||
const matchesSearch = v.plate.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
(v.customer || '').toLowerCase().includes(searchTerm.toLowerCase());
|
||||
const matchesDept = filterDept === 'All' || v.department === filterDept;
|
||||
const matchesPlate = filterPlate === 'All' || v.plate === filterPlate;
|
||||
const matchesProject = filterProject === 'All' || v.customer === filterProject;
|
||||
const matchesEntity = filterEntity === 'All' || true;
|
||||
const matchesRegion = filterRegionCode === 'All' || true;
|
||||
|
||||
// Mileage range filter
|
||||
const mileage = v.dailyKm || 0;
|
||||
const minMileage = filterMileageRange.min === '' ? -Infinity : Number(filterMileageRange.min);
|
||||
const maxMileage = filterMileageRange.max === '' ? Infinity : Number(filterMileageRange.max);
|
||||
const matchesMileage = mileage >= minMileage && mileage <= maxMileage;
|
||||
|
||||
return matchesSearch && matchesDept && matchesPlate && matchesProject && matchesEntity && matchesRegion && matchesMileage;
|
||||
}).sort((a, b) => {
|
||||
const valA = sortBy === 'today' ? (a.dailyKm || 0) : (a.totalKm || 0);
|
||||
const valB = sortBy === 'today' ? (b.dailyKm || 0) : (b.totalKm || 0);
|
||||
return sortOrder === 'desc' ? valB - valA : valA - valB;
|
||||
});
|
||||
}, [allVehicles, searchTerm, filterDept, sortBy, sortOrder, filterPlate, filterProject, filterEntity, filterRegionCode, filterMileageRange]);
|
||||
|
||||
const departments = Array.from(new Set(allVehicles.map(v => v.department).filter(Boolean))) as string[];
|
||||
const plateNumbers = Array.from(new Set(allVehicles.map(v => v.plate).filter(Boolean)));
|
||||
const projects = Array.from(new Set(allVehicles.map(v => v.customer).filter(Boolean))) as string[];
|
||||
|
||||
const stats = useMemo(() => {
|
||||
const totalToday = filteredVehicles.reduce((sum, v) => sum + (v.dailyKm || 0), 0);
|
||||
const totalAll = filteredVehicles.reduce((sum, v) => sum + (v.totalKm || 0), 0);
|
||||
@@ -164,8 +165,8 @@ export default function MonitoringView() {
|
||||
const activeTotal = sortBy === 'today' ? totalToday : totalAll;
|
||||
const activeAvg = filteredVehicles.length > 0 ? activeTotal / filteredVehicles.length : 0;
|
||||
|
||||
return { totalToday, totalAll, activeTotal, activeAvg, count: filteredVehicles.length };
|
||||
}, [filteredVehicles, sortBy]);
|
||||
return { totalToday, totalAll, activeTotal, activeAvg, count: totalCount };
|
||||
}, [filteredVehicles, sortBy, totalCount]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user