fix(svod2): при поиске/фильтре на глубине total берётся из запасного offset=0, а не из долгого ответа за концом списка
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
eef358c56e
commit
ea6915c52f
@ -17,6 +17,7 @@ import {
|
||||
getVisiblePage,
|
||||
getWindowPages,
|
||||
getWindowRange,
|
||||
shouldFetchFirstPageFallback,
|
||||
shouldRefine,
|
||||
svod2PagingReducer,
|
||||
} from './svod2Paging';
|
||||
@ -59,7 +60,7 @@ export function useSvod2Pages({ sheet, year, orgIds, queryKey, search, columnFil
|
||||
if (mountedRef.current) setState(next);
|
||||
}, []);
|
||||
|
||||
const fetchPage = useCallback(async (ctx, pageIndex) => {
|
||||
const fetchPage = useCallback(async (ctx, pageIndex, signal = ctx.controller.signal) => {
|
||||
ctx.inflight.add(pageIndex);
|
||||
try {
|
||||
const response = await SummaryApi.getSvod2Page(
|
||||
@ -71,7 +72,7 @@ export function useSvod2Pages({ sheet, year, orgIds, queryKey, search, columnFil
|
||||
columnFilters: ctx.columnFilters,
|
||||
offset: pageIndex * PAGE_SIZE,
|
||||
}),
|
||||
{ signal: ctx.controller.signal },
|
||||
{ signal },
|
||||
);
|
||||
const rows = response.result || [];
|
||||
return { rows, total: response.total ?? rows.length };
|
||||
@ -138,14 +139,43 @@ export function useSvod2Pages({ sheet, year, orgIds, queryKey, search, columnFil
|
||||
|
||||
const loadPages = async () => {
|
||||
try {
|
||||
const first = await fetchPage(ctx, candidate);
|
||||
// Страница по прокрутке и (на глубине) запасная offset=0 летят параллельно: если страница по прокрутке
|
||||
// за концом нового списка, сервер отвечает на неё долго и без строк, а страница 0 уже даёт total.
|
||||
const candidateController = new AbortController();
|
||||
const zeroController = new AbortController();
|
||||
const abortRequests = () => {
|
||||
candidateController.abort();
|
||||
zeroController.abort();
|
||||
};
|
||||
ctx.controller.signal.addEventListener('abort', abortRequests);
|
||||
const settle = (request, index) =>
|
||||
request.then(
|
||||
(result) => ({ result, index }),
|
||||
(error) => ({ error, index }),
|
||||
);
|
||||
const candidateRequest = settle(fetchPage(ctx, candidate, candidateController.signal), candidate);
|
||||
const zeroRequest = candidate > 0 ? settle(fetchPage(ctx, 0, zeroController.signal), 0) : null;
|
||||
let answer = zeroRequest ? await Promise.race([candidateRequest, zeroRequest]) : await candidateRequest;
|
||||
if (
|
||||
answer.index === 0 &&
|
||||
candidate > 0 &&
|
||||
!answer.error &&
|
||||
shouldFetchFirstPageFallback({ candidate, total: answer.result.total })
|
||||
) {
|
||||
candidateController.abort();
|
||||
} else {
|
||||
zeroController.abort();
|
||||
answer = await candidateRequest;
|
||||
if (answer.error) throw answer.error;
|
||||
}
|
||||
if (ctx.controller.signal.aborted) return;
|
||||
const first = answer.result;
|
||||
const { total } = first;
|
||||
const pages = getWindowFor(total);
|
||||
const pageCount = getPageCount(total);
|
||||
let cache = new Map();
|
||||
if (total === 0 || candidate < pageCount) {
|
||||
const pageIndex = total === 0 ? 0 : candidate;
|
||||
if (total === 0 || answer.index < pageCount) {
|
||||
const pageIndex = total === 0 ? 0 : answer.index;
|
||||
dispatch({ type: 'page', sheet: sheetKey, generation, pageIndex, rows: first.rows, total, keepPages: pages });
|
||||
cache = stateRef.current[sheetKey].pages;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user