feat: имя PDF при печати — название формы, ФИО и номер заявки

Окно печати ui-kit было без заголовка, и при «Сохранить как PDF» браузер
называл файл как попало. Теперь имя — «<Форма> — <ФИО> №<код>» во всех
15 просмотрах с печатью (у подбора без ФИО — это заявка на вакансию).

Пока временно локальная копия printRoot/PrintButton в shared/ui/PrintButton
с параметром заголовка; параметр будет перенесён в ui-kit, после чего копия
удаляется.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-29 17:44:03 +05:00
parent 36432c75e6
commit 583f400e26
20 changed files with 362 additions and 53 deletions
@@ -2,7 +2,7 @@ import * as React from 'react';
import { useState, useEffect, useMemo } from 'react';
import type { WebPartContext } from '@microsoft/sp-webpart-base';
import styles from './BusinessTripView.module.scss';
import { Alert, FormCard, InitiatorLine, FormModeProvider, PrintButton } from '../../shared/ui';
import { Alert, FormCard, InitiatorLine, FormModeProvider, PrintButton, buildPrintTitle } from '../../shared/ui';
import {
ApproverService,
ApprovalMatrix,
@@ -55,6 +55,7 @@ const BusinessTripView: React.FC<IBusinessTripViewProps> = ({ context, itemId, f
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
const [employeeName, setEmployeeName] = useState<string>('');
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
@@ -84,6 +85,7 @@ const BusinessTripView: React.FC<IBusinessTripViewProps> = ({ context, itemId, f
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
setEmployeeName(loaded.employeeName);
notifyCode(loaded.code);
setError(null);
setLoading(false);
@@ -128,7 +130,9 @@ const BusinessTripView: React.FC<IBusinessTripViewProps> = ({ context, itemId, f
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
<PrintButton />
<PrintButton
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: employeeName, code, itemId })}
/>
</div>
<div className="rp-print-root">
@@ -11,6 +11,8 @@ export interface ILoadedRequest {
status: string;
/** Уникальный код заявки; '' — если запись создана до появления поля. */
code: string;
/** ФИО командируемого (Employee/Title) — для имени печатного документа. */
employeeName: string;
}
/**
@@ -37,11 +39,12 @@ export async function loadBusinessTripRequest(itemId: number, listId?: string):
'TripObligationAccepted',
'RequestStatus',
'RequestUniqueCode',
'Employee/EMail'
'Employee/EMail',
'Employee/Title'
)
.expand('Employee')()) as Record<string, unknown>;
const employee = item.Employee as { EMail?: string } | undefined;
const employee = item.Employee as { EMail?: string; Title?: string } | undefined;
const data: IFormData = {
...EMPTY_DATA,
@@ -61,6 +64,7 @@ export async function loadBusinessTripRequest(itemId: number, listId?: string):
return {
data,
status: (item.RequestStatus as string) || '',
code: (item.RequestUniqueCode as string) || ''
code: (item.RequestUniqueCode as string) || '',
employeeName: employee?.Title || ''
};
}
@@ -2,7 +2,16 @@ import * as React from 'react';
import { useState, useEffect, useMemo, useCallback } from 'react';
import type { WebPartContext } from '@microsoft/sp-webpart-base';
import styles from './ClearanceView.module.scss';
import { Alert, Button, FormCard, InitiatorLine, FormModeProvider, PrintSplitButton, OrgLetterhead } from '../../shared/ui';
import {
Alert,
Button,
FormCard,
InitiatorLine,
FormModeProvider,
PrintSplitButton,
OrgLetterhead,
buildPrintTitle
} from '../../shared/ui';
import {
ApproverService,
DecisionPanel,
@@ -48,6 +57,8 @@ interface IClearanceViewProps {
type SaveState = 'idle' | 'saving' | 'saved' | 'error';
const FORM_TITLE = 'Обходной лист';
// Обходной лист в режиме согласующего. Форма read-only, КРОМЕ отметок, которые
// заполняет профильный отдел на своём шаге: КДП — карта СКУД и сумма обучения,
// отдел подбора — парковочная карта (см. approverRights.ts).
@@ -60,6 +71,8 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
// ФИО увольняемого — для имени печатного документа.
const [employeeName, setEmployeeName] = useState<string>('');
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const [hrRecordsEditable, setHrRecordsEditable] = useState<boolean>(false);
@@ -123,6 +136,7 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
setEmployeeName(loaded.employeeName);
notifyCode(loaded.code);
setError(null);
setLoading(false);
@@ -274,7 +288,12 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: employeeName, code, itemId })}
/>
</div>
{canEditAnything && (
@@ -295,7 +314,7 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Обходной лист"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -2,7 +2,15 @@ import * as React from 'react';
import { useState, useEffect, useMemo, useCallback } from 'react';
import type { WebPartContext } from '@microsoft/sp-webpart-base';
import styles from './ConcreteRequestView.module.scss';
import { Alert, FormCard, InitiatorLine, FormModeProvider, PrintSplitButton, OrgLetterhead } from '../../shared/ui';
import {
Alert,
FormCard,
InitiatorLine,
FormModeProvider,
PrintSplitButton,
OrgLetterhead,
buildPrintTitle
} from '../../shared/ui';
import {
ApproverService,
DecisionPanel,
@@ -42,6 +50,8 @@ interface IConcreteRequestViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Заявка на бетон';
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
const NOOP_SET: SetField = () => undefined;
@@ -137,13 +147,18 @@ const ConcreteRequestView: React.FC<IConcreteRequestViewProps> = ({ context, ite
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.SiteChiefName, code, itemId })}
/>
</div>
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Заявка на бетон"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -2,7 +2,7 @@ import * as React from 'react';
import { useState, useEffect, useMemo, useCallback } from 'react';
import type { WebPartContext } from '@microsoft/sp-webpart-base';
import styles from './DismissalView.module.scss';
import { Alert, FormCard, InitiatorLine, FormModeProvider, PrintButton, FormNotice } from '../../shared/ui';
import { Alert, FormCard, InitiatorLine, FormModeProvider, PrintButton, FormNotice, buildPrintTitle } from '../../shared/ui';
import {
ApproverService,
DecisionPanel,
@@ -58,6 +58,8 @@ interface IDismissalViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Заявление на увольнение';
// Заявление на увольнение только для просмотра (режим согласующего).
// Переиспользует ту же секцию, что и форма подачи; редактирование выключено через
// <FormModeProvider readOnly> — поля сами становятся неизменяемыми.
@@ -70,6 +72,8 @@ const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
// ФИО увольняющегося — для имени печатного документа.
const [employeeName, setEmployeeName] = useState<string>('');
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
// Итог автосоздания обходного листа после согласования (см. onDecided ниже).
@@ -107,6 +111,7 @@ const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
setEmployeeName(loaded.employeeName);
notifyCode(loaded.code);
setError(null);
setLoading(false);
@@ -265,7 +270,9 @@ const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey
<div>
<div className={`${styles.toolbar} rp-no-print`}>
{printGate === 'allowed' ? (
<PrintButton />
<PrintButton
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: employeeName, code, itemId })}
/>
) : (
<span className={styles.printBlocked} title="Печать откроется после согласования обходного листа по этому увольнению">
Печать станет доступна после согласования обходного листа
@@ -275,7 +282,7 @@ const DismissalView: React.FC<IDismissalViewProps> = ({ context, itemId, formKey
<div className="rp-print-root">
<FormCard
title="Заявление на увольнение"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -2,7 +2,15 @@ import * as React from 'react';
import { useState, useEffect, useMemo, useCallback } from 'react';
import type { WebPartContext } from '@microsoft/sp-webpart-base';
import styles from './EmployeeTransferView.module.scss';
import { Alert, FormCard, InitiatorLine, FormModeProvider, PrintSplitButton, OrgLetterhead } from '../../shared/ui';
import {
Alert,
FormCard,
InitiatorLine,
FormModeProvider,
PrintSplitButton,
OrgLetterhead,
buildPrintTitle
} from '../../shared/ui';
import {
ApproverService,
DecisionPanel,
@@ -41,6 +49,8 @@ interface IEmployeeTransferViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Заявка на перемещение сотрудника';
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
const NOOP_SET: SetField = () => undefined;
@@ -56,6 +66,8 @@ const EmployeeTransferView: React.FC<IEmployeeTransferViewProps> = ({ context, i
const [data, setData] = useState<IFormData>(EMPTY_DATA);
const [status, setStatus] = useState<string>('');
const [code, setCode] = useState<string>('');
// ФИО перемещаемого — для имени печатного документа.
const [employeeName, setEmployeeName] = useState<string>('');
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
// Какая из организаций сотрудника (см. OrganizationField) идёт в печать —
@@ -89,6 +101,7 @@ const EmployeeTransferView: React.FC<IEmployeeTransferViewProps> = ({ context, i
setData(loaded.data);
setStatus(loaded.status);
setCode(loaded.code);
setEmployeeName(loaded.employeeName);
notifyCode(loaded.code);
setError(null);
setLoading(false);
@@ -136,13 +149,18 @@ const EmployeeTransferView: React.FC<IEmployeeTransferViewProps> = ({ context, i
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: employeeName, code, itemId })}
/>
</div>
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Заявка на перемещение сотрудника"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -12,7 +12,8 @@ import {
PrintButton,
FieldChangesProvider,
FieldChangesBanner,
issueLabels
issueLabels,
buildPrintTitle
} from '../../shared/ui';
import { IFieldChange, mergeFieldChanges, toChangeMap } from '../../shared/fieldChanges/fieldChanges';
import { HIRE_CHANGE_TRACKING } from './changeTracking';
@@ -87,6 +88,7 @@ const HIRE_DATE_REQUIRED_MESSAGE = 'укажите дату приёма (п. 2.
const PAYROLL_HINT = 'Как согласующий вы можете указать оклады (п. 4.2, 4.3) и отдел/участок (п. 2.4).';
const HIRE_DATE_HINT = 'Как исполнитель укажите дату приёма (п. 2.2) — она обязательна для отметки «Выполнено».';
const FULL_EDIT_HINT = 'Как согласующий вы можете редактировать все поля и вложения заявки.';
const FORM_TITLE = 'Заявка на прием';
// Заявка «на прием» только для просмотра (режим согласующего). Переиспользует
// те же секции, что и форма подачи; редактирование выключено через
@@ -382,7 +384,11 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
<Icon name="copy" size="sm" />
Организация рабочего места на основе этой
</Button>
{isApprovedStatus(status) && <PrintButton />}
{isApprovedStatus(status) && (
<PrintButton
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.HireCandidateName, code, itemId })}
/>
)}
</div>
{hasEditableFields && (
@@ -400,7 +406,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
<div className="rp-print-root">
<FormCard
title="Заявка на прием"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -10,7 +10,8 @@ import {
FormModeProvider,
PrintButton,
FieldChangesProvider,
FieldChangesBanner
FieldChangesBanner,
buildPrintTitle
} from '../../shared/ui';
import { IFieldChange, mergeFieldChanges, toChangeMap } from '../../shared/fieldChanges/fieldChanges';
import { SELECTION_CHANGE_TRACKING } from './changeTracking';
@@ -80,6 +81,7 @@ interface IRecruitingSelectionViewProps {
type SaveState = 'idle' | 'saving' | 'saved' | 'error';
const FULL_EDIT_HINT = 'Как согласующий вы можете редактировать все поля и вложения заявки.';
const FORM_TITLE = 'Заявка на подбор';
// Заявка «на подбор» только для просмотра (режим согласующего). Переиспользует те же
// секции, что и форма подачи; редактирование выключено через <FormModeProvider readOnly>,
@@ -366,7 +368,10 @@ const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ cont
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
{isApprovedStatus(status) && <PrintButton />}
{/* Подбор — на вакансию, конкретного человека ещё нет: имя файла без ФИО. */}
{isApprovedStatus(status) && (
<PrintButton documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: '', code, itemId })} />
)}
</div>
{fullEditable && (
@@ -384,7 +389,7 @@ const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ cont
<div className="rp-print-root">
<FormCard
title="Заявка на подбор"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -11,7 +11,8 @@ import {
FormField,
AttachmentList,
PrintSplitButton,
OrgLetterhead
OrgLetterhead,
buildPrintTitle
} from '../../shared/ui';
import {
ApproverService,
@@ -60,6 +61,8 @@ interface IReferralViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Реферальная рекомендация';
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
const NOOP_SET: SetField = () => undefined;
@@ -189,14 +192,19 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
<div>
<div className={`${styles.toolbar} rp-no-print`}>
{isApprovedStatus(status) && (
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.CandidateName, code, itemId })}
/>
)}
</div>
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Реферальная рекомендация"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -10,7 +10,8 @@ import {
FormModeProvider,
PrintSplitButton,
OrgLetterhead,
Icon
Icon,
buildPrintTitle
} from '../../shared/ui';
import { navigate } from '../../shared/routing';
import {
@@ -57,6 +58,8 @@ interface IServiceRequestViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Заявка на услуги';
// Заявка «Заявка на услуги» только для просмотра (режим согласующего).
const ServiceRequestView: React.FC<IServiceRequestViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
// onCodeLoaded — колбэк родителя, его ссылка меняется на каждом рендере; в зависимостях эффекта
@@ -166,13 +169,18 @@ const ServiceRequestView: React.FC<IServiceRequestViewProps> = ({ context, itemI
Редактировать
</Button>
)}
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.RequesterName, code, itemId })}
/>
</div>
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Заявка на услуги"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -2,7 +2,15 @@ import * as React from 'react';
import { useState, useEffect, useMemo } from 'react';
import type { WebPartContext } from '@microsoft/sp-webpart-base';
import styles from './SkudExplanationView.module.scss';
import { Alert, FormCard, InitiatorLine, FormModeProvider, PrintSplitButton, OrgLetterhead } from '../../shared/ui';
import {
Alert,
FormCard,
InitiatorLine,
FormModeProvider,
PrintSplitButton,
OrgLetterhead,
buildPrintTitle
} from '../../shared/ui';
import {
ApproverService,
DecisionPanel,
@@ -130,7 +138,12 @@ const SkudExplanationView: React.FC<ISkudExplanationViewProps> = ({ context, ite
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.EmployeeFio, code, itemId })}
/>
</div>
<FormCard
@@ -12,7 +12,8 @@ import {
FormField,
AttachmentList,
PrintButton,
Icon
Icon,
buildPrintTitle
} from '../../shared/ui';
import { navigate } from '../../shared/routing';
import {
@@ -56,6 +57,8 @@ interface ITicket1CViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Заявка в отдел 1С';
// Заявка в отдел 1С только для просмотра (режим согласующего).
const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
// onCodeLoaded — колбэк родителя (RequestPortal → ApproveFeature): его ссылка
@@ -185,12 +188,12 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey,
Редактировать
</Button>
)}
<PrintButton />
<PrintButton documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.FIO, code, itemId })} />
</div>
<div className="rp-print-root">
<FormCard
title="Заявка в отдел 1С"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -13,7 +13,8 @@ import {
AttachmentList,
PrintSplitButton,
OrgLetterhead,
Icon
Icon,
buildPrintTitle
} from '../../shared/ui';
import { navigate } from '../../shared/routing';
import {
@@ -55,6 +56,8 @@ interface ITmcTransferViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Служебная записка на перемещение ТМЦ';
// Заявка «СЗ на перемещение ТМЦ» только для просмотра (режим согласующего).
const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, formKey, listId, onCodeLoaded }) => {
// onCodeLoaded — колбэк родителя (RequestPortal → ApproveFeature): его ссылка
@@ -169,13 +172,18 @@ const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, for
Редактировать
</Button>
)}
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.AuthorName, code, itemId })}
/>
</div>
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Служебная записка на перемещение ТМЦ"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -10,7 +10,8 @@ import {
PrintSplitButton,
OrgLetterhead,
FormNotice,
PrintSignature
PrintSignature,
buildPrintTitle
} from '../../shared/ui';
import {
ApproverService,
@@ -50,6 +51,8 @@ interface IUnpaidLeaveViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Заявление на отпуск без сохранения заработной платы';
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
const NOOP_SET: SetField = () => undefined;
@@ -148,13 +151,18 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: employeeName, code, itemId })}
/>
</div>
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Заявление на отпуск без сохранения заработной платы"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -11,7 +11,8 @@ import {
PrintSplitButton,
OrgLetterhead,
FormNotice,
PrintSignature
PrintSignature,
buildPrintTitle
} from '../../shared/ui';
import {
ApproverService,
@@ -57,6 +58,8 @@ interface IVacationViewProps {
onCodeLoaded?: (code: string) => void;
}
const FORM_TITLE = 'Заявление на оплачиваемый ежегодный трудовой отпуск';
// В режиме чтения поля не редактируются, поэтому обновление — пустышка.
const NOOP_SET: SetField = () => undefined;
@@ -207,13 +210,18 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
return (
<div>
<div className={`${styles.toolbar} rp-no-print`}>
<PrintSplitButton value={data.Organization} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={data.Organization}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: employeeName, code, itemId })}
/>
</div>
<div className="rp-print-root">
<OrgLetterhead value={data.Organization} selectedIndex={printOrgIndex} />
<FormCard
title="Заявление на оплачиваемый ежегодный трудовой отпуск"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine
@@ -12,7 +12,8 @@ import {
OrgLetterhead,
Icon,
FieldChangesProvider,
FieldChangesBanner
FieldChangesBanner,
buildPrintTitle
} from '../../shared/ui';
import { navigate } from '../../shared/routing';
import {
@@ -66,6 +67,7 @@ interface IWorkplaceSetupViewProps {
type SaveState = 'idle' | 'saving' | 'saved' | 'error';
const FORM_TITLE = 'Организация рабочего места';
const REVIEW_FIELDS_HINT = 'Как согласующий вы можете заполнить «Необходимое ПО», «Доступы» и «Мебель».';
const FULL_EDIT_HINT = 'Как согласующий вы можете редактировать все поля и вложения заявки.';
@@ -271,7 +273,12 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
Редактировать
</Button>
)}
<PrintSplitButton value={organizationText(data)} selectedIndex={printOrgIndex} onChange={setPrintOrgIndex} />
<PrintSplitButton
value={organizationText(data)}
selectedIndex={printOrgIndex}
onChange={setPrintOrgIndex}
documentTitle={buildPrintTitle({ formTitle: FORM_TITLE, personName: data.FullName, code, itemId })}
/>
</div>
{canEditAnything && (
@@ -290,7 +297,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
<div className="rp-print-root">
<OrgLetterhead value={organizationText(data)} selectedIndex={printOrgIndex} />
<FormCard
title="Организация рабочего места"
title={FORM_TITLE}
subtitle={`№${code || itemId}`}
belowSubtitle={
<InitiatorLine listTitle={dataListName} itemId={itemId} />