|
@@ -421,7 +421,7 @@ def _fig_to_base64(fig, *, dpi=120):
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_report_charts(filtered_df, *, daily_trend_df=None):
|
|
def generate_report_charts(filtered_df, *, daily_trend_df=None):
|
|
|
- """生成报告内嵌的三张核心图表,返回 dict of base64 data URIs。"""
|
|
|
|
|
|
|
+ """生成报告内嵌的四张核心图表,返回 dict of base64 data URIs。"""
|
|
|
charts = {}
|
|
charts = {}
|
|
|
|
|
|
|
|
# --- 1. 缺陷类型分布条形图 ---
|
|
# --- 1. 缺陷类型分布条形图 ---
|
|
@@ -491,7 +491,7 @@ def generate_report_charts(filtered_df, *, daily_trend_df=None):
|
|
|
sev_counts = filtered_df["severity"].value_counts()
|
|
sev_counts = filtered_df["severity"].value_counts()
|
|
|
if not sev_counts.empty:
|
|
if not sev_counts.empty:
|
|
|
fig, ax = plt.subplots(figsize=(4.5, 3.5))
|
|
fig, ax = plt.subplots(figsize=(4.5, 3.5))
|
|
|
- sev_colors = {"轻微": "#22c55e", "一般": "#f59e0b", "严重": "#ef4444"}
|
|
|
|
|
|
|
+ sev_colors = {"轻微": "#22c55e", "中等": "#f59e0b", "严重": "#ef4444"}
|
|
|
colors = [sev_colors.get(name, "#94a3b8") for name in sev_counts.index]
|
|
colors = [sev_colors.get(name, "#94a3b8") for name in sev_counts.index]
|
|
|
wedges, texts, autotexts = ax.pie(
|
|
wedges, texts, autotexts = ax.pie(
|
|
|
sev_counts.values, labels=sev_counts.index,
|
|
sev_counts.values, labels=sev_counts.index,
|
|
@@ -516,6 +516,32 @@ def _series_rows(series):
|
|
|
return list(series.items())
|
|
return list(series.items())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def build_report_chart_summaries(type_counts, equipment_counts=None, severity_counts=None, trend_summary="-"):
|
|
|
|
|
+ """生成图表旁的结构化摘要,便于报告快速阅读和追溯。"""
|
|
|
|
|
+ summaries = []
|
|
|
|
|
+ type_rows = _series_rows(type_counts)
|
|
|
|
|
+ if type_rows:
|
|
|
|
|
+ total = max(sum(int(count) for _, count in type_rows), 1)
|
|
|
|
|
+ name, count = type_rows[0]
|
|
|
|
|
+ summaries.append(f"TOP1 缺陷类型:{name},{int(count)} 个,占比 {count / total:.1%}")
|
|
|
|
|
+
|
|
|
|
|
+ equipment_rows = _series_rows(equipment_counts)
|
|
|
|
|
+ if equipment_rows:
|
|
|
|
|
+ name, count = equipment_rows[0]
|
|
|
|
|
+ summaries.append(f"最高缺陷设备:{name},{int(count)} 个缺陷")
|
|
|
|
|
+
|
|
|
|
|
+ severity_rows = _series_rows(severity_counts)
|
|
|
|
|
+ if severity_rows:
|
|
|
|
|
+ total = max(sum(int(count) for _, count in severity_rows), 1)
|
|
|
|
|
+ serious_count = int(dict(severity_rows).get("严重", 0))
|
|
|
|
|
+ summaries.append(f"严重缺陷占比:{serious_count / total:.1%}")
|
|
|
|
|
+
|
|
|
|
|
+ if trend_summary and trend_summary != "-":
|
|
|
|
|
+ summaries.append(str(trend_summary))
|
|
|
|
|
+
|
|
|
|
|
+ return summaries
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def build_html_report(
|
|
def build_html_report(
|
|
|
*,
|
|
*,
|
|
|
generated_at,
|
|
generated_at,
|
|
@@ -531,11 +557,13 @@ def build_html_report(
|
|
|
anomaly_rows=None,
|
|
anomaly_rows=None,
|
|
|
recommendations=None,
|
|
recommendations=None,
|
|
|
charts=None,
|
|
charts=None,
|
|
|
|
|
+ chart_summaries=None,
|
|
|
):
|
|
):
|
|
|
"""生成可直接在浏览器打开的自包含综合 HTML 报告。"""
|
|
"""生成可直接在浏览器打开的自包含综合 HTML 报告。"""
|
|
|
anomaly_rows = anomaly_rows or []
|
|
anomaly_rows = anomaly_rows or []
|
|
|
recommendations = recommendations or []
|
|
recommendations = recommendations or []
|
|
|
charts = charts or {}
|
|
charts = charts or {}
|
|
|
|
|
+ chart_summaries = chart_summaries or []
|
|
|
type_rows = _series_rows(type_counts)
|
|
type_rows = _series_rows(type_counts)
|
|
|
equipment_rows = _series_rows(equipment_counts)
|
|
equipment_rows = _series_rows(equipment_counts)
|
|
|
seat_rows = _series_rows(seat_top)
|
|
seat_rows = _series_rows(seat_top)
|
|
@@ -566,6 +594,9 @@ def build_html_report(
|
|
|
recommendation_items = "\n".join(
|
|
recommendation_items = "\n".join(
|
|
|
f"<li>{_escape(item)}</li>" for item in recommendations
|
|
f"<li>{_escape(item)}</li>" for item in recommendations
|
|
|
) or "<li>暂无建议</li>"
|
|
) or "<li>暂无建议</li>"
|
|
|
|
|
+ chart_summary_items = "\n".join(
|
|
|
|
|
+ f"<li>{_escape(item)}</li>" for item in chart_summaries
|
|
|
|
|
+ ) or "<li>暂无图表摘要</li>"
|
|
|
|
|
|
|
|
return f"""<!doctype html>
|
|
return f"""<!doctype html>
|
|
|
<html lang="zh-CN">
|
|
<html lang="zh-CN">
|
|
@@ -656,6 +687,11 @@ def build_html_report(
|
|
|
<tr><td>严重缺陷</td><td>{int(kpis.get('critical_defects', 0))} 个</td></tr>
|
|
<tr><td>严重缺陷</td><td>{int(kpis.get('critical_defects', 0))} 个</td></tr>
|
|
|
</table>
|
|
</table>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div class="card">
|
|
|
|
|
+ <h2>图表摘要</h2>
|
|
|
|
|
+ <ul>{chart_summary_items}</ul>
|
|
|
|
|
+ <p class="note">摘要由导出时的筛选数据自动生成,适合会议或邮件快速阅读。</p>
|
|
|
|
|
+ </div>
|
|
|
<div class="card">
|
|
<div class="card">
|
|
|
<h2>2. 趋势分析</h2>
|
|
<h2>2. 趋势分析</h2>
|
|
|
<p>{_escape(trend_summary)}</p>
|
|
<p>{_escape(trend_summary)}</p>
|