feat: подсветка незаполненных полей в заявке в отдел 1С
Проверки обязательных полей вынесены в validation.ts и показываются под полями через FieldIssuesProvider, как в приёме, подборе и отпуске: форма прокручивается к первому полю, над кнопками — кликабельный список. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@ import { useState, useMemo, useCallback, useEffect } from 'react';
|
||||
import styles from './Ticket1CForm.module.scss';
|
||||
import {
|
||||
Alert,
|
||||
FieldIssuesProvider,
|
||||
issueLabels,
|
||||
FormCard,
|
||||
InitiatorLine,
|
||||
FormModeProvider,
|
||||
@@ -49,7 +51,8 @@ import {
|
||||
dataListTitle,
|
||||
dataListTitleForListId
|
||||
} from '../../shared/listTitles';
|
||||
import { FORM_ID, IFormData, EMPTY_DATA, SetField, hasOtherDatabase } from './model';
|
||||
import { FORM_ID, IFormData, EMPTY_DATA, SetField } from './model';
|
||||
import { formIssues } from './validation';
|
||||
import { saveTicketRequest, ticket1cApprovalService } from './submit';
|
||||
import { loadTicketRequest } from './load';
|
||||
import { getApplicantProfile } from './services/profile.service';
|
||||
@@ -240,20 +243,11 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
||||
);
|
||||
const matrixEditor = useMemo(() => ({ ...matrix, rows: matrixRows }), [matrix, matrixRows]);
|
||||
|
||||
const isOtherDatabaseMissing = hasOtherDatabase(data) && !data.DB1COther.trim();
|
||||
const areRequiredFilled = !!(
|
||||
data.TaskName.trim() &&
|
||||
data.WorkType &&
|
||||
data.Organization &&
|
||||
data.DB1C.length > 0 &&
|
||||
data.Question.trim()
|
||||
);
|
||||
const isValid = areRequiredFilled && !isOtherDatabaseMissing;
|
||||
// Проблемы полей (см. validation.ts) подсвечиваются под полями через FieldIssuesProvider.
|
||||
const issues = formIssues(data);
|
||||
const isValid = issues.length === 0;
|
||||
const validate = (): string | undefined => {
|
||||
if (!areRequiredFilled) {
|
||||
return 'Заполните обязательные поля: наименование задачи, вид работ, организация, база 1С, вопрос.';
|
||||
}
|
||||
if (isOtherDatabaseMissing) return 'Выбрана база 1С «Другое» — укажите её название.';
|
||||
if (!isValid) return `Заполните или исправьте поля: ${issueLabels(issues)}.`;
|
||||
if (requestTypeIdState.error) return `Не удалось определить тип заявки: ${requestTypeIdState.error}`;
|
||||
if (!requestTypeId) return 'Тип заявки ещё определяется — подождите немного и повторите.';
|
||||
return undefined;
|
||||
@@ -391,7 +385,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FieldIssuesProvider draftIssues={issues} submitIssues={issues}>
|
||||
<button type="button" className={styles.back} onClick={onCancel}>
|
||||
<Icon name="arrow-left" size="sm" />
|
||||
<span>К списку заявок</span>
|
||||
@@ -486,7 +480,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
||||
submitLabel="Отправить"
|
||||
/>
|
||||
</FormCard>
|
||||
</div>
|
||||
</FieldIssuesProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { IFieldIssue } from '../../shared/ui';
|
||||
import { IFormData, hasOtherDatabase } from './model';
|
||||
|
||||
/** Название базы вручную обязательно, только если в «База 1С» отмечено «Другое». */
|
||||
function otherDatabaseIssue(data: IFormData): IFieldIssue | undefined {
|
||||
if (!hasOtherDatabase(data) || data.DB1COther.trim()) return undefined;
|
||||
return { field: 'DB1COther', label: 'Другая база 1С', message: 'выбрано «Другое» — укажите название базы' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Всё, что мешает сохранить или отправить заявку, в порядке формы (пусто — можно).
|
||||
* field — ключ FormField (htmlFor/fieldKey): по нему поле подсвечивается и к нему
|
||||
* прокручивается форма.
|
||||
*/
|
||||
export function formIssues(data: IFormData): IFieldIssue[] {
|
||||
const issues: Array<IFieldIssue | undefined> = [
|
||||
data.TaskName.trim() ? undefined : { field: 'TaskName', label: 'Наименование задачи' },
|
||||
data.WorkType ? undefined : { field: 'WorkType', label: 'Виды работ' },
|
||||
data.Organization ? undefined : { field: 'Organization', label: 'Организация' },
|
||||
data.DB1C.length > 0 ? undefined : { field: 'DB1C', label: 'База 1С' },
|
||||
otherDatabaseIssue(data),
|
||||
data.Question.trim() ? undefined : { field: 'Question', label: 'Вопрос' }
|
||||
];
|
||||
return issues.filter((issue): issue is IFieldIssue => issue !== undefined);
|
||||
}
|
||||
Reference in New Issue
Block a user