diff --git a/src/webparts/requestPortal/forms/UnpaidLeave/README.md b/src/webparts/requestPortal/forms/UnpaidLeave/README.md index 677b3df..8cdf4d7 100644 --- a/src/webparts/requestPortal/forms/UnpaidLeave/README.md +++ b/src/webparts/requestPortal/forms/UnpaidLeave/README.md @@ -33,6 +33,9 @@ (черновик проверяется так же строго, как отправка). - **Замещающий** (`Substitute`, People) — необязателен. - **Заголовок элемента** (`Title`): `Отпуск без содержания — {ФИО} — дд.мм.гггг`. +- **Место для подписи на печати** (с 10-29, `PrintSignature`) — как в «Заявке на отпуск»: + столбиком «ФИО / линия / (подпись)» в правом верхнем углу шапки под статусом; ФИО сотрудника, + а не инициатора. ## Отличия от «Заявка на отпуск» (hr-vacation) - Те же «дата начала + количество дней»: даты окончания нет, праздники и выходные не считаются. diff --git a/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.module.scss b/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.module.scss index b52e802..488855a 100644 --- a/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.module.scss +++ b/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.module.scss @@ -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; +} diff --git a/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.tsx b/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.tsx index 0ff119b..162b59d 100644 --- a/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.tsx +++ b/src/webparts/requestPortal/forms/UnpaidLeave/UnpaidLeaveView.tsx @@ -9,7 +9,8 @@ import { FormModeProvider, PrintSplitButton, OrgLetterhead, - LeaveNotice + LeaveNotice, + PrintSignature } from '../../shared/ui'; import { ApproverService, @@ -64,6 +65,8 @@ const UnpaidLeaveView: React.FC = ({ context, itemId, for const [data, setData] = useState(EMPTY_DATA); const [status, setStatus] = useState(''); const [code, setCode] = useState(''); + // Ф.И.О. сотрудника (Employee/Title) — для строки подписи на печатном заявлении. + const [employeeName, setEmployeeName] = useState(''); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Какая из организаций сотрудника (см. OrganizationField) идёт в печать — @@ -97,6 +100,7 @@ const UnpaidLeaveView: React.FC = ({ 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 = ({ context, itemId, for itemId={itemId} /> } - headerRight={status ? : undefined} + headerRight={ +
+ {status && } + {/* Подписывает сотрудник, а не инициатор: заявку могут оформить за него. */} + +
+ } > diff --git a/src/webparts/requestPortal/forms/Vacation/README.md b/src/webparts/requestPortal/forms/Vacation/README.md index f06c8dc..5974657 100644 --- a/src/webparts/requestPortal/forms/Vacation/README.md +++ b/src/webparts/requestPortal/forms/Vacation/README.md @@ -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`): решение последнего diff --git a/src/webparts/requestPortal/forms/Vacation/VacationView.module.scss b/src/webparts/requestPortal/forms/Vacation/VacationView.module.scss index b52e802..488855a 100644 --- a/src/webparts/requestPortal/forms/Vacation/VacationView.module.scss +++ b/src/webparts/requestPortal/forms/Vacation/VacationView.module.scss @@ -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; +} diff --git a/src/webparts/requestPortal/forms/Vacation/VacationView.tsx b/src/webparts/requestPortal/forms/Vacation/VacationView.tsx index 244d8dc..1f41ef5 100644 --- a/src/webparts/requestPortal/forms/Vacation/VacationView.tsx +++ b/src/webparts/requestPortal/forms/Vacation/VacationView.tsx @@ -10,7 +10,8 @@ import { FormModeProvider, PrintSplitButton, OrgLetterhead, - LeaveNotice + LeaveNotice, + PrintSignature } from '../../shared/ui'; import { ApproverService, @@ -220,7 +221,13 @@ const VacationView: React.FC = ({ context, itemId, formKey, itemId={itemId} /> } - headerRight={status ? : undefined} + headerRight={ +
+ {status && } + {/* Подписывает сотрудник, а не инициатор: заявку могут оформить за него. */} + +
+ } > diff --git a/src/webparts/requestPortal/shared/ui/PrintSignature/PrintSignature.module.scss b/src/webparts/requestPortal/shared/ui/PrintSignature/PrintSignature.module.scss new file mode 100644 index 0000000..8782584 --- /dev/null +++ b/src/webparts/requestPortal/shared/ui/PrintSignature/PrintSignature.module.scss @@ -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; + } +} diff --git a/src/webparts/requestPortal/shared/ui/PrintSignature/PrintSignature.tsx b/src/webparts/requestPortal/shared/ui/PrintSignature/PrintSignature.tsx new file mode 100644 index 0000000..724260f --- /dev/null +++ b/src/webparts/requestPortal/shared/ui/PrintSignature/PrintSignature.tsx @@ -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 = ({ name }) => ( +
+ {name && {name}} + + {CAPTION} +
+); diff --git a/src/webparts/requestPortal/shared/ui/index.ts b/src/webparts/requestPortal/shared/ui/index.ts index 75ec2e9..d90c0af 100644 --- a/src/webparts/requestPortal/shared/ui/index.ts +++ b/src/webparts/requestPortal/shared/ui/index.ts @@ -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';