feat: место для подписи сотрудника на печати заявлений на отпуск
Печатное заявление подписывают от руки, а на листе было негде. В правом верхнем углу шапки, под статусом, теперь ФИО сотрудника, место под роспись и линия «(подпись)» — только при печати. ФИО именно сотрудника, а не инициатора: заявку могут оформить за него. Общий компонент shared/ui/PrintSignature, подключён в «Заявку на отпуск» и «Отпуск без содержания». Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,9 @@
|
||||
(черновик проверяется так же строго, как отправка).
|
||||
- **Замещающий** (`Substitute`, People) — необязателен.
|
||||
- **Заголовок элемента** (`Title`): `Отпуск без содержания — {ФИО} — дд.мм.гггг`.
|
||||
- **Место для подписи на печати** (с 10-29, `PrintSignature`) — как в «Заявке на отпуск»:
|
||||
столбиком «ФИО / линия / (подпись)» в правом верхнем углу шапки под статусом; ФИО сотрудника,
|
||||
а не инициатора.
|
||||
|
||||
## Отличия от «Заявка на отпуск» (hr-vacation)
|
||||
- Те же «дата начала + количество дней»: даты окончания нет, праздники и выходные не считаются.
|
||||
|
||||
@@ -15,3 +15,12 @@
|
||||
gap: $sp-3;
|
||||
margin-bottom: $sp-4;
|
||||
}
|
||||
|
||||
// Правый угол шапки: статус, под ним (только в печати) подпись сотрудника.
|
||||
// headerRight у FormCard раскладывает содержимое в строку — здесь нужен столбик.
|
||||
.headerAside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: $sp-3;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
FormModeProvider,
|
||||
PrintSplitButton,
|
||||
OrgLetterhead,
|
||||
LeaveNotice
|
||||
LeaveNotice,
|
||||
PrintSignature
|
||||
} from '../../shared/ui';
|
||||
import {
|
||||
ApproverService,
|
||||
@@ -64,6 +65,8 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
|
||||
const [data, setData] = useState<IFormData>(EMPTY_DATA);
|
||||
const [status, setStatus] = useState<string>('');
|
||||
const [code, setCode] = useState<string>('');
|
||||
// Ф.И.О. сотрудника (Employee/Title) — для строки подписи на печатном заявлении.
|
||||
const [employeeName, setEmployeeName] = useState<string>('');
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
// Какая из организаций сотрудника (см. OrganizationField) идёт в печать —
|
||||
@@ -97,6 +100,7 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
|
||||
setData(loaded.data);
|
||||
setStatus(loaded.status);
|
||||
setCode(loaded.code);
|
||||
setEmployeeName(loaded.employeeName);
|
||||
notifyCode(loaded.code);
|
||||
setError(null);
|
||||
setLoading(false);
|
||||
@@ -158,7 +162,13 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
|
||||
itemId={itemId}
|
||||
/>
|
||||
}
|
||||
headerRight={status ? <StatusBadge status={status} /> : undefined}
|
||||
headerRight={
|
||||
<div className={styles.headerAside}>
|
||||
{status && <StatusBadge status={status} />}
|
||||
{/* Подписывает сотрудник, а не инициатор: заявку могут оформить за него. */}
|
||||
<PrintSignature name={employeeName} />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<LeaveNotice title={NOTICE_TITLE} items={NOTICE_ITEMS} />
|
||||
<FormModeProvider readOnly>
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
- **Комментарий** (с 10-28, `VacationComment`, Note) — необязательный, заполняет инициатор,
|
||||
последним полем секции; в просмотре пустой не показывается. В DOCX для ЭДО (`vacationDocument.ts`) не идёт; в печать
|
||||
тоже не попадает (обёртка `rp-no-print` с `display: contents`, чтобы на экране поле оставалось ячейкой сетки).
|
||||
- **Место для подписи на печати** (с 10-29, `PrintSignature` из `shared/ui`) — столбиком «ФИО /
|
||||
линия / (подпись)» в правом верхнем углу шапки под статусом (`headerAside`), только при печати. ФИО — **сотрудника** (`Employee/Title`), а не
|
||||
инициатора: заявку могут оформить за сотрудника, а заявление подписывает он сам.
|
||||
|
||||
## Подписание в ЭДО
|
||||
> **Сейчас выключено** (`VACATION_EDO_SIGNING_ENABLED = false` в `shared/config.ts`): решение последнего
|
||||
|
||||
@@ -15,3 +15,12 @@
|
||||
gap: $sp-3;
|
||||
margin-bottom: $sp-4;
|
||||
}
|
||||
|
||||
// Правый угол шапки: статус, под ним (только в печати) подпись сотрудника.
|
||||
// headerRight у FormCard раскладывает содержимое в строку — здесь нужен столбик.
|
||||
.headerAside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: $sp-3;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
FormModeProvider,
|
||||
PrintSplitButton,
|
||||
OrgLetterhead,
|
||||
LeaveNotice
|
||||
LeaveNotice,
|
||||
PrintSignature
|
||||
} from '../../shared/ui';
|
||||
import {
|
||||
ApproverService,
|
||||
@@ -220,7 +221,13 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
|
||||
itemId={itemId}
|
||||
/>
|
||||
}
|
||||
headerRight={status ? <StatusBadge status={status} /> : undefined}
|
||||
headerRight={
|
||||
<div className={styles.headerAside}>
|
||||
{status && <StatusBadge status={status} />}
|
||||
{/* Подписывает сотрудник, а не инициатор: заявку могут оформить за него. */}
|
||||
<PrintSignature name={employeeName} />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<LeaveNotice title={NOTICE_TITLE} items={NOTICE_ITEMS} />
|
||||
<FormModeProvider readOnly>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
@import '../../../../../styles/design-tokens';
|
||||
|
||||
// Длина линии ≈ 5 см на листе A4 — хватает на роспись от руки.
|
||||
$signature-line-width: 200px;
|
||||
// Место под роспись между ФИО и линией.
|
||||
$signature-height: $sp-8;
|
||||
|
||||
// На экране блока нет: расписываться негде.
|
||||
.signature {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
// Столбик, а не строка «ФИО ____»: в шапке рядом с заголовком места мало,
|
||||
// строка в ширину сжала бы заголовок до трёх строк.
|
||||
.signature {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
// min-width, а не width: длинное ФИО растягивает столбик (и линию), а не
|
||||
// вылезает за край листа.
|
||||
min-width: $signature-line-width;
|
||||
font-size: $fs-sm;
|
||||
color: #000;
|
||||
break-inside: avoid;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.name {
|
||||
white-space: nowrap; // перенос фамилии на бланке выглядит как опечатка
|
||||
}
|
||||
|
||||
.line {
|
||||
align-self: stretch;
|
||||
height: $signature-height;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
|
||||
.caption {
|
||||
margin-top: 2px;
|
||||
font-size: $fs-caption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import styles from './PrintSignature.module.scss';
|
||||
|
||||
const CAPTION = '(подпись)';
|
||||
|
||||
interface IPrintSignatureProps {
|
||||
/** ФИО того, кто подписывает. Пусто — печатается только линия. */
|
||||
name?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Место для подписи на печатном заявлении — столбиком: ФИО, под ним место под
|
||||
* роспись и линия, под линией «(подпись)». Узкий столбик рассчитан на правый
|
||||
* верхний угол шапки (FormCard headerRight), как угол бумажного заявления.
|
||||
* Видно только при печати — на экране расписываться негде.
|
||||
*/
|
||||
export const PrintSignature: React.FC<IPrintSignatureProps> = ({ name }) => (
|
||||
<div className={styles.signature}>
|
||||
{name && <span className={styles.name}>{name}</span>}
|
||||
<span className={styles.line} />
|
||||
<span className={styles.caption}>{CAPTION}</span>
|
||||
</div>
|
||||
);
|
||||
@@ -50,6 +50,7 @@ export { OrganizationField } from './OrganizationField/OrganizationField';
|
||||
export { OrganizationTable } from './OrganizationField/OrganizationTable';
|
||||
export { PrintSplitButton } from './PrintSplitButton/PrintSplitButton';
|
||||
export { OrgLetterhead } from './OrgLetterhead/OrgLetterhead';
|
||||
export { PrintSignature } from './PrintSignature/PrintSignature';
|
||||
export { LinkField } from './LinkField/LinkField';
|
||||
export { ErrorOverlay } from './ErrorOverlay/ErrorOverlay';
|
||||
export { SubmitActions } from './SubmitActions/SubmitActions';
|
||||
|
||||
Reference in New Issue
Block a user