dev #1
@ -168,6 +168,7 @@ def aggregate_report_data(result: RiskAssessmentResult) -> dict[str, Any]:
|
||||
supplier_cards = [card for card in cards if card.type == "supplier"]
|
||||
material_cards = [card for card in cards if card.type == "material"]
|
||||
solution_cards = [card for card in cards if card.type == "solution"]
|
||||
standard_cards = [card for card in cards if card.type in {"standard", "compliance"}]
|
||||
standards = _unique_by(
|
||||
[*result.standard_judgment, *(item for card in cards for item in card.standards)],
|
||||
lambda item: (item.category, item.risk_point, item.rule, item.status),
|
||||
@ -182,10 +183,10 @@ def aggregate_report_data(result: RiskAssessmentResult) -> dict[str, Any]:
|
||||
item.solution,
|
||||
),
|
||||
)
|
||||
suggestions = _unique_by(
|
||||
[*result.ai_suggestions, *(item for card in cards for item in card.suggestions)],
|
||||
lambda item: item,
|
||||
)
|
||||
# Only base assessment suggestions belong to the prevention section.
|
||||
# Card-specific suggestions stay with their owning section (supplier,
|
||||
# material, standard/compliance or AI reasoning) to avoid duplication.
|
||||
suggestions = _unique_by(list(result.ai_suggestions), lambda item: item)
|
||||
detected_values = [item for card in cards for item in card.detected_values]
|
||||
risks = [(card.title, risk) for card in solution_cards for risk in card.risks]
|
||||
analyses = [card for card in solution_cards if card.analysis_base or card.confidence or card.warning]
|
||||
@ -194,6 +195,7 @@ def aggregate_report_data(result: RiskAssessmentResult) -> dict[str, Any]:
|
||||
"supplier_cards": supplier_cards,
|
||||
"material_cards": material_cards,
|
||||
"solution_cards": solution_cards,
|
||||
"standard_cards": standard_cards,
|
||||
"standards": standards,
|
||||
"similar_cases": similar_cases,
|
||||
"suggestions": suggestions,
|
||||
@ -252,6 +254,9 @@ def build_risk_report_pdf(result: RiskAssessmentResult) -> bytes:
|
||||
standards = report_data["standards"]
|
||||
similar_cases = report_data["similar_cases"]
|
||||
suggestions = report_data["suggestions"]
|
||||
material_cards = report_data["material_cards"]
|
||||
standard_cards = report_data["standard_cards"]
|
||||
section_shift = 1 if material_cards else 0
|
||||
story = [
|
||||
Paragraph("新品风险预估报告", title),
|
||||
Paragraph(f"蝶雅产品部 · 风险预估系统 · 自动生成 · {generated_at}", subtitle),
|
||||
@ -308,7 +313,7 @@ def build_risk_report_pdf(result: RiskAssessmentResult) -> bytes:
|
||||
order_text = f"合作 {supplier.cooperation_count} 次、" if supplier.cooperation_count is not None else ""
|
||||
conclusion = f"{round(score)} 分 · {order_text}异常 {supplier.anomaly_count or 0} 次"
|
||||
elif name == "标准符合性" and result.standard_judgment:
|
||||
conclusion = f"{round(score)} 分 · 命中 {len(result.standard_judgment)} 条判定标准,待检测项需人工确认"
|
||||
conclusion = f"{round(score)} 分 · 命中 {len(standards)} 条判定标准,待检测项需人工确认"
|
||||
else:
|
||||
conclusion = f"{round(score)} 分" + (f" · {reason}" if reason else "")
|
||||
rows.append([f"{name}({weight:g}%)", conclusion])
|
||||
@ -353,7 +358,6 @@ def build_risk_report_pdf(result: RiskAssessmentResult) -> bytes:
|
||||
supplier_rows.append([label, value, "追加供应商画像数据"])
|
||||
story += [Paragraph("三、供应商合作频次分析", section), table(supplier_rows, [38 * mm, 35 * mm, 87 * mm])]
|
||||
|
||||
material_cards = report_data["material_cards"]
|
||||
if material_cards:
|
||||
story += [Paragraph("四、物料风险分析", section)]
|
||||
material_rows = [["物料/字段", "分析结果"]]
|
||||
@ -370,7 +374,7 @@ def build_risk_report_pdf(result: RiskAssessmentResult) -> bytes:
|
||||
)
|
||||
story.append(table(material_rows, [45 * mm, 115 * mm]))
|
||||
|
||||
story += [Paragraph(f"五、相似案例匹配({len(similar_cases)} 条)", section)]
|
||||
story += [Paragraph(f"{'五' if section_shift else '四'}、相似案例匹配({len(similar_cases)} 条)", section)]
|
||||
if similar_cases:
|
||||
story.append(
|
||||
table(
|
||||
@ -385,11 +389,11 @@ def build_risk_report_pdf(result: RiskAssessmentResult) -> bytes:
|
||||
else:
|
||||
story.append(Paragraph("暂无相关案例,RAG 相似案例检索未返回匹配结果。", small))
|
||||
|
||||
story += [Paragraph("六、预防建议", section)]
|
||||
story += [Paragraph(f"{'六' if section_shift else '五'}、预防建议", section)]
|
||||
for index, suggestion in enumerate(suggestions or ["优先针对低分维度安排专项验证,并明确责任人与完成节点。"], 1):
|
||||
story.append(Paragraph(f"{index}. {suggestion}", body))
|
||||
story += [
|
||||
Paragraph("七、AI 推理方案(无历史案例场景)", section),
|
||||
Paragraph(f"{'七' if section_shift else '六'}、AI 推理方案(无历史案例场景)", section),
|
||||
Paragraph(
|
||||
"本次评估已采用历史案例与标准库双引擎结论;若后续未匹配到足够历史案例,将基于相似品类、相似物料生成类比方案,并由标准库进行规则兜底。",
|
||||
body,
|
||||
@ -406,15 +410,28 @@ def build_risk_report_pdf(result: RiskAssessmentResult) -> bytes:
|
||||
if card.warning:
|
||||
story.append(Paragraph(f"风险提示:{card.warning}", body))
|
||||
|
||||
story += [Paragraph("八、标准判定结果", section)]
|
||||
if standards:
|
||||
story += [Paragraph(f"{'八' if section_shift else '七'}、标准判定结果", section)]
|
||||
standard_rows = [
|
||||
[f"{item.category} · {item.risk_point}", item.rule, item.source or "标准文件.xlsx", item.status]
|
||||
for item in standards
|
||||
]
|
||||
for card in standard_cards:
|
||||
if card.detected_values:
|
||||
standard_rows.append(
|
||||
[
|
||||
"检测值",
|
||||
"、".join(f"{item.get('name', '')}:{item.get('value', '')}" for item in card.detected_values),
|
||||
card.title,
|
||||
"待确认",
|
||||
]
|
||||
)
|
||||
if card.note:
|
||||
standard_rows.append(["补充说明", card.note, card.title, "待确认"])
|
||||
if standard_rows:
|
||||
story.append(
|
||||
table(
|
||||
[["判定维度", "判定标准", "标准来源", "当前状态"]]
|
||||
+ [
|
||||
[f"{item.category} · {item.risk_point}", item.rule, item.source or "标准文件.xlsx", item.status]
|
||||
for item in standards
|
||||
],
|
||||
+ standard_rows,
|
||||
[38 * mm, 55 * mm, 40 * mm, 27 * mm],
|
||||
)
|
||||
)
|
||||
@ -525,7 +542,7 @@ def build_risk_report_docx(result: RiskAssessmentResult) -> bytes:
|
||||
order_text = f"合作 {supplier.cooperation_count} 次、" if supplier.cooperation_count is not None else ""
|
||||
conclusion = f"{round(score)} 分 · {order_text}异常 {supplier.anomaly_count or 0} 次"
|
||||
elif name == "标准符合性" and result.standard_judgment:
|
||||
conclusion = f"{round(score)} 分 · 命中 {len(result.standard_judgment)} 条判定标准,待检测项需人工确认"
|
||||
conclusion = f"{round(score)} 分 · 命中 {len(standards)} 条判定标准,待检测项需人工确认"
|
||||
else:
|
||||
conclusion = f"{round(score)} 分" + (f" · {reason}" if reason else "")
|
||||
rows.append([f"{name}({weight:g}%)", conclusion])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user