feat: поля вида «Изменение трудовой функции» в изменении условий ТД
Восьмой вид, ровно по шаблону ТЗ: дата изменения, «в связи с» свободным текстом (списка причин в ТЗ нет) и обязательная новая должностная инструкция — отдельный слот вложений. Инициатор — только руководитель. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -64,7 +64,8 @@ RequestTypeId» в `docs/forms.md`). Тип и маршрут в админке
|
||||
| Изменение места работы (другая местность) | `WorkplaceChange` | место работы «было → стало» парой **организация + проект**: текущая организация — из «Организации» сотрудника (только чтение, отдельно не хранится — это `EmployeeCompany`), текущий проект (`ProjectPicker`); новая организация (`Dictionary/Companies`, **обязательна при отправке**, не подставляется) и новый проект; адрес нового места, дата, причина (новый объект / переезд подразделения или работодателя / иное), условия переезда и компенсации; переключатель **«Вахта»** → «График работы» (тот же набор, что в подборе и приёме, «Другое» → ручной ввод; без вахты график очищается); обоснование |
|
||||
| Продление срока ТД | — | **пропущен** (2026-10-29): по ТЗ это автоматический запрос ОК за месяц до окончания срочного ТД (маршрут В), а не обычная заявка — решать отдельно |
|
||||
| Изменение режима / графика работы | `ScheduleChange` | по ролям строго по ТЗ. Общее: текущий график + текущее время работы (списки как в подборе/приёме, «Другое» → текст; `OptionWithOtherField`, наборы — `byType/workSchedule.ts`), дата начала, вложение «Новый график» (необязательно). **Работник:** неполный рабочий день (часов) / неполная рабочая неделя (дней) — одно или оба, текст заявления. **Работодатель:** новый режим (вахтовый / сменный / иной + описание), новые график и время работы, причина (специфика объекта / смещение сроков проекта — только из ТЗ), обоснование. Поля другой роли при сохранении очищаются |
|
||||
| Остальные 3 | — | ещё не разобраны с кадрами |
|
||||
| Изменение трудовой функции (без смены должности) | `FunctionChange` | ровно по шаблону ТЗ: дата изменения, «В связи с» (свободный текст — списка причин в ТЗ нет), вложение **«Новая должностная инструкция»** — обязательно. Инициатор — только руководитель |
|
||||
| Остальные 2 | — | ещё не разобраны с кадрами |
|
||||
|
||||
Обязательное по виду при отправке (инициатор, документы, принимающий руководитель,
|
||||
новая организация) — одна функция `byType/submitChecks.ts`; черновик сохраняется без них.
|
||||
|
||||
@@ -7,6 +7,7 @@ import { PositionTransferSection } from './PositionTransfer/PositionTransferSect
|
||||
import { DepartmentTransferSection } from './DepartmentTransfer/DepartmentTransferSection';
|
||||
import { WorkplaceChangeSection } from './WorkplaceChange/WorkplaceChangeSection';
|
||||
import { ScheduleChangeSection } from './ScheduleChange/ScheduleChangeSection';
|
||||
import { FunctionChangeSection } from './FunctionChange/FunctionChangeSection';
|
||||
|
||||
/**
|
||||
* Вид изменения → секция с его полями. Partial: поля видов добавляются по мере
|
||||
@@ -19,7 +20,8 @@ const SECTION_BY_TYPE: Partial<Record<ChangeType, React.FC<ISectionProps>>> = {
|
||||
'position-transfer': PositionTransferSection,
|
||||
'department-transfer': DepartmentTransferSection,
|
||||
'workplace-change': WorkplaceChangeSection,
|
||||
'schedule-change': ScheduleChangeSection
|
||||
'schedule-change': ScheduleChangeSection,
|
||||
'function-change': FunctionChangeSection
|
||||
};
|
||||
|
||||
/** Секции всех выбранных видов, в порядке выбора (сейчас вид один — см. MAX_CHANGE_TYPES). */
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import * as React from 'react';
|
||||
import { CollapseSection, FormField, TextInput, TextArea } from '../../../../shared/ui';
|
||||
import { useFormReadOnly } from '@tnsu/ui-kit';
|
||||
import { AttachmentSlotField } from '../../../../shared/attachments/AttachmentSlotField';
|
||||
import { CHANGE_TYPE_LABELS } from '../../changeTypes';
|
||||
import { ISectionProps } from '../../model';
|
||||
import { NEW_JOB_DESCRIPTION_ATTACHMENT } from './options';
|
||||
|
||||
/**
|
||||
* Поля вида «Изменение трудовой функции (без смены должности)». Ровно по шаблону
|
||||
* ТЗ: «прошу внести изменения в трудовую функцию работника согласно ДИ во
|
||||
* вложении с __.__.20__ в связи с ___ (текст)» — дата, «в связи с» (свободный
|
||||
* текст, списка причин в ТЗ нет) и обязательная новая ДИ. Инициатор — только
|
||||
* руководитель.
|
||||
*
|
||||
* Поля — прямо в CollapseSection, без FormGrid (тело секции само сетка).
|
||||
*/
|
||||
export const FunctionChangeSection: React.FC<ISectionProps> = ({ data, set, attachments }) => {
|
||||
const readOnly = useFormReadOnly();
|
||||
|
||||
return (
|
||||
<CollapseSection title={CHANGE_TYPE_LABELS['function-change']} icon="document">
|
||||
<FormField label="Дата изменения" htmlFor="FunctionChangeDate">
|
||||
<TextInput
|
||||
id="FunctionChangeDate"
|
||||
type="date"
|
||||
value={data.FunctionChangeDate}
|
||||
onChange={(v) => set('FunctionChangeDate', v)}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="В связи с" htmlFor="FunctionChangeReason" full>
|
||||
<TextArea
|
||||
id="FunctionChangeReason"
|
||||
value={data.FunctionChangeReason}
|
||||
onChange={(v) => set('FunctionChangeReason', v)}
|
||||
/>
|
||||
</FormField>
|
||||
{attachments && (
|
||||
<AttachmentSlotField
|
||||
label={NEW_JOB_DESCRIPTION_ATTACHMENT}
|
||||
editor={attachments}
|
||||
editable={!readOnly}
|
||||
groupKey={NEW_JOB_DESCRIPTION_ATTACHMENT}
|
||||
category={NEW_JOB_DESCRIPTION_ATTACHMENT}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
</CollapseSection>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Вложение «Новая должностная инструкция» — по ТЗ «приложить документ», обязательно.
|
||||
* Отдельная подпись от «Должностной инструкции» перевода на должность: это разные слоты.
|
||||
*/
|
||||
export const NEW_JOB_DESCRIPTION_ATTACHMENT = 'Новая должностная инструкция';
|
||||
@@ -4,6 +4,7 @@ import { IFormData } from '../model';
|
||||
import { ATTESTATION_ATTACHMENT, requiresAttestation } from './Allowance/options';
|
||||
import { JOB_DESCRIPTION_ATTACHMENT } from './PositionTransfer/options';
|
||||
import { NEW_SCHEDULE_ATTACHMENT } from './ScheduleChange/options';
|
||||
import { NEW_JOB_DESCRIPTION_ATTACHMENT } from './FunctionChange/options';
|
||||
|
||||
/**
|
||||
* Подписанный слот вложений по колонке ТЗ «Что приложить». Подпись (category)
|
||||
@@ -24,6 +25,9 @@ export function activeAttachmentSlots(data: IFormData): IAttachmentSlot[] {
|
||||
if (data.ChangeTypes.includes('position-transfer')) {
|
||||
slots.push({ category: JOB_DESCRIPTION_ATTACHMENT, required: true });
|
||||
}
|
||||
if (data.ChangeTypes.includes('function-change')) {
|
||||
slots.push({ category: NEW_JOB_DESCRIPTION_ATTACHMENT, required: true });
|
||||
}
|
||||
if (data.ChangeTypes.includes('schedule-change')) {
|
||||
// «Можно приложить документ» — необязательно.
|
||||
slots.push({ category: NEW_SCHEDULE_ATTACHMENT, required: false });
|
||||
|
||||
@@ -139,7 +139,9 @@ export async function loadContractChangeRequest(itemId: number, listId?: string)
|
||||
'ScheduleChangeNewHours',
|
||||
'ScheduleChangeNewHoursOther',
|
||||
'ScheduleChangeReason',
|
||||
'ScheduleChangeJustification'
|
||||
'ScheduleChangeJustification',
|
||||
'FunctionChangeDate',
|
||||
'FunctionChangeReason'
|
||||
)
|
||||
.expand('DepartmentTransferReceivingHead')()) as Record<string, unknown>;
|
||||
const receivingHead = item.DepartmentTransferReceivingHead as { EMail?: string } | undefined;
|
||||
@@ -200,7 +202,9 @@ export async function loadContractChangeRequest(itemId: number, listId?: string)
|
||||
ScheduleChangeNewHours: text(item.ScheduleChangeNewHours),
|
||||
ScheduleChangeNewHoursOther: text(item.ScheduleChangeNewHoursOther),
|
||||
ScheduleChangeReason: text(item.ScheduleChangeReason),
|
||||
ScheduleChangeJustification: text(item.ScheduleChangeJustification)
|
||||
ScheduleChangeJustification: text(item.ScheduleChangeJustification),
|
||||
FunctionChangeDate: spDateOnlyToIso(text(item.FunctionChangeDate)),
|
||||
FunctionChangeReason: text(item.FunctionChangeReason)
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -151,6 +151,13 @@ export interface IFormData {
|
||||
ScheduleChangeReason: string;
|
||||
/** Работодатель — обоснование, работник — текст заявления. */
|
||||
ScheduleChangeJustification: string;
|
||||
|
||||
// ── Вид «Изменение трудовой функции» (byType/FunctionChange). Только работодатель.
|
||||
// Поля необязательные; вложение «Новая должностная инструкция» — обязательно (attachmentSlots).
|
||||
/** С какой даты, ISO YYYY-MM-DD. */
|
||||
FunctionChangeDate: string;
|
||||
/** «В связи с ___ (текст)» из шаблона ТЗ — списка причин нет. */
|
||||
FunctionChangeReason: string;
|
||||
}
|
||||
|
||||
/** Обновление одного поля формы с сохранением типа значения. */
|
||||
@@ -219,7 +226,9 @@ export const EMPTY_DATA: IFormData = {
|
||||
ScheduleChangeNewHours: '',
|
||||
ScheduleChangeNewHoursOther: '',
|
||||
ScheduleChangeReason: '',
|
||||
ScheduleChangeJustification: ''
|
||||
ScheduleChangeJustification: '',
|
||||
FunctionChangeDate: '',
|
||||
FunctionChangeReason: ''
|
||||
};
|
||||
|
||||
/** Плейсхолдер для поля выбора сотрудника. */
|
||||
|
||||
@@ -106,6 +106,9 @@
|
||||
{ "internalName": "ScheduleChangeNewHours", "title": "Режим работы: новое время работы", "type": "Text" },
|
||||
{ "internalName": "ScheduleChangeNewHoursOther", "title": "Режим работы: новое время работы (другое)", "type": "Text" },
|
||||
{ "internalName": "ScheduleChangeReason", "title": "Режим работы: причина", "type": "Choice", "choices": ["Специфика объекта", "Смещение сроков проекта"] },
|
||||
{ "internalName": "ScheduleChangeJustification", "title": "Режим работы: обоснование / текст заявления", "type": "Note" }
|
||||
{ "internalName": "ScheduleChangeJustification", "title": "Режим работы: обоснование / текст заявления", "type": "Note" },
|
||||
|
||||
{ "internalName": "FunctionChangeDate", "title": "Трудовая функция: дата изменения", "type": "DateTime", "dateOnly": true },
|
||||
{ "internalName": "FunctionChangeReason", "title": "Трудовая функция: в связи с", "type": "Note" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -238,7 +238,11 @@ function buildItem(data: IFormData, status: string, receivingHeadId: number | un
|
||||
...positionTransferColumns(data),
|
||||
...departmentTransferColumns(data, receivingHeadId),
|
||||
...workplaceChangeColumns(data),
|
||||
...scheduleChangeColumns(data)
|
||||
...scheduleChangeColumns(data),
|
||||
...keepOrClear(data.ChangeTypes.includes('function-change'), {
|
||||
FunctionChangeDate: data.FunctionChangeDate,
|
||||
FunctionChangeReason: data.FunctionChangeReason
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user