feat: исполнение не печатается ни в одной форме

Исполнение — внутренняя работа после согласования, к печатному документу
заявки оно не относится: на печати остаётся только маршрут согласования.
Раньше так было лишь в отпусках, через ручную обёртку. Теперь у
ApprovalMatrix есть признак printable, ExecutorsMatrix всегда выключает
печать (и для будущих форм), а блоки «Исполнение», выведенные через
ApprovalMatrix напрямую, помечены явно. На экране ничего не меняется.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-29 12:51:50 +05:00
parent 0005bf0cbd
commit b77261079b
13 changed files with 26 additions and 12 deletions
@@ -156,6 +156,7 @@ const BusinessTripView: React.FC<IBusinessTripViewProps> = ({ context, itemId, f
{!executors.loading && executors.rows.length > 0 && ( {!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={searchUsers} search={searchUsers}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -315,6 +315,7 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
{!executors.loading && executors.rows.length > 0 && ( {!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={(q) => approval.searchUsers(q)} search={(q) => approval.searchUsers(q)}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -452,6 +452,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
{!executors.loading && (executors.rows.length > 0 || canAddExecutor) && ( {!executors.loading && (executors.rows.length > 0 || canAddExecutor) && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={(q) => approval.searchUsers(q)} search={(q) => approval.searchUsers(q)}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -438,6 +438,7 @@ const RecruitingSelectionView: React.FC<IRecruitingSelectionViewProps> = ({ cont
{!executors.loading && (executors.rows.length > 0 || canAddExecutor) && ( {!executors.loading && (executors.rows.length > 0 || canAddExecutor) && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={(q) => approval.searchUsers(q)} search={(q) => approval.searchUsers(q)}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -234,6 +234,7 @@ const ReferralView: React.FC<IReferralViewProps> = ({ context, itemId, formKey,
{!executors.loading && executors.rows.length > 0 && ( {!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={(q) => approval.searchUsers(q)} search={(q) => approval.searchUsers(q)}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -11,7 +11,8 @@ interface ISkudRouteTablesProps {
/** /**
* Маршрут согласования + исполнение (если исполнители есть). Рисуется дважды: * Маршрут согласования + исполнение (если исполнители есть). Рисуется дважды:
* на экране под карточкой и внутри печатного блока под запиской — на печати * на экране под карточкой и внутри печатного блока под запиской — на печати
* таблица маршрута заменяет подпись сотрудника. * таблица маршрута заменяет подпись сотрудника. Исполнение на печать не идёт
* (printable={false}), как во всех формах, — только согласование.
*/ */
export const SkudRouteTables: React.FC<ISkudRouteTablesProps> = ({ approvers, executors, search }) => { export const SkudRouteTables: React.FC<ISkudRouteTablesProps> = ({ approvers, executors, search }) => {
const hasExecutors = !executors.loading && executors.rows.length > 0; const hasExecutors = !executors.loading && executors.rows.length > 0;
@@ -26,6 +27,7 @@ export const SkudRouteTables: React.FC<ISkudRouteTablesProps> = ({ approvers, ex
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
emptyText="Исполнители не назначены." emptyText="Исполнители не назначены."
printable={false}
/> />
)} )}
</> </>
@@ -224,6 +224,7 @@ const Ticket1CView: React.FC<ITicket1CViewProps> = ({ context, itemId, formKey,
{!executors.loading && executors.rows.length > 0 && ( {!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={(q) => approval.searchUsers(q)} search={(q) => approval.searchUsers(q)}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -204,6 +204,7 @@ const TmcTransferView: React.FC<ITmcTransferViewProps> = ({ context, itemId, for
{!executors.loading && executors.rows.length > 0 && ( {!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={(q) => approval.searchUsers(q)} search={(q) => approval.searchUsers(q)}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -178,12 +178,9 @@ const UnpaidLeaveView: React.FC<IUnpaidLeaveViewProps> = ({ context, itemId, for
<ApprovalMatrix editor={approvers} search={(q) => approval.searchUsers(q)} /> <ApprovalMatrix editor={approvers} search={(q) => approval.searchUsers(q)} />
{/* Исполнение — внутренняя работа кадров после согласования, к заявлению {/* Исполнение на печать не идёт — это делает сам ExecutorsMatrix (printable={false}). */}
сотрудника не относится: на печати только маршрут согласования. */}
<div className="rp-no-print">
<ExecutorsMatrix editor={executors} search={(q) => approval.searchUsers(q)} /> <ExecutorsMatrix editor={executors} search={(q) => approval.searchUsers(q)} />
</div> </div>
</div>
{/* Панель решения — ВНЕ печати и FormModeProvider (комментарий редактируемый). */} {/* Панель решения — ВНЕ печати и FormModeProvider (комментарий редактируемый). */}
{/* История согласования: маршрут пересохраняется патчем (см. {/* История согласования: маршрут пересохраняется патчем (см.
@@ -236,12 +236,9 @@ const VacationView: React.FC<IVacationViewProps> = ({ context, itemId, formKey,
</FormCard> </FormCard>
<ApprovalMatrix editor={approvers} search={(q) => approval.searchUsers(q)} /> <ApprovalMatrix editor={approvers} search={(q) => approval.searchUsers(q)} />
{/* Исполнение — внутренняя работа кадров после согласования, к заявлению {/* Исполнение на печать не идёт — это делает сам ExecutorsMatrix (printable={false}). */}
сотрудника не относится: на печати только маршрут согласования. */}
<div className="rp-no-print">
<ExecutorsMatrix editor={executors} search={(q) => approval.searchUsers(q)} /> <ExecutorsMatrix editor={executors} search={(q) => approval.searchUsers(q)} />
</div> </div>
</div>
{/* Панель решения — ВНЕ печати и FormModeProvider (комментарий редактируемый). */} {/* Панель решения — ВНЕ печати и FormModeProvider (комментарий редактируемый). */}
{/* История согласования: маршрут пересохраняется патчем (см. {/* История согласования: маршрут пересохраняется патчем (см.
@@ -296,6 +296,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
{!executors.loading && executors.rows.length > 0 && ( {!executors.loading && executors.rows.length > 0 && (
<ApprovalMatrix <ApprovalMatrix
editor={executors} editor={executors}
printable={false}
search={(q) => approval.searchUsers(q)} search={(q) => approval.searchUsers(q)}
title="Исполнение" title="Исполнение"
roleLabel="Исполнитель" roleLabel="Исполнитель"
@@ -76,6 +76,13 @@ export interface IApprovalMatrixProps {
* editable. В черновике не нужен: там пикер добавляет строку локально. * editable. В черновике не нужен: там пикер добавляет строку локально.
*/ */
onAddRow?: (user: ISiteUser) => void; onAddRow?: (user: ISiteUser) => void;
/**
* Попадает ли блок в печатную версию заявки. По умолчанию да — маршрут
* согласования печатается. Исполнение (внутренняя работа после согласования)
* не печатается ни в одной форме: false у ExecutorsMatrix и у блоков
* «Исполнение», выведенных через ApprovalMatrix напрямую.
*/
printable?: boolean;
} }
/** Таблица маршрута (согласование или исполнение) + (если editable) правка состава. */ /** Таблица маршрута (согласование или исполнение) + (если editable) правка состава. */
@@ -95,6 +102,7 @@ export const ApprovalMatrix: React.FC<IApprovalMatrixProps> = ({
canMoveRow, canMoveRow,
onMoveRow, onMoveRow,
onAddRow, onAddRow,
printable = true,
}) => { }) => {
const { rows, loading, error, editable, blocks, retry } = editor; const { rows, loading, error, editable, blocks, retry } = editor;
// Строка, для которой открыт выбор замены (ReplaceRowPanel); undefined — закрыт. // Строка, для которой открыт выбор замены (ReplaceRowPanel); undefined — закрыт.
@@ -218,7 +226,7 @@ export const ApprovalMatrix: React.FC<IApprovalMatrixProps> = ({
const hasActionsCol = editable || hasRemovable; const hasActionsCol = editable || hasRemovable;
return ( return (
<div className={styles.matrixWrap}> <div className={printable ? styles.matrixWrap : `${styles.matrixWrap} rp-no-print`}>
<div className={styles.matrixTitle}>{title}</div> <div className={styles.matrixTitle}>{title}</div>
{waiting && <div className={styles.matrixNote}>{waitingText}</div>} {waiting && <div className={styles.matrixNote}>{waitingText}</div>}
{!waiting && loading && <div className={styles.matrixNote}>Загрузка маршрута…</div>} {!waiting && loading && <div className={styles.matrixNote}>Загрузка маршрута…</div>}
@@ -13,6 +13,7 @@ interface IExecutorsMatrixProps {
/** /**
* Таблица исполнителей — рисуется только когда в маршруте из админки они есть: * Таблица исполнителей — рисуется только когда в маршруте из админки они есть:
* у форм без фазы исполнения блока нет вовсе (кроме редактора маршрута, см. canEditExecutors). * у форм без фазы исполнения блока нет вовсе (кроме редактора маршрута, см. canEditExecutors).
* В печатную версию заявки не попадает (printable={false}) — на печати только согласование.
*/ */
export const ExecutorsMatrix: React.FC<IExecutorsMatrixProps> = ({ editor, search, title = 'Исполнение' }) => { export const ExecutorsMatrix: React.FC<IExecutorsMatrixProps> = ({ editor, search, title = 'Исполнение' }) => {
// Редактор маршрута видит блок и пустым — иначе исполнителя некуда добавить. // Редактор маршрута видит блок и пустым — иначе исполнителя некуда добавить.
@@ -26,6 +27,7 @@ export const ExecutorsMatrix: React.FC<IExecutorsMatrixProps> = ({ editor, searc
canRemoveRow={editor.editable ? () => true : undefined} canRemoveRow={editor.editable ? () => true : undefined}
pickerPlaceholder="Добавить исполнителя: начните вводить ФИО…" pickerPlaceholder="Добавить исполнителя: начните вводить ФИО…"
emptyText="Исполнители не назначены." emptyText="Исполнители не назначены."
printable={false}
/> />
); );
}; };