import { IHttpClient } from './httpClient'; import { CreateRequestTypeAccessInput, CreateRequestTypeInput, CreateTemplateRouteInput, CreateTemplateRouteStepInput, ManagedApprovalRow, ManagedApprovalRowApi, ManagedRequestMatrix, ManagedRequestMatrixApi, ManagedRequestPage, PatchRequestTypeInput, PatchTemplateRouteInput, PatchTemplateRouteStepInput, RequestListPartition, RequestType, RequestTypeAccess, RequestTypeListSeries, ResolveTemplateRouteQuery, ResolveTemplateRouteResult, TemplateRoute, TemplateRouteStep, UpdateRequestTypeInput, UpdateTemplateRouteInput, UpdateTemplateRouteStepInput, UserApprovalRow, UserApprovalRowApi } from '../models'; import { formatDateIso } from '../utils/date'; // Api-формы (dateIso, без отформатированного date) → формы, которыми пользуются // экраны (ManageRequestsScreen/ManageByUserScreen) — см. requestManage.ts/ // ManagedApprovalRowApi. Единственная разница — производное поле date. function toApprovalRow(r: ManagedApprovalRowApi): ManagedApprovalRow { return { ...r, date: formatDateIso(r.dateIso) }; } function toMatrix(m: ManagedRequestMatrixApi): ManagedRequestMatrix { return { ...m, rows: m.rows.map(toApprovalRow) }; } function toUserApprovalRow(r: UserApprovalRowApi): UserApprovalRow { return { ...r, date: formatDateIso(r.dateIso) }; } // Тонкий 1:1 фасад над контроллерами бэкенда: // backend/Tnsu.ApprovalRoute.Api/Controllers/{RequestTypes,TemplateRoutes,TemplateRouteSteps}Controller.cs export class ApprovalRouteApi { constructor(private readonly http: IHttpClient) {} public readonly requestTypes = { list: (): Promise => this.http.get('/api/request-types'), get: (id: number): Promise => this.http.get(`/api/request-types/${id}`), create: (body: CreateRequestTypeInput): Promise => this.http.post('/api/request-types', body), update: (id: number, body: UpdateRequestTypeInput): Promise => this.http.put(`/api/request-types/${id}`, body), patch: (id: number, body: PatchRequestTypeInput): Promise => this.http.patch(`/api/request-types/${id}`, body), remove: (id: number): Promise => this.http.delete(`/api/request-types/${id}`), // Серии партиций СРАЗУ по всем типам заявок (см. // ListPartitionService.ListAllAsync) — для дашборда (счётчик партиций) и // портала, которому нужен весь список адресов разом, а не по одному запросу // на тип. listsAll: (): Promise => this.http.get('/api/request-types/lists'), // Вся серия партиций ОДНОГО типа заявки (архив + текущая) — нужна экрану // редактирования заявок: заявка может лежать в любой из них, не только в // текущей (см. requestManageService.ts). lists: (requestTypeId: number): Promise => this.http.get(`/api/request-types/${requestTypeId}/lists`) }; // Доступ «видеть все заявки типа» (Application/RequestTypeAccesses/*.cs) — // тот же список email по типу, что и ручка для Power Automate // (GET .../{requestTypeId}/emails), только здесь читается ВЕСЬ реестр разом // (requestTypeId не передан) — админке нужна одна таблица по всем типам. public readonly requestTypeAccess = { list: (requestTypeId?: number): Promise => this.http.get('/api/request-type-access', { requestTypeId }), create: (body: CreateRequestTypeAccessInput): Promise => this.http.post('/api/request-type-access', body), remove: (id: number): Promise => this.http.delete(`/api/request-type-access/${id}`) }; public readonly templateRoutes = { list: (requestTypeId?: number): Promise => this.http.get('/api/template-routes', { requestTypeId }), get: (id: number): Promise => this.http.get(`/api/template-routes/${id}`), create: (body: CreateTemplateRouteInput): Promise => this.http.post('/api/template-routes', body), update: (id: number, body: UpdateTemplateRouteInput): Promise => this.http.put(`/api/template-routes/${id}`, body), patch: (id: number, body: PatchTemplateRouteInput): Promise => this.http.patch(`/api/template-routes/${id}`, body), remove: (id: number): Promise => this.http.delete(`/api/template-routes/${id}`), // POST, а не GET: запрос несёт список условий (fieldValues) переменной длины — // не ложится на плоскую query-строку (см. IHttpClient.QueryParams). resolve: (query: ResolveTemplateRouteQuery): Promise => this.http.post('/api/template-routes/resolve', query) }; public readonly templateRouteSteps = { list: (routeId: number): Promise => this.http.get(`/api/template-routes/${routeId}/steps`), get: (routeId: number, id: number): Promise => this.http.get(`/api/template-routes/${routeId}/steps/${id}`), create: (routeId: number, body: CreateTemplateRouteStepInput): Promise => this.http.post(`/api/template-routes/${routeId}/steps`, body), update: (routeId: number, id: number, body: UpdateTemplateRouteStepInput): Promise => this.http.put(`/api/template-routes/${routeId}/steps/${id}`, body), patch: (routeId: number, id: number, body: PatchTemplateRouteStepInput): Promise => this.http.patch(`/api/template-routes/${routeId}/steps/${id}`, body), remove: (routeId: number, id: number): Promise => this.http.delete(`/api/template-routes/${routeId}/steps/${id}`), // Сквозной поиск ПО ВСЕМ маршрутам разом (не вложен под конкретный routeId) — // для экрана «Заявки по согласующему» (ManageByUserScreen): шаги, где // исполнитель задан этим конкретным email, а не должностью/ролью. listByExecutorEmail: (executorEmail: string): Promise => this.http.get('/api/template-route-steps', { executorEmail }) }; // Чтение заявок и маршрутов согласования от имени ПРИЛОЖЕНИЯ (см. // backend/Tnsu.ApprovalRoute.Application/RequestManage/RequestManageService.cs) — // в отличие от остальных групп выше, это НЕ CRUD над сущностями самого API: // данные по-прежнему живут в списках SharePoint, которыми управляет // request-portal (см. requestManageService.ts), только читаются они теперь // не PnP-клиентом текущего пользователя, а этим бэкендом, поэтому видимость // заявок не зависит от прав администратора на списки SharePoint. public readonly requestManage = { search: (requestTypeId: number, query: string, page: number, pageSize = 20): Promise => this.http.get('/api/request-manage/search', { requestTypeId, query, page, pageSize }), matrix: (requestTypeId: number, listId: string, requestId: number): Promise => this.http .get('/api/request-manage/matrix', { requestTypeId, listId, requestId }) .then(toMatrix), byApprover: (approverEmail: string, activeStatuses: string[]): Promise => this.http .get('/api/request-manage/by-approver', { approverEmail, statuses: activeStatuses.join(',') }) .then(rows => rows.map(toUserApprovalRow)) }; }