feat: убрано поле «Цель» из заявки на командировку

Поле убрано из формы, модели, чтения/записи и проверки. Колонка TripPurpose
убрана из манифеста; в уже созданном списке SP она остаётся с данными
тестовых заявок (провизионер колонки не удаляет).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-23 14:27:06 +05:00
parent cd7b27daa2
commit 6122370bbf
7 changed files with 4 additions and 16 deletions
@@ -97,7 +97,7 @@
## Секции формы ## Секции формы
EmployeeSection (сотрудник · должность · дата подачи · командирующая организация) → RouteSection (маршрут EmployeeSection (сотрудник · должность · дата подачи · командирующая организация) → RouteSection (маршрут
лентой + цель) → TasksSection (задачи) → EstimateSection (смета + итог) → лентой; поле «Цель» убрано 10-23, колонка `TripPurpose` в SP осталась от тестовых заявок) → TasksSection (задачи) → EstimateSection (смета + итог) →
ObligationSection (текст обязательства + согласие). ObligationSection (текст обязательства + согласие).
## Точки входа ## Точки входа
@@ -31,7 +31,6 @@ export async function loadBusinessTripRequest(itemId: number, listId?: string):
'TripCompany', 'TripCompany',
'TripCompanyId', 'TripCompanyId',
'TripRouteJson', 'TripRouteJson',
'TripPurpose',
'TripTasksJson', 'TripTasksJson',
'TripEstimateJson', 'TripEstimateJson',
'TripObligationAccepted', 'TripObligationAccepted',
@@ -52,7 +51,6 @@ export async function loadBusinessTripRequest(itemId: number, listId?: string):
TripCompany: (item.TripCompany as string) || '', TripCompany: (item.TripCompany as string) || '',
TripCompanyId: (item.TripCompanyId as string) || '', TripCompanyId: (item.TripCompanyId as string) || '',
Route: parseRoute(item.TripRouteJson), Route: parseRoute(item.TripRouteJson),
TripPurpose: (item.TripPurpose as string) || '',
Tasks: parseTasks(item.TripTasksJson), Tasks: parseTasks(item.TripTasksJson),
Estimate: parseEstimate(item.TripEstimateJson), Estimate: parseEstimate(item.TripEstimateJson),
TripObligationAccepted: item.TripObligationAccepted === true TripObligationAccepted: item.TripObligationAccepted === true
@@ -272,7 +272,6 @@ export interface IFormData {
TripCompanyId: string; TripCompanyId: string;
Route: ITripRoute; Route: ITripRoute;
TripPurpose: string;
/** Задание на командировку — список задач по порядку. */ /** Задание на командировку — список задач по порядку. */
Tasks: string[]; Tasks: string[];
@@ -308,8 +307,6 @@ export interface ISectionProps {
employee?: ITripEmployee; employee?: ITripEmployee;
} }
export const DEFAULT_PURPOSE = 'Производственная необходимость';
/** Первая точка новой заявки. id фиксированный: у новой заявки на неё ссылаются позиции сметы. */ /** Первая точка новой заявки. id фиксированный: у новой заявки на неё ссылаются позиции сметы. */
export const FIRST_STOP_ID = 'stop-1'; export const FIRST_STOP_ID = 'stop-1';
@@ -358,7 +355,6 @@ export const EMPTY_DATA: IFormData = {
TripCompany: '', TripCompany: '',
TripCompanyId: '', TripCompanyId: '',
Route: EMPTY_ROUTE, Route: EMPTY_ROUTE,
TripPurpose: DEFAULT_PURPOSE,
// Новая заявка сразу показывает одну пустую строку задачи — понятнее, что заполнять. // Новая заявка сразу показывает одну пустую строку задачи — понятнее, что заполнять.
Tasks: [''], Tasks: [''],
Estimate: EMPTY_ESTIMATE, Estimate: EMPTY_ESTIMATE,
@@ -20,7 +20,6 @@
{ "internalName": "TripStartDate", "title": "Командировка с", "type": "DateTime", "dateOnly": true }, { "internalName": "TripStartDate", "title": "Командировка с", "type": "DateTime", "dateOnly": true },
{ "internalName": "TripEndDate", "title": "Командировка по", "type": "DateTime", "dateOnly": true }, { "internalName": "TripEndDate", "title": "Командировка по", "type": "DateTime", "dateOnly": true },
{ "internalName": "TripDaysCount", "title": "Дней командировки", "type": "Number" }, { "internalName": "TripDaysCount", "title": "Дней командировки", "type": "Number" },
{ "internalName": "TripPurpose", "title": "Цель командировки", "type": "Note" },
{ "internalName": "TripTasks", "title": "Задание на командировку", "type": "Note" }, { "internalName": "TripTasks", "title": "Задание на командировку", "type": "Note" },
{ "internalName": "TripTasksJson", "title": "Задание на командировку (JSON)", "type": "Note" }, { "internalName": "TripTasksJson", "title": "Задание на командировку (JSON)", "type": "Note" },
@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import styles from './RouteSection.module.scss'; import styles from './RouteSection.module.scss';
import { CollapseSection, FormField, TextArea, useFormReadOnly } from '../../../shared/ui'; import { CollapseSection, useFormReadOnly } from '../../../shared/ui';
import { ISectionProps } from '../model'; import { ISectionProps } from '../model';
import { RouteEditor } from '../components/route/RouteEditor'; import { RouteEditor } from '../components/route/RouteEditor';
import { RouteScheme } from '../components/route/RouteScheme'; import { RouteScheme } from '../components/route/RouteScheme';
@@ -9,8 +9,8 @@ import { RouteViewMode, RouteViewSwitch } from '../components/route/RouteViewSwi
import { stopCardDomId } from '../components/route/RouteStopCard'; import { stopCardDomId } from '../components/route/RouteStopCard';
/** /**
* Куда и зачем: маршрут (города + объекты + даты) и цель командировки. Маршрут — * Куда едет сотрудник: маршрут (города + объекты + даты) в двух видах — «Форма»
* в двух видах: «Форма» для заполнения и «Схема» для просмотра. Заявитель * для заполнения и «Схема» для просмотра. Заявитель
* начинает с формы (он пришёл заполнять), согласующий — со схемы (ему важнее * начинает с формы (он пришёл заполнять), согласующий — со схемы (ему важнее
* увидеть маршрут целиком). * увидеть маршрут целиком).
*/ */
@@ -41,9 +41,6 @@ export const RouteSection: React.FC<ISectionProps> = ({ data, set, context }) =>
<RouteScheme route={data.Route} articles={data.Estimate} onSelectStop={openStopInForm} /> <RouteScheme route={data.Route} articles={data.Estimate} onSelectStop={openStopInForm} />
)} )}
</div> </div>
<FormField label="Цель" htmlFor="TripPurpose" required full>
<TextArea id="TripPurpose" value={data.TripPurpose} onChange={(v) => set('TripPurpose', v)} rows={2} />
</FormField>
</CollapseSection> </CollapseSection>
); );
}; };
@@ -46,7 +46,6 @@ function buildItem(data: IFormData, status: string, employeeId: number, employee
TripStartDate: period.start || null, TripStartDate: period.start || null,
TripEndDate: period.end || null, TripEndDate: period.end || null,
TripDaysCount: tripDays(period.start, period.end) ?? null, TripDaysCount: tripDays(period.start, period.end) ?? null,
TripPurpose: data.TripPurpose || null,
// Читаемая строка — для представлений списка; источник для формы — JSON. // Читаемая строка — для представлений списка; источник для формы — JSON.
TripTasks: formatTasks(data.Tasks) || null, TripTasks: formatTasks(data.Tasks) || null,
@@ -141,7 +141,6 @@ export function submitIssues(
issues.push({ field: 'TripCompany', label: 'Командирующая организация', message: 'выберите, от какой организации командировка' }); issues.push({ field: 'TripCompany', label: 'Командирующая организация', message: 'выберите, от какой организации командировка' });
} }
issues.push(...routeIssues(data.Route, today)); issues.push(...routeIssues(data.Route, today));
if (!data.TripPurpose.trim()) issues.push({ field: 'TripPurpose', label: 'Цель' });
if (filledTasks(data.Tasks).length === 0) { if (filledTasks(data.Tasks).length === 0) {
issues.push({ field: 'Tasks', label: 'Задание на командировку', message: 'добавьте хотя бы одну задачу' }); issues.push({ field: 'Tasks', label: 'Задание на командировку', message: 'добавьте хотя бы одну задачу' });
} }