Anonymous
Динамическое основное содержимое перекрывается с верхним и нижним колонтитулом в PDF с использованием useReactToPrint.
Сообщение
Anonymous » 16 янв 2025, 12:36
Я пытаюсь создать PDF-файл, используя useReactToPrint.
Я хочу, чтобы верхний и нижний колонтитулы были фиксированными на каждой странице, а динамический контент генерировался в теле между ними. Если на текущей странице не осталось места для рендеринга, она должна перейти на следующую страницу и начать печать после заголовка. (Надеюсь, я ясно объяснил требование) Пример:
Заголовок
{Динамический контент
Нижний колонтитул
-> на каждой странице.
Мне удалось зафиксировать верхний и нижний колонтитулы на каждой странице с помощью CSS, но сначала он перекрывался нижним колонтитулом. странице и с верхним и нижним колонтитулом на каждой следующей странице. Как мне добиться, чтобы динамический контент отображался между ними и не перекрывал ни верхний, ни нижний колонтитул?
Мне известно о свойстве разрыва страницы, с помощью которого я могу добавить разрыв страницы. вручную где угодно, но я не уверен в этом, поскольку это вмешательство вручную.
Добавляю скриншот того, что происходит сейчас (некоторый контент размыт, поскольку он содержит конфиденциальную информацию):
Код:
Код: Выделить всё
import {
formatInvoiceData,
getFormattedNumber,
isAbnormal,
isOutsideRange,
summaryReason,
} from '../../../utils'
import { forwardRef, useEffect, useState } from 'react'
import { startSxpProxy } from '../../../../../utils/api'
import {
InvoiceData,
InvoicePanel,
InvoiceTest,
LmsOrder,
labDepartments,
numericOutcome,
} from '../../../models'
import { intent } from '../../../../administration/constants'
import { LABS_PROJECT_ID } from '../../../../../utils/constants'
import { Box, Typography } from '@mui/material'
import medunitedLogo from '../../../../../assets/images/medunited.png'
import LocationOnIcon from '@mui/icons-material/LocationOn'
import CallIcon from '@mui/icons-material/Call'
import EmailIcon from '@mui/icons-material/Email'
import './PatientReport.css'
import { invoiceDateTimeFormat } from '../../../../../utils/dateUtils'
import JsBarcode from 'jsbarcode'
import Table from '@mui/material/Table'
import TableBody from '@mui/material/TableBody'
import TableCell from '@mui/material/TableCell'
import TableHead from '@mui/material/TableHead'
import TableRow from '@mui/material/TableRow'
interface Props {
item: LmsOrder
labDepartments: labDepartments[]
locationAddress: any
pathologySignature: any
}
type ORProps = {
title: string
content: any
boldContent?: boolean
}
const styles = {
boldText: {
fontFamily: 'Roboto',
fontWeight: 'bold',
},
}
const TopLine = () => {
return (
)
}
const Logo = () => {
return (
[img]{medunitedLogo} /[/img]
)
}
const HeaderData = ({ data }: { data: InvoiceData }) => (
Reg. Address: {data?.patientAddress?.address?.line?.[0]}
{data?.patientAddress?.telecom?.[1]?.value}
{data?.patientAddress?.telecom?.[0]?.value}
)
const InvoiceFooter = () => (
1. This Is An Electronically Authenticated Report.
2. Please Correlate With Clinical Findings, Consult a Doctor For
Discussion & Further Medication
)
const PanelView = ({
panel,
isLast,
summary,
}: {
panel: InvoicePanel
index: number
isLast: boolean
summary: string
}) => {
const organization = panel?.tests?.[0]?.organization
return (
Department of
{panel?.department?.department_name?.toUpperCase() ?? 'N/A'}
{panel?.resultType === 'Observation' ? (
) : (
)}
{panel?.tests?.[0]?.summaryReason && (
Impression:
{summaryReason(panel?.tests?.[0]?.summaryReason)}
)}
{organization?.name && (
Note: Test processed at {organization?.name}
)}
{panel?.interpretation && (
Interpretation:
{panel?.interpretation}
)}
{panel?.interpretationImage && (
[img]{panel?.interpretationImage} /[/img]
)}
{isLast && summary ? : null}
)
}
const InvoiceSummary = ({ text }: { text: string }) => (
Summary: {text}
)
const ObservationRow = ({ title, content }: ORProps) => {
return (
{title}:
{content}
)
}
const ObservationView = ({ panel }: { panel: InvoicePanel }) => {
const test = panel?.tests?.[0]
const sample = test?.values?.summary?.replace(/\\+/g, '\\')
return (
{test?.values?.observations?.length > 0 &&
test?.values?.observations?.map((tvo) => (
))}
)
}
const SignatureView = ({ panel }: { panel: InvoicePanel }) => {
return (
{panel?.tests?.[0]?.enteredName && (
{panel?.tests?.[0]?.enteredName}
Technician
)}
{panel?.pathologySignature && (
[img]{panel?.pathologySignature} /[/img]
)}
{panel?.pathologyName && (
Dr.{panel?.pathologyName}
({panel?.tests?.[0]?.pathologyDepartment})
)}
)
}
const Row = ({ dt }: { dt: InvoiceTest }) => {
console.log(dt?.range)
return (
{dt?.name}
Method: {dt?.method || '-'}
{getFormattedNumber(dt?.value)}
{dt?.resultType === numericOutcome && dt?.rangeValue && (
({dt?.rangeValue ?? ''})
)}
{dt?.extraValue && {dt?.extraValue}}
{dt?.unit || '-'}
{dt?.resultType === numericOutcome ? (
dt?.range?.map((rangeValue: any) => (
{rangeValue?.trim()}
))
) : (
{dt?.range?.join(' - ') || '-'}
)}
)
}
const NormalView = ({ panel }: { panel: InvoicePanel }) => (
Test Name: {panel?.name}
Sample Type: {panel?.sample}
Parameter Name
Value
Unit
Biological-Ref-Range
{panel?.tests?.map((pt) => (
))}
)
const HeaderRow = ({
label,
value,
}: {
label: string
value: string | number
}) => (
{label}
: {value}
)
const InvoiceHeader = ({ data }: { data: InvoiceData }) => (
{data?.requestedBy?.indexOf('[') > 0 ? (
) : (
)}
[img]{generateBarcodeImage(data?.lrNumber ?? data?.id)} /[/img]
)
const barcodeOptions = {
format: 'CODE128',
width: 2,
height: 40,
displayValue: false,
}
const generateBarcodeImage = (data: any) => {
const canvas = document.createElement('canvas')
JsBarcode(canvas, data, barcodeOptions)
return canvas.toDataURL('image/png')
}
const PatientReport = forwardRef(function PatientReport(
{ item, labDepartments, locationAddress, pathologySignature },
ref
) {
const [pdfData, setPdfData] = useState(null)
const createPdf = async () => {
const panelIds =
item?.panels?.flatMap((ip) => ip?.lab_tests?.map((ipl) => ipl?.id)) ?? []
const testIds = item?.lab_tests?.map((il) => il?.id) ?? []
const state = {
orderId: item?.id,
ids: [...panelIds, ...testIds],
}
try {
const data = await startSxpProxy(
LABS_PROJECT_ID,
intent?.getLabTestsByIds,
state
)
const panels = formatInvoiceData(
data?.data?.lab_test ?? [],
item?.status ?? '',
labDepartments
)
const obj = {
id: item?.patientUhid ?? item?.patientThopId ?? item?.patient_id ?? '',
name: item?.patientName,
patientAddress: locationAddress,
age: item?.patientAge,
gender: item?.patientGender,
mobile: item?.patientMobile ?? '',
lrNumber: item?.lr_number ?? '',
orderType: item?.origin ?? '',
orderedOn: item?.ordered_on ?? '',
completedOn: item?.collection_completed_on ?? '',
requestedBy: item?.requested_by ?? item?.ordered_by_name ?? '',
validatedOn: item?.validation_completed_on ?? '',
panels: panels,
summary: item?.summary ? item?.summary : '',
invoiceWithHeaderValue: true,
pathologySignature: pathologySignature ?? '',
pathologistName: item?.authorised_by_name,
}
setPdfData(obj)
} catch (error) {
console.error(error)
throw error
}
}
useEffect(() => {
createPdf()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
if (!pdfData) return Failed to get Lab report data
return (
{pdfData?.panels?.map((p: InvoicePanel, i: any, arr: any) => (
key={i}
panel={p}
index={i}
isLast={arr.length === i + 1}
summary={pdfData?.summary}
/>
))}
)
})
export default PatientReport
и файл CSS:
Код: Выделить всё
@media print {
body {
background-color: white;
margin: 0;
}
.print-header {
position: fixed;
top: 0;
left: 0;
right: 0;
text-align: center;
}
.print-footer {
border: 5px solid green;
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
.main-content {
border: 5px solid red;
margin-top: 340px;
margin-bottom: 200px;
}
.page-break {
page-break-before: always;
}
.avoid-break {
page-break-inside: avoid;
}
}
Как это исправить?
Я пробовал использовать свойство CSS Page-Brake, но хочу, чтобы динамическое содержимое отображалось между фиксированным верхним и нижним колонтитулом.< /п>
Подробнее здесь:
https://stackoverflow.com/questions/793 ... usereactto
1737020195
Anonymous
Я пытаюсь создать PDF-файл, используя useReactToPrint. [code]Requirement:[/code] Я хочу, чтобы верхний и нижний колонтитулы были фиксированными на каждой странице, а динамический контент генерировался в теле между ними. Если на текущей странице не осталось места для рендеринга, она должна перейти на следующую страницу и начать печать после заголовка. (Надеюсь, я ясно объяснил требование) Пример: Заголовок {Динамический контент Нижний колонтитул -> на каждой странице. Мне удалось зафиксировать верхний и нижний колонтитулы на каждой странице с помощью CSS, но сначала он перекрывался нижним колонтитулом. странице и с верхним и нижним колонтитулом на каждой следующей странице. Как мне добиться, чтобы динамический контент отображался между ними и не перекрывал ни верхний, ни нижний колонтитул? Мне известно о свойстве разрыва страницы, с помощью которого я могу добавить разрыв страницы. вручную где угодно, но я не уверен в этом, поскольку это вмешательство вручную. Добавляю скриншот того, что происходит сейчас (некоторый контент размыт, поскольку он содержит конфиденциальную информацию): [img]https://i.sstatic.net/oTDvceGA.jpg[/img] Код: [code]import { formatInvoiceData, getFormattedNumber, isAbnormal, isOutsideRange, summaryReason, } from '../../../utils' import { forwardRef, useEffect, useState } from 'react' import { startSxpProxy } from '../../../../../utils/api' import { InvoiceData, InvoicePanel, InvoiceTest, LmsOrder, labDepartments, numericOutcome, } from '../../../models' import { intent } from '../../../../administration/constants' import { LABS_PROJECT_ID } from '../../../../../utils/constants' import { Box, Typography } from '@mui/material' import medunitedLogo from '../../../../../assets/images/medunited.png' import LocationOnIcon from '@mui/icons-material/LocationOn' import CallIcon from '@mui/icons-material/Call' import EmailIcon from '@mui/icons-material/Email' import './PatientReport.css' import { invoiceDateTimeFormat } from '../../../../../utils/dateUtils' import JsBarcode from 'jsbarcode' import Table from '@mui/material/Table' import TableBody from '@mui/material/TableBody' import TableCell from '@mui/material/TableCell' import TableHead from '@mui/material/TableHead' import TableRow from '@mui/material/TableRow' interface Props { item: LmsOrder labDepartments: labDepartments[] locationAddress: any pathologySignature: any } type ORProps = { title: string content: any boldContent?: boolean } const styles = { boldText: { fontFamily: 'Roboto', fontWeight: 'bold', }, } const TopLine = () => { return ( ) } const Logo = () => { return ( [img]{medunitedLogo} /[/img] ) } const HeaderData = ({ data }: { data: InvoiceData }) => ( Reg. Address: {data?.patientAddress?.address?.line?.[0]} {data?.patientAddress?.telecom?.[1]?.value} {data?.patientAddress?.telecom?.[0]?.value} ) const InvoiceFooter = () => ( 1. This Is An Electronically Authenticated Report. 2. Please Correlate With Clinical Findings, Consult a Doctor For Discussion & Further Medication ) const PanelView = ({ panel, isLast, summary, }: { panel: InvoicePanel index: number isLast: boolean summary: string }) => { const organization = panel?.tests?.[0]?.organization return ( Department of {panel?.department?.department_name?.toUpperCase() ?? 'N/A'} {panel?.resultType === 'Observation' ? ( ) : ( )} {panel?.tests?.[0]?.summaryReason && ( Impression: {summaryReason(panel?.tests?.[0]?.summaryReason)} )} {organization?.name && ( Note: Test processed at {organization?.name} )} {panel?.interpretation && ( Interpretation: {panel?.interpretation} )} {panel?.interpretationImage && ( [img]{panel?.interpretationImage} /[/img] )} {isLast && summary ? : null} ) } const InvoiceSummary = ({ text }: { text: string }) => ( Summary: {text} ) const ObservationRow = ({ title, content }: ORProps) => { return ( {title}: {content} ) } const ObservationView = ({ panel }: { panel: InvoicePanel }) => { const test = panel?.tests?.[0] const sample = test?.values?.summary?.replace(/\\+/g, '\\') return ( {test?.values?.observations?.length > 0 && test?.values?.observations?.map((tvo) => ( ))} ) } const SignatureView = ({ panel }: { panel: InvoicePanel }) => { return ( {panel?.tests?.[0]?.enteredName && ( {panel?.tests?.[0]?.enteredName} Technician )} {panel?.pathologySignature && ( [img]{panel?.pathologySignature} /[/img] )} {panel?.pathologyName && ( Dr.{panel?.pathologyName} ({panel?.tests?.[0]?.pathologyDepartment}) )} ) } const Row = ({ dt }: { dt: InvoiceTest }) => { console.log(dt?.range) return ( {dt?.name} Method: {dt?.method || '-'} {getFormattedNumber(dt?.value)} {dt?.resultType === numericOutcome && dt?.rangeValue && ( ({dt?.rangeValue ?? ''}) )} {dt?.extraValue && {dt?.extraValue}} {dt?.unit || '-'} {dt?.resultType === numericOutcome ? ( dt?.range?.map((rangeValue: any) => ( {rangeValue?.trim()} )) ) : ( {dt?.range?.join(' - ') || '-'} )} ) } const NormalView = ({ panel }: { panel: InvoicePanel }) => ( Test Name: {panel?.name} Sample Type: {panel?.sample} Parameter Name Value Unit Biological-Ref-Range {panel?.tests?.map((pt) => ( ))} ) const HeaderRow = ({ label, value, }: { label: string value: string | number }) => ( {label} : {value} ) const InvoiceHeader = ({ data }: { data: InvoiceData }) => ( {data?.requestedBy?.indexOf('[') > 0 ? ( ) : ( )} [img]{generateBarcodeImage(data?.lrNumber ?? data?.id)} /[/img] ) const barcodeOptions = { format: 'CODE128', width: 2, height: 40, displayValue: false, } const generateBarcodeImage = (data: any) => { const canvas = document.createElement('canvas') JsBarcode(canvas, data, barcodeOptions) return canvas.toDataURL('image/png') } const PatientReport = forwardRef(function PatientReport( { item, labDepartments, locationAddress, pathologySignature }, ref ) { const [pdfData, setPdfData] = useState(null) const createPdf = async () => { const panelIds = item?.panels?.flatMap((ip) => ip?.lab_tests?.map((ipl) => ipl?.id)) ?? [] const testIds = item?.lab_tests?.map((il) => il?.id) ?? [] const state = { orderId: item?.id, ids: [...panelIds, ...testIds], } try { const data = await startSxpProxy( LABS_PROJECT_ID, intent?.getLabTestsByIds, state ) const panels = formatInvoiceData( data?.data?.lab_test ?? [], item?.status ?? '', labDepartments ) const obj = { id: item?.patientUhid ?? item?.patientThopId ?? item?.patient_id ?? '', name: item?.patientName, patientAddress: locationAddress, age: item?.patientAge, gender: item?.patientGender, mobile: item?.patientMobile ?? '', lrNumber: item?.lr_number ?? '', orderType: item?.origin ?? '', orderedOn: item?.ordered_on ?? '', completedOn: item?.collection_completed_on ?? '', requestedBy: item?.requested_by ?? item?.ordered_by_name ?? '', validatedOn: item?.validation_completed_on ?? '', panels: panels, summary: item?.summary ? item?.summary : '', invoiceWithHeaderValue: true, pathologySignature: pathologySignature ?? '', pathologistName: item?.authorised_by_name, } setPdfData(obj) } catch (error) { console.error(error) throw error } } useEffect(() => { createPdf() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) if (!pdfData) return Failed to get Lab report data return ( {pdfData?.panels?.map((p: InvoicePanel, i: any, arr: any) => ( key={i} panel={p} index={i} isLast={arr.length === i + 1} summary={pdfData?.summary} /> ))} ) }) export default PatientReport [/code] и файл CSS: [code] @media print { body { background-color: white; margin: 0; } .print-header { position: fixed; top: 0; left: 0; right: 0; text-align: center; } .print-footer { border: 5px solid green; position: fixed; bottom: 0; left: 0; right: 0; } .main-content { border: 5px solid red; margin-top: 340px; margin-bottom: 200px; } .page-break { page-break-before: always; } .avoid-break { page-break-inside: avoid; } } [/code] Как это исправить? Я пробовал использовать свойство CSS Page-Brake, но хочу, чтобы динамическое содержимое отображалось между фиксированным верхним и нижним колонтитулом.< /п> Подробнее здесь: [url]https://stackoverflow.com/questions/79361012/dynamic-body-content-overlapping-with-header-and-footer-in-pdf-using-usereactto[/url]