у поиска нормальный роутинг
This commit is contained in:
@@ -97,6 +97,10 @@ const OWN_STATUS_STORAGE_KEY = 'rp-own-status';
|
||||
// уйдя со страницы 3 «Моих заявок» в «На согласовании», где страница всего
|
||||
// одна, пользователь попал бы в пустоту.
|
||||
const PAGE_STORAGE_PREFIX = 'rp-page:';
|
||||
// Текст поиска — тоже свой на каждую таблицу. Префикс НЕ меняем: под ним
|
||||
// поисковые запросы уже лежат (раньше их хранил хук usePersistedQuery), и
|
||||
// сохранённое у пользователей должно пережить переезд в маршрут.
|
||||
const QUERY_STORAGE_PREFIX = 'rp-search-query:';
|
||||
|
||||
/**
|
||||
* Ключ таблицы для запоминания страницы. Совпадает по смыслу с ListView в
|
||||
@@ -132,6 +136,34 @@ export function storedPageFor(nav: NavSection, ownTab?: OwnTab): number {
|
||||
return readStoredPage(viewKeyOf(nav, tab)) ?? 1;
|
||||
}
|
||||
|
||||
function readStoredQuery(viewKey: string): string {
|
||||
try {
|
||||
return window.localStorage.getItem(QUERY_STORAGE_PREFIX + viewKey) || '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/** Запомненный текст поиска таблицы — по тем же причинам, что и storedPageFor. */
|
||||
export function storedQueryFor(nav: NavSection, ownTab?: OwnTab): string {
|
||||
const tab = nav === 'own' ? ownTab ?? readStoredOwnTab() : undefined;
|
||||
return readStoredQuery(viewKeyOf(nav, tab));
|
||||
}
|
||||
|
||||
/** Запомнить текст поиска текущей таблицы. */
|
||||
export function persistQuery(route: IRoute, query: string): void {
|
||||
const viewKey = viewKeyOf(route.nav, route.ownTab);
|
||||
try {
|
||||
if (query) {
|
||||
window.localStorage.setItem(QUERY_STORAGE_PREFIX + viewKey, query);
|
||||
} else {
|
||||
window.localStorage.removeItem(QUERY_STORAGE_PREFIX + viewKey);
|
||||
}
|
||||
} catch {
|
||||
// localStorage недоступен (приватный режим и т.п.) — просто не сохраняем.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Запомнить страницу текущей таблицы. Ключ выводится из самого маршрута —
|
||||
* вызывающей стороне не нужно знать, как таблицы различаются между собой.
|
||||
@@ -248,22 +280,25 @@ export function parseRoute(search: string = window.location.search): IRoute {
|
||||
const page =
|
||||
Number.isInteger(pageRaw) && pageRaw > 1 ? pageRaw : readStoredPage(viewKeyOf(nav, ownTab)) ?? 1;
|
||||
|
||||
// Текст поиска — из адреса, иначе запомненный для этой же таблицы.
|
||||
const query = params.get('rpq') ?? readStoredQuery(viewKeyOf(nav, ownTab));
|
||||
|
||||
// Открытая заявка (панель поверх раздела) — при полном наборе параметров.
|
||||
// Раздел под панелью сохраняется целиком, вместе с подвкладкой, фильтром и
|
||||
// страницей: закрыв панель, пользователь должен вернуться ровно в тот же
|
||||
// список и на то же место в нём.
|
||||
if (mode === 'approve' && formKey && itemId && !isNaN(itemId)) {
|
||||
return { mode: 'approve', nav, formKey, itemId, ownTab, ownStatus, page };
|
||||
return { mode: 'approve', nav, formKey, itemId, ownTab, ownStatus, page, query };
|
||||
}
|
||||
// Редактирование собственной незавершённой заявки — та же панель, но с формой.
|
||||
if (mode === 'edit' && formKey && itemId && !isNaN(itemId)) {
|
||||
return { mode: 'edit', nav, formKey, itemId, ownTab, ownStatus, page };
|
||||
return { mode: 'edit', nav, formKey, itemId, ownTab, ownStatus, page, query };
|
||||
}
|
||||
// Создание производной заявки с предзаполнением из исходной.
|
||||
if (formKey && sourceId && !isNaN(sourceId)) {
|
||||
return { mode: 'create', nav: 'new', formKey, sourceId };
|
||||
}
|
||||
return { mode: 'submit', nav, ownTab, ownStatus, page };
|
||||
return { mode: 'submit', nav, ownTab, ownStatus, page, query };
|
||||
}
|
||||
|
||||
// Собрать query-строку маршрута, сохранив посторонние параметры страницы.
|
||||
@@ -277,6 +312,7 @@ function buildQuery(route: IRoute): string {
|
||||
params.delete('rptab');
|
||||
params.delete('rpstatus');
|
||||
params.delete('rppage');
|
||||
params.delete('rpq');
|
||||
|
||||
if (route.nav !== 'new') {
|
||||
params.set('rpnav', route.nav);
|
||||
@@ -290,6 +326,7 @@ function buildQuery(route: IRoute): string {
|
||||
}
|
||||
// Первая страница — тоже значение по умолчанию (см. выше про чистую ссылку).
|
||||
if (route.page && route.page > 1) params.set('rppage', String(route.page));
|
||||
if (route.query) params.set('rpq', route.query);
|
||||
if ((route.mode === 'approve' || route.mode === 'edit') && route.formKey && route.itemId) {
|
||||
params.set('rpmode', route.mode);
|
||||
params.set('rptype', route.formKey);
|
||||
@@ -307,9 +344,19 @@ function buildQuery(route: IRoute): string {
|
||||
* Перейти на другой маршрут без перезагрузки страницы (SPA): обновляет
|
||||
* query-параметры адресной строки через history.pushState и оповещает
|
||||
* useRoute() своим событием (popstate на pushState сам не срабатывает).
|
||||
*
|
||||
* replace=true заменяет текущую запись истории вместо добавления новой —
|
||||
* для набора текста в поиске: иначе каждая буква становилась бы отдельным
|
||||
* шагом «назад», и чтобы уйти со страницы, пришлось бы стереть весь запрос
|
||||
* по одному нажатию.
|
||||
*/
|
||||
export function navigate(route: IRoute): void {
|
||||
window.history.pushState({}, '', buildQuery(route));
|
||||
export function navigate(route: IRoute, options?: { replace?: boolean }): void {
|
||||
const url = buildQuery(route);
|
||||
if (options?.replace) {
|
||||
window.history.replaceState({}, '', url);
|
||||
} else {
|
||||
window.history.pushState({}, '', url);
|
||||
}
|
||||
window.dispatchEvent(new Event(ROUTE_CHANGE_EVENT));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user