From bce2283bf34d0efded0453f7111240f0817dd77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B8=D0=BC=D1=83=D1=80=20=D0=93=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D1=86=D0=BA=D0=B8=D0=B9?= Date: Wed, 7 Oct 2026 14:36:58 +0500 Subject: [PATCH] =?UTF-8?q?fix:=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BC=D0=B0=D1=80=D1=88=D1=80=D1=83=D1=82=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=BE=D1=80=D0=B3=D0=B0=D0=BD=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=B2=20=D0=B7=D0=B0=D1=8F=D0=B2=D0=BA?= =?UTF-8?q?=D0=B5=20=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B1=D0=BE=D1=87=D0=B5?= =?UTF-8?q?=D0=B5=20=D0=BC=D0=B5=D1=81=D1=82=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Форма не передавала в approval-route значения полей, только отдел, поэтому условные шаги («WorkplaceCompaniesJson содержит АСТЕЛ-К», «Organization содержит …», «Software содержит AutoCAD») считались неверно. Теперь передаются организации (имена через пробел, как в приёме и подборе) и «Необходимое ПО»; матрица пересчитывается при их смене. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../WorkplaceSetup/WorkplaceSetupForm.tsx | 25 ++++++++++---- .../forms/WorkplaceSetup/routeFields.ts | 33 +++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 src/webparts/requestPortal/forms/WorkplaceSetup/routeFields.ts diff --git a/src/webparts/requestPortal/forms/WorkplaceSetup/WorkplaceSetupForm.tsx b/src/webparts/requestPortal/forms/WorkplaceSetup/WorkplaceSetupForm.tsx index 9e9003e..3fcced6 100644 --- a/src/webparts/requestPortal/forms/WorkplaceSetup/WorkplaceSetupForm.tsx +++ b/src/webparts/requestPortal/forms/WorkplaceSetup/WorkplaceSetupForm.tsx @@ -34,8 +34,11 @@ import { isEditableStatus, IApproverToWrite, APPROVAL_PHASE, + IResolveFieldValue, unassignedStepMessage } from '../../shared/approval'; +import { useDebouncedQuery } from '../../shared/usePersistedQuery'; +import { routeFieldValues } from './routeFields'; import { uploadAttachments, getAttachments, @@ -165,6 +168,15 @@ const WorkplaceSetupForm: React.FC = ({ // data/requests.ts) → числовой RequestTypeId, нужный approval-route API. const requestTypeIdState = useRequestTypeId(context, requestType.id); const requestTypeId = requestTypeIdState.id; + // Условные шаги маршрута зависят от организаций и ПО (см. routeFields.ts). + // ПО — свободный текст: в маршрут уходит после паузы в наборе, а не на + // каждую букву. Сравниваем по содержимому — массив пересоздаётся на каждый рендер. + const softwareForRoute = useDebouncedQuery(data.Software); + const fieldValuesKey = JSON.stringify(routeFieldValues(data, softwareForRoute)); + const fieldValues = useMemo(() => JSON.parse(fieldValuesKey) as IResolveFieldValue[], [fieldValuesKey]); + // Отдел и поля условий влияют на резолв маршрута — их смена у НОВОЙ заявки перепланирует матрицу. + const matrixKey = `${userEmail}-${editId ?? 'new'}-${data.DepartmentId}-${fieldValuesKey}`; + // У новой заявки маршрут ПЛАНИРУЕТСЯ (resolve по внешнему API), у открытой на // редактирование — читается из уже записанных строк: их могли поправить // вручную при первом сохранении, и планирование затёрло бы эти правки. @@ -174,13 +186,12 @@ const WorkplaceSetupForm: React.FC = ({ ? approval .getMatrixForRequest(editId) .then((rows) => rows.filter((r) => r.phase !== APPROVAL_PHASE.execution)) - : getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Approval', data.DepartmentId), - [context, userEmail, approval, editId, data.DepartmentId, requestTypeId] + : getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Approval', data.DepartmentId, fieldValues), + [context, userEmail, approval, editId, data.DepartmentId, requestTypeId, fieldValues] ); const matrix = useMatrixEditor( loadMatrix, - // Отдел влияет на резолв маршрута — смена отдела у НОВОЙ заявки должна перепланировать матрицу. - `${userEmail}-${editId ?? 'new'}-${data.DepartmentId}`, + matrixKey, !readOnly, !!editId || !!requestTypeId, (login) => approval.getJobTitle(login) @@ -193,12 +204,12 @@ const WorkplaceSetupForm: React.FC = ({ ? approval .getMatrixForRequest(editId) .then((rows) => rows.filter((r) => r.phase === APPROVAL_PHASE.execution)) - : getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Execution', data.DepartmentId), - [context, userEmail, approval, editId, data.DepartmentId, requestTypeId] + : getPlannedMatrix(context, requestTypeId as number, userEmail, approval, 'Execution', data.DepartmentId, fieldValues), + [context, userEmail, approval, editId, data.DepartmentId, requestTypeId, fieldValues] ); const executors = useMatrixEditor( loadExecutors, - `${userEmail}-${editId ?? 'new'}-${data.DepartmentId}`, + matrixKey, canEditExecutors(context, readOnly), !!editId || !!requestTypeId, (login) => approval.getJobTitle(login) diff --git a/src/webparts/requestPortal/forms/WorkplaceSetup/routeFields.ts b/src/webparts/requestPortal/forms/WorkplaceSetup/routeFields.ts new file mode 100644 index 0000000..913db03 --- /dev/null +++ b/src/webparts/requestPortal/forms/WorkplaceSetup/routeFields.ts @@ -0,0 +1,33 @@ +import { IResolveFieldValue } from '../../shared/approval'; +import { COMPANIES_JSON_FIELD, IFormData } from './model'; + +/** + * Значения полей заявки для условных шагов маршрута (fieldValues при resolve). + * В админке approval-route условия заданы по internalName колонок: + * «WorkplaceCompaniesJson содержит АСТЕЛ-К», «Organization содержит …», + * «Software содержит AutoCAD». + * + * Организации — одной строкой, имена через пробел: бэкенд принимает только + * строку (массив → 400), а «содержит» ищет подстроку. Тот же формат, что в + * заявках на приём и подбор (см. RecruitingHireForm). + * + * Маршрут планируется при подаче, поэтому условие по Software сработает, + * только если «Необходимое ПО» указал сам инициатор (руководитель заполняет + * его позже, на своём шаге). + */ +export function routeFieldValues( + data: Pick, + software: string +): IResolveFieldValue[] { + const fieldValues: IResolveFieldValue[] = []; + const companyNames = data.Companies.map((c) => c.Name).sort().join(' '); + if (companyNames) { + fieldValues.push({ fieldName: COMPANIES_JSON_FIELD, value: companyNames }); + fieldValues.push({ fieldName: 'Organization', value: companyNames }); + } + const softwareText = software.trim(); + if (softwareText) { + fieldValues.push({ fieldName: 'Software', value: softwareText }); + } + return fieldValues; +}