feat: добавил поле организация во все заявки, а также расширил компонет выбора даты для ui-kit

This commit is contained in:
Тимур Городецкий
2026-08-25 11:43:57 +05:00
parent a146877327
commit 3b4ee93b48
55 changed files with 641 additions and 143 deletions
@@ -27,6 +27,7 @@ import {
initialSubmitStatus
} from '../../shared/approval';
import { IRequestFormProps } from '../../models/types';
import { getEmployeeOrganizations, formatEmployeeOrganizations } from '../../shared/dictionary';
import { friendlyErrorMessage } from '../../shared/diagnostics';
import {
approvalListTitle,
@@ -94,9 +95,10 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [editId, editListId]);
// Новая заявка: рекомендатель — сам подающий (подставляем его, должность и
// подразделение из профиля SharePoint — SPS-JobTitle/SPS-Department, как в
// «Обходном листе»), дата подачи — сегодня.
// Новая заявка: рекомендатель — сам подающий (подставляем его; подразделение —
// из профиля SharePoint SPS-Department, как в «Обходном листе»; должность и
// организации — из Employee/ByEmail, см. shared/dictionary/
// employeeOrganizations.service.ts), дата подачи — сегодня.
useEffect(() => {
if (editId) {
return;
@@ -114,24 +116,35 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
if (alive) {
setData((prev) => ({
...prev,
ReferrerPosition: prev.ReferrerPosition || profile.jobTitle,
ReferrerDepartment: prev.ReferrerDepartment || profile.department
}));
}
})
.catch(() => undefined);
getEmployeeOrganizations(context, user.email)
.then((records) => {
if (!alive) return;
setData((prev) => ({
...prev,
ReferrerPosition: prev.ReferrerPosition || records[0]?.position || prev.ReferrerPosition,
Organization: formatEmployeeOrganizations(records)
}));
})
.catch(() => undefined);
return () => {
alive = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [editId]);
// Выбор другого рекомендателя подтягивает его должность и подразделение из
// профиля — оба поля остаются редактируемыми (фолбэк, если профиль не
// синхронизирован), поэтому не затираем то, что уже введено, пустым значением.
// Выбор другого рекомендателя подтягивает его подразделение из профиля,
// должность и организации — из Employee/ByEmail. Оба поля (Position/
// Department) остаются редактируемыми (фолбэк, если источник недоступен),
// поэтому не затираем то, что уже введено, пустым значением.
const handleReferrerChange = (login: string): void => {
setData((prev) => ({ ...prev, Referrer: login }));
if (!login) {
setData((prev) => ({ ...prev, Organization: '' }));
return;
}
approval
@@ -139,11 +152,19 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
.then((profile) =>
setData((prev) => ({
...prev,
ReferrerPosition: profile.jobTitle || prev.ReferrerPosition,
ReferrerDepartment: profile.department || prev.ReferrerDepartment
}))
)
.catch(() => undefined);
getEmployeeOrganizations(context, login)
.then((records) =>
setData((prev) => ({
...prev,
ReferrerPosition: records[0]?.position || prev.ReferrerPosition,
Organization: formatEmployeeOrganizations(records)
}))
)
.catch(() => undefined);
};
// Планируемый маршрут резолвится по e-mail РЕКОМЕНДАТЕЛЯ (кандидата в тенанте
@@ -29,6 +29,7 @@ export async function loadReferralRequest(itemId: number, listId?: string): Prom
'ReferrerPosition',
'ReferrerDepartment',
'ReferrerPhone',
'Organization',
'CandidateName',
'CandidatePhone',
'CandidateEmail',
@@ -62,6 +63,7 @@ export async function loadReferralRequest(itemId: number, listId?: string): Prom
ReferrerPosition: (item.ReferrerPosition as string) || '',
ReferrerDepartment: (item.ReferrerDepartment as string) || '',
ReferrerPhone: (item.ReferrerPhone as string) || '',
Organization: (item.Organization as string) || '',
CandidateName: (item.CandidateName as string) || '',
CandidatePhone: (item.CandidatePhone as string) || '',
CandidateEmail: (item.CandidateEmail as string) || '',
@@ -42,6 +42,12 @@ export interface IFormData {
ReferrerPosition: string;
ReferrerDepartment: string;
ReferrerPhone: string;
/**
* Организации рекомендателя (`\n`-joined «Компания — должность» на строку) —
* подтягивается автоматически из Employee/ByEmail при выборе Referrer,
* read-only (см. shared/ui/OrganizationField).
*/
Organization: string;
CandidateName: string;
CandidatePhone: string;
@@ -87,6 +93,7 @@ export const EMPTY_DATA: IFormData = {
ReferrerPosition: '',
ReferrerDepartment: '',
ReferrerPhone: '',
Organization: '',
CandidateName: '',
CandidatePhone: '',
CandidateEmail: '',
@@ -9,6 +9,7 @@
{ "internalName": "ReferrerPosition", "title": "Должность рекомендателя", "type": "Text" },
{ "internalName": "ReferrerDepartment", "title": "Подразделение / Объект рекомендателя", "type": "Text" },
{ "internalName": "ReferrerPhone", "title": "Контактный телефон рекомендателя", "type": "Text" },
{ "internalName": "Organization", "title": "Организация", "type": "Note" },
{ "internalName": "CandidateName", "title": "ФИО кандидата", "type": "Text", "required": true },
{ "internalName": "CandidatePhone", "title": "Контактный телефон кандидата", "type": "Text" },
@@ -1,5 +1,5 @@
import * as React from 'react';
import { CollapseSection, FormField, TextInput, PhoneInput, PeopleField } from '../../../shared/ui';
import { CollapseSection, FormField, TextInput, PhoneInput, PeopleField, OrganizationField } from '../../../shared/ui';
import { ISectionProps, REFERRER_PLACEHOLDER } from '../model';
/** Секция 1: кто рекомендует — дата подачи, сам рекомендатель и его контакты. */
@@ -31,6 +31,7 @@ export const ReferrerSection: React.FC<ISectionProps> = ({ data, set, context, o
placeholder="Подставится автоматически по выбранному сотруднику"
/>
</FormField>
<OrganizationField value={data.Organization} />
<FormField label="Контактный телефон" htmlFor="ReferrerPhone" required>
<PhoneInput id="ReferrerPhone" value={data.ReferrerPhone} onChange={(v) => set('ReferrerPhone', v)} />
</FormField>
@@ -33,6 +33,7 @@ function buildItem(data: IFormData, status: string, referrerId: number): Record<
ReferrerPosition: data.ReferrerPosition || null,
ReferrerDepartment: data.ReferrerDepartment || null,
ReferrerPhone: data.ReferrerPhone || null,
Organization: data.Organization || null,
CandidateName: data.CandidateName || null,
CandidatePhone: data.CandidatePhone || null,
CandidateEmail: data.CandidateEmail || null,