скрипт

This commit is contained in:
gorbenko.pavel
2026-08-17 13:19:43 +05:00
parent 364835eaf7
commit e2c7f96021
37 changed files with 377 additions and 198 deletions
@@ -35,14 +35,9 @@ import {
} from '../../shared/attachments/attachments.service';
import { effectiveUserEmail } from '../../shared/impersonation';
import { IRequestFormProps } from '../../models/types';
import { IFormData, EMPTY_DATA, SetField } from './model';
import {
saveTicketRequest,
setPlannerTaskId,
ticket1cApprovalService,
DATA_LIST_TITLE,
APPROVAL_LIST_TITLE
} from './submit';
import { approvalListTitle, dataListTitle } from '../../shared/listTitles';
import { FORM_ID, IFormData, EMPTY_DATA, SetField } from './model';
import { saveTicketRequest, setPlannerTaskId, ticket1cApprovalService } from './submit';
import { loadTicketRequest } from './load';
import { PlannerTicketService } from './services/plannerTicket.service';
import { getApplicantProfile } from './services/profile.service';
@@ -86,7 +81,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({ requestType, context, onCan
return;
}
let alive = true;
Promise.all([loadTicketRequest(editId), getAttachments(DATA_LIST_TITLE, editId)])
Promise.all([loadTicketRequest(editId), getAttachments(dataListTitle(FORM_ID), editId)])
.then(([loaded, atts]) => {
if (alive) {
setData(loaded.data);
@@ -193,7 +188,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({ requestType, context, onCan
if (requestId === undefined) {
return;
}
deleteAttachment(DATA_LIST_TITLE, requestId, fileName)
deleteAttachment(dataListTitle(FORM_ID), requestId, fileName)
.then(() => setExistingAttachments((prev) => prev.filter((a) => a.fileName !== fileName)))
.catch(() => undefined);
};
@@ -224,9 +219,9 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({ requestType, context, onCan
let attachments = existingAttachments;
if (files.length > 0) {
await uploadAttachments(DATA_LIST_TITLE, id, files);
await uploadAttachments(dataListTitle(FORM_ID), id, files);
setFiles([]);
attachments = await getAttachments(DATA_LIST_TITLE, id);
attachments = await getAttachments(dataListTitle(FORM_ID), id);
setExistingAttachments(attachments);
}
@@ -237,8 +232,8 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({ requestType, context, onCan
if (finalStatus === REQUEST_STATUS.onApproval) {
await notifyActiveStep(context, approval, id, {
requestTypeId: rtId,
dataListName: DATA_LIST_TITLE,
approvalListName: APPROVAL_LIST_TITLE
dataListName: dataListTitle(FORM_ID),
approvalListName: approvalListTitle(FORM_ID)
});
} else if (finalStatus === REQUEST_STATUS.approved) {
// Согласование не требуется для этого вида работ — сразу передаём в отдел 1С.
@@ -289,7 +284,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({ requestType, context, onCan
<FormCard
title={requestType.title}
subtitle="Категория: IT"
belowSubtitle={<InitiatorLine listTitle={DATA_LIST_TITLE} itemId={requestId} />}
belowSubtitle={<InitiatorLine listTitle={dataListTitle(FORM_ID)} itemId={requestId} />}
headerRight={
requestId || requestStatus ? (
<>
@@ -27,15 +27,10 @@ import {
REQUEST_STATUS
} from '../../shared/approval';
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
import { IFormData, EMPTY_DATA, SetField } from './model';
import { approvalListTitle, dataListTitle } from '../../shared/listTitles';
import { FORM_ID, IFormData, EMPTY_DATA, SetField } from './model';
import { loadTicketRequest } from './load';
import {
ticket1cApprovalService,
getPlannerTaskId,
setPlannerTaskId,
DATA_LIST_TITLE,
APPROVAL_LIST_TITLE
} from './submit';
import { ticket1cApprovalService, getPlannerTaskId, setPlannerTaskId } from './submit';
import { PlannerTicketService } from './services/plannerTicket.service';
import { PLANNER_PLAN_ID, PLANNER_BUCKET_NAME, PLANNER_REJECTED_BUCKET_NAME } from './config';
import { RequestSection } from './sections/RequestSection';
@@ -89,7 +84,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey }
const set: SetField = (key, value) => setData((prev) => ({ ...prev, [key]: value }));
const approverService = useMemo(
() => new ApproverService(ticket1cApprovalService(), DATA_LIST_TITLE),
() => new ApproverService(ticket1cApprovalService(), dataListTitle(FORM_ID)),
[]
);
const approval = useMemo(() => ticket1cApprovalService(), []);
@@ -105,7 +100,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey }
useEffect(() => {
let alive = true;
setLoading(true);
Promise.all([loadTicketRequest(itemId), getAttachments(DATA_LIST_TITLE, itemId)])
Promise.all([loadTicketRequest(itemId), getAttachments(dataListTitle(FORM_ID), itemId)])
.then(([loaded, files]) => {
if (alive) {
setData(loaded.data);
@@ -148,7 +143,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey }
const bucketName =
finalStatus === REQUEST_STATUS.rejected ? PLANNER_REJECTED_BUCKET_NAME : PLANNER_BUCKET_NAME;
const atts = await getAttachments(DATA_LIST_TITLE, itemId);
const atts = await getAttachments(dataListTitle(FORM_ID), itemId);
const taskId = await new PlannerTicketService(context).createTask({
planId: PLANNER_PLAN_ID,
bucketName,
@@ -179,8 +174,8 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey }
if (!requestTypeId) return;
notifyActiveStep(context, approval, itemId, {
requestTypeId,
dataListName: DATA_LIST_TITLE,
approvalListName: APPROVAL_LIST_TITLE
dataListName: dataListTitle(FORM_ID),
approvalListName: approvalListTitle(FORM_ID)
}).catch(() => undefined);
};
@@ -203,7 +198,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey }
<FormCard
title="Заявка в отдел 1С"
subtitle={`№${code || itemId}`}
belowSubtitle={<InitiatorLine listTitle={DATA_LIST_TITLE} itemId={itemId} />}
belowSubtitle={<InitiatorLine listTitle={dataListTitle(FORM_ID)} itemId={itemId} />}
headerRight={status ? <StatusBadge status={status} /> : undefined}
>
<FormModeProvider readOnly>
@@ -1,7 +1,6 @@
import { getSP } from '../../shared/pnp/pnpjs';
import { IFormData, EMPTY_DATA } from './model';
const LIST_TITLE = 'Заявка в отдел 1С — данные';
import { dataListTitle } from '../../shared/listTitles';
import { FORM_ID, IFormData, EMPTY_DATA } from './model';
// TaskName пишется/читается через системную колонку Title (см. provisioning.json/titleColumnName).
const SCALAR_FIELDS: (keyof IFormData)[] = [
@@ -18,7 +17,7 @@ export interface ILoadedRequest {
/** Прочитать заявку по id: модель формы + статус (для режима чтения). */
export async function loadTicketRequest(itemId: number): Promise<ILoadedRequest> {
const item = (await getSP()
.web.lists.getByTitle(LIST_TITLE)
.web.lists.getByTitle(dataListTitle(FORM_ID))
.items.getById(itemId)
.select(...SCALAR_FIELDS, 'Title', 'RequestStatus', 'RequestUniqueCode')()) as Record<string, unknown>;
@@ -1,8 +1,15 @@
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { RequestTypeId } from '../../models/types';
/**
* Данные формы «Заявка в отдел 1С». Ключи = internalName колонок SP-списка
* «Заявка в отдел 1С — данные».
* Тип заявки этой формы — ключ реестра форм (forms/registry.ts). Имена списков
* SharePoint выводятся из него, см. shared/listTitles.ts.
*/
export const FORM_ID: RequestTypeId = 'it-1c-ticket';
/**
* Данные формы «Заявка в отдел 1С». Ключи = internalName колонок списка данных
* этой формы (см. shared/listTitles.ts).
*/
export interface IFormData {
/** Пишется в системную колонку Title (см. provisioning.json/titleColumnName). */
@@ -1,10 +1,9 @@
import { getSP } from '../../shared/pnp/pnpjs';
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
import { buildRequestUniqueCode } from '../../shared/requestCode';
import { IFormData } from './model';
import { approvalListTitle, dataListTitle } from '../../shared/listTitles';
import { FORM_ID, IFormData } from './model';
export const DATA_LIST_TITLE = 'Заявка в отдел 1С — данные';
export const APPROVAL_LIST_TITLE = 'Заявка в отдел 1С — согласование';
// Префикс уникального кода заявки — буквенная метка «1С» вместо числового id
// типа заявки. Числовой RequestTypeId (для резолва маршрута/уведомлений)
// больше не хардкодится — см. useRequestTypeId в Form.tsx/View.tsx.
@@ -12,7 +11,7 @@ export const TICKET1C_CODE_PREFIX = '1С';
/** Экземпляр сервиса списка согласования этой формы. */
export function ticket1cApprovalService(): ApprovalListService {
return new ApprovalListService(APPROVAL_LIST_TITLE);
return new ApprovalListService(approvalListTitle(FORM_ID));
}
/** Поля элемента списка данных из модели формы. TaskName пишется в системную колонку Title. */
@@ -46,7 +45,7 @@ export async function saveTicketRequest(
approvers: IApproverToWrite[],
status: string
): Promise<ISaveResult> {
const list = getSP().web.lists.getByTitle(DATA_LIST_TITLE);
const list = getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
const item = buildItem(data, status);
let id: number;
@@ -73,12 +72,12 @@ export async function saveTicketRequest(
*/
export async function getPlannerTaskId(id: number): Promise<string | undefined> {
const item = (await getSP()
.web.lists.getByTitle(DATA_LIST_TITLE)
.web.lists.getByTitle(dataListTitle(FORM_ID))
.items.getById(id)
.select('PlannerTaskId')()) as { PlannerTaskId?: string };
return item.PlannerTaskId || undefined;
}
export async function setPlannerTaskId(id: number, taskId: string): Promise<void> {
await getSP().web.lists.getByTitle(DATA_LIST_TITLE).items.getById(id).update({ PlannerTaskId: taskId });
await getSP().web.lists.getByTitle(dataListTitle(FORM_ID)).items.getById(id).update({ PlannerTaskId: taskId });
}