feat: added optin to add delegant for executor and change delegant

This commit is contained in:
Тимур Городецкий
2026-08-10 13:55:05 +05:00
parent 3a15d83ded
commit 99f0946968
23 changed files with 407 additions and 40 deletions
@@ -177,6 +177,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
<DecisionPanel
service={approverService}
requestId={itemId}
search={(q) => approval.searchUsers(q)}
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
@@ -187,6 +188,16 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
approvalListName: APPROVAL_LIST_TITLE,
}).catch(() => undefined);
}}
onDelegated={() => {
// Шаг переназначен: активной стала строка делегата — обновляем
// матрицу и уведомляем нового активного участника.
setDecisionSeq((n) => n + 1);
notifyActiveStep(context, approval, itemId, {
requestTypeId: HIRE_REQUEST_TYPE_ID,
dataListName: DATA_LIST_TITLE,
approvalListName: APPROVAL_LIST_TITLE,
}).catch(() => undefined);
}}
/>
</div>
</div>
@@ -8,6 +8,7 @@
{ "internalName": "Comment", "title": "Комментарий", "type": "Note" },
{ "internalName": "StepOrder", "title": "Порядок", "type": "Number" },
{ "internalName": "AllowReassignToOtherApprovers", "title": "Можно перепоручать", "type": "Boolean" },
{ "internalName": "Phase", "title": "Фаза", "type": "Choice", "choices": ["Согласование", "Исполнение"] }
{ "internalName": "Phase", "title": "Фаза", "type": "Choice", "choices": ["Согласование", "Исполнение"] },
{ "internalName": "DelegatedBy", "title": "Кем переназначено", "type": "User", "userSelectionMode": "PeopleOnly" }
]
}
@@ -120,12 +120,13 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({ requestType, context,
? approval
.getMatrixForRequest(editId)
.then((rows) => rows.filter((r) => r.phase !== APPROVAL_PHASE.execution))
: getPlannedMatrix(context, WORKPLACE_REQUEST_TYPE_ID, userEmail, approval, 'Approval'),
[context, userEmail, approval, editId]
: getPlannedMatrix(context, WORKPLACE_REQUEST_TYPE_ID, userEmail, approval, 'Approval', data.DepartmentId),
[context, userEmail, approval, editId, data.DepartmentId]
);
const matrix = useMatrixEditor(
loadMatrix,
`${userEmail}-${editId ?? 'new'}`,
// Отдел влияет на резолв маршрута — смена отдела у НОВОЙ заявки должна перепланировать матрицу.
`${userEmail}-${editId ?? 'new'}-${data.DepartmentId}`,
!readOnly,
true,
(login) => approval.getJobTitle(login)
@@ -138,12 +139,12 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({ requestType, context,
? approval
.getMatrixForRequest(editId)
.then((rows) => rows.filter((r) => r.phase === APPROVAL_PHASE.execution))
: getPlannedMatrix(context, WORKPLACE_REQUEST_TYPE_ID, userEmail, approval, 'Execution'),
[context, userEmail, approval, editId]
: getPlannedMatrix(context, WORKPLACE_REQUEST_TYPE_ID, userEmail, approval, 'Execution', data.DepartmentId),
[context, userEmail, approval, editId, data.DepartmentId]
);
const executors = useMatrixEditor(
loadExecutors,
`${userEmail}-${editId ?? 'new'}`,
`${userEmail}-${editId ?? 'new'}-${data.DepartmentId}`,
false,
true,
(login) => approval.getJobTitle(login)
@@ -236,6 +236,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
<DecisionPanel
service={approverService}
requestId={itemId}
search={(q) => approval.searchUsers(q)}
onBeforeDecide={canEditFields ? saveReviewFields : undefined}
onDecided={(newStatus) => {
setStatus(newStatus);
@@ -247,6 +248,16 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
approvalListName: APPROVAL_LIST_TITLE,
}).catch(() => undefined);
}}
onDelegated={() => {
// Шаг переназначен: активной стала строка делегата — обновляем
// матрицу и уведомляем нового активного участника.
setDecisionSeq((n) => n + 1);
notifyActiveStep(context, approval, itemId, {
requestTypeId: WORKPLACE_REQUEST_TYPE_ID,
dataListName: DATA_LIST_TITLE,
approvalListName: APPROVAL_LIST_TITLE,
}).catch(() => undefined);
}}
/>
</div>
</div>
@@ -8,6 +8,7 @@
{ "internalName": "Comment", "title": "Комментарий", "type": "Note" },
{ "internalName": "StepOrder", "title": "Порядок", "type": "Number" },
{ "internalName": "AllowReassignToOtherApprovers", "title": "Можно перепоручать", "type": "Boolean" },
{ "internalName": "Phase", "title": "Фаза", "type": "Choice", "choices": ["Согласование", "Исполнение"] }
{ "internalName": "Phase", "title": "Фаза", "type": "Choice", "choices": ["Согласование", "Исполнение"] },
{ "internalName": "DelegatedBy", "title": "Кем переназначено", "type": "User", "userSelectionMode": "PeopleOnly" }
]
}
@@ -4,7 +4,7 @@ import { IFormData, EMPTY_DATA } from './model';
const LIST_TITLE = 'Организация рабочего места — данные';
const SCALAR_FIELDS: (keyof IFormData)[] = [
'FullName', 'NameLatin', 'Phone', 'Position', 'Department', 'WorkKind', 'Location', 'StartDate',
'FullName', 'NameLatin', 'Phone', 'Position', 'Department', 'DepartmentId', 'WorkKind', 'Location', 'StartDate',
'Software', 'AccessRights'
];
@@ -12,6 +12,8 @@ export interface IFormData {
Phone: string;
Position: string;
Department: string;
/** Id отдела из справочника (Dictionary/Departments); '' — если введён вручную без выбора из списка. */
DepartmentId: string;
WorkKind: string;
Location: string;
StartDate: string;
@@ -37,6 +39,7 @@ export const EMPTY_DATA: IFormData = {
Phone: '',
Position: '',
Department: '',
DepartmentId: '',
WorkKind: '',
Location: '',
StartDate: '',
@@ -9,6 +9,7 @@
{ "internalName": "Phone", "title": "Телефон", "type": "Text" },
{ "internalName": "Position", "title": "Должность", "type": "Text", "required": true },
{ "internalName": "Department", "title": "Отдел / участок", "type": "Text" },
{ "internalName": "DepartmentId", "title": "Id отдела (справочник)", "type": "Text" },
{ "internalName": "WorkKind", "title": "Вид работ", "type": "Text" },
{ "internalName": "Location", "title": "Местоположение", "type": "Text" },
{ "internalName": "StartDate", "title": "Дата приёма", "type": "DateTime", "dateOnly": true },
@@ -1,8 +1,9 @@
import * as React from 'react';
import { CollapseSection, FormField, TextInput, PhoneInput } from '../../../shared/ui';
import { DepartmentPicker } from '../../../shared/dictionary';
import { ISectionProps } from '../model';
export const EmployeeSection: React.FC<ISectionProps> = ({ data, set }) => (
export const EmployeeSection: React.FC<ISectionProps> = ({ data, set, context }) => (
<CollapseSection title="Сотрудник" icon="people">
<FormField label="Ф.И.О." htmlFor="FullName" required full>
<TextInput id="FullName" value={data.FullName} onChange={(v) => set('FullName', v)} />
@@ -17,7 +18,15 @@ export const EmployeeSection: React.FC<ISectionProps> = ({ data, set }) => (
<TextInput id="Position" value={data.Position} onChange={(v) => set('Position', v)} />
</FormField>
<FormField label="Отдел / участок" htmlFor="Department">
<TextInput id="Department" value={data.Department} onChange={(v) => set('Department', v)} />
<DepartmentPicker
id="Department"
context={context}
value={data.Department}
onChange={(name, id) => {
set('Department', name);
set('DepartmentId', id);
}}
/>
</FormField>
<FormField label="Вид работ" htmlFor="WorkKind">
<TextInput id="WorkKind" value={data.WorkKind} onChange={(v) => set('WorkKind', v)} />