#!/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, '"'); // 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() 里的打印样式保持一致(表头渲染成 ,所以底色写 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 [ '', '' + title + '(预览)', '

' + title + '

' + sub + '

', table, '

标记说明:最高分 标红、' + '红字;合格次数 始终显示(含 0 次),' + '达 ' + meta.pass_times + ' 次标绿、绿底;未达标显示次数、不标绿。', '

教师签字:______________  教研组长签字:______________  日期:____________

', '
', ].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 (单场宽表)');