feat: focus hydrogen order drilldowns

This commit is contained in:
kkfluous
2026-08-07 17:22:46 +08:00
parent 18287a2c70
commit 70498fc4fa
2 changed files with 27 additions and 4 deletions
+22 -3
View File
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Building2, ChevronRight, Fuel, Plug, ReceiptText, TrendingUp, Truck, UserRound, X } from 'lucide-react';
import { motion, AnimatePresence } from 'motion/react';
import { BarChart, Bar, XAxis, YAxis, ResponsiveContainer, Cell, Tooltip, ReferenceLine } from 'recharts';
@@ -29,6 +29,8 @@ const VEHICLE_SCOPE_OPTIONS: readonly AnalysisScopeOption<CustomerType>[] = [
{ id: 'external', label: '外部车辆' },
];
const HYDROGEN_ORDERS_ID = 'hydrogen-orders';
export default function HydrogenDaily() {
const [drillContext, setDrillContext] = useState<HydrogenDrillContext>(() => (
parseHydrogenDrillContext(window.location.search)
@@ -48,6 +50,7 @@ export default function HydrogenDaily() {
const [rows, setRows] = useState<HydrogenDailyRow[] | null>(null);
const [error, setError] = useState<string | null>(null);
const [retryKey, setRetryKey] = useState(0);
const orderTriggerRef = useRef<HTMLElement | SVGElement | null>(null);
const effectiveRange = useMemo(() => normalizeDateRange(dateRange.start, dateRange.end), [dateRange.start, dateRange.end]);
const selectedStationId = drillContext.level === 'station' ? drillContext.stationId : undefined;
@@ -159,6 +162,10 @@ export default function HydrogenDaily() {
};
const openOrders = (date: string) => {
const activeElement = document.activeElement;
if (activeElement instanceof HTMLElement || activeElement instanceof SVGElement) {
orderTriggerRef.current = activeElement;
}
commitDrillContext({
...drillContext,
vehicleScope,
@@ -166,7 +173,15 @@ export default function HydrogenDaily() {
endDate: effectiveRange.end,
selectedDate: date,
orderPage: undefined,
}, 'push');
}, selectedDate === date ? 'replace' : 'push');
window.requestAnimationFrame(() => {
const orders = document.getElementById(HYDROGEN_ORDERS_ID);
orders?.focus({ preventScroll: true });
orders?.scrollIntoView({
behavior: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth',
block: 'start',
});
});
};
const closeOrders = () => {
@@ -178,6 +193,7 @@ export default function HydrogenDaily() {
selectedDate: undefined,
orderPage: undefined,
}, 'replace');
window.requestAnimationFrame(() => orderTriggerRef.current?.focus());
};
const changeOrderPage = useCallback((page: number, mode: 'push' | 'replace') => {
@@ -375,7 +391,8 @@ export default function HydrogenDaily() {
className={item.totalKg > 0 ? 'cursor-pointer outline-none focus:stroke-blue-700 focus:stroke-2' : undefined}
role={item.totalKg > 0 ? 'button' : undefined}
tabIndex={item.totalKg > 0 ? 0 : -1}
aria-pressed={item.totalKg > 0 ? selectedDate === item.date : undefined}
aria-expanded={item.totalKg > 0 ? selectedDate === item.date : undefined}
aria-controls={item.totalKg > 0 ? HYDROGEN_ORDERS_ID : undefined}
aria-label={`${item.date},加氢量 ${item.totalKg.toLocaleString('zh-CN', { maximumFractionDigits: 2 })} Kg${item.totalKg > 0 ? `,查看${orderScopeLabel}加氢订单` : ',无可下钻订单'}`}
onClick={item.totalKg > 0 ? () => openOrders(item.date) : undefined}
onKeyDown={item.totalKg > 0
@@ -457,6 +474,8 @@ export default function HydrogenDaily() {
disabled={r.totalKg <= 0}
className="ml-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-lg text-slate-400 hover:bg-blue-100 hover:text-blue-700 disabled:cursor-not-allowed disabled:opacity-25"
aria-label={`查看 ${r.date} 加氢订单`}
aria-expanded={selectedDate === r.date}
aria-controls={HYDROGEN_ORDERS_ID}
title="查看当日订单"
>
<ReceiptText size={13} />
+5 -1
View File
@@ -73,7 +73,11 @@ export default function HydrogenOrders({
: '';
return (
<section className="overflow-hidden rounded-lg border border-blue-100 bg-white shadow-sm">
<section
id="hydrogen-orders"
tabIndex={-1}
className="scroll-mt-3 overflow-hidden rounded-lg border border-blue-100 bg-white shadow-sm outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
>
<header className="flex items-start justify-between gap-3 border-b border-blue-100 bg-blue-50/60 px-3 py-3 md:px-4">
<div className="min-w-0">
<div className="flex items-center gap-2 text-xs font-black text-blue-800">