fix: 对照《财务处Skill002》验收整改并升版 v1.0.2
All checks were successful
技能自动化发布 / release (push) Successful in 9s
All checks were successful
技能自动化发布 / release (push) Successful in 9s
- 状态标签:C3 触发且 D 未判 → 待补录,优先级对齐需求 §6.2 - broadcast-monthly 逐项目增量 emit,任务中心可见进行中进度 - progress_reports 回填 project_id;新增 items_json/updated_at;旧库重建式安全迁移(含回归测试) - 简报:TITLE 转义防注入、章节对齐 §10(独立「暂付款/结题提醒」)、页脚逐字统一 - 金标准测试 +17:±10%/20% 阈值恰界、C2 钳位、N2 反例、C3 逐字段、HTML 转义、async+cron 定位守护、迁移回归 - 文档 v1.1(开发文档 + REQUIREMENTS):ERROR:<CODE> <message>、reports_brief、--all-status、skill-detail 表外挂载、C1 level=warn - 落盘验收报告 acceptance-reports/20260924-105401-acceptance.md(338 测试全绿) - 版本 1.0.1 → 1.0.2(constants / SKILL.md / CHANGELOG 三处对齐)
This commit is contained in:
@@ -100,6 +100,19 @@ def _project_info_table(result: dict[str, Any]) -> str:
|
||||
return f'<table class="info">{"".join(rows)}</table>'
|
||||
|
||||
|
||||
def _reminder_section(result: dict[str, Any]) -> str:
|
||||
"""§10 独立「暂付款 / 结题提醒」章节:取 N1/N2 规则命中明细(kernel 与重建同源 items_json)。"""
|
||||
reminders = [i for i in (result.get("items") or []) if i.get("rule_id") in ("N1", "N2")]
|
||||
if not reminders:
|
||||
return ""
|
||||
rows = []
|
||||
for item in reminders:
|
||||
suggestion = item.get("suggestion") or ""
|
||||
tail = f'<br/><span class="muted">{_esc(suggestion)}</span>' if suggestion else ""
|
||||
rows.append(f"<li><strong>{_esc(item.get('name'))}</strong>:{_esc(item.get('detail'))}{tail}</li>")
|
||||
return f'<div class="section"><h2>暂付款 / 结题提醒</h2><ul>{"".join(rows)}</ul></div>'
|
||||
|
||||
|
||||
def build_progress_html(result: dict[str, Any], batch_no: str = "") -> str:
|
||||
"""组装单个项目的《经费执行简报》HTML 文本。"""
|
||||
status = str(result.get("status_tag") or "")
|
||||
@@ -114,22 +127,23 @@ def build_progress_html(result: dict[str, Any], batch_no: str = "") -> str:
|
||||
<span class="tag {badge}">{mark}</span>
|
||||
<span class="muted">批次 {_esc(batch_no or result.get("batch_no"))} · 评估基准日 {_esc(result.get("as_of"))}</span>
|
||||
</div>
|
||||
<div class="section"><h2>项目信息</h2>{_project_info_table(result)}</div>
|
||||
<div class="section"><h2>执行进度对比</h2>
|
||||
{_bar("实际支出率", result.get("spend_rate"), "fill-spend")}
|
||||
{_bar("序时进度", result.get("time_progress"), "fill-time")}
|
||||
<p class="muted">偏差 = 实际支出率 − 序时进度 = {_esc(_pct(result.get("deviation")))}</p>
|
||||
</div>
|
||||
<div class="section"><h2>项目信息</h2>{_project_info_table(result)}</div>
|
||||
<div class="section"><h2>播报摘要</h2>{summary_html}</div>
|
||||
<div class="section"><h2>建议</h2>{_suggestion_list(result.get("suggestions"))}</div>
|
||||
<footer>本简报由项目台账数据自动生成,仅作提醒;金额与执行进度请以财务系统账面为准。</footer>
|
||||
{_reminder_section(result)}
|
||||
<footer>播报由台账数据自动生成,请以财务系统账面为准。</footer>
|
||||
"""
|
||||
|
||||
template = load_html_template(_PROGRESS_TEMPLATE_REL)
|
||||
return render_html_placeholders(
|
||||
template,
|
||||
{
|
||||
"TITLE": f"经费执行简报 · {result.get('project_name') or result.get('project_no') or ''}",
|
||||
"TITLE": _esc(f"经费执行简报 · {result.get('project_name') or result.get('project_no') or ''}"),
|
||||
"GENERATED_AT": "",
|
||||
"BODY": body,
|
||||
},
|
||||
@@ -193,6 +207,10 @@ def _record_to_result(record: dict[str, Any]) -> dict[str, Any]:
|
||||
result["suggestions"] = json.loads(record.get("suggestions_json") or "[]")
|
||||
except (TypeError, ValueError):
|
||||
result["suggestions"] = []
|
||||
try:
|
||||
result["items"] = json.loads(record.get("items_json") or "[]")
|
||||
except (TypeError, ValueError):
|
||||
result["items"] = []
|
||||
return result
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user