fix(assets): emphasize daily flow details and sort newest first
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -48,7 +48,8 @@ function groupRows(rows: FlowDetailItem[], dimensions: Dimension[]): FlowGroup[]
|
|||||||
group.rows.push(row);
|
group.rows.push(row);
|
||||||
groups.set(key, group);
|
groups.set(key, group);
|
||||||
}
|
}
|
||||||
return Array.from(groups.values()).sort((a, b) => b.rows.length - a.rows.length || a.key.localeCompare(b.key, 'zh-CN'));
|
const dateIndex = dimensions.indexOf('date');
|
||||||
|
return Array.from(groups.values()).sort((a, b) => (dateIndex >= 0 ? b.values[dateIndex].localeCompare(a.values[dateIndex]) : 0) || b.rows.length - a.rows.length || a.key.localeCompare(b.key, 'zh-CN'));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FlowAnalysisModal(props: FlowAnalysisModalProps) {
|
export function FlowAnalysisModal(props: FlowAnalysisModalProps) {
|
||||||
@@ -68,7 +69,8 @@ function FlowAnalysisContent({ selectedFlow, selectedFlowDetails, setSelectedFlo
|
|||||||
useDialogFocus(true, dialog, close);
|
useDialogFocus(true, dialog, close);
|
||||||
|
|
||||||
const rows = useMemo(() => selectedFlowDetails.filter(row => matchesType(row, selectedFlow.type)
|
const rows = useMemo(() => selectedFlowDetails.filter(row => matchesType(row, selectedFlow.type)
|
||||||
&& ('date' in selectedFlow ? row.date === selectedFlow.date : row.date >= selectedFlow.start && row.date <= selectedFlow.end)), [selectedFlowDetails, selectedFlow]);
|
&& ('date' in selectedFlow ? row.date === selectedFlow.date : row.date >= selectedFlow.start && row.date <= selectedFlow.end))
|
||||||
|
.sort((a, b) => b.date.localeCompare(a.date) || (b.eventTime || '').localeCompare(a.eventTime || '')), [selectedFlowDetails, selectedFlow]);
|
||||||
const filterOptions = useMemo(() => Object.fromEntries(DIMENSIONS.map(({ key }) => {
|
const filterOptions = useMemo(() => Object.fromEntries(DIMENSIONS.map(({ key }) => {
|
||||||
const eligible = rows.filter(row => DIMENSIONS.every(({ key: other }) => other === key || !filters[other]?.length || filters[other]!.includes(dimensionValue(row, other))));
|
const eligible = rows.filter(row => DIMENSIONS.every(({ key: other }) => other === key || !filters[other]?.length || filters[other]!.includes(dimensionValue(row, other))));
|
||||||
const counts = new Map<string, number>();
|
const counts = new Map<string, number>();
|
||||||
@@ -79,7 +81,8 @@ function FlowAnalysisContent({ selectedFlow, selectedFlowDetails, setSelectedFlo
|
|||||||
const filteredRows = useMemo(() => rows.filter(row => DIMENSIONS.every(({ key }) => !filters[key]?.length || filters[key]!.includes(dimensionValue(row, key)))), [rows, filters]);
|
const filteredRows = useMemo(() => rows.filter(row => DIMENSIONS.every(({ key }) => !filters[key]?.length || filters[key]!.includes(dimensionValue(row, key)))), [rows, filters]);
|
||||||
const groups = useMemo(() => {
|
const groups = useMemo(() => {
|
||||||
const flat = groupRows(filteredRows, dimensions);
|
const flat = groupRows(filteredRows, dimensions);
|
||||||
return mergeActive ? orderDimensionGroups(flat, dimensions.length, group => group.values, group => group.rows.length) : flat;
|
return mergeActive ? orderDimensionGroups(flat, dimensions.length, group => group.values, group => group.rows.length, dimensions.includes('date') ? 'label' : 'count-desc',
|
||||||
|
(a, b, index) => dimensions[index] === 'date' ? b.values[index].localeCompare(a.values[index]) : a.values[index].localeCompare(b.values[index], 'zh-CN')) : flat;
|
||||||
}, [filteredRows, dimensions, mergeActive]);
|
}, [filteredRows, dimensions, mergeActive]);
|
||||||
const detailGroup = useMemo(() => detailKey === null ? null : groups.find(group => group.key === detailKey), [groups, detailKey]);
|
const detailGroup = useMemo(() => detailKey === null ? null : groups.find(group => group.key === detailKey), [groups, detailKey]);
|
||||||
const detailRows = detailGroup?.rows ?? EMPTY_FLOW_ROWS;
|
const detailRows = detailGroup?.rows ?? EMPTY_FLOW_ROWS;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CalendarDays, ChevronDown, Download, Loader2 } from 'lucide-react';
|
import { CalendarDays, ChevronDown, Download, ListFilter, Loader2 } from 'lucide-react';
|
||||||
import { AnimatePresence, motion } from 'motion/react';
|
import { AnimatePresence, motion } from 'motion/react';
|
||||||
import type { FlowType } from '../../api';
|
import type { FlowType } from '../../api';
|
||||||
import { FLOW_META } from '../FlowDetailModal';
|
import { FLOW_META } from '../FlowDetailModal';
|
||||||
@@ -65,18 +65,24 @@ export function FlowStatisticsCard({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
data-testid="asset-flow-daily-toggle"
|
data-testid="asset-flow-daily-toggle"
|
||||||
|
aria-expanded={flowDailyExpanded}
|
||||||
|
aria-controls="asset-flow-daily-details"
|
||||||
onClick={() => setFlowDailyExpanded((prev) => !prev)}
|
onClick={() => setFlowDailyExpanded((prev) => !prev)}
|
||||||
className="mt-2 flex w-full items-center justify-between rounded-xl border border-slate-100 bg-white px-3 py-1.5 text-[12px] font-black text-slate-500 transition hover:border-blue-100 hover:bg-blue-50/50 hover:text-blue-600"
|
className="mt-3 flex min-h-16 w-full items-center justify-between gap-3 rounded-xl border border-blue-200 bg-blue-50 px-4 py-3 text-left text-blue-700 shadow-sm transition hover:border-blue-400 hover:bg-blue-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||||
>
|
>
|
||||||
<span>{flowDailyExpanded ? '收起每日明细' : '展开每日明细'}</span>
|
<span className="flex min-w-0 items-center gap-3">
|
||||||
<span className="flex items-center gap-2 text-[11px] text-slate-400">
|
<span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-white text-blue-600"><ListFilter size={21} /></span>
|
||||||
{flowStats?.daily.length ?? 0} 天
|
<span><span className="block text-sm font-black">{flowDailyExpanded ? '收起每日明细' : '展开每日明细'}</span><span className="mt-0.5 block text-[11px] font-medium text-blue-600">查看每日交还车数量 · 最新日期在前</span></span>
|
||||||
<ChevronDown size={15} className={`transition-transform ${flowDailyExpanded ? 'rotate-180' : ''}`} />
|
</span>
|
||||||
|
<span className="flex shrink-0 items-center gap-2 text-xs font-bold">
|
||||||
|
<span className="rounded-lg bg-white px-2 py-1">{flowStats?.daily.length ?? 0} 天</span>
|
||||||
|
<ChevronDown size={20} className={`transition-transform ${flowDailyExpanded ? 'rotate-180' : ''}`} />
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<AnimatePresence initial={false}>
|
<AnimatePresence initial={false}>
|
||||||
{flowDailyExpanded && (
|
{flowDailyExpanded && (
|
||||||
<motion.div
|
<motion.div
|
||||||
|
id="asset-flow-daily-details"
|
||||||
initial={{ height: 0, opacity: 0 }}
|
initial={{ height: 0, opacity: 0 }}
|
||||||
animate={{ height: 'auto', opacity: 1 }}
|
animate={{ height: 'auto', opacity: 1 }}
|
||||||
exit={{ height: 0, opacity: 0 }}
|
exit={{ height: 0, opacity: 0 }}
|
||||||
|
|||||||
Reference in New Issue
Block a user