feat: трудовой отпуск — не более 24 дней в одной заявке
Требование HR: ограничение на поле «Количество дней» и проверка при отправке с понятным сообщением. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -44,7 +44,7 @@ import {
|
||||
dataListTitle,
|
||||
dataListTitleForListId
|
||||
} from '../../shared/listTitles';
|
||||
import { FORM_ID, IFormData, EMPTY_DATA, SetField, MIN_NOTICE_DAYS } from './model';
|
||||
import { FORM_ID, IFormData, EMPTY_DATA, SetField, MIN_NOTICE_DAYS, MAX_DAYS } from './model';
|
||||
import { saveVacationRequest, vacationApprovalService } from './submit';
|
||||
import { loadVacationRequest } from './load';
|
||||
import { RequestSection } from './sections/RequestSection';
|
||||
@@ -202,17 +202,20 @@ const VacationForm: React.FC<IRequestFormProps> = ({
|
||||
// выбрать более раннюю дату, но проверяем и здесь на случай обхода UI.
|
||||
const minStartDate = isoDatePlusDays(MIN_NOTICE_DAYS);
|
||||
const isStartDateValid = !data.StartDate || data.StartDate >= minStartDate;
|
||||
const isDaysCountTooLarge = Number.isFinite(daysNum) && daysNum > MAX_DAYS;
|
||||
const isValid = !!(
|
||||
data.Employee &&
|
||||
data.StartDate &&
|
||||
isStartDateValid &&
|
||||
Number.isFinite(daysNum) &&
|
||||
daysNum > 0
|
||||
daysNum > 0 &&
|
||||
!isDaysCountTooLarge
|
||||
);
|
||||
const validate = (): string | undefined => {
|
||||
if (data.StartDate && !isStartDateValid) {
|
||||
return `Заявку на отпуск нужно подать не позднее чем за ${MIN_NOTICE_DAYS} дней до даты начала — минимально доступная дата: ${formatIsoDate(minStartDate)}.`;
|
||||
}
|
||||
if (isDaysCountTooLarge) return `Отпуск — не более ${MAX_DAYS} календарных дней в одной заявке.`;
|
||||
if (!isValid) return 'Заполните обязательные поля: сотрудник, дата начала, количество дней (> 0).';
|
||||
if (requestTypeIdState.error) return `Не удалось определить тип заявки: ${requestTypeIdState.error}`;
|
||||
if (!requestTypeId) return 'Тип заявки ещё определяется — подождите немного и повторите.';
|
||||
|
||||
@@ -80,5 +80,7 @@ export const EMPTY_DATA: IFormData = {
|
||||
export const EMPLOYEE_PLACEHOLDER = 'Начните вводить Ф.И.О. сотрудника…';
|
||||
/** Заявку нужно подавать не позднее чем за столько дней до даты начала отпуска. */
|
||||
export const MIN_NOTICE_DAYS = 7;
|
||||
/** Ежегодный трудовой отпуск — не более стольких календарных дней в одной заявке (требование HR). */
|
||||
export const MAX_DAYS = 24;
|
||||
/** Плейсхолдер для поля выбора замещающего. */
|
||||
export const SUBSTITUTE_PLACEHOLDER = 'Начните вводить Ф.И.О. замещающего…';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { FormGrid, FormField, TextInput, PeopleField, OrganizationTable } from '../../../shared/ui';
|
||||
import { ProjectPicker } from '../../../shared/dictionary';
|
||||
import { ISectionProps, EMPLOYEE_PLACEHOLDER, SUBSTITUTE_PLACEHOLDER, MIN_NOTICE_DAYS } from '../model';
|
||||
import { ISectionProps, EMPLOYEE_PLACEHOLDER, SUBSTITUTE_PLACEHOLDER, MIN_NOTICE_DAYS, MAX_DAYS } from '../model';
|
||||
import { isoDatePlusDays } from '../../../shared/dateUtils';
|
||||
|
||||
/** Единственная секция формы «Заявка на отпуск»: сотрудник (должность и подразделение подтягиваются из справочника), даты. */
|
||||
@@ -38,7 +38,14 @@ export const RequestSection: React.FC<ISectionProps> = ({ data, set, context, on
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="Количество дней" htmlFor="DaysCount" required>
|
||||
<TextInput id="DaysCount" type="number" value={data.DaysCount} onChange={(v) => set('DaysCount', v)} />
|
||||
<TextInput
|
||||
id="DaysCount"
|
||||
type="number"
|
||||
value={data.DaysCount}
|
||||
onChange={(v) => set('DaysCount', v)}
|
||||
min={1}
|
||||
max={MAX_DAYS}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="Лицо, замещающее на время отсутствия" htmlFor="Substitute" full>
|
||||
<PeopleField
|
||||
|
||||
Reference in New Issue
Block a user