Заявление на увольнение (#15)
Tests / frontend-test (push) Successful in 1m17s

Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/15
This commit was merged in pull request #15.
This commit is contained in:
2026-08-26 07:07:03 +00:00
parent f751f03060
commit df29d080ed
39 changed files with 2460 additions and 46 deletions
@@ -412,6 +412,69 @@ export function routeUrl(route: IRoute): string {
return buildQuery(route);
}
/**
* АБСОЛЮТНАЯ ссылка на просмотр заявки — для того, что переживёт текущую сессию:
* колонка-гиперссылка в списке SharePoint, письмо, сообщение в чат.
*
* Отличается от routeUrl() двумя вещами, и обе важны именно для «хранимой» ссылки:
* она с origin (в списке относительный путь бесполезен — его открывают из
* представления SharePoint, а не со страницы портала) и без посторонних
* query-параметров текущей страницы (routeUrl их намеренно сохраняет, потому что
* это навигация ВНУТРИ открытой страницы).
*
* Страница портала берётся из адреса текущей — портал живёт на одной странице,
* другого способа узнать её путь у клиентского кода нет.
*/
export function requestLinkUrl(formKey: string, itemId: number, listId?: string): string {
const params = new URLSearchParams();
params.set('rpmode', 'approve');
params.set('rptype', formKey);
params.set('rpid', String(itemId));
if (listId) {
params.set('rplist', listId);
}
return `${window.location.origin}${window.location.pathname}?${params.toString()}`;
}
/**
* Открыть заявку по её АБСОЛЮТНОЙ ссылке (см. requestLinkUrl) БЕЗ перезагрузки
* страницы — если ссылка ведёт на эту же страницу портала.
*
* Зачем: страница SharePoint со SPFx грузится секунды, а ссылка между парными
* заявками (заявление на увольнение ↔ обходной лист) — это по сути та же страница
* с другими rp-параметрами, то есть ровно то, что умеет navigate(). Полная
* перезагрузка здесь ничего не даёт.
*
* Возвращает false, если ссылка ведёт куда-то ещё (другой сайт, другая страница,
* не на просмотр заявки) — тогда вызывающий НЕ должен подавлять клик и обязан
* дать браузеру перейти по ней обычным образом.
*/
export function navigateToRequestLink(url: string): boolean {
let target: URL;
try {
target = new URL(url, window.location.href);
} catch {
return false;
}
// Путь в SharePoint регистронезависим, а ссылка могла быть записана в список
// когда-то с другим регистром — сравниваем в нижнем.
if (
target.origin !== window.location.origin ||
target.pathname.toLowerCase() !== window.location.pathname.toLowerCase()
) {
return false;
}
const route = parseRoute(target.search);
if (route.mode !== 'approve' || !route.formKey || !route.itemId) {
return false;
}
// Раздел бокового меню берём ТЕКУЩИЙ, а не из ссылки: заявка показывается в
// панели поверх раздела, и уход по ссылке не должен переключать раздел под ней.
navigate({ ...route, nav: parseRoute().nav });
return true;
}
/** Текущий маршрут, реактивно обновляется по navigate() и кнопке «назад». */
export function useRoute(): IRoute {
const [route, setRoute] = React.useState<IRoute>(() => parseRoute());