Compare commits
2 Commits
49568e00e8
...
9fd94e0adf
| Author | SHA1 | Date | |
|---|---|---|---|
| 9fd94e0adf | |||
| d3940ce584 |
@@ -33,6 +33,11 @@
|
||||
(черновик проверяется так же строго, как отправка).
|
||||
- **Замещающий** (`Substitute`, People) — необязателен.
|
||||
- **Заголовок элемента** (`Title`): `Отпуск без содержания — {ФИО} — дд.мм.гггг`.
|
||||
- **Место для подписи на печати** (с 10-29, `PrintSignature`) — как в «Заявке на отпуск»:
|
||||
столбиком «ФИО / линия / (подпись)» в правом верхнем углу шапки под статусом; ФИО сотрудника,
|
||||
а не инициатора.
|
||||
- **Таблица «Исполнение» на печать не идёт** (с 10-29, `rp-no-print`) — как в «Заявке на отпуск»;
|
||||
на печати только маршрут согласования.
|
||||
|
||||
## Отличия от «Заявка на отпуск» (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>
|
||||
@@ -168,8 +178,12 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
|
||||
|
||||
<ApprovalMatrix editor={approvers} search={(q) => approval.searchUsers(q)} />
|
||||
|
||||
{/* Исполнение — внутренняя работа кадров после согласования, к заявлению
|
||||
сотрудника не относится: на печати только маршрут согласования. */}
|
||||
<div className="rp-no-print">
|
||||
<ExecutorsMatrix editor={executors} search={(q) => approval.searchUsers(q)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Панель решения — ВНЕ печати и FormModeProvider (комментарий редактируемый). */}
|
||||
{/* История согласования: маршрут пересохраняется патчем (см.
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
- **Комментарий** (с 10-28, `VacationComment`, Note) — необязательный, заполняет инициатор,
|
||||
последним полем секции; в просмотре пустой не показывается. В DOCX для ЭДО (`vacationDocument.ts`) не идёт; в печать
|
||||
тоже не попадает (обёртка `rp-no-print` с `display: contents`, чтобы на экране поле оставалось ячейкой сетки).
|
||||
- **Место для подписи на печати** (с 10-29, `PrintSignature` из `shared/ui`) — столбиком «ФИО /
|
||||
линия / (подпись)» в правом верхнем углу шапки под статусом (`headerAside`), только при печати. ФИО — **сотрудника** (`Employee/Title`), а не
|
||||
инициатора: заявку могут оформить за сотрудника, а заявление подписывает он сам.
|
||||
- **Таблица «Исполнение» на печать не идёт** (с 10-29, обёртка `rp-no-print`) — это внутренняя
|
||||
работа кадров после согласования; на печати только маршрут согласования. На экране видна.
|
||||
|
||||
## Подписание в ЭДО
|
||||
> **Сейчас выключено** (`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>
|
||||
@@ -229,8 +236,12 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
|
||||
</FormCard>
|
||||
|
||||
<ApprovalMatrix editor={approvers} search={(q) => approval.searchUsers(q)} />
|
||||
{/* Исполнение — внутренняя работа кадров после согласования, к заявлению
|
||||
сотрудника не относится: на печати только маршрут согласования. */}
|
||||
<div className="rp-no-print">
|
||||
<ExecutorsMatrix editor={executors} search={(q) => approval.searchUsers(q)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Панель решения — ВНЕ печати и FormModeProvider (комментарий редактируемый). */}
|
||||
{/* История согласования: маршрут пересохраняется патчем (см.
|
||||
|
||||
@@ -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