diff --git a/package-lock.json b/package-lock.json
index dd5f401..e3f05c2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ln-bi",
- "version": "1.1.14",
+ "version": "1.1.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ln-bi",
- "version": "1.1.14",
+ "version": "1.1.15",
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@hono/node-server": "^1.13.0",
diff --git a/package.json b/package.json
index 03b0d3f..fb2e3d1 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "ln-bi",
"private": true,
- "version": "1.1.14",
+ "version": "1.1.15",
"type": "module",
"scripts": {
"dev": "concurrently -n server,client -c blue,green \"npm run dev:server\" \"npm run dev:client\"",
diff --git a/src/modules/mileage/MileageLoadingOverlay.tsx b/src/modules/mileage/MileageLoadingOverlay.tsx
new file mode 100644
index 0000000..eb0cd71
--- /dev/null
+++ b/src/modules/mileage/MileageLoadingOverlay.tsx
@@ -0,0 +1,44 @@
+import { RefreshCw } from 'lucide-react';
+import { motion } from 'motion/react';
+
+export default function MileageLoadingOverlay({ title = '正在查询里程', description = '正在加载所选条件的里程数据,请稍候' }: { title?: string; description?: string }) {
+ return (
+
+
+
+
+
+
+
+
+ {title}
+ {description}
+
+
+
+
+
+ );
+}
diff --git a/src/modules/mileage/MonitoringView.tsx b/src/modules/mileage/MonitoringView.tsx
index 33be734..aee70fd 100644
--- a/src/modules/mileage/MonitoringView.tsx
+++ b/src/modules/mileage/MonitoringView.tsx
@@ -12,6 +12,7 @@ import type {
import { fetchMonitoring } from './api';
import { exportMileageXlsx } from './xlsx-export';
import VehicleDetailModal from './VehicleDetailModal';
+import MileageLoadingOverlay from './MileageLoadingOverlay';
import {
defaultMileageDate,
getRangePreset,
@@ -148,10 +149,14 @@ export default function MonitoringView() {
return inAlertTarget && Math.max(0, v.dailyKm || 0) >= HIGH_MILEAGE_ALERT_KM;
}, [filterTargetNames]);
+ const queryRequestRef = useRef(0);
+
// 加载首页数据
const loadFirstPage = useCallback((showPageLoading = true) => {
+ const requestId = ++queryRequestRef.current;
if (showPageLoading) setPageLoading(true);
return fetchMonitoring(buildInitialMonitoringQuery(monitoringQuery, PAGE_SIZE)).then(d => {
+ if (requestId !== queryRequestRef.current) return;
setVehicles(d.vehicles);
setStats(d.stats);
setFilterOptions(d.filters);
@@ -162,31 +167,33 @@ export default function MonitoringView() {
setHasMore(d.page < d.totalPages);
setLastRefreshedAt(new Date());
}).catch(() => {}).finally(() => {
- if (showPageLoading) setPageLoading(false);
+ if (requestId === queryRequestRef.current) setPageLoading(false);
});
}, [monitoringQuery, rangeStart, rangeEnd]);
const handleManualRefresh = useCallback(async () => {
- if (manualRefreshing) return;
+ if (manualRefreshing || pageLoading) return;
setManualRefreshing(true);
try {
await loadFirstPage(false);
} finally {
setManualRefreshing(false);
}
- }, [loadFirstPage, manualRefreshing]);
+ }, [loadFirstPage, manualRefreshing, pageLoading]);
// 加载更多
const loadMore = useCallback(() => {
- if (loadingMore || !hasMore) return;
+ if (pageLoading || loadingMore || !hasMore) return;
+ const requestId = queryRequestRef.current;
const nextPage = page + 1;
setLoadingMore(true);
fetchMonitoring(buildNextPageMonitoringQuery(monitoringQuery, PAGE_SIZE, nextPage)).then(d => {
+ if (requestId !== queryRequestRef.current) return;
setVehicles(prev => [...prev, ...d.vehicles]);
setPage(nextPage);
setHasMore(nextPage < d.totalPages);
}).catch(() => {}).finally(() => setLoadingMore(false));
- }, [monitoringQuery, page, loadingMore, hasMore]);
+ }, [monitoringQuery, page, pageLoading, loadingMore, hasMore]);
// 筛选/排序变化时重新加载
useEffect(() => {
@@ -302,6 +309,9 @@ export default function MonitoringView() {
return (
<>
+
+ {pageLoading && }
+
{/* 顶部哨兵:离开视口时显示回到顶部按钮 */}
diff --git a/src/modules/mileage/daily-report/DailyReportLoadingOverlay.tsx b/src/modules/mileage/daily-report/DailyReportLoadingOverlay.tsx
index fe065be..4507260 100644
--- a/src/modules/mileage/daily-report/DailyReportLoadingOverlay.tsx
+++ b/src/modules/mileage/daily-report/DailyReportLoadingOverlay.tsx
@@ -1,45 +1,6 @@
-import { RefreshCw } from 'lucide-react';
-import { motion } from 'motion/react';
+import MileageLoadingOverlay from '../MileageLoadingOverlay';
import { fmtDate } from './utils';
export default function DailyReportLoadingOverlay({ reportDate }: { reportDate: string }) {
- return (
-
-
-
-
-
-
-
-
- 正在加载日报
- 正在汇总 {fmtDate(reportDate)} 的里程数据
-
-
-
-
-
- );
+ return ;
}
diff --git a/src/modules/mileage/monitoring/components/VehicleList.tsx b/src/modules/mileage/monitoring/components/VehicleList.tsx
index 1bbb7c8..38ab994 100644
--- a/src/modules/mileage/monitoring/components/VehicleList.tsx
+++ b/src/modules/mileage/monitoring/components/VehicleList.tsx
@@ -134,7 +134,7 @@ export default function VehicleList({
})}
- {vehicles.length === 0 && !loadingMore && (
+ {vehicles.length === 0 && !pageLoading && !loadingMore && (
@@ -146,7 +146,7 @@ export default function VehicleList({
加载中...
)}
- {!hasMore && vehicles.length > 0 && (
+ {!pageLoading && !hasMore && vehicles.length > 0 && (
已加载全部 {total} 条