From 9f781c766a6fdc62e4342d6f7d8330fb6cab6c1b Mon Sep 17 00:00:00 2001 From: kkfluous Date: Thu, 16 Apr 2026 23:03:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(scheduling):=20rename=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E2=86=92=E5=B9=B4=E5=BA=A6=E8=BE=BE=E6=A0=87,=20add=20sort=20b?= =?UTF-8?q?y=20=E5=AE=A2=E6=88=B7=E6=97=A5=E5=9D=87/=E5=B9=B4=E5=BA=A6?= =?UTF-8?q?=E8=BE=BE=E6=A0=87=20to=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/scheduling/SuggestionList.tsx | 139 +++++++++++++++------- 1 file changed, 93 insertions(+), 46 deletions(-) diff --git a/src/modules/scheduling/SuggestionList.tsx b/src/modules/scheduling/SuggestionList.tsx index 620e943..caa9ee2 100644 --- a/src/modules/scheduling/SuggestionList.tsx +++ b/src/modules/scheduling/SuggestionList.tsx @@ -1,4 +1,5 @@ -import { ArrowRightLeft, ChevronRight } from 'lucide-react'; +import { useState, useMemo } from 'react'; +import { ArrowRightLeft, ChevronRight, ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react'; import { motion } from 'motion/react'; import type { SchedulingSuggestion } from './types'; import Blur from '../../components/Blur'; @@ -12,7 +13,27 @@ function fmtRate(rate: number): string { return (rate * 100).toFixed(1) + '%'; } +type SortKey = 'default' | 'avgDaily' | 'completion'; +type SortDir = 'asc' | 'desc'; + export default function SuggestionList({ suggestions, onSelect }: Props) { + const [sortKey, setSortKey] = useState('default'); + const [sortDir, setSortDir] = useState('desc'); + + const toggleSort = (key: SortKey) => { + if (sortKey === key) { setSortDir(d => d === 'desc' ? 'asc' : 'desc'); } + else { setSortKey(key); setSortDir('desc'); } + }; + + const sorted = useMemo(() => { + if (sortKey === 'default') return suggestions; + return [...suggestions].sort((a, b) => { + const va = sortKey === 'avgDaily' ? a.currentVehicle.customerAvgDaily : a.currentVehicle.completionRate; + const vb = sortKey === 'avgDaily' ? b.currentVehicle.customerAvgDaily : b.currentVehicle.completionRate; + return sortDir === 'desc' ? vb - va : va - vb; + }); + }, [suggestions, sortKey, sortDir]); + if (suggestions.length === 0) { return (
@@ -23,55 +44,81 @@ export default function SuggestionList({ suggestions, onSelect }: Props) { } return ( -
- {suggestions.map((s, idx) => { - const isRescue = s.type === 'rescue_hopeless'; - const v = s.currentVehicle; +
+ {/* Sort controls */} +
+ + +
- return ( - onSelect(s)} - > - {/* Color bar */} -
+
+ {sorted.map((s, idx) => { + const isRescue = s.type === 'rescue_hopeless'; + const v = s.currentVehicle; - {/* Info */} -
-
- - {v.plateNumber} - - - {isRescue ? '里程低·换走' : '里程高·换下'} - - {v.vehicleType} - · - {v.region} + return ( + onSelect(s)} + > + {/* Color bar */} +
+ + {/* Info */} +
+
+ + {v.plateNumber} + + + {isRescue ? '里程低·换走' : '里程高·换下'} + + {v.vehicleType} + · + {v.region} +
+
+ {v.department && {v.department}} + {v.manager && {v.manager}} + {v.customer || '-'} + 日均 {Math.round(v.customerAvgDaily)} + 年度达标 = 1 ? 'text-emerald-600' : v.completionRate >= 0.5 ? 'text-amber-600' : 'text-rose-500'}`}>{fmtRate(v.completionRate)} +
-
- {v.department && {v.department}} - {v.manager && {v.manager}} - {v.customer || '-'} - 日均 {Math.round(v.customerAvgDaily)} - 完成 = 1 ? 'text-emerald-600' : v.completionRate >= 0.5 ? 'text-amber-600' : 'text-rose-500'}`}>{fmtRate(v.completionRate)} -
-
- {/* Right */} -
- 干预 - -
-
- ); - })} + {/* Right */} +
+ 干预 + +
+ + ); + })} +
); }