Feature/request type access all requests (#22)
Tests / frontend-test (push) Successful in 1m24s
Tests / frontend-test (push) Successful in 1m24s
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/22
This commit was merged in pull request #22.
This commit is contained in:
@@ -41,7 +41,7 @@ export type PortalMode = 'submit' | 'approve' | 'create' | 'edit';
|
||||
* «Возвращена на доработку»); в отличие от первых двух смотрит
|
||||
* на список данных по автору, а не на строки маршрута.
|
||||
*/
|
||||
export type NavSection = 'new' | 'approvals' | 'execution' | 'rework' | 'own' | 'search' | 'reports';
|
||||
export type NavSection = 'new' | 'approvals' | 'execution' | 'rework' | 'own' | 'search' | 'reports' | 'allRequests';
|
||||
|
||||
/**
|
||||
* Подвкладка раздела «Мои заявки». 'created' — заявки, где пользователь автор
|
||||
@@ -90,6 +90,12 @@ export interface IRoute {
|
||||
ownTab?: OwnTab;
|
||||
/** Фильтр по статусу заявки; задан только при nav='own' и ownTab='created'. */
|
||||
ownStatus?: string;
|
||||
/**
|
||||
* Выбранный тип заявки в разделе «Все заявки» (nav='allRequests') — числовой
|
||||
* RequestTypeId approval-route. Не задан — раздел сам выберет тип (первый
|
||||
* доступный текущему пользователю, см. AllRequestsFeature).
|
||||
*/
|
||||
allTypeId?: number;
|
||||
/** Номер страницы таблицы (1-based). 1 — значение по умолчанию, в адрес не пишется. */
|
||||
page?: number;
|
||||
/** Текст поиска по таблице. Пустой — значение по умолчанию, в адрес не пишется. */
|
||||
@@ -283,6 +289,7 @@ function readStoredNav(): NavSection {
|
||||
raw === 'own' ||
|
||||
raw === 'search' ||
|
||||
raw === 'reports' ||
|
||||
raw === 'allRequests' ||
|
||||
raw === 'new'
|
||||
? raw
|
||||
: 'new';
|
||||
@@ -291,6 +298,37 @@ function readStoredNav(): NavSection {
|
||||
}
|
||||
}
|
||||
|
||||
// Выбранный тип заявки в разделе «Все заявки» — тем же приёмом, что и
|
||||
// подвкладка/фильтр «Моих заявок» (OWN_TAB_STORAGE_KEY выше): переживает
|
||||
// перезагрузку страницы и новый визит, но не более того. Без этого переход в
|
||||
// другой раздел и обратно (клик по пункту меню, без rpalltype в адресе)
|
||||
// каждый раз сбрасывал бы выбор на первый доступный тип.
|
||||
const ALL_TYPE_STORAGE_KEY = 'rp-all-type';
|
||||
|
||||
function readStoredAllTypeId(): number | undefined {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(ALL_TYPE_STORAGE_KEY);
|
||||
const id = Number(raw);
|
||||
return raw && Number.isInteger(id) && id > 0 ? id : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/** Запомненный тип «Все заявки» — как и storedOwnTab, нужен там, где маршрут СТРОИТСЯ. */
|
||||
export function storedAllTypeId(): number | undefined {
|
||||
return readStoredAllTypeId();
|
||||
}
|
||||
|
||||
/** Запомнить тип «Все заявки» — вызывать только при явном выборе пользователя. */
|
||||
export function persistAllTypeId(typeId: number): void {
|
||||
try {
|
||||
window.localStorage.setItem(ALL_TYPE_STORAGE_KEY, String(typeId));
|
||||
} catch {
|
||||
// localStorage недоступен (приватный режим и т.п.) — просто не сохраняем.
|
||||
}
|
||||
}
|
||||
|
||||
/** Запомнить раздел бокового меню — вызывать только при явном выборе пользователя. */
|
||||
export function persistNav(nav: NavSection): void {
|
||||
try {
|
||||
@@ -308,6 +346,7 @@ function parseNav(raw: string | undefined): NavSection {
|
||||
raw === 'own' ||
|
||||
raw === 'search' ||
|
||||
raw === 'reports' ||
|
||||
raw === 'allRequests' ||
|
||||
raw === 'new'
|
||||
) {
|
||||
return raw;
|
||||
@@ -347,6 +386,18 @@ export function parseRoute(search: string = window.location.search): IRoute {
|
||||
const ownTab = nav === 'own' ? parseOwnTab(params.get('rptab') ?? undefined) : undefined;
|
||||
const ownStatus = ownTab === 'created' ? params.get('rpstatus') ?? readStoredOwnStatus() : undefined;
|
||||
|
||||
// Тип заявки в разделе «Все заявки» — из адреса, иначе запомненный (та же
|
||||
// логика, что у ownTab/ownStatus выше). Если ни того, ни другого нет (первый
|
||||
// визит) — undefined, и раздел сам выберет первый доступный тип (см.
|
||||
// AllRequestsFeature), а как только он выберет — маршрут и localStorage
|
||||
// подхватят выбор (см. gotoAllRequestsType в RequestPortal.tsx).
|
||||
const allTypeIdParam = nav === 'allRequests' ? params.get('rpalltype') : null;
|
||||
const allTypeIdFromUrl = allTypeIdParam ? Number(allTypeIdParam) : NaN;
|
||||
const allTypeId =
|
||||
nav === 'allRequests'
|
||||
? (Number.isInteger(allTypeIdFromUrl) && allTypeIdFromUrl > 0 ? allTypeIdFromUrl : readStoredAllTypeId())
|
||||
: undefined;
|
||||
|
||||
// Страница: из адреса, иначе — запомненная для ЭТОЙ таблицы. Мусор в
|
||||
// параметре (0, минус, буквы) трактуем как первую страницу, а не как ошибку:
|
||||
// ссылка приходит извне, ронять из-за неё раздел незачем.
|
||||
@@ -362,11 +413,11 @@ export function parseRoute(search: string = window.location.search): IRoute {
|
||||
// страницей: закрыв панель, пользователь должен вернуться ровно в тот же
|
||||
// список и на то же место в нём.
|
||||
if (mode === 'approve' && formKey && itemId && !isNaN(itemId)) {
|
||||
return { mode: 'approve', nav, formKey, itemId, listId, ownTab, ownStatus, page, query };
|
||||
return { mode: 'approve', nav, formKey, itemId, listId, ownTab, ownStatus, allTypeId, page, query };
|
||||
}
|
||||
// Редактирование собственной незавершённой заявки — та же панель, но с формой.
|
||||
if (mode === 'edit' && formKey && itemId && !isNaN(itemId)) {
|
||||
return { mode: 'edit', nav, formKey, itemId, listId, ownTab, ownStatus, page, query };
|
||||
return { mode: 'edit', nav, formKey, itemId, listId, ownTab, ownStatus, allTypeId, page, query };
|
||||
}
|
||||
// Создание производной заявки с предзаполнением из исходной.
|
||||
if (formKey && sourceId && !isNaN(sourceId)) {
|
||||
@@ -383,7 +434,7 @@ export function parseRoute(search: string = window.location.search): IRoute {
|
||||
if (formKey && mode !== 'approve' && mode !== 'edit') {
|
||||
return { mode: 'create', nav: 'new', formKey, positionId, nomenclatureId, storeName };
|
||||
}
|
||||
return { mode: 'submit', nav, ownTab, ownStatus, page, query };
|
||||
return { mode: 'submit', nav, ownTab, ownStatus, allTypeId, page, query };
|
||||
}
|
||||
|
||||
// Собрать query-строку маршрута, сохранив посторонние параметры страницы.
|
||||
@@ -399,6 +450,7 @@ function buildQuery(route: IRoute): string {
|
||||
params.delete('rpstatus');
|
||||
params.delete('rppage');
|
||||
params.delete('rpq');
|
||||
params.delete('rpalltype');
|
||||
|
||||
if (route.nav !== 'new') {
|
||||
params.set('rpnav', route.nav);
|
||||
@@ -410,6 +462,9 @@ function buildQuery(route: IRoute): string {
|
||||
if (ownTab !== 'created') params.set('rptab', ownTab);
|
||||
else if (route.ownStatus) params.set('rpstatus', route.ownStatus);
|
||||
}
|
||||
if (route.nav === 'allRequests' && route.allTypeId) {
|
||||
params.set('rpalltype', String(route.allTypeId));
|
||||
}
|
||||
// Первая страница — тоже значение по умолчанию (см. выше про чистую ссылку).
|
||||
if (route.page && route.page > 1) params.set('rppage', String(route.page));
|
||||
if (route.query) params.set('rpq', route.query);
|
||||
|
||||
Reference in New Issue
Block a user