feat(export/dashboard): 导出增强与大屏公开化
导出-每次考试/多考试对比: - 合格次数阈值等标记项抽为常显区块,三类成绩表共用 - 附缺考名单扩展到多考试导出(取所选考试全都没交的人) - 块表每场固定2列(成绩+合并空位),修复漏推空串导致的整行左移/串列 - 列宽按实际内容估算,合并区空位只给最小宽度 - 合格次数始终显示实际次数(含0),仅 ≥ 阈值标绿底 - 打印标题改为「成绩明细」,缺考名单分页单独成页 - 打印样式加 print-color-adjust:exact,绿底/红字可正常印出 数据大屏: - ?class= 班级大屏免登录公开访问,接口侧放行并按班级裁剪后回传 - 单班大屏移除退出按钮,仅首页保留 - 修复红绿判定真bug:membersTable 误用 window.DASH(DASH为let声明取不到) 改为 scoreGrade() 直接读自由变量,按后台合格率正确判红/黄/绿 测试/样例/文档同步更新,全量回归通过。
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
#!/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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
// 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 (单场宽表)');
|
||||
Reference in New Issue
Block a user