- форматтер сумм: проверка числа до сдвига запятой, Intl.StringNumericLiteral (ES2023.Intl) вместо any, без разбора скобок; - запасные имена выгрузок xlsxFilename, отдельные флаги загрузки у двух «Экспорт»; - useNotificationApi мемоизирован, загрузки — useCallback, зависимости эффектов полные; - ячейки: расхождение в скобках, значок пропущенных строк ОСВ, «—» вместо выдуманного нуля; - «Год»/«Период» версии только для чтения; - сервис services/api/intercompanyMatrix.ts с withJsonBody, типы шахматки в types/api.ts, Account.kind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
45 lines
1.8 KiB
TypeScript
45 lines
1.8 KiB
TypeScript
/** Имя файла из Content-Disposition: `filename*=UTF-8''…` важнее `filename=`. */
|
||
export function filenameFromContentDisposition(header: string | null): string | null {
|
||
if (!header) {
|
||
return null;
|
||
}
|
||
const star = /filename\*\s*=\s*(?:UTF-8|utf-8)''([^;]+)/.exec(header);
|
||
if (star) {
|
||
try {
|
||
return decodeURIComponent(star[1].trim());
|
||
} catch {
|
||
return star[1].trim();
|
||
}
|
||
}
|
||
const plain = /filename\s*=\s*"?([^";]+)"?/.exec(header);
|
||
return plain ? plain[1].trim() : null;
|
||
}
|
||
|
||
const safeName = (name: string) => name.replace(/[\\/:*?"<>|\s]+/g, '_');
|
||
|
||
/** Запасное имя экспорта свода, если Content-Disposition недоступен. */
|
||
export function exportFilename(groupName: string, year: number, quarter: string): string {
|
||
return `Сводная_ОСВ_${safeName(groupName)}_${year}_${quarter}.xlsx`;
|
||
}
|
||
|
||
/** Запасное имя xlsx-выгрузки версии: `<префикс>_<ГК>_<год>_<квартал>.xlsx`, без карточки версии — `<префикс>.xlsx`. */
|
||
export function xlsxFilename(prefix: string, version: { groupName: string; year: number; quarter: string } | null): string {
|
||
if (!version) {
|
||
return `${prefix}.xlsx`;
|
||
}
|
||
return `${prefix}_${safeName(version.groupName)}_${version.year}_${version.quarter}.xlsx`;
|
||
}
|
||
|
||
/** Сохранить blob файлом через временную ссылку. */
|
||
export function saveBlob(blob: Blob, filename: string): void {
|
||
const url = URL.createObjectURL(blob);
|
||
const link = document.createElement('a');
|
||
link.href = url;
|
||
link.download = filename;
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
link.remove();
|
||
// не сразу: Safari/Firefox иначе могут оборвать скачивание
|
||
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
||
}
|