feat(ui): 报告预览改用 pdf.js、读标页左右布局、「导出」改称「生成」
Some checks are pending
ci / server (push) Waiting to run
ci / web (push) Waiting to run
ci / contract (push) Waiting to run

- 报告页:预览从浏览器自带 PDF 查看器(深色、改不了配色)换成 pdf.js 连续滚动(components/ReportViewer.vue),顶栏带下载;
  「导出 PDF」改为「生成报告 / 重新生成报告」,列表改称「已生成的报告」,最新一份之后又检查或致命数变了时提示重新生成
- 报告 PDF 模板 2026.11-v4:「导出人 / 导出时」改为「生成」;其余页面的「导出的报告」同步改称
- 读标页:改成和查标、概览一样的左右布局,项目头和清单栏滚出屏幕;分类导航、搜索栏和卡片上沿贴在顶栏下方留出间距
- 读标页:响应方式收进清单栏「响应方式」按钮的浮层,招标文件没写明或写法不一致且没人改过时按钮上加提示点;清单状态改为标题下一行
- 概览检查记录:报告列只写份数和「查看报告」,跳到报告标签页并预览那次检查最新的一份
- 招标 / 投标文件切换标签:双箭头放在文字两头,方向改为指向展开的方向
- 项目头:投标截止、状态、就绪三项取值同高对齐

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
YANG JIANKUAN
2026-11-05 15:57:00 +08:00
parent dd8c04001d
commit 0b783ababa
17 changed files with 455 additions and 190 deletions

View File

@@ -1,7 +1,7 @@
"""检查报告的 HTML(设计规范 §7.17,原型 report.html):纯函数,输入整理好的数据,输出正文、页眉、页脚三段 HTML,
由 Gotenberg 的 Chromium 转成 PDF(A4 竖版,页边距 20mm,页眉页脚每页重复、页码自动生成)。
- 首页:项目信息、投标文件版本、检查依据、检查时间、规则版本、导出人和时间、**检查覆盖范围**(查了 / 没查)、
- 首页:项目信息、投标文件版本、检查依据、检查时间、规则版本、生成人和时间、**检查覆盖范围**(查了 / 没查)、
汇总、免责声明;
- 问题明细:级别、问题、说明、出处(可选)、处理状态和处理人;
- 附录:需人工核对的条目和勾选结果(可选);
@@ -19,11 +19,11 @@ from pathlib import Path
from typing import Any
from zoneinfo import ZoneInfo
TEMPLATE_VERSION = "2026.11-v3" # v2:资质问题的「依据:资质库记录」;v3:出处不重复写文件名
TEMPLATE_VERSION = "2026.11-v4" # v2:资质问题的「依据:资质库记录」;v3:出处不重复写文件名;v4:「导出」改称「生成」
TITLE = "投标文件辅助检查报告"
FOOTER = "本报告为辅助检查结果,仅供投标前自查参考"
DISCLAIMER = (
"本报告由标博士比对招标文件和投标文件生成,经用户逐项处理后导出,供投标前自查使用。检查范围以首页「检查覆盖范围」为准;"
"本报告由标博士比对招标文件和投标文件生成,经用户逐项处理后生成,供投标前自查使用。检查范围以首页「检查覆盖范围」为准;"
"结果可能有遗漏或误判,不代表资格审查、符合性审查或评标的结论。是否递交、如何修改,由投标人自行决定。"
)
SEVERITY = {"fatal": "致命", "important": "重要", "hint": "提示"}
@@ -152,7 +152,7 @@ def cover(d: dict[str, Any]) -> str:
checked_at = f'<span class="fig">{when(r.get("finished_at") or r.get("created_at"))}</span>'
run_no = f'第 <span class="fig">{r["run_no"]}</span> 次检查'
alert = (
f'<div class="alert">导出时还有 <b class="fig">{open_fatal}</b> 项致命问题待处理,报告如实列出。</div>'
f'<div class="alert">生成时还有 <b class="fig">{open_fatal}</b> 项致命问题待处理,报告如实列出。</div>'
if open_fatal
else ""
)
@@ -169,7 +169,7 @@ def cover(d: dict[str, Any]) -> str:
<dt>检查依据</dt><dd>{basis}</dd>
<dt>检查时间</dt><dd>{checked_at}({run_no})</dd>
<dt>规则版本</dt><dd class="fig">{_e(r.get("rule_set_version"))}</dd>
<dt>导出</dt><dd>{_e(d["exported_by"])} · <span class="fig">{when(d["exported_at"])}</span></dd>
<dt>生成</dt><dd>{_e(d["exported_by"])} · <span class="fig">{when(d["exported_at"])}</span></dd>
</dl>
{alert}
<h2>检查覆盖范围</h2>
@@ -230,7 +230,7 @@ def appendix(d: dict[str, Any]) -> str:
return f"""
<h2>附录 · 需人工核对</h2>
<p class="cap">这些要求在投标文件里看不出来,需要投标人递交前自己核对。
「未勾选」表示导出时还没有人在系统里勾选核对。</p>
「未勾选」表示生成时还没有人在系统里勾选核对。</p>
<table><thead><tr><th>要求</th><th style="width:48mm">出处</th><th style="width:30mm">核对</th></tr></thead>
<tbody>{body}</tbody></table>
"""