From 81e622fa095b15cbe83ead9de1e59852a71874f7 Mon Sep 17 00:00:00 2001 From: wangziqi Date: Wed, 5 Aug 2026 17:20:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AD=A6=E7=94=9F=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E6=B5=81=E5=BC=8F=E6=8E=92=E7=89=88=E5=B9=B6?= =?UTF-8?q?=E9=9A=90=E8=97=8F=E7=A9=BA=E6=95=B0=E6=8D=AE=E5=8C=BA=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/archive/archive-report.attendance.ts | 15 +- .../src/archive/archive-report.cover.ts | 34 +++-- .../src/archive/archive-report.enrollment.ts | 50 +++---- .../server/src/archive/archive-report.exam.ts | 34 ++--- .../src/archive/archive-report.helpers.ts | 8 +- .../src/archive/archive-report.learning.ts | 128 +++++++----------- .../archive/archive-report.service.spec.ts | 127 ++++++++++++++--- .../src/archive/archive-report.service.ts | 30 +++- .../src/archive/archive-report.styles.ts | 47 +++++-- 9 files changed, 269 insertions(+), 204 deletions(-) diff --git a/apps/server/src/archive/archive-report.attendance.ts b/apps/server/src/archive/archive-report.attendance.ts index 18292f2..0e48e1f 100644 --- a/apps/server/src/archive/archive-report.attendance.ts +++ b/apps/server/src/archive/archive-report.attendance.ts @@ -1,7 +1,9 @@ import { AttendanceRecord } from '../entities/attendance-record.entity'; -import { esc, pageFrame, pageFooter, pageHeader } from './archive-report.helpers'; +import { esc, sectionFrame, sectionHeader } from './archive-report.helpers'; export function buildAttendance(records: AttendanceRecord[], now: string): string { + if (records.length === 0) return ''; + const present = records.filter((r) => r.status === 'present').length; const absent = records.filter((r) => r.status === 'absent').length; const late = records.filter((r) => r.status === 'late').length; @@ -42,18 +44,11 @@ export function buildAttendance(records: AttendanceRecord[], now: string): strin const chart = renderAttendanceBar(records); const matrix = renderAttendanceMatrix(records); - let extraHtml = ''; - if (records.length === 0) { - extraHtml = ''; - } - - return pageFrame(` - ${pageHeader('出勤记录')} + return sectionFrame(` + ${sectionHeader('出勤记录')} ${metricHtml} - ${extraHtml} ${chart} ${matrix} - ${pageFooter()} `); } diff --git a/apps/server/src/archive/archive-report.cover.ts b/apps/server/src/archive/archive-report.cover.ts index 7ed0618..70f0cb7 100644 --- a/apps/server/src/archive/archive-report.cover.ts +++ b/apps/server/src/archive/archive-report.cover.ts @@ -1,7 +1,7 @@ import { Student } from '../entities/student.entity'; import { StudentProfile } from '../entities/student-profile.entity'; import { StudentEnrollment } from '../entities/student-enrollment.entity'; -import { esc, pageFrame, pageFooter, pageHeader } from './archive-report.helpers'; +import { esc, sectionFrame, sectionHeader, coverFooter } from './archive-report.helpers'; import { buildEnrollmentSection } from './archive-report.enrollment'; export function buildCover( @@ -9,11 +9,22 @@ export function buildCover( profile: StudentProfile | null, enrollments: StudentEnrollment[], now: string, + tocNames: string[], ): string { const types = enrollments.map((e) => e.classType).filter(Boolean).join(' / ') || '-'; - return pageFrame(` - ${pageHeader('封面')} + const tocHtml = + tocNames.length > 0 + ? tocNames + .map( + (name, i) => ` +
${String(i + 1).padStart(2, '0')}${esc(name)}
`, + ) + .join('') + : '
暂无章节
'; + + return sectionFrame(` + ${sectionHeader('封面')}
学生档案报告
生成日期: ${esc(now)}
@@ -40,16 +51,10 @@ export function buildCover(
-
-
01基础信息与报读记录第 2 页
-
02考试成绩总览第 3 页
-
03出勤记录第 4 页
-
04文化课考试成绩第 5 页
-
05学情记录与录取归档第 6 页
-
+
${tocHtml}
恭学教育
- ${pageFooter()} - `); + ${coverFooter()} + `, true); } export function buildBasicInfo( @@ -80,10 +85,9 @@ export function buildBasicInfo( const enrollmentSection = buildEnrollmentSection(enrollments); - return pageFrame(` - ${pageHeader('基础信息')} + return sectionFrame(` + ${sectionHeader('基础信息')} ${infoCards} ${enrollmentSection} - ${pageFooter()} `); } diff --git a/apps/server/src/archive/archive-report.enrollment.ts b/apps/server/src/archive/archive-report.enrollment.ts index 666e47a..6dada58 100644 --- a/apps/server/src/archive/archive-report.enrollment.ts +++ b/apps/server/src/archive/archive-report.enrollment.ts @@ -2,14 +2,10 @@ import { StudentEnrollment } from '../entities/student-enrollment.entity'; import { esc } from './archive-report.helpers'; export function buildEnrollmentSection(enrollments: StudentEnrollment[]): string { - if (enrollments.length === 0) { - return ``; - } + if (enrollments.length === 0) return ''; const renderEnrollmentTable = (enrs: StudentEnrollment[]): string => { - if (enrs.length === 0) { - return ``; - } + if (enrs.length === 0) return ''; let rows = ''; for (const e of enrs) { @@ -46,35 +42,21 @@ export function buildEnrollmentSection(enrollments: StudentEnrollment[]): string (!e.courseCategory.includes('文化') && !e.courseCategory.includes('专业')), ); - if (cultureEnrollments.length > 0 || profEnrollments.length > 0) { - let html = - '

报读记录

'; + const cultureTable = renderEnrollmentTable(cultureEnrollments); + const profTable = renderEnrollmentTable(profEnrollments); + const otherTable = renderEnrollmentTable(otherEnrollments); + + let html = '

报读记录

'; + if (cultureTable && profTable) { html += '
'; - - html += '
'; - html += '

文化课报读

'; - html += renderEnrollmentTable(cultureEnrollments); + html += `

文化课报读

${cultureTable}
`; + html += `

专业课报读

${profTable}
`; html += '
'; - - html += '
'; - html += '

专业课报读

'; - html += renderEnrollmentTable(profEnrollments); - html += '
'; - - html += '
'; - - if (otherEnrollments.length > 0) { - html += - '

其他报读

'; - html += renderEnrollmentTable(otherEnrollments); - } - - html += '
'; - return html; + } else { + if (cultureTable) html += `

文化课报读

${cultureTable}`; + if (profTable) html += `

专业课报读

${profTable}`; } - - return `
-

报读记录

- ${renderEnrollmentTable(enrollments)} -
`; + if (otherTable) html += `

其他报读

${otherTable}`; + html += '
'; + return html; } diff --git a/apps/server/src/archive/archive-report.exam.ts b/apps/server/src/archive/archive-report.exam.ts index e3df623..f099c5d 100644 --- a/apps/server/src/archive/archive-report.exam.ts +++ b/apps/server/src/archive/archive-report.exam.ts @@ -1,7 +1,9 @@ import { ExamScore } from '../entities/exam-score.entity'; -import { esc, pageFrame, pageFooter, pageHeader } from './archive-report.helpers'; +import { esc, sectionFrame, sectionHeader } from './archive-report.helpers'; export function buildExamOverview(exams: ExamScore[], now: string): string { + if (exams.length === 0) return ''; + const cultureExams = exams.filter( (e) => e.examType && e.examType.includes('文化'), ); @@ -64,18 +66,11 @@ export function buildExamOverview(exams: ExamScore[], now: string): string { const scoreTable = renderScoreTable(cultureExams); const trendChart = renderScoreTrendChart(cultureExams); - let extraHtml = ''; - if (cultureExams.length === 0) { - extraHtml = ''; - } - - return pageFrame(` - ${pageHeader('考试成绩总览')} + return sectionFrame(` + ${sectionHeader('考试成绩总览')} ${metricHtml} - ${extraHtml} ${scoreTable} ${trendChart} - ${pageFooter()} `); } @@ -183,19 +178,7 @@ export function buildExamDetail(exams: ExamScore[], now: string): string { (e) => e.examType && e.examType.includes('文化'), ); - if (cultureExams.length === 0) { - return pageFrame(` - ${pageHeader('文化课考试成绩')} -
-
-
${esc(now)} · 系统生成
-
文化课考试成绩
-
-
- - ${pageFooter()} - `); - } + if (cultureExams.length === 0) return ''; // Group by subject const subjectMap = new Map(); @@ -235,8 +218,8 @@ export function buildExamDetail(exams: ExamScore[], now: string): string { `; } - return pageFrame(` - ${pageHeader('文化课考试成绩')} + return sectionFrame(` + ${sectionHeader('文化课考试成绩')}
${esc(now)} · 系统生成
@@ -244,6 +227,5 @@ export function buildExamDetail(exams: ExamScore[], now: string): string {
${subjectCards} - ${pageFooter()} `); } diff --git a/apps/server/src/archive/archive-report.helpers.ts b/apps/server/src/archive/archive-report.helpers.ts index f2ea33f..a905173 100644 --- a/apps/server/src/archive/archive-report.helpers.ts +++ b/apps/server/src/archive/archive-report.helpers.ts @@ -7,14 +7,14 @@ export function esc(value: string): string { .replace(/'/g, '''); } -export function pageFrame(inner: string): string { - return `
${inner}
`; +export function sectionFrame(inner: string, cover = false): string { + return `
${cover ? '
' : ''}${inner}
`; } -export function pageHeader(title: string): string { +export function sectionHeader(title: string): string { return `
恭学教育 · 学生档案${esc(title)}
`; } -export function pageFooter(): string { +export function coverFooter(): string { return ``; } diff --git a/apps/server/src/archive/archive-report.learning.ts b/apps/server/src/archive/archive-report.learning.ts index 2039e9d..db9c133 100644 --- a/apps/server/src/archive/archive-report.learning.ts +++ b/apps/server/src/archive/archive-report.learning.ts @@ -1,85 +1,61 @@ import { LearningRecord } from '../entities/learning-record.entity'; import { ResultArchive } from '../entities/result-archive.entity'; -import { esc, pageFrame, pageFooter, pageHeader } from './archive-report.helpers'; +import { esc, sectionFrame, sectionHeader } from './archive-report.helpers'; -export function buildLearningAndResult( - learnings: LearningRecord[], - result: ResultArchive | null, - now: string, -): string { - let learningHtml = ''; - if (learnings.length === 0) { - learningHtml = ` -
-
-
${esc(now)} · 系统生成
-
学情记录
-
-
- `; - } else { - const latest = learnings.slice(0, 15); - let rows = ''; - for (const r of latest) { - rows += ` - ${esc(r.recordDate || '-')} - ${esc(r.recordType || '-')} - ${esc((r.content || '-').slice(0, 200))} - ${esc(r.followUpMethod || '-')} - `; - } +export function buildLearning(learnings: LearningRecord[], now: string): string { + if (learnings.length === 0) return ''; - learningHtml = ` -
-
-
${esc(now)} · 系统生成
-
学情记录
-
-
-
-

最近学情记录

- - - - - - ${rows} -
日期类型内容跟进方式
-
`; + const latest = learnings.slice(0, 15); + let rows = ''; + for (const r of latest) { + rows += ` + ${esc(r.recordDate || '-')} + ${esc(r.recordType || '-')} + ${esc((r.content || '-').slice(0, 200))} + ${esc(r.followUpMethod || '-')} + `; } - let resultHtml = ''; - if (result) { - resultHtml = ` -
-
-
录取归档
-
+ return sectionFrame(` + ${sectionHeader('学情记录')} +
+
+
${esc(now)} · 系统生成
+
学情记录
-
-
-
文化课成绩${result.cultureFinalScore != null ? result.cultureFinalScore : '-'}
-
专业课成绩${result.professionalFinalScore != null ? result.professionalFinalScore : '-'}
-
录取状态${esc(result.admissionStatus || '-')}
-
录取院校${esc(result.admittedCollege || '-')}
-
录取专业${esc(result.admittedMajor || '-')}
-
-
-
录取归档信息为最终结果,如有疑问请联系教务处
`; - } else { - resultHtml = ` -
-
-
录取归档
-
-
- `; - } - - return pageFrame(` - ${pageHeader('学情记录与录取归档')} - ${learningHtml} - ${resultHtml} - ${pageFooter()} +
+
+

最近学情记录

+ + + + + + ${rows} +
日期类型内容跟进方式
+
+ `); +} + +export function buildResult(result: ResultArchive | null, now: string): string { + if (!result) return ''; + + return sectionFrame(` + ${sectionHeader('录取归档')} +
+
+
录取归档
+
+
+
+
+
文化课成绩${result.cultureFinalScore != null ? result.cultureFinalScore : '-'}
+
专业课成绩${result.professionalFinalScore != null ? result.professionalFinalScore : '-'}
+
录取状态${esc(result.admissionStatus || '-')}
+
录取院校${esc(result.admittedCollege || '-')}
+
录取专业${esc(result.admittedMajor || '-')}
+
+
+
录取归档信息为最终结果,如有疑问请联系教务处
`); } diff --git a/apps/server/src/archive/archive-report.service.spec.ts b/apps/server/src/archive/archive-report.service.spec.ts index 457b337..6ec69b6 100644 --- a/apps/server/src/archive/archive-report.service.spec.ts +++ b/apps/server/src/archive/archive-report.service.spec.ts @@ -1,26 +1,45 @@ import { ArchiveReportService } from './archive-report.service'; +interface MockData { + student?: Record; + profile?: Record | null; + enrollments?: Array>; + exams?: Array>; + learnings?: Array>; + result?: Record | null; + attendances?: Array>; +} + +function makeService(data: MockData = {}): ArchiveReportService { + return new ArchiveReportService( + { findOne: jest.fn().mockResolvedValue(data.profile ?? null) } as never, + { find: jest.fn().mockResolvedValue(data.enrollments ?? []) } as never, + { find: jest.fn().mockResolvedValue(data.exams ?? []) } as never, + { find: jest.fn().mockResolvedValue(data.learnings ?? []) } as never, + { findOne: jest.fn().mockResolvedValue(data.result ?? null) } as never, + { find: jest.fn().mockResolvedValue(data.attendances ?? []) } as never, + { + findOne: jest.fn().mockResolvedValue( + data.student ?? { id: 1, name: '测试学生', studentNo: 'S001' }, + ), + } as never, + ); +} + describe('ArchiveReportService retired profile fields', () => { it('does not render the retired campus field in a student report', async () => { - const service = new ArchiveReportService( - { findOne: jest.fn().mockResolvedValue({ campusLocation: '旧校区', grade: '高三' }) } as never, - { find: jest.fn().mockResolvedValue([]) } as never, - { find: jest.fn().mockResolvedValue([]) } as never, - { find: jest.fn().mockResolvedValue([]) } as never, - { findOne: jest.fn().mockResolvedValue(null) } as never, - { find: jest.fn().mockResolvedValue([]) } as never, - { - findOne: jest.fn().mockResolvedValue({ - id: 1, - name: '测试学生', - gender: '男', - phone: '', - ethnicity: '', - emergencyContact: '', - emergencyPhone: '', - }), - } as never, - ); + const service = makeService({ + profile: { campusLocation: '旧校区', grade: '高三' }, + student: { + id: 1, + name: '测试学生', + gender: '男', + phone: '', + ethnicity: '', + emergencyContact: '', + emergencyPhone: '', + }, + }); const html = await service.generateReportHtml(1); @@ -29,3 +48,73 @@ describe('ArchiveReportService retired profile fields', () => { expect(html).toContain('高三'); }); }); + +describe('ArchiveReportService empty sections', () => { + it('hides empty sections and removes fixed TOC page numbers', async () => { + const service = makeService({ profile: { grade: '高三' } }); + const html = await service.generateReportHtml(1); + + expect(html).toContain('学生档案报告'); + expect(html).toContain('基础信息'); + expect(html).not.toContain('考试成绩总览'); + expect(html).not.toContain('出勤记录'); + expect(html).not.toContain('文化课考试成绩'); + expect(html).not.toContain('学情记录'); + expect(html).not.toContain('录取归档'); + expect(html).not.toContain('第 2 页'); + expect(html).not.toContain('暂无'); + }); + + it('renders sections with data and lists only those sections in the TOC', async () => { + const service = makeService({ + profile: { grade: '高三' }, + enrollments: [{ courseCategory: '文化课', classType: '全日制' }], + exams: [ + { + examType: '文化课月考', + examName: '一月月考', + subject: '数学', + score: 88, + examDate: '2026-01-10', + }, + ], + attendances: [ + { attendanceDate: '2026-01-12', session: '上午', status: 'present' }, + ], + learnings: [ + { + recordDate: '2026-01-13', + recordType: '回访', + content: '状态良好', + followUpMethod: '电话', + }, + ], + result: { + cultureFinalScore: 90, + professionalFinalScore: 85, + admissionStatus: '录取', + admittedCollege: '示例大学', + admittedMajor: '计算机', + }, + }); + + const html = await service.generateReportHtml(1); + + expect(html).toContain('考试成绩总览'); + expect(html).toContain('出勤记录'); + expect(html).toContain('文化课考试成绩'); + expect(html).toContain('学情记录'); + expect(html).toContain('录取归档'); + expect(html).toContain('

报读记录

'); + expect(html).not.toContain('第 1 页'); + expect(html).not.toContain('第 2 页'); + }); + + it('omits the enrollment card when there are no enrollments', async () => { + const service = makeService({ profile: { grade: '高三' } }); + const html = await service.generateReportHtml(1); + + expect(html).not.toContain('

报读记录

'); + expect(html).not.toContain('暂无报读记录'); + }); +}); diff --git a/apps/server/src/archive/archive-report.service.ts b/apps/server/src/archive/archive-report.service.ts index 6994219..5542940 100644 --- a/apps/server/src/archive/archive-report.service.ts +++ b/apps/server/src/archive/archive-report.service.ts @@ -13,7 +13,7 @@ import { esc } from './archive-report.helpers'; import { buildCover, buildBasicInfo } from './archive-report.cover'; import { buildExamOverview, buildExamDetail } from './archive-report.exam'; import { buildAttendance } from './archive-report.attendance'; -import { buildLearningAndResult } from './archive-report.learning'; +import { buildLearning, buildResult } from './archive-report.learning'; interface ReportData { student: Student; @@ -71,17 +71,33 @@ export class ArchiveReportService { day: 'numeric', }); + const sections = [ + { + name: enrollments.length > 0 ? '基础信息与报读记录' : '基础信息', + html: buildBasicInfo(student, profile, enrollments, now), + }, + { name: '考试成绩总览', html: buildExamOverview(exams, now) }, + { name: '出勤记录', html: buildAttendance(attendances, now) }, + { name: '文化课考试成绩', html: buildExamDetail(exams, now) }, + { name: '学情记录', html: buildLearning(learnings, now) }, + { name: '录取归档', html: buildResult(result, now) }, + ].filter((section) => section.html.length > 0); + + const cover = buildCover( + student, + profile, + enrollments, + now, + sections.map((section) => section.name), + ); + return ` 学生档案报告 - ${esc(name)} -${buildCover(student, profile, enrollments, now)} -${buildBasicInfo(student, profile, enrollments, now)} -${buildExamOverview(exams, now)} -${buildAttendance(attendances, now)} -${buildExamDetail(exams, now)} -${buildLearningAndResult(learnings, result, now)} +${cover} +${sections.map((section) => section.html).join('\n')} `; } } diff --git a/apps/server/src/archive/archive-report.styles.ts b/apps/server/src/archive/archive-report.styles.ts index fa21ea8..54d2bde 100644 --- a/apps/server/src/archive/archive-report.styles.ts +++ b/apps/server/src/archive/archive-report.styles.ts @@ -6,10 +6,14 @@ export const ARCHIVE_REPORT_CSS = ` font-family: "PingFang SC", "Microsoft YaHei", Arial, sans-serif; -webkit-print-color-adjust: exact; print-color-adjust: exact; } - .page { - position: relative; width: 210mm; height: 297mm; + .section { + position: relative; width: 210mm; max-width: 100%; margin: 0 auto 18px; padding: 14mm 15mm 10mm; - overflow: hidden; background: #fff; page-break-after: always; + background: #fff; + } + .section-cover { + height: 297mm; overflow: hidden; + page-break-after: always; break-after: page; } .frame { position: absolute; inset: 14mm; border: 1px solid #cfe0f2; pointer-events: none; @@ -17,6 +21,7 @@ export const ARCHIVE_REPORT_CSS = ` .header { position: relative; z-index: 1; display: flex; align-items: center; height: 39px; padding-bottom: 8px; border-bottom: 1px solid #cfe0f2; + page-break-after: avoid; break-after: avoid; } .logo { width: 24px; height: 24px; border-radius: 6px; @@ -33,11 +38,13 @@ export const ARCHIVE_REPORT_CSS = ` font-size: 10px; color: #667085; } h1, h2, h3, p { margin: 0; } + h1, h2, h3 { page-break-after: avoid; break-after: avoid; } .section-title { font-size: 24px; line-height: 1.24; font-weight: 800; } .source { font-size: 12px; color: #667085; padding-bottom: 2px; } .title-row { display: flex; align-items: flex-end; justify-content: space-between; margin: 26px 0 17px; + page-break-after: avoid; break-after: avoid; } .cover-title { margin-top: 60px; font-size: 34px; line-height: 1.22; font-weight: 800; } .cover-subtitle { margin-top: 22px; font-size: 16px; color: #667085; } @@ -60,7 +67,7 @@ export const ARCHIVE_REPORT_CSS = ` .value { font-size: 14px; line-height: 1.5; font-weight: 700; } .toc { margin-top: 58px; } .toc-row { - display: grid; grid-template-columns: 48px 1fr 72px; align-items: center; + display: grid; grid-template-columns: 48px 1fr; align-items: center; height: 47px; border-bottom: 1px solid #cfe0f2; } .toc-index { color: #155aa8; font-size: 15px; font-weight: 800; } @@ -70,9 +77,18 @@ export const ARCHIVE_REPORT_CSS = ` position: absolute; right: 36px; bottom: 82px; color: #eaf1fb; font-size: 56px; font-weight: 900; writing-mode: vertical-rl; } - .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } - .grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; } - .card { border: 1px solid #cfe0f2; padding: 14px; background: #fff; } + .grid-2 { + display: grid; grid-template-columns: 1fr 1fr; gap: 12px; + page-break-inside: avoid; break-inside: avoid; + } + .grid-4 { + display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; + page-break-inside: avoid; break-inside: avoid; + } + .card { + border: 1px solid #cfe0f2; padding: 14px; background: #fff; + page-break-inside: avoid; break-inside: avoid; + } .card h3 { font-size: 16px; margin-bottom: 14px; } .data-table { width: 100%; border-collapse: collapse; table-layout: fixed; @@ -86,8 +102,10 @@ export const ARCHIVE_REPORT_CSS = ` } .data-table td { overflow-wrap: anywhere; word-break: break-word; } .data-table .nowrap { white-space: nowrap; } + .data-table tr { page-break-inside: avoid; break-inside: avoid; } .metric { min-height: 88px; border: 1px solid #cfe0f2; padding: 13px 14px; + page-break-inside: avoid; break-inside: avoid; } .metric .label { margin-bottom: 7px; } .metric strong { @@ -107,13 +125,16 @@ export const ARCHIVE_REPORT_CSS = ` .note { margin-top: 14px; padding: 12px 16px; border-left: 4px solid #155aa8; background: #eef5ff; color: #173f6f; font-size: 12px; line-height: 1.7; + page-break-inside: avoid; break-inside: avoid; } - .banner-note { - margin-top: 12px; padding: 11px 16px; background: #eef5ff; - color: #173f6f; font-size: 12px; line-height: 1.7; + .line-chart { + width: 100%; height: 180px; display: block; + page-break-inside: avoid; break-inside: avoid; + } + .bar-chart { + width: 100%; height: 150px; display: block; + page-break-inside: avoid; break-inside: avoid; } - .line-chart { width: 100%; height: 180px; display: block; } - .bar-chart { width: 100%; height: 150px; display: block; } .status { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 5px; margin-right: 6px; @@ -137,6 +158,6 @@ export const ARCHIVE_REPORT_CSS = ` .muted { color: #667085; } @media print { body { background: #fff; } - .page { margin: 0; box-shadow: none; } + .section { margin: 0; box-shadow: none; } } `;