diff --git a/src/modules/mileage/MonitoringView.tsx b/src/modules/mileage/MonitoringView.tsx index 14b0b24..84e692c 100644 --- a/src/modules/mileage/MonitoringView.tsx +++ b/src/modules/mileage/MonitoringView.tsx @@ -1,9 +1,9 @@ -import { useState, useEffect, useCallback, useMemo } from 'react'; +import { useState, useEffect, useCallback, useMemo, useRef } from 'react'; import { motion, AnimatePresence } from 'motion/react'; import { Truck, Search, Filter, ChevronDown, Maximize2, Minimize2, RotateCcw, - ArrowUp, ArrowDown, ChevronLeft, ChevronRight, + ArrowUp, ArrowDown, ChevronsUp, } from 'lucide-react'; import type { MonitoringVehicle, MonitoringStats, MonitoringFilters } from './types'; import { fetchMonitoring } from './api'; @@ -111,20 +111,24 @@ export default function MonitoringView() { const [filterOptions, setFilterOptions] = useState({ departments: [], customers: [], plates: [] }); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); - const [totalPages, setTotalPages] = useState(1); - const [updatedAt, setUpdatedAt] = useState(''); + const [hasMore, setHasMore] = useState(true); + const [loadingMore, setLoadingMore] = useState(false); + const [showBackToTop, setShowBackToTop] = useState(false); const PAGE_SIZE = 50; + const listEndRef = useRef(null); + const scrollContainerRef = useRef(null); const departments = filterOptions.departments; const plateNumbers = filterOptions.plates; const projects = filterOptions.customers; - const loadData = useCallback((p = page) => { + // 加载首页数据 + const loadFirstPage = useCallback(() => { fetchMonitoring({ sortBy, sortOrder, limit: PAGE_SIZE, - page: p, + page: 1, search: searchTerm || undefined, dept: filterDept !== 'All' ? filterDept : undefined, customer: filterProject !== 'All' ? filterProject : undefined, @@ -133,22 +137,54 @@ export default function MonitoringView() { setStats(d.stats); setFilterOptions(d.filters); setTotal(d.total); - setPage(d.page); - setTotalPages(d.totalPages); - setUpdatedAt(d.updatedAt); + setPage(1); + setHasMore(d.page < d.totalPages); }).catch(() => {}); - }, [sortBy, sortOrder, searchTerm, filterDept, filterProject, page]); - - // 筛选/排序变化时重置到第1页 - useEffect(() => { - setPage(1); - loadData(1); }, [sortBy, sortOrder, searchTerm, filterDept, filterProject]); - // 翻页时加载 + // 加载更多 + const loadMore = useCallback(() => { + if (loadingMore || !hasMore) return; + const nextPage = page + 1; + setLoadingMore(true); + fetchMonitoring({ + sortBy, + sortOrder, + limit: PAGE_SIZE, + page: nextPage, + search: searchTerm || undefined, + dept: filterDept !== 'All' ? filterDept : undefined, + customer: filterProject !== 'All' ? filterProject : undefined, + }).then(d => { + setVehicles(prev => [...prev, ...d.vehicles]); + setPage(nextPage); + setHasMore(nextPage < d.totalPages); + }).catch(() => {}).finally(() => setLoadingMore(false)); + }, [sortBy, sortOrder, searchTerm, filterDept, filterProject, page, loadingMore, hasMore]); + + // 筛选/排序变化时重新加载 useEffect(() => { - loadData(page); - }, [page]); + loadFirstPage(); + }, [loadFirstPage]); + + // 滚动触底检测 + 回到顶部按钮 + useEffect(() => { + const handleScroll = () => { + const scrollY = window.scrollY; + setShowBackToTop(scrollY > 600); + const scrollHeight = document.documentElement.scrollHeight; + const clientHeight = window.innerHeight; + if (scrollHeight - scrollY - clientHeight < 200) { + loadMore(); + } + }; + window.addEventListener('scroll', handleScroll, { passive: true }); + return () => window.removeEventListener('scroll', handleScroll); + }, [loadMore]); + + const scrollToTop = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; const filteredVehicles = vehicles; @@ -706,11 +742,11 @@ export default function MonitoringView() {
车辆详情清单 - {filteredVehicles.length} 条 + {total} 条
- {filteredVehicles.slice(0, 60).map((v) => ( + {filteredVehicles.map((v) => ( - {filteredVehicles.length === 0 && ( + {filteredVehicles.length === 0 && !loadingMore && (

未找到匹配数据

)} - {/* 分页控件 */} - {totalPages > 1 && ( -
- - - {page} / {totalPages} - - + {/* 加载更多提示 */} + {loadingMore && ( +
+ 加载中...
)} + {!hasMore && filteredVehicles.length > 0 && ( +
+ 已加载全部 {total} 条 +
+ )} +
+ + {/* 回到顶部按钮 */} + + {showBackToTop && ( + + + + )} + ); }