成绩单是学校、培训机构与在线教育平台的高频文档,学期末要向学生和家长发送成绩单,申请奖学金、保研和留学时也要出具正式成绩单。传统方案中,教务系统导出成绩单常依赖后端或桌面端组件,部署麻烦、字体兼容性差,打印效果参差不齐。dompdf.js可以在前端直接生成成绩单PDF:成绩数据组织成HTML表格,渲染成矢量PDF后下载或打印,版式统一、中文清晰。本文将完整讲解学生成绩单PDF的生成方案,包括成绩表格设计、学分绩点计算、多科目分页、批量导出全班成绩和常见问题,帮助教务系统快速集成成绩单导出功能。本文还会讨论留学申请需要的中英文双语成绩单、多学期对比视图、评语处理,以及保护成绩数据的隐私控制。无论你服务的是中小学、高校还是在线学习平台,这些模式都能帮你交付一个老师们真正愿意用的成绩单功能。
成绩单的典型场景包括:学期末向家长发送成绩单、学生申请奖学金时提交成绩证明、转学或升学时出具正式成绩单、在线教育平台课程结业成绩单。不同场景对成绩单的格式要求略有差异,但都要求准确、规范、可打印。
一份标准成绩单通常包含:学生基本信息(姓名、学号、班级)、学期信息、科目成绩表格(科目名称、学分、成绩、绩点、备注)、学期汇总(总学分、平均绩点、排名)、教师评语和学校落款,层次结构清晰。
成绩单的准确性要求极高,成绩数据来自教务系统,前端方案可以直接读取接口数据渲染,减少人工转录错误;同时生成速度快,学期末批量导出全班几十份成绩单也毫无压力,班主任和教务老师都能快速上手。
成绩单还有一个容易被忽视的需求:中英文双语版本。出国留学申请需要英文成绩单,模板可以做成中英双语的,科目名称附英文翻译,或者提供单独的中文版和英文版两个模板;前端方案切换模板成本极低,一套数据两种输出,满足国内使用和海外申请两种场景。
成绩单本质是结构化表格,HTML的table标签与成绩数据的行列结构完美对应;dompdf.js渲染DOM为矢量PDF,成绩数字、科目名称、评语中的中文都能精确呈现,表格边框和列对齐完全可控。
前端方案让成绩单模板与网页展示模板可以复用同一份HTML,教务系统页面里预览的成绩单与导出的PDF完全一致,所见即所得;模板调整即时生效,无需后端发版,教务老师反馈的样式问题当天就能解决。
批量导出是成绩单场景的刚需,前端循环遍历学生列表,逐人addPage生成一个包含全班成绩单的PDF,配合自动分页和页眉页脚,每位学生的成绩单独立成页,打印分拣高效,还能按需导出单个学生的成绩单。
从部署角度看,前端生成让成绩单功能可以随前端一起灰度发布:先对部分班级开放,验证无误后全量放开;出问题时也可以快速回退,无需后端配合。对教务系统这类迭代频繁的业务系统来说,这种灵活性非常宝贵。
成绩单模板建议分为头部、主体和尾部三个区域:头部是学校名称、成绩单标题、学生信息和学期;主体是成绩表格,列包含科目、学分、成绩、绩点和备注;尾部是学期汇总、评语、落款和日期,整体庄重规范。
成绩表格建议科目列左对齐、成绩列右对齐或居中,学分列居中,绩点保留两位小数;分数成绩和等级制成绩可以同时展示,例如92(优秀);不及格科目可以用特殊标记,但打印场景建议使用灰色或边框标记而非仅依赖颜色。
平均绩点(GPA)是成绩单的核心汇总指标,建议在前端按学分加权计算:每门课的绩点乘以学分求和,再除以总学分,保留两位小数;同时展示总学分和班级排名,为奖学金评选和升学申请提供依据。
成绩单的评语区域建议限制字数并支持自动截断,防止长评语撑乱版面;评语中的敏感词过滤也值得考虑,避免不当表述打印到纸质成绩单上;评语留白区域可以适当大一些,方便老师手写补充意见,兼顾系统化和个性化。
下面演示成绩单的生成代码,包括学生信息、成绩表格、GPA计算和评语区,展示成绩单的完整结构,数据全部来自教务接口,前端只负责渲染。
GPA计算逻辑放在渲染前完成,等级转换规则(优秀/良好/及格/不及格)建议配置化,不同学校标准不同,通过配置对象维护,避免硬编码导致规则变更时改代码。
示例中的等级转换用三元表达式实现,逻辑清晰但只适合简单场景;更复杂的规则(如百分比排名、标准分)建议抽成独立函数,返回等级和备注两个字段,模板里直接渲染。转换规则集中管理,学校调整标准时只需改配置,不需要动模板代码。
如果学校需要展示历次考试成绩对比,可以在表格下方增加趋势区,用简单的行内条形或文字说明展示进步情况;也可以把多学期成绩合并成一张汇总表,每学期一组列,横向排列,配合自动分页控制宽度,一张成绩单就能看到完整的学习轨迹。
成绩单的落款区域建议同时预留班主任签名和教务处盖章位置,图片盖章和手写签名都可以;如果批量生成后还需要人工盖章,落款区留出足够空白即可,两种流程都能兼容。
import { DomPDF } from 'dompdf.js';
const student = {
name: '李明轩',
studentNo: '2023050102',
className: '高二(3)班',
semester: '2025-2026学年第二学期',
scores: [
{ subject: '语文', credit: 4, score: 92, gradePoint: 4.0 },
{ subject: '数学', credit: 4, score: 88, gradePoint: 3.7 },
{ subject: '英语', credit: 4, score: 85, gradePoint: 3.3 },
{ subject: '物理', credit: 3, score: 90, gradePoint: 4.0 },
{ subject: '化学', credit: 3, score: 78, gradePoint: 2.7 },
{ subject: '生物', credit: 3, score: 95, gradePoint: 4.0 },
],
comment: '学习态度端正,成绩稳步提升,望继续保持。',
};
const totalCredit = student.scores.reduce((s, x) => s + x.credit, 0);
const gpa = (student.scores.reduce((s, x) => s + x.credit * x.gradePoint, 0) / totalCredit).toFixed(2);
const scoreRows = student.scores.map(x => `
<tr>
<td style='border:1px solid #333;padding:6px'>${x.subject}</td>
<td style='border:1px solid #333;padding:6px;text-align:center'>${x.credit}</td>
<td style='border:1px solid #333;padding:6px;text-align:center'>${x.score}</td>
<td style='border:1px solid #333;padding:6px;text-align:center'>${x.gradePoint.toFixed(1)}</td>
<td style='border:1px solid #333;padding:6px;text-align:center'>${x.score >= 90 ? '优秀' : x.score >= 80 ? '良好' : x.score >= 60 ? '及格' : '不及格'}</td>
</tr>
`).join('');
const transcriptHtml = `
<h1 style='text-align:center;font-size:16pt'>学生成绩单</h1>
<p style='text-align:center;font-size:10pt'>${student.semester}</p>
<div style='display:flex;justify-content:space-between;margin:10px 0;font-size:11pt'>
<span>姓名:${student.name}</span>
<span>学号:${student.studentNo}</span>
<span>班级:${student.className}</span>
</div>
<table style='width:100%;border-collapse:collapse'>
<tr style='background:#f5f5f5'>
<th style='border:1px solid #333;padding:6px'>科目</th>
<th style='border:1px solid #333;padding:6px'>学分</th>
<th style='border:1px solid #333;padding:6px'>成绩</th>
<th style='border:1px solid #333;padding:6px'>绩点</th>
<th style='border:1px solid #333;padding:6px'>等级</th>
</tr>
${scoreRows}
<tr style='font-weight:bold'>
<td style='border:1px solid #333;padding:6px;text-align:right'>汇总</td>
<td style='border:1px solid #333;padding:6px;text-align:center'>${totalCredit}</td>
<td style='border:1px solid #333;padding:6px' colspan='3'>平均绩点(GPA):${gpa}</td>
</tr>
</table>
<p style='font-size:11pt;margin-top:10px'>教师评语:${student.comment}</p>
<div style='display:flex;justify-content:space-between;font-size:11pt;margin-top:16px'>
<span>班主任签名:</span>
<span>教务处(盖章) 2026年7月10日</span>
</div>
`;
const pdf = new DomPDF();
pdf.addPage(transcriptHtml, { format: 'A4', margin: '20mm' });
pdf.save(`成绩单-${student.name}.pdf`);
学期末班主任需要导出全班成绩单,前端方案只需循环学生列表:每个学生构建成绩单HTML后addPage,全班添加完毕一次save,生成包含全班成绩单的PDF文件,每位学生独立一页,打印后按人分拣即可。
批量场景建议显示生成进度,例如正在生成第10/45份,大班额或整个年级导出时可以分批处理,每50人一个PDF文件,避免单文件过大导致打开缓慢,也方便按班级分发。
学生信息核对是批量导出的关键步骤:导出前校验每位学生的姓名、学号、成绩是否完整,缺成绩的科目明确标注缺考或未录入,避免生成不完整成绩单引发家长咨询,同时保留生成日志便于追溯。
批量导出前建议先按班级生成一份名单核对表,列出每位学生的姓名、学号和成绩状态,老师确认无误后再批量生成PDF;核对表本身也可以用dompdf.js生成,整个流程都在前端完成,步骤清晰、可留痕。
常见问题一:成绩单打印时表格被裁切。确认@page的margin设置合理,表格宽度不超过页面可用宽度;科目较多时允许自动分页,表头会重复显示,避免强行压缩字号导致打印模糊。
常见问题二:绩点计算与学校标准不一致。不同学校的绩点算法不同(4.0制、5.0制、等级对应分数制),建议将算法封装为独立函数并支持配置,生成前与教务处确认口径,避免成绩单被质疑。
常见问题三:学生姓名存在生僻字导致乱码。dompdf.js内置思源黑体覆盖常用汉字,若仍出现个别生僻字问题,检查数据编码是否为UTF-8,并确认模板中未使用过期的字符集声明。
最后提醒数据安全:成绩单包含学生个人隐私,批量导出的PDF建议设置打开密码或通过内部系统分发,不要用公共网盘传递;系统层面控制导出权限,只有班主任、教务处等授权角色可以导出全班成绩单,并记录导出日志,防止成绩数据外泄。
下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:
这是由 dompdf.js 渲染的示例 PDF 内容。