fix: папка файлов чата называется по RequestUniqueCode, а не formKey-id

Раньше папка в библиотеке «Файлы чата» называлась «clearance-form-42» —
это техническое имя ничего не говорит без открытого портала. Теперь имя
папки — тот же код заявки, что показан в её заголовке («13-2608-42»),
поэтому папку легко узнать прямо в библиотеке.
This commit is contained in:
gorbenko.pavel
2026-08-24 16:18:39 +05:00
parent bf4c4c517a
commit af8d39152e
2 changed files with 49 additions and 14 deletions
@@ -1,16 +1,21 @@
import '@pnp/sp/webs';
import '@pnp/sp/lists';
import '@pnp/sp/items';
import '@pnp/sp/folders';
import '@pnp/sp/files';
import type { IFolder } from '@pnp/sp/folders';
import { getSP } from '../pnp/pnpjs';
import { resolveDataList } from '../dataList';
import { CHAT_FILES_LIBRARY_TITLE } from '../listTitles';
import { RequestTypeId } from '../../models/types';
import { fileStamp, storedFileName } from './chatFileNames';
import { fileStamp, sanitizeFileName, storedFileName } from './chatFileNames';
/**
* Файлы, прикреплённые к сообщениям чата, — библиотека «Файлы чата» на сайте
* данных, папка на каждую заявку: «Файлы чата/<тип заявки>-<id>».
* данных, папка на каждую заявку: «Файлы чата/<RequestUniqueCode>», например
* «Файлы чата/13-2608-42» — тот же код, что показан в заголовке заявки (см.
* FormCard subtitle в <Форма>View.tsx). Так папку легко узнать в самой
* библиотеке, не открывая портал.
*
* Почему не вложения самой заявки (shared/attachments): вложения — это
* документы заявки, они попадают в её карточку и печать. Файл из переписки —
@@ -57,18 +62,41 @@ function chatLibraryRoot(): Promise<string> {
return libraryRootPromise;
}
/** Имя папки заявки в библиотеке. Тип заявки в имени — чтобы id разных типов не смешивались. */
function requestFolderName(formKey: RequestTypeId, itemId: number): string {
return `${formKey}-${itemId}`;
/**
* Имя папки заявки в библиотеке — RequestUniqueCode элемента.
*
* Код читаем из самого элемента, а не собираем строкой (formKey+itemId), чтобы
* папка называлась ровно тем номером, который видит пользователь на заявке.
* Код записывается сразу после создания элемента (см. saveRequestItem в
* shared/dataList.ts) и с этого момента не меняется, поэтому лишний раз его
* не кешируем: запрос — это одно select-поле, а не тяжёлая операция.
*
* Пустой код (гипотетическая гонка на только что созданной заявке) — откат на
* старую схему имени, чтобы папка всё равно нашлась однозначно.
*/
async function requestFolderName(
formKey: RequestTypeId,
itemId: number,
listId: string | undefined
): Promise<string> {
const item = (await resolveDataList(formKey, listId)
.items.getById(itemId)
.select('RequestUniqueCode')()) as { RequestUniqueCode?: string };
const code = (item.RequestUniqueCode || '').trim();
return sanitizeFileName(code || `${formKey}-${itemId}`);
}
/** Адрес папки заявки. Папки может ещё не существовать — для чтения ссылок это неважно. */
export async function chatFilesFolderUrl(
formKey: RequestTypeId,
itemId: number
itemId: number,
listId?: string
): Promise<string> {
const root = await chatLibraryRoot();
return `${root}/${requestFolderName(formKey, itemId)}`;
const [root, name] = await Promise.all([
chatLibraryRoot(),
requestFolderName(formKey, itemId, listId)
]);
return `${root}/${name}`;
}
/**
@@ -79,9 +107,15 @@ export async function chatFilesFolderUrl(
* addUsingPath с overwrite=true СНОСИТ содержимое — то есть все ранее
* приложенные к заявке файлы.
*/
async function ensureRequestFolder(formKey: RequestTypeId, itemId: number): Promise<IFolder> {
const root = await chatLibraryRoot();
const name = requestFolderName(formKey, itemId);
async function ensureRequestFolder(
formKey: RequestTypeId,
itemId: number,
listId: string | undefined
): Promise<IFolder> {
const [root, name] = await Promise.all([
chatLibraryRoot(),
requestFolderName(formKey, itemId, listId)
]);
const folder = getSP().web.getFolderByServerRelativePath(`${root}/${name}`);
const exists = await folder
@@ -106,11 +140,12 @@ async function ensureRequestFolder(formKey: RequestTypeId, itemId: number): Prom
export async function uploadChatFiles(
formKey: RequestTypeId,
itemId: number,
listId: string | undefined,
files: File[]
): Promise<string[]> {
if (files.length === 0) return [];
const folder = await ensureRequestFolder(formKey, itemId);
const folder = await ensureRequestFolder(formKey, itemId, listId);
const stamp = fileStamp(new Date());
const storedNames: string[] = [];
@@ -55,7 +55,7 @@ export async function getChatMessages(
// Адрес библиотеки спрашиваем, только если в переписке ЕСТЬ файлы: у заявки
// без вложений чат тогда вообще не зависит от библиотеки — ни лишнего
// запроса, ни падения, если её переименуют.
const folderUrl = hasAttachments(comments) ? await chatFilesFolderUrl(formKey, itemId) : '';
const folderUrl = hasAttachments(comments) ? await chatFilesFolderUrl(formKey, itemId, listId) : '';
return toChatMessages(comments, currentUserEmail, folderUrl);
}
@@ -73,6 +73,6 @@ export async function addChatMessage(
text: string,
files: File[] = []
): Promise<void> {
const storedNames = await uploadChatFiles(formKey, itemId, files);
const storedNames = await uploadChatFiles(formKey, itemId, listId, files);
await commentsOf(formKey, itemId, listId).add(buildCommentText(text, storedNames));
}