Просмотр исходного кода

fix(reports): align word and worksheet text with meaning font size

彭峰 5 часов назад
Родитель
Сommit
b8fe8b1311

+ 156 - 0
docs/qa/word-report-font-size-2026-11-15.json

@@ -0,0 +1,156 @@
+{
+  "scope": "three word report variants on admin and mobile export components",
+  "deployed": false,
+  "fontReference": "existing full report Chinese meaning, 18px",
+  "wordFontSize": "inherit",
+  "worksheetFontSize": "inherit",
+  "chineseWorksheetWeight": "400",
+  "englishWorksheetWeight": "600",
+  "fullEnglishWeight": "700",
+  "renderedVariants": [
+    {
+      "id": "admin-full",
+      "pages": 3,
+      "measure": {
+        "tableFont": "18px",
+        "promptFont": "18px",
+        "promptWeight": "700",
+        "meaningFont": "18px",
+        "rows": 36,
+        "overflow": 0,
+        "breakInside": "avoid"
+      }
+    },
+    {
+      "id": "admin-english",
+      "pages": 2,
+      "measure": {
+        "tableFont": "18px",
+        "promptFont": "18px",
+        "promptWeight": "600",
+        "meaningFont": null,
+        "rows": 18,
+        "overflow": 0,
+        "breakInside": "avoid"
+      }
+    },
+    {
+      "id": "admin-chinese",
+      "pages": 2,
+      "measure": {
+        "tableFont": "18px",
+        "promptFont": "18px",
+        "promptWeight": "400",
+        "meaningFont": null,
+        "rows": 18,
+        "overflow": 0,
+        "breakInside": "avoid"
+      }
+    },
+    {
+      "id": "mobile-full",
+      "pages": 3,
+      "measure": {
+        "tableFont": "18px",
+        "promptFont": "18px",
+        "promptWeight": "700",
+        "meaningFont": "18px",
+        "rows": 36,
+        "overflow": 0,
+        "breakInside": "avoid"
+      }
+    },
+    {
+      "id": "mobile-english",
+      "pages": 2,
+      "measure": {
+        "tableFont": "18px",
+        "promptFont": "18px",
+        "promptWeight": "600",
+        "meaningFont": null,
+        "rows": 18,
+        "overflow": 0,
+        "breakInside": "avoid"
+      }
+    },
+    {
+      "id": "mobile-chinese",
+      "pages": 2,
+      "measure": {
+        "tableFont": "18px",
+        "promptFont": "18px",
+        "promptWeight": "400",
+        "meaningFont": null,
+        "rows": 18,
+        "overflow": 0,
+        "breakInside": "avoid"
+      }
+    }
+  ],
+  "pdfPages": [
+    {
+      "page": "admin-chinese-page-1.png",
+      "inkRatio": 0.08236723163841808
+    },
+    {
+      "page": "admin-chinese-page-2.png",
+      "inkRatio": 0.04505649717514124
+    },
+    {
+      "page": "admin-english-page-1.png",
+      "inkRatio": 0.056097457627118645
+    },
+    {
+      "page": "admin-english-page-2.png",
+      "inkRatio": 0.02132627118644068
+    },
+    {
+      "page": "admin-full-page-1.png",
+      "inkRatio": 0.06407344632768362
+    },
+    {
+      "page": "admin-full-page-2.png",
+      "inkRatio": 0.09238983050847457
+    },
+    {
+      "page": "admin-full-page-3.png",
+      "inkRatio": 0.05324858757062147
+    },
+    {
+      "page": "mobile-chinese-page-1.png",
+      "inkRatio": 0.08242372881355932
+    },
+    {
+      "page": "mobile-chinese-page-2.png",
+      "inkRatio": 0.04505649717514124
+    },
+    {
+      "page": "mobile-english-page-1.png",
+      "inkRatio": 0.05615395480225989
+    },
+    {
+      "page": "mobile-english-page-2.png",
+      "inkRatio": 0.02132627118644068
+    },
+    {
+      "page": "mobile-full-page-1.png",
+      "inkRatio": 0.06410593220338984
+    },
+    {
+      "page": "mobile-full-page-2.png",
+      "inkRatio": 0.09238983050847457
+    },
+    {
+      "page": "mobile-full-page-3.png",
+      "inkRatio": 0.05303531073446328
+    }
+  ],
+  "existingAdminReportTests": 14,
+  "existingMobileReportTests": 12,
+  "actualComponentVisualChecks": 6,
+  "bothProductionBuildsPassed": true,
+  "independentReviewPassed": true,
+  "productionDataAccessed": false,
+  "financialCodeChanged": false,
+  "privateEvidenceDirectory": "/Users/mac/.local/state/xiaoshu/qa/2026-11-15-report-fonts"
+}

+ 23 - 0
docs/qa/word-report-font-size-2026-11-15.md

@@ -0,0 +1,23 @@
+# 三种单词报表明细字号对齐
+
+用户根据17:37截图要求:完整单词报表的英文与中文意思同字号;英文填中文、中文填英文的题目也使用完整报表中文意思的字号;中文填英文的中文不加粗。
+
+当前实际两份组件样式的正文中文为18px,而英文为24px、练习题目为20px。按当前中文18px统一,不引用历史更大版本的字号。
+
+## 修改
+
+- 管理端及手机端PDF组件:完整表格英文和两种练习题目的字号都改为继承表格正文18px,避免今后独立字号再分叉。
+- 两个模板仅在中文填英文变体加`chinese-worksheet`样式钩子,该变体题目字重400。完整英文原700与英文填中文原600保持。
+- 标题、中文释义、音标、例句、行高、列宽、复习计划、单词数据和财务逻辑均未修改。
+
+## 验证
+
+- 用实际Angular组件分别挂载管理端/手机端×完整/英文填中文/中文填英文六种情况,使用36个合成单词,包含长英文、较长中文释义及音标;没有读取生产数据。
+- 修改前六种浏览器检查均失败:英文24px、题目20px,中文题目600。修改后六种检查全部通过:明细字号18px、中文题目400,单元格水平溢出0,`break-inside: avoid`保留。
+- 使用真实组件生成的DOM和组件CSS,调用已安装html2pdf.js并沿用生产导出参数,输出六份样例PDF。完整报表各3页,两种练习各2页,共14页;全部渲染成PNG并检查,包括续页、长词换行、中文正常字重及非空尾页,未发现截断/溢出/空白尾页。
+- 管理端报表现有14项、手机端报表现有12项测试通过;`npm run build`两端生产构建成功。既有样式体积和CommonJS警告未导致失败。
+- 独立静态审查通过;`git diff --check`通过。
+
+验证样例、临时组件挂载脚本及截图位于`/Users/mac/.local/state/xiaoshu/qa/2026-11-15-report-fonts/`。临时挂载脚本已移出源码,不加入常规测试。没有用截图重写页面,也没有用简化CSS替代真实组件CSS。样例数据仅用于排版验证,不等同于用户指定学员的正式报表或实体打印验收。
+
+**状态:本地修改与验证完成,待另行授权上线;本次不发布网页、不打包APP、不修改云函数或数据库。**

+ 1 - 1
projects/xiaoshu-admin/src/app/pages/operations-learning-reports.component.html

@@ -67,7 +67,7 @@
   @if(reportVariant()!=='full'){<p class="worksheet-hint">每次打开复习版都会打乱顺序,下载 PDF 与当前预览一致。</p>}
   @if(reportVariant()!=='full'){<p class="worksheet-hint">每次打开复习版都会打乱顺序,下载 PDF 与当前预览一致。</p>}
   }
   }
   @if (error()) { <p class="notice error" role="alert">{{ error() }}</p> }
   @if (error()) { <p class="notice error" role="alert">{{ error() }}</p> }
-  <div class="preview-scroll"><article #pdfContent class="pdf-sheet" [class.worksheet-sheet]="reportVariant()!=='full'">
+  <div class="preview-scroll"><article #pdfContent class="pdf-sheet" [class.worksheet-sheet]="reportVariant()!=='full'" [class.chinese-worksheet]="reportVariant()==='chinese'">
     <section class="pdf-title"><div class="brand-mark"><lucide-icon [img]="icons.FileChartColumn" [size]="28" /></div><div><p>小树陪练</p><h1>{{ report.status === 'writing' ? '语法写作学习报表' : reportTitle() }}</h1></div><span>NO. {{ report.generalId }}</span></section>
     <section class="pdf-title"><div class="brand-mark"><lucide-icon [img]="icons.FileChartColumn" [size]="28" /></div><div><p>小树陪练</p><h1>{{ report.status === 'writing' ? '语法写作学习报表' : reportTitle() }}</h1></div><span>NO. {{ report.generalId }}</span></section>
     <dl class="report-meta"><div><dt>学员</dt><dd>{{ report.studentName }}</dd></div><div><dt>陪练老师</dt><dd>{{ report.coachName }}</dd></div><div><dt>课程</dt><dd>{{ report.courseName }}</dd></div><div><dt>学习日期</dt><dd>{{ report.studyDate }} @if(report.appointmentAt){ {{ report.appointmentAt | date:'HH:mm' }} }</dd></div><div><dt>课型</dt><dd>{{ report.classTypeLabel }}</dd></div><div><dt>预约编号</dt><dd>{{ report.appointmentId || '历史记录' }}</dd></div></dl>
     <dl class="report-meta"><div><dt>学员</dt><dd>{{ report.studentName }}</dd></div><div><dt>陪练老师</dt><dd>{{ report.coachName }}</dd></div><div><dt>课程</dt><dd>{{ report.courseName }}</dd></div><div><dt>学习日期</dt><dd>{{ report.studyDate }} @if(report.appointmentAt){ {{ report.appointmentAt | date:'HH:mm' }} }</dd></div><div><dt>课型</dt><dd>{{ report.classTypeLabel }}</dd></div><div><dt>预约编号</dt><dd>{{ report.appointmentId || '历史记录' }}</dd></div></dl>
     @if (report.status === 'writing') {
     @if (report.status === 'writing') {

+ 3 - 2
projects/xiaoshu-admin/src/app/pages/operations-learning-reports.component.scss

@@ -411,7 +411,7 @@
   font-style: normal;
   font-style: normal;
 }
 }
 .word-table strong {
 .word-table strong {
-  font-size: 24px;
+  font-size: inherit;
 }
 }
 .word-row {
 .word-row {
   break-inside: avoid;
   break-inside: avoid;
@@ -462,7 +462,8 @@
 .worksheet-sheet .pdf-section { margin-top: 14px; }
 .worksheet-sheet .pdf-section { margin-top: 14px; }
 .worksheet-sheet .worksheet-table th, .worksheet-sheet .worksheet-table td { padding: 7px 6px; }
 .worksheet-sheet .worksheet-table th, .worksheet-sheet .worksheet-table td { padding: 7px 6px; }
 .worksheet-sheet .worksheet-table .word-row td { padding-block: 4.9px; }
 .worksheet-sheet .worksheet-table .word-row td { padding-block: 4.9px; }
-.word-prompt { font-size: 20px; font-weight: 600; }
+.word-prompt { font-size: inherit; font-weight: 600; }
+.chinese-worksheet .word-prompt { font-weight: 400; }
 .review-words { font-size: 10px; line-height: 1.8; overflow-wrap: anywhere; }
 .review-words { font-size: 10px; line-height: 1.8; overflow-wrap: anywhere; }
 .review-section { break-inside: avoid; }
 .review-section { break-inside: avoid; }
 .review-table { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 9px; break-inside: avoid; }
 .review-table { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 9px; break-inside: avoid; }

+ 1 - 1
projects/xiaoshu-mobile/src/app/features/appointment/lesson-report-pdf.component.html

@@ -1,5 +1,5 @@
 @for (report of reports(); track report.generalId) {
 @for (report of reports(); track report.generalId) {
-  <article class="pdf-sheet" [class.worksheet-sheet]="variant()!=='full'">
+  <article class="pdf-sheet" [class.worksheet-sheet]="variant()!=='full'" [class.chinese-worksheet]="variant()==='chinese'">
     <section class="pdf-title"><div class="brand-mark"><lucide-icon [img]="icon" [size]="28" /></div><div><p>小树陪练</p><h1>{{ title() }}</h1></div><span>NO. {{ report.generalId }}</span></section>
     <section class="pdf-title"><div class="brand-mark"><lucide-icon [img]="icon" [size]="28" /></div><div><p>小树陪练</p><h1>{{ title() }}</h1></div><span>NO. {{ report.generalId }}</span></section>
     <dl class="report-meta"><div><dt>学员</dt><dd>{{ report.studentName }}</dd></div><div><dt>陪练老师</dt><dd>{{ report.coachName }}</dd></div><div><dt>课程</dt><dd>{{ report.courseName }}</dd></div><div><dt>学习日期</dt><dd>{{ report.studyDate }} @if(report.appointmentAt){ {{ report.appointmentAt.slice(11, 16) }} }</dd></div><div><dt>课型</dt><dd>{{ report.classTypeLabel }}</dd></div><div><dt>预约编号</dt><dd>{{ report.appointmentId || '历史记录' }}</dd></div></dl>
     <dl class="report-meta"><div><dt>学员</dt><dd>{{ report.studentName }}</dd></div><div><dt>陪练老师</dt><dd>{{ report.coachName }}</dd></div><div><dt>课程</dt><dd>{{ report.courseName }}</dd></div><div><dt>学习日期</dt><dd>{{ report.studyDate }} @if(report.appointmentAt){ {{ report.appointmentAt.slice(11, 16) }} }</dd></div><div><dt>课型</dt><dd>{{ report.classTypeLabel }}</dd></div><div><dt>预约编号</dt><dd>{{ report.appointmentId || '历史记录' }}</dd></div></dl>
     @if(variant()==='full') {
     @if(variant()==='full') {

+ 3 - 2
projects/xiaoshu-mobile/src/app/features/appointment/lesson-report-pdf.component.scss

@@ -152,7 +152,7 @@
   font-style: normal;
   font-style: normal;
 }
 }
 .word-table strong {
 .word-table strong {
-  font-size: 24px;
+  font-size: inherit;
 }
 }
 .word-row {
 .word-row {
   break-inside: avoid;
   break-inside: avoid;
@@ -237,4 +237,5 @@
 .worksheet-sheet .pdf-section { margin-top: 14px; }
 .worksheet-sheet .pdf-section { margin-top: 14px; }
 .worksheet-sheet .worksheet-table th, .worksheet-sheet .worksheet-table td { padding: 7px 6px; }
 .worksheet-sheet .worksheet-table th, .worksheet-sheet .worksheet-table td { padding: 7px 6px; }
 .worksheet-sheet .worksheet-table .word-row td { padding-block: 4.9px; }
 .worksheet-sheet .worksheet-table .word-row td { padding-block: 4.9px; }
-.word-prompt { font-size: 20px; font-weight: 600; }
+.word-prompt { font-size: inherit; font-weight: 600; }
+.chinese-worksheet .word-prompt { font-weight: 400; }