fix: внес изменения в заявках рекрутинга от 22.09.2026
Tests / frontend-test (push) Successful in 1m19s

This commit is contained in:
Тимур Городецкий
2026-09-22 12:38:40 +05:00
parent b6708a7e72
commit 64f53b7814
35 changed files with 836 additions and 124 deletions
@@ -28,7 +28,9 @@ import {
unassignedStepMessage,
resolveWriteListId,
APPROVAL_PHASE,
initialSubmitStatus
initialSubmitStatus,
resolveApproverOrgInfo,
canEditRoute
} from '../../shared/approval';
import {
uploadAttachments,
@@ -37,6 +39,7 @@ import {
IAttachmentInfo
} from '../../shared/attachments/attachments.service';
import { IRequestFormProps } from '../../models/types';
import { effectiveUserEmail } from '../../shared/impersonation';
import { getEmployeeOrganizations, formatEmployeeOrganizations } from '../../shared/dictionary';
import { friendlyErrorMessage } from '../../shared/diagnostics';
import {
@@ -82,6 +85,11 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
const readOnly = !isEditableStatus(requestStatus);
const set: SetField = (key, value) => setData((prev) => ({ ...prev, [key]: value }));
// Право удалять согласующих из маршрута ещё на этапе составления заявки —
// см. shared/approval/routeEditRights.ts (сейчас — Алтынай Бултурукова).
// Проверяем ТЕКУЩЕГО пользователя портала, а не выбранного «Рекомендателя»
// (data.Referrer) — это разные роли, заявку может составлять не сам рекомендатель.
const canRemoveApprover = canEditRoute(effectiveUserEmail(context));
// editListId уже проверен в EditFeature — если бы партиции не нашлось в реестре,
// форма сюда вообще не смонтировалась бы, поэтому referralApprovalService можно
@@ -210,7 +218,8 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
`${data.Referrer}-${editId ?? 'new'}`,
!readOnly,
!!editId || (!!data.Referrer && !!requestTypeId),
(login) => approval.getJobTitle(login)
(login) => approval.getJobTitle(login),
resolveApproverOrgInfo(context)
);
// Фаза исполнения: реальный исполнитель, назначаемый по маршруту (не
@@ -231,7 +240,8 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
`${data.Referrer}-${editId ?? 'new'}`,
false,
!!editId || (!!data.Referrer && !!requestTypeId),
(login) => approval.getJobTitle(login)
(login) => approval.getJobTitle(login),
resolveApproverOrgInfo(context)
);
// «Другое» в «откуда знаете» без уточнения — незаполненное поле по сути.
@@ -440,7 +450,11 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
{/* Блок остаётся видимым и пустым (не скрываем по noApprovalPhase) —
маршрут без согласующих не значит, что их нельзя добавить: матрица
редактируема, заявитель вправе вписать согласующего сам. */}
<ApprovalMatrix editor={matrix} search={(q) => approval.searchUsers(q)} />
<ApprovalMatrix
editor={matrix}
search={(q) => approval.searchUsers(q)}
canRemoveRow={canRemoveApprover ? () => true : undefined}
/>
{!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix
@@ -22,9 +22,14 @@ import {
notifyActiveStep,
useRequestTypeId,
APPROVAL_PHASE,
isApprovedStatus
isApprovedStatus,
resolveApproverOrgInfo,
canEditRoute,
REQUEST_STATUS,
IMatrixRow
} from '../../shared/approval';
import { getAttachments, IAttachmentInfo } from '../../shared/attachments/attachments.service';
import { effectiveUserEmail } from '../../shared/impersonation';
import { friendlyErrorMessage } from '../../shared/diagnostics';
import {
approvalListTitle,
@@ -74,6 +79,10 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
// Какая из организаций рекомендателя (см. OrganizationField) идёт в печать —
// выбор в тулбаре через PrintSplitButton, по умолчанию первая.
const [printOrgIndex, setPrintOrgIndex] = useState<number>(0);
// Право удалять согласующих из уже поданного маршрута — см.
// shared/approval/routeEditRights.ts (сейчас — Алтынай Бултурукова).
const canRemoveApprover = canEditRoute(effectiveUserEmail(context));
const [routeError, setRouteError] = useState<string | undefined>(undefined);
// listId уже проверен в ApproveFeature (не смонтировались бы сюда иначе) —
// referralApprovalService можно звать не опасаясь исключения.
@@ -97,7 +106,7 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
[approval, itemId]
);
const approvers = useMatrixEditor(loadApprovers, `a-${itemId}-${decisionSeq}`, false, true, (l) =>
approval.getJobTitle(l)
approval.getJobTitle(l), resolveApproverOrgInfo(context)
);
const loadExecutors = useCallback(
() =>
@@ -107,9 +116,19 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
[approval, itemId]
);
const executors = useMatrixEditor(loadExecutors, `e-${itemId}-${decisionSeq}`, false, true, (l) =>
approval.getJobTitle(l)
approval.getJobTitle(l), resolveApproverOrgInfo(context)
);
// Удалить ещё не решённый шаг маршрута (см. ApproverService.deleteQueuedStep).
const handleRemoveApprover = (row: IMatrixRow): void => {
if (!row.id) return;
setRouteError(undefined);
approverService
.deleteQueuedStep(itemId, row.id)
.then(() => setDecisionSeq((n) => n + 1))
.catch((e) => setRouteError(friendlyErrorMessage(e)));
};
useEffect(() => {
let alive = true;
setLoading(true);
@@ -199,7 +218,13 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
</div>
</FormCard>
<ApprovalMatrix editor={approvers} search={(q) => approval.searchUsers(q)} />
{routeError && <Alert variant="err">{routeError}</Alert>}
<ApprovalMatrix
editor={approvers}
search={(q) => approval.searchUsers(q)}
canRemoveRow={canRemoveApprover ? (row) => row.status === REQUEST_STATUS.queued : undefined}
onRemoveRow={handleRemoveApprover}
/>
{!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix