feat: persist hydrogen order pages

This commit is contained in:
kkfluous
2026-08-07 17:19:34 +08:00
parent d786b984bb
commit 18287a2c70
4 changed files with 49 additions and 12 deletions
+14
View File
@@ -117,6 +117,7 @@ export default function HydrogenDaily() {
startDate: nextRange.start,
endDate: nextRange.end,
selectedDate: undefined,
orderPage: undefined,
}, 'replace');
};
@@ -132,6 +133,7 @@ export default function HydrogenDaily() {
startDate: normalized.start,
endDate: normalized.end,
selectedDate: undefined,
orderPage: undefined,
}, 'replace');
};
@@ -142,6 +144,7 @@ export default function HydrogenDaily() {
vehicleScope: next,
startDate: effectiveRange.start,
endDate: effectiveRange.end,
orderPage: undefined,
}, 'replace');
};
@@ -162,6 +165,7 @@ export default function HydrogenDaily() {
startDate: effectiveRange.start,
endDate: effectiveRange.end,
selectedDate: date,
orderPage: undefined,
}, 'push');
};
@@ -172,9 +176,17 @@ export default function HydrogenDaily() {
startDate: effectiveRange.start,
endDate: effectiveRange.end,
selectedDate: undefined,
orderPage: undefined,
}, 'replace');
};
const changeOrderPage = useCallback((page: number, mode: 'push' | 'replace') => {
commitDrillContext({
...drillContext,
orderPage: page > 1 ? page : undefined,
}, mode);
}, [commitDrillContext, drillContext]);
const retryLoad = () => {
setRows(null);
setError(null);
@@ -388,9 +400,11 @@ export default function HydrogenDaily() {
<HydrogenOrders
date={selectedDate}
dailyRow={selectedDailyRow}
page={drillContext.orderPage ?? 1}
vehicleScope={vehicleScope}
stationId={selectedStationId}
customerName={selectedCustomerName}
onPageChange={changeOrderPage}
onClose={closeOrders}
/>
)}
+15 -9
View File
@@ -13,41 +13,47 @@ function fmtMoney(value: number): string {
export default function HydrogenOrders({
date,
dailyRow,
page,
vehicleScope,
stationId,
customerName,
onPageChange,
onClose,
}: {
date: string;
dailyRow?: HydrogenDailyRow;
page: number;
vehicleScope: CustomerType;
stationId?: number;
customerName?: string;
onPageChange: (page: number, mode: 'push' | 'replace') => void;
onClose: () => void;
}) {
const [page, setPage] = useState(1);
const [data, setData] = useState<HydrogenOrderResponse | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [retryKey, setRetryKey] = useState(0);
useEffect(() => {
setPage(1);
}, [vehicleScope, customerName, date, stationId]);
useEffect(() => {
let cancelled = false;
setLoading(true);
setError(null);
setData(null);
fetchHydrogenOrders({ date, customer: vehicleScope, stationId, customerName, page, limit: 20 })
.then(result => { if (!cancelled) setData(result); })
.then(result => {
if (cancelled) return;
if (page > result.totalPages) {
onPageChange(result.totalPages, 'replace');
return;
}
setData(result);
})
.catch(loadError => {
if (!cancelled) setError(loadError instanceof Error ? loadError.message : String(loadError));
})
.finally(() => { if (!cancelled) setLoading(false); });
return () => { cancelled = true; };
}, [vehicleScope, customerName, date, page, retryKey, stationId]);
}, [vehicleScope, customerName, date, onPageChange, page, retryKey, stationId]);
const totalPages = data?.totalPages ?? 1;
const scope = customerName
@@ -165,8 +171,8 @@ export default function HydrogenOrders({
<footer className="flex items-center justify-between border-t border-slate-100 px-3 py-3 md:px-4">
<span className="text-[10px] font-bold text-slate-400"> {page} / {totalPages} </span>
<div className="flex gap-2">
<button type="button" onClick={() => setPage(current => Math.max(1, current - 1))} disabled={page <= 1 || loading} className="flex h-8 w-8 items-center justify-center rounded-lg border border-slate-200 text-slate-500 disabled:opacity-30" aria-label="上一页加氢订单" title="上一页"><ChevronLeft size={14} /></button>
<button type="button" onClick={() => setPage(current => Math.min(totalPages, current + 1))} disabled={page >= totalPages || loading} className="flex h-8 w-8 items-center justify-center rounded-lg border border-slate-200 text-slate-500 disabled:opacity-30" aria-label="下一页加氢订单" title="下一页"><ChevronRight size={14} /></button>
<button type="button" onClick={() => onPageChange(Math.max(1, page - 1), 'push')} disabled={page <= 1 || loading} className="flex h-8 w-8 items-center justify-center rounded-lg border border-slate-200 text-slate-500 disabled:opacity-30" aria-label="上一页加氢订单" title="上一页"><ChevronLeft size={14} /></button>
<button type="button" onClick={() => onPageChange(Math.min(totalPages, page + 1), 'push')} disabled={page >= totalPages || loading} className="flex h-8 w-8 items-center justify-center rounded-lg border border-slate-200 text-slate-500 disabled:opacity-30" aria-label="下一页加氢订单" title="下一页"><ChevronRight size={14} /></button>
</div>
</footer>
) : null}
@@ -82,20 +82,30 @@ test('clears station parameters when returning to overview', () => {
assert.equal(url, '/energy?company=5&hydrogenScope=lingniu#hydrogen');
});
test('preserves a selected order date in the hydrogen analysis URL', () => {
test('preserves a selected order date and page in the hydrogen analysis URL', () => {
const context = parseHydrogenDrillContext(
'?hydrogenScope=lingniu&hydrogenStart=2026-08-01&hydrogenEnd=2026-08-07&hydrogenDate=2026-08-05',
'?hydrogenScope=lingniu&hydrogenStart=2026-08-01&hydrogenEnd=2026-08-07&hydrogenDate=2026-08-05&hydrogenPage=3',
);
assert.equal(context.selectedDate, '2026-08-05');
assert.equal(context.orderPage, 3);
assert.equal(
buildHydrogenDrillUrl(
{ pathname: '/energy', search: '?company=5', hash: '#hydrogen' },
context,
),
'/energy?company=5&hydrogenScope=lingniu&hydrogenStart=2026-08-01&hydrogenEnd=2026-08-07&hydrogenDate=2026-08-05#hydrogen',
'/energy?company=5&hydrogenScope=lingniu&hydrogenStart=2026-08-01&hydrogenEnd=2026-08-07&hydrogenDate=2026-08-05&hydrogenPage=3#hydrogen',
);
assert.equal(
parseHydrogenDrillContext('?hydrogenStart=2026-08-01&hydrogenEnd=2026-08-07&hydrogenDate=2026-08-08').selectedDate,
undefined,
);
assert.equal(parseHydrogenDrillContext('?hydrogenPage=3').orderPage, undefined);
assert.equal(parseHydrogenDrillContext('?hydrogenDate=2026-08-05&hydrogenPage=0').orderPage, undefined);
assert.equal(
buildHydrogenDrillUrl(
{ pathname: '/energy', search: '', hash: '#hydrogen' },
{ level: 'overview', vehicleScope: 'lingniu', orderPage: 3 },
),
'/energy?hydrogenScope=lingniu#hydrogen',
);
});
@@ -12,6 +12,7 @@ export interface HydrogenDrillContext {
startDate?: string;
endDate?: string;
selectedDate?: string;
orderPage?: number;
}
interface LocationParts {
@@ -74,6 +75,8 @@ export function parseHydrogenDrillContext(search: string): HydrogenDrillContext
const rangeEnd = startDate && endDate ? (startDate <= endDate ? endDate : startDate) : undefined;
if (selectedDate && (!rangeStart || !rangeEnd || (selectedDate >= rangeStart && selectedDate <= rangeEnd))) {
context.selectedDate = selectedDate;
const orderPage = positiveInteger(params.get('hydrogenPage'));
if (orderPage && orderPage > 1) context.orderPage = orderPage;
}
return context;
}
@@ -93,6 +96,7 @@ export function buildHydrogenDrillUrl(
'hydrogenStart',
'hydrogenEnd',
'hydrogenDate',
'hydrogenPage',
]) {
params.delete(key);
}
@@ -110,6 +114,9 @@ export function buildHydrogenDrillUrl(
if (context.startDate) params.set('hydrogenStart', context.startDate);
if (context.endDate) params.set('hydrogenEnd', context.endDate);
if (context.selectedDate) params.set('hydrogenDate', context.selectedDate);
if (context.selectedDate && context.orderPage && context.orderPage > 1) {
params.set('hydrogenPage', String(context.orderPage));
}
const query = params.toString();
return `${location.pathname}${query ? `?${query}` : ''}${location.hash}`;