feat: справочник компаний кэшируется в localStorage на 4 часа

Раньше он жил только пока открыта страница и загружался заново при каждой перезагрузке.
Теперь между перезагрузками API не дёргается 4 часа; просроченный, битый или записанный
«из будущего» кэш игнорируется и удаляется, недоступное хранилище кэш не ломает.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
gorbenko.pavel
2026-10-02 14:59:12 +05:00
parent 7f5f59fc81
commit cce4dfa4b3
3 changed files with 189 additions and 4 deletions
@@ -1,10 +1,11 @@
import { AadHttpClient, HttpClientResponse } from '@microsoft/sp-http';
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { APPROVAL_API_CLIENT_ID, DICTIONARY_API_BASE_URL } from '../config';
import { IStorageLike, readCachedCompanies, writeCachedCompanies } from './companiesCache';
import { ICompany } from './models/ICompany';
// GET /Dictionary/Companies — справочник компаний, ответ — плоский массив
// { Id, Name } (без обёртки, как /Dictionary/Departments).
// { Id, Name, Bin } (без обёртки, как /Dictionary/Departments).
async function fetchCompanies(context: WebPartContext): Promise<ICompany[]> {
const client = await context.aadHttpClientFactory.getClient(APPROVAL_API_CLIENT_ID);
const response: HttpClientResponse = await client.get(
@@ -17,12 +18,33 @@ async function fetchCompanies(context: WebPartContext): Promise<ICompany[]> {
return response.json();
}
// Справочник в рамках сессии не меняется — грузим один раз и отдаём тот же
// промис повторным вызовам (как в departments.service).
/** localStorage, если он есть: в некоторых режимах браузера обращение к нему бросает исключение. */
function browserStorage(): IStorageLike | undefined {
try {
return window.localStorage;
} catch {
return undefined;
}
}
async function loadCompanies(context: WebPartContext): Promise<ICompany[]> {
const storage = browserStorage();
const cached = storage ? readCachedCompanies(storage, Date.now()) : undefined;
if (cached) return cached;
const fresh = await fetchCompanies(context);
if (storage) writeCachedCompanies(storage, fresh, Date.now());
return fresh;
}
// Справочник живёт в localStorage 4 часа (см. companiesCache.ts) — между перезагрузками страницы
// к API не ходим. Поверх этого один промис на сессию: параллельные вызовы делят один запрос и не
// читают хранилище заново (как в departments.service). Ошибку не кешируем — следующий вызов
// попробует ещё раз.
let cache: Promise<ICompany[]> | undefined;
export function getCompanies(context: WebPartContext): Promise<ICompany[]> {
if (!cache) {
cache = fetchCompanies(context).catch((e) => {
cache = loadCompanies(context).catch((e) => {
cache = undefined;
throw e;
});