fix: в заголовке заявковк на чтение теперь показывает правильный номер

This commit is contained in:
Тимур Городецкий
2026-08-26 16:38:10 +05:00
parent 418e30dfc3
commit 488d3b20da
27 changed files with 118 additions and 28 deletions
@@ -45,7 +45,8 @@ const ClearanceForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [requestId, setRequestId] = useState<number | undefined>(editId);
@@ -77,6 +78,7 @@ const ClearanceForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
}
})
.catch((e) => {
@@ -39,6 +39,8 @@ interface IClearanceViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
type SaveState = 'idle' | 'saving' | 'saved' | 'error';
@@ -46,7 +48,7 @@ type SaveState = 'idle' | 'saving' | 'saved' | 'error';
// Обходной лист в режиме согласующего. Форма read-only, КРОМЕ отметок, которые
// заполняет профильный отдел на своём шаге: КДП — карта СКУД и сумма обучения,
// отдел подбора — парковочная карта (см. approverRights.ts).
const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey, listId }) => {
const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -113,6 +115,7 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setError(null);
setLoading(false);
setLockedWriteOffs(
@@ -45,7 +45,8 @@ const DismissalForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [requestId, setRequestId] = useState<number | undefined>(editId);
@@ -81,6 +82,7 @@ const DismissalForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
}
})
.catch((e) => {
@@ -48,12 +48,14 @@ interface IDismissalViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
// Заявление на увольнение только для просмотра (режим согласующего).
// Переиспользует ту же секцию, что и форма подачи; редактирование выключено через
// <FormModeProvider readOnly> — поля сами становятся неизменяемыми.
const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey, listId }) => {
const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -92,6 +94,7 @@ const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setError(null);
setLoading(false);
}
@@ -67,7 +67,8 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
// Вложения — три зоны: удостоверение, резюме и прочие (см. attachmentCategories.ts).
@@ -100,6 +101,7 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
setExistingAttachments(atts);
}
})
@@ -41,6 +41,8 @@ interface IRecruitingHireViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
// Ключ формы «Организация рабочего места» в реестре (data/requests) — цель
@@ -53,7 +55,7 @@ const NOOP_SET: SetField = () => undefined;
// Заявка «на прием» только для просмотра (режим согласующего).
// Переиспользует те же секции, что и форма подачи; редактирование выключено
// через <FormModeProvider readOnly> — поля сами становятся неизменяемыми.
const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemId, formKey, listId }) => {
const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -114,6 +116,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setAttachments(files);
setError(null);
setLoading(false);
@@ -113,7 +113,6 @@ export const HIRE_TYPE_OPTIONS: ISelectOption[] = [
/** Варианты «Испытательный срок» — самые частые сроки (совпадают с choices колонки ProbationPeriod). */
export const PROBATION_PERIOD_OPTIONS: ISelectOption[] = [
{ value: 'Без испытательного срока', label: 'Без испытательного срока' },
{ value: '1 месяц', label: '1 месяц' },
{ value: '2 месяца', label: '2 месяца' },
{ value: '3 месяца', label: '3 месяца' },
@@ -31,7 +31,7 @@
{ "internalName": "PpeClothingSize", "title": "СИЗ: размер одежды", "type": "Text" },
{ "internalName": "PpeShoeSize", "title": "СИЗ: размер обуви", "type": "Number" },
{ "internalName": "ProbationPeriod", "title": "Испытательный срок", "type": "Choice", "choices": ["Без испытательного срока", "1 месяц", "2 месяца", "3 месяца", "6 месяцев"] },
{ "internalName": "ProbationPeriod", "title": "Испытательный срок", "type": "Choice", "choices": ["1 месяц", "2 месяца", "3 месяца", "6 месяцев"] },
{ "internalName": "SalaryProbation", "title": "Оклад при испытательном сроке", "type": "Number", "decimals": 2 },
{ "internalName": "SalaryAfterProbation", "title": "Оклад по завершении ИС", "type": "Number", "decimals": 2 },
{ "internalName": "WorkSchedule", "title": "График работы", "type": "Text" },
@@ -59,7 +59,8 @@ const RecruitingSelectionForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [files, setFiles] = useState<File[]>([]);
@@ -85,6 +86,7 @@ const RecruitingSelectionForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
setExistingAttachments(atts);
}
})
@@ -37,6 +37,8 @@ interface IRecruitingSelectionViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
@@ -44,7 +46,7 @@ const NOOP_SET: SetField = () => undefined;
// Заявка «на подбор» только для просмотра (режим согласующего). Переиспользует те же
// секции, что и форма подачи; редактирование выключено через <FormModeProvider readOnly>.
const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ context, itemId, formKey, listId }) => {
const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -78,6 +80,7 @@ const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ cont
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setAttachments(files);
setError(null);
setLoading(false);
@@ -50,7 +50,8 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [requestId, setRequestId] = useState<number | undefined>(editId);
@@ -82,6 +83,7 @@ const ReferralForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
}
})
.catch((e) => {
@@ -37,6 +37,8 @@ interface IReferralViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
@@ -45,7 +47,7 @@ const NOOP_SET: SetField = () => undefined;
// Реферальная рекомендация только для просмотра (режим согласующего). Переиспользует
// те же секции, что и форма подачи; редактирование выключено через
// <FormModeProvider readOnly> — поля сами становятся неизменяемыми.
const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey, listId }) => {
const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -99,6 +101,7 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setError(null);
setLoading(false);
}
@@ -76,7 +76,8 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [files, setFiles] = useState<File[]>([]);
@@ -101,6 +102,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
setExistingAttachments(atts);
}
})
@@ -49,6 +49,8 @@ interface ITicket1CViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
/** Текст карточки Planner из данных заявки; rejection — автор и причина отклонения, если есть. */
@@ -80,7 +82,7 @@ function buildPlannerNotes(
}
// Заявка в отдел 1С только для просмотра (режим согласующего).
const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey, listId }) => {
const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -116,6 +118,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey,
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setAttachments(files);
setError(null);
setLoading(false);
@@ -57,7 +57,8 @@ const TmcTransferForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [files, setFiles] = useState<File[]>([]);
@@ -134,6 +135,7 @@ const TmcTransferForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
setExistingAttachments(atts);
}
})
@@ -49,10 +49,12 @@ interface ITmcTransferViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
// Заявка «СЗ на перемещение ТМЦ» только для просмотра (режим согласующего).
const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, formKey, listId }) => {
const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -106,6 +108,7 @@ const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, for
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setAttachments(files);
setError(null);
setLoading(false);
@@ -45,7 +45,8 @@ const UnpaidLeaveForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [requestId, setRequestId] = useState<number | undefined>(editId);
@@ -77,6 +78,7 @@ const UnpaidLeaveForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
}
})
.catch((e) => {
@@ -31,6 +31,8 @@ interface IUnpaidLeaveViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
@@ -39,7 +41,7 @@ const NOOP_SET: SetField = () => undefined;
// Заявка без содержания только для просмотра (режим согласующего). Переиспользует
// ту же секцию, что и форма подачи; редактирование выключено через
// <FormModeProvider readOnly> — поля сами становятся неизменяемыми.
const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, formKey, listId }) => {
const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -75,6 +77,7 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setError(null);
setLoading(false);
}
@@ -45,7 +45,8 @@ const VacationForm: React.FC<IRequestFormProps> = ({
onCancel,
onSaved,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [requestId, setRequestId] = useState<number | undefined>(editId);
@@ -77,6 +78,7 @@ const VacationForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
}
})
.catch((e) => {
@@ -31,6 +31,8 @@ interface IVacationViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
@@ -39,7 +41,7 @@ const NOOP_SET: SetField = () => undefined;
// Заявка на отпуск только для просмотра (режим согласующего). Переиспользует ту
// же секцию, что и форма подачи; редактирование выключено через
// <FormModeProvider readOnly> — поля сами становятся неизменяемыми.
const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey, listId }) => {
const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -75,6 +77,7 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setError(null);
setLoading(false);
}
@@ -59,7 +59,8 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
onSaved,
sourceId,
editId,
editListId
editListId,
onCodeLoaded
}) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [files, setFiles] = useState<File[]>([]);
@@ -90,6 +91,7 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
setData(loaded.data);
setRequestStatus(loaded.status);
setRequestCode(loaded.code || undefined);
if (loaded.code) onCodeLoaded?.(loaded.code);
setExistingAttachments(atts);
}
})
@@ -49,6 +49,8 @@ interface IWorkplaceSetupViewProps {
formKey: string;
/** Партиция, где лежит ЭТА заявка — см. IApprovalViewProps.listId. */
listId?: string;
/** Уведомление о загруженном уникальном коде заявки — см. IApprovalViewProps.onCodeLoaded. */
onCodeLoaded?: (code: string) => void;
}
type SaveState = 'idle' | 'saving' | 'saved' | 'error';
@@ -56,7 +58,7 @@ type SaveState = 'idle' | 'saving' | 'saved' | 'error';
// Заявка «орг. рабочего места» только для просмотра (режим согласующего).
// Исключение: первый согласующий шаг (по маршруту — непосредственный руководитель)
// на своём этапе может заполнить «Необходимое ПО» и «Доступы» (инициатор их не знает).
const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemId, formKey, listId }) => {
const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
@@ -121,6 +123,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
onCodeLoaded?.(loaded.code);
setAttachments(files);
setError(null);
setLoading(false);
@@ -17,6 +17,12 @@ export interface IApprovalViewProps {
* текущую партицию типа заявки (старые ссылки без параметра).
*/
listId?: string;
/**
* Уведомление о загруженном уникальном коде заявки — нужен родителю
* (RequestPortal) для заголовка Drawer, который рендерится ДО того, как
* View успевает загрузить саму заявку и узнать её код.
*/
onCodeLoaded?: (code: string) => void;
}
type ViewComponent = React.ComponentType<IApprovalViewProps>;