feat: 结题报告初稿助手首版 v1.0.1(draft-closing-report-default)
All checks were successful
技能自动化发布 / release (push) Successful in 6s
All checks were successful
技能自动化发布 / release (push) Successful in 6s
This commit is contained in:
104
scripts/service/report_service.py
Normal file
104
scripts/service/report_service.py
Normal file
@@ -0,0 +1,104 @@
|
||||
"""初稿 HTML 预览组装。
|
||||
|
||||
与 Word 初稿同构内容写入 `{skill_data}/html/draft-{id}.html`,宿主侧栏可预览;
|
||||
重建走固定 Action id `render-html`。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from service.html_page_service import load_html_template, render_html_placeholders, write_html_page
|
||||
from util.logging_config import get_skill_logger
|
||||
|
||||
_TEMPLATE_REL = "assets/html/draft-preview.html"
|
||||
|
||||
|
||||
def _esc(value: Any) -> str:
|
||||
import html
|
||||
|
||||
return html.escape(str(value if value is not None else "—"), quote=True)
|
||||
|
||||
|
||||
def _sections_html(sections: dict[str, list[str]]) -> str:
|
||||
parts = []
|
||||
for title, paragraphs in (sections or {}).items():
|
||||
items = "".join(f"<p class='para{' placeholder' if p.startswith('[待补充') else ''}'>{_esc(p)}</p>" for p in paragraphs)
|
||||
parts.append(f"<div class='section'><h2>{_esc(title)}</h2>{items}</div>")
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
def build_preview_html(draft: dict[str, Any]) -> str:
|
||||
body = f"""
|
||||
<div class="verdict-line">
|
||||
<span class="tag tier-info">初稿</span>
|
||||
<span class="muted">项目 {_esc(draft.get("project_no"))} · 批次 {_esc(draft.get("batch_no"))}</span>
|
||||
</div>
|
||||
<div class="section"><h2>生成说明</h2>
|
||||
<p class="para">数据章节(完成情况/决算/成果清单)由台账自动生成,请逐项核对;叙事章节仅提供素材要点,须由项目负责人本人终审。</p>
|
||||
</div>
|
||||
{_sections_html(draft.get("sections") or {})}
|
||||
<footer>本预览与 Word 初稿同构;严禁引入台账之外的成果或结论。以本单位结题报告模板为准。</footer>
|
||||
"""
|
||||
template = load_html_template(_TEMPLATE_REL)
|
||||
return render_html_placeholders(
|
||||
template,
|
||||
{
|
||||
"TITLE": f"结题报告初稿预览 · {draft.get('project_name') or draft.get('project_no') or ''}",
|
||||
"GENERATED_AT": "",
|
||||
"BODY": body,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def write_preview_for_kernel(*, draft: dict[str, Any]) -> str:
|
||||
html_text = build_preview_html(draft)
|
||||
log = get_skill_logger()
|
||||
path = write_html_page("draft-preview.html", html_text)
|
||||
log.info("draft_preview_written project_no=%s path=%s stage=report", draft.get("project_no"), path)
|
||||
return path
|
||||
|
||||
|
||||
def build_preview_for_draft_id(draft_id: int) -> str:
|
||||
"""按初稿记录 id 重建 HTML 预览(重建入口用)。"""
|
||||
from db.connection import get_conn
|
||||
|
||||
log = get_skill_logger()
|
||||
log.info("preview_render_start draft_id=%s stage=render", draft_id)
|
||||
conn = get_conn()
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT * FROM report_drafts WHERE id = ?", (draft_id,))
|
||||
row = cur.fetchone()
|
||||
if not row:
|
||||
raise ValueError(f"初稿记录不存在:{draft_id}")
|
||||
columns = [d[0] for d in cur.description]
|
||||
record = dict(zip(columns, row))
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
try:
|
||||
completion = json.loads(record.get("completion_json") or "[]")
|
||||
except (TypeError, ValueError):
|
||||
completion = []
|
||||
try:
|
||||
narrative_points = json.loads(record.get("narrative_points_json") or "[]")
|
||||
except (TypeError, ValueError):
|
||||
narrative_points = []
|
||||
|
||||
sections: dict[str, list[str]] = {
|
||||
"完成情况(自动生成)": [f"{row.get('type')}:{row.get('detail')}" for row in completion] or ["指标未配置(W1)。"],
|
||||
"叙事素材要点": [f"· {p.get('point')}(来源:{p.get('source')})" for p in narrative_points] or ["无素材,请补录成果/年度报告摘句。"],
|
||||
"Word 初稿": [f"文件:{record.get('draft_file') or '—'}(output 目录可取)"],
|
||||
}
|
||||
draft = {
|
||||
"project_no": record.get("project_no"),
|
||||
"project_name": record.get("project_name"),
|
||||
"batch_no": record.get("batch_no"),
|
||||
"sections": sections,
|
||||
}
|
||||
html_text = build_preview_html(draft)
|
||||
path = write_html_page(f"draft-{draft_id}.html", html_text)
|
||||
log.info("preview_render_done draft_id=%s path=%s stage=render", draft_id, path)
|
||||
return path
|
||||
Reference in New Issue
Block a user