переименование столбцов

This commit is contained in:
gorbenko.pavel
2026-08-10 15:18:00 +05:00
parent bba75b5ddd
commit 4cfb9a545d
12 changed files with 60 additions and 45 deletions
@@ -38,18 +38,22 @@ const OWN_REST_TOP = 200;
// ApproverOWSUSER в схеме поиска не находилось (разбирались 2026-08-06).
// Суффикс — тип исходного поля: OWSUSER для Person/Group.
const MP_APPROVER = 'TansuSiteApproverOWSUSER';
// Статус строки маршрута — Choice-поле, отсюда суффикс OWSCHCS (подтверждено
// отладочным перебором 2026-08-06; у Person-полей он OWSUSER, см. MP_APPROVER).
const MP_STATUS = 'RequestStatusOWSCHCS';
// Статус СТРОКИ МАРШРУТА (колонка ApprovalStatus списка «— согласование») —
// Choice-поле, отсюда суффикс OWSCHCS (подтверждено отладочным перебором
// 2026-08-06; у Person-полей он OWSUSER, см. MP_APPROVER). Колонку не путать с
// RequestStatus списка ДАННЫХ — это статус ЗАЯВКИ целиком, у него своя
// managed property (см. MP_TICKET_STATUS ниже).
const MP_STATUS = 'ApprovalStatusOWSCHCS';
// То же самое для Choice-колонки «Статус» списка ДАННЫХ (внутреннее имя Status,
// см. forms/*/provisioning.json) — по ней отбираются «Доработка» и фильтр по
// статусу в «Моих заявках». Кириллица в значении проблемы не создаёт: KQL — не
// $filter (там она действительно подводит, см. indexApprovalsForType), и по
// MP_STATUS выше точно так же ищутся русские статусы строк маршрута.
// То же самое для Choice-колонки «Статус» списка ДАННЫХ (внутреннее имя
// RequestStatus, см. forms/*/provisioning.json) — по ней отбираются
// «Доработка» и фильтр по статусу в «Моих заявках». Кириллица в значении
// проблемы не создаёт: KQL — не $filter (там она действительно подводит, см.
// indexApprovalsForType), и по MP_STATUS выше точно так же ищутся русские
// статусы строк маршрута.
// Если отбор по статусу вдруг начнёт стабильно возвращать 0 — проверять надо в
// первую очередь ЭТО имя в схеме поиска (см. предупреждение в searchOwnRequests).
const MP_TICKET_STATUS = 'StatusOWSCHCS';
const MP_TICKET_STATUS = 'RequestStatusOWSCHCS';
export function currentUserEmail(context: WebPartContext): string {
return (context.pageContext.user.email || '').toLowerCase();
@@ -99,11 +103,11 @@ const MY_TURN_STATUSES: string[] = [REQUEST_STATUS.onApproval, REQUEST_STATUS.on
// (иначе на клиенте нечем было посчитать «чья очередь»). Теперь очередь
// проставляется при создании/решении (см. approvalList.service.ts/createSteps,
// approverDecision.service.ts/decide) — «чья сейчас очередь» это просто
// значение колонки Status, поэтому здесь достаточно ОДНОГО отфильтрованного
// запроса: ApproverId (+ Status для 'myTurn'). Список согласования больше НЕ
// сканируется целиком, независимо от его размера.
// значение колонки ApprovalStatus, поэтому здесь достаточно ОДНОГО
// отфильтрованного запроса: ApproverId (+ ApprovalStatus для 'myTurn').
// Список согласования больше НЕ сканируется целиком, независимо от его размера.
//
// Заявку (Title/Status/Created) читаем сразу через expand по Lookup-полю
// Заявку (Title/RequestStatus/Created) читаем сразу через expand по Lookup-полю
// Ticket — отдельный запрос к списку данных нужен только за Author
// (двухуровневый expand Ticket/Author у SharePoint REST ненадёжен), и то —
// ТОЛЬКО для строк текущей страницы (см. hydrateAuthors ниже), а не для всего
@@ -227,7 +231,7 @@ export async function hydratePendingAuthors(
}
// Лёгкий индекс совпадающих заявок для одного типа: строки согласования по
// ApproverId → Title/Status/Created заявки отдельным запросом к списку ДАННЫХ
// ApproverId → Title/RequestStatus/Created заявки отдельным запросом к списку ДАННЫХ
// (НЕ через expand по Lookup-полю Ticket — SharePoint REST не отдаёт так
// произвольные поля связанного элемента, только через Person-поля вроде
// Author; попытка `expand('Ticket').select('Ticket/Status', ...)` падает с 400).
@@ -267,8 +271,8 @@ async function indexApprovalsForType(
// SharePoint REST — резолвим email в числовой Id пользователя (как и везде в
// проекте, см. ensureUser) и фильтруем по TansuSiteApproverId.
//
// RequestStatus в $filter НЕ используем: подтверждено на практике — фильтр
// вида `RequestStatus eq 'На согласовании'` (кириллица в $filter) молча
// ApprovalStatus в $filter НЕ используем: подтверждено на практике — фильтр
// вида `ApprovalStatus eq 'На согласовании'` (кириллица в $filter) молча
// возвращает 0 строк, даже когда без него те же строки находятся с этим же
// значением статуса. Поэтому фильтруем только по TansuSiteApproverId
// (числовое значение, проблем нет), а статус сравниваем в JS после
@@ -289,7 +293,7 @@ async function indexApprovalsForType(
const cutoffIso = new Date(Date.now() - RECENT_MS).toISOString();
const recentRows = (await approvalList.items
.filter(`TansuSiteApproverId eq ${approver.Id} and Modified ge '${cutoffIso}'`)
.select('Id', 'TicketId', 'RequestStatus')
.select('Id', 'TicketId', 'ApprovalStatus')
.top(2000)()) as Array<Record<string, unknown>>;
// Статусы уходят в KQL: сервер сразу отдаёт только нужные строки,
@@ -300,7 +304,7 @@ async function indexApprovalsForType(
// REST-довесок берётся по Modified без учёта статуса (кириллица в $filter
// ненадёжна, см. выше) — отбор по статусу делаем здесь, на клиенте.
stepRows = allRows.filter((r) => statuses.indexOf(r.RequestStatus as string) !== -1);
stepRows = allRows.filter((r) => statuses.indexOf(r.ApprovalStatus as string) !== -1);
} else {
// 'involved' — используется ТОЛЬКО для текстового поиска (см.
// getPendingApprovalIndex/searchMyRequests) — здесь важна не мгновенная
@@ -328,7 +332,7 @@ async function indexApprovalsForType(
stepRows.forEach((r) => {
const ticketId = r.TicketId as number | undefined;
if (ticketId && !stepStatusByTicket.has(ticketId)) {
stepStatusByTicket.set(ticketId, (r.RequestStatus as string) || '');
stepStatusByTicket.set(ticketId, (r.ApprovalStatus as string) || '');
}
});
if (ticketIds.length === 0) {
@@ -341,7 +345,7 @@ async function indexApprovalsForType(
const ticketFilter = ticketIds.map((id) => `Id eq ${id}`).join(' or ');
const ticketRows = (await list.items
.filter(ticketFilter)
.select('Id', 'Title', 'Status', 'Created')
.select('Id', 'Title', 'RequestStatus', 'Created')
.top(ticketIds.length)()) as Array<Record<string, unknown>>;
const rows = ticketRows.map((r) => ({
@@ -430,7 +434,7 @@ async function getInvolvedRowsViaSearch(
return (await approvalList.items
.filter(ids.map((id) => `Id eq ${id}`).join(' or '))
.select('Id', 'TicketId', 'RequestStatus')
.select('Id', 'TicketId', 'ApprovalStatus')
.top(ids.length)()) as Array<Record<string, unknown>>;
} catch (e) {
console.error(
@@ -573,7 +577,7 @@ async function loadByIds(
const rows = (await sp.web
.getList(type.listId as string)
.items.filter(ids.map((id) => `Id eq ${id}`).join(' or '))
.select('Id', 'Title', 'Status', 'Created', 'Author/EMail', 'Author/Title')
.select('Id', 'Title', 'RequestStatus', 'Created', 'Author/EMail', 'Author/Title')
.expand('Author')
.top(ids.length)()) as Array<Record<string, unknown>>;
rows.forEach((r) => {
@@ -599,7 +603,7 @@ async function getOwnRowsForType(context: WebPartContext, type: IRequestType): P
const rows = (await sp.web
.getList(type.listId as string)
.items.filter(`AuthorId eq ${me.Id}`)
.select('Id', 'Title', 'Status', 'Created', 'Author/EMail', 'Author/Title')
.select('Id', 'Title', 'RequestStatus', 'Created', 'Author/EMail', 'Author/Title')
.expand('Author')
.orderBy('Created', false)
.top(OWN_REST_TOP)()) as Array<Record<string, unknown>>;
@@ -861,7 +865,7 @@ function toMyRequest(
return {
id: r.Id as number,
title: (r.Title as string) || '',
status: (r.Status as string) || '',
status: (r.RequestStatus as string) || '',
authorEmail: author?.EMail || '',
authorName: author?.Title || '',
created: (r.Created as string) || '',