Files
nxxy335 d05fd4a9b5 feat(export/dashboard): 导出增强与大屏公开化
导出-每次考试/多考试对比:
- 合格次数阈值等标记项抽为常显区块,三类成绩表共用
- 附缺考名单扩展到多考试导出(取所选考试全都没交的人)
- 块表每场固定2列(成绩+合并空位),修复漏推空串导致的整行左移/串列
- 列宽按实际内容估算,合并区空位只给最小宽度
- 合格次数始终显示实际次数(含0),仅 ≥ 阈值标绿底
- 打印标题改为「成绩明细」,缺考名单分页单独成页
- 打印样式加 print-color-adjust:exact,绿底/红字可正常印出

数据大屏:
- ?class= 班级大屏免登录公开访问,接口侧放行并按班级裁剪后回传
- 单班大屏移除退出按钮,仅首页保留
- 修复红绿判定真bug:membersTable 误用 window.DASH(DASH为let声明取不到)
  改为 scoreGrade() 直接读自由变量,按后台合格率正确判红/黄/绿

测试/样例/文档同步更新,全量回归通过。
2026-09-27 22:04:17 +08:00

81 lines
4.1 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* 把 tools/make-samples.php 产出的数据渲染成可打开的样例页面。
*
* 关键点:页面里的表格**直接调用 assets/app.js 里生产环境的 sheetToHtml()**——
* 不是另写一份渲染逻辑,所以预览长什么样,打印就长什么样,不会两边漂移。
* 配色 / 字号沿用 printDoc() 里打印用的那套样式。
*
* 用法:node tools/make-samples.js
*/
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.join(__dirname, '..');
const data = JSON.parse(fs.readFileSync(path.join(ROOT, 'docs', 'samples', 'sheet-data.json'), 'utf8'));
/* ---- 抽出生产环境的 sheetToHtml ---- */
const appSrc = fs.readFileSync(path.join(ROOT, 'assets', 'app.js'), 'utf8');
const m = appSrc.match(/function sheetToHtml\(sheet\)\s*\{[\s\S]*?\n \}/);
if (!m) {
console.error('未能从 assets/app.js 抽取 sheetToHtml');
process.exit(1);
}
const esc = s => String(s == null ? '' : s)
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
// eslint-disable-next-line no-new-func
const sheetToHtml = new Function('esc', 'return ' + m[0])(esc);
/* ---- 沿用 printDoc() 里的打印配色 ---- */
const PRINT_CSS = [
'body{font-family:"Microsoft YaHei","PingFang SC",sans-serif;color:#222;background:#f7f7f7;margin:0;padding:24px}',
'.page{background:#fff;border:1px solid #e3e3e3;border-radius:6px;padding:20px 22px;margin:0 auto 20px;max-width:1100px}',
'.page h2{font-size:16px;margin:0 0 4px}',
'.page .sub{font-size:12px;color:#777;margin:0 0 14px}',
// 与 printDoc() 里的打印样式保持一致(表头渲染成 <td>,所以底色写 thead td)
'table.bt{border-collapse:collapse;border:1px solid #999;width:100%;background:#fff;font-size:11px}',
'table.bt td,table.bt th{border:1px solid #999;text-align:center;padding:3px 5px}',
'table.bt th,table.bt thead td{background:#eaeaea;font-weight:700}',
'table.bt thead tr:first-child td{background:#eaeaea}',
'table.bt td.absent{color:#888}',
'table.bt td.max{color:#d0021b;font-weight:700}',
'table.bt td.pass{background:#63c384;font-weight:700;-webkit-print-color-adjust:exact;print-color-adjust:exact}',
'html,body,.pass,.absent,.max{-webkit-print-color-adjust:exact;print-color-adjust:exact}',
'.legend{margin:10px 0 0;font-size:12px;color:#555}',
'.legend i{display:inline-block;width:11px;height:11px;vertical-align:-1px;margin:0 4px 0 12px}',
'.legend .r{color:#d0021b;font-weight:700}',
'.legend .g{background:#63c384;font-weight:700}',
'.sign{margin-top:16px;font-size:12px}',
].join('');
function render(item) {
const s = item.sheet;
const table = sheetToHtml(s);
const meta = item.meta || {};
const title = esc(item.title);
const sub = meta.exam_name
? esc(meta.exam_name) + ' · 合格线 ' + meta.pass_line + ' 分,达 ' + meta.pass_times + ' 次标绿'
: '合格线 ' + meta.pass_line + ' 分,达 ' + meta.pass_times + ' 次标绿';
return [
'<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8">',
'<title>' + title + '(预览)</title><style>' + PRINT_CSS + '</style></head><body>',
'<div class="page"><h2>' + title + '</h2><p class="sub">' + sub + '</p>',
table,
'<p class="legend">标记说明:<span class="r">最高分</span> 标红、'
+ '<i class="r">红字</i>;<span class="g">合格次数</span> 始终显示(含 0 次),'
+ '达 ' + meta.pass_times + ' 次标绿、<i class="g">绿底</i>;未达标显示次数、不标绿。',
'<p class="sign">教师签字:______________  教研组长签字:______________  日期:____________</p>',
'</div></body></html>',
].join('\n');
}
const outDir = path.join(ROOT, 'docs', 'samples');
fs.writeFileSync(path.join(outDir, 'preview-multi-block.html'), render(data.block));
fs.writeFileSync(path.join(outDir, 'preview-single-wide.html'), render(data.wide));
console.log('已生成:');
console.log(' docs/samples/preview-multi-block.html (多考试块表)');
console.log(' docs/samples/preview-single-wide.html (单场宽表)');