-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreport_utils.py
More file actions
160 lines (145 loc) · 6.31 KB
/
Copy pathreport_utils.py
File metadata and controls
160 lines (145 loc) · 6.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""
report_utils.py
自动生成桥梁设计说明书(Word 文档),汇总设计参数、工程量、配筋估算与合理性提示
"""
import io
from datetime import datetime
from typing import Any, Dict, List, Optional
from docx import Document
def _add_kv_table(doc: Document, headers: List[str], rows: List[List[str]]) -> None:
table = doc.add_table(rows=1, cols=len(headers))
table.style = "Light Grid Accent 1"
hdr_cells = table.rows[0].cells
for i, h in enumerate(headers):
hdr_cells[i].text = h
for row in rows:
cells = table.add_row().cells
for i, v in enumerate(row):
cells[i].text = str(v)
def generate_design_report_docx(
spans: List[float],
beam_h: float,
pier_h: float,
bridge_w: float,
quantities: Dict[str, Any],
warnings: Optional[List[str]] = None,
rebar_results: Optional[List[Dict[str, Any]]] = None,
stirrup_spec: Optional[Dict[str, Any]] = None,
ai_chat_history: Optional[List[Dict[str, str]]] = None,
force_results: Optional[List[Dict[str, Any]]] = None,
capacity_results: Optional[List[Dict[str, Any]]] = None,
) -> bytes:
"""生成设计说明书 Word 文档,返回文件的二进制内容(供 Streamlit download_button 使用)"""
doc = Document()
doc.add_heading("桥梁设计说明书", level=0)
doc.add_paragraph(f"生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
doc.add_paragraph(
"本文档由 AutoBridge-CAD 自动生成,用于方案设计阶段参考,"
"不能替代正式工程计算、审图与专家评审流程。"
)
doc.add_heading("一、设计参数", level=1)
span_text = "、".join(f"{s:.1f}m" for s in spans)
_add_kv_table(
doc,
["参数", "数值"],
[
["跨径布置", f"{len(spans)} 跨:{span_text}"],
["主梁高度", f"{beam_h:.2f} m"],
["桥墩高度", f"{pier_h:.2f} m"],
["桥面宽度", f"{bridge_w:.2f} m"],
],
)
doc.add_heading("二、工程量统计", level=1)
_add_kv_table(
doc,
["项目", "数值"],
[
["桥梁总长", f"{quantities.get('total_length_m', '-')} m"],
["桥面总面积", f"{quantities.get('deck_area_m2', '-')} m²"],
["主梁混凝土体积", f"{quantities.get('beam_volume_m3', '-')} m³"],
["中间桥墩数量", f"{quantities.get('num_piers', '-')} 座"],
["桥墩混凝土总量", f"{quantities.get('total_pier_volume_m3', '-')} m³"],
["主体混凝土总用量", f"{quantities.get('total_concrete_m3', '-')} m³"],
],
)
if rebar_results:
doc.add_heading("三、主梁配筋估算(简化参考)", level=1)
p = doc.add_paragraph()
run = p.add_run(
"以下配筋数据基于\"截面面积 × 经验配筋率\"的简化估算,"
"仅用于方案演示参考,不是正式的结构受弯承载力计算结果,"
"不能作为实际工程设计或施工依据。"
)
run.bold = True
rows = [
[
f"第{i + 1}片梁",
f"Φ{r['bar_diameter_mm']}mm × {r['num_bars']}根",
f"{r['spacing_mm']}mm",
f"{r['provided_area_mm2']}mm²",
]
for i, r in enumerate(rebar_results)
]
_add_kv_table(doc, ["梁片", "主筋规格", "净间距", "提供钢筋面积"], rows)
if stirrup_spec:
doc.add_paragraph(
f"箍筋建议规格:Φ{stirrup_spec['diameter_mm']}mm @ "
f"{stirrup_spec['spacing_mm']}mm(经验构造做法,非计算值)"
)
if force_results:
doc.add_heading("四、结构分析(连续梁矩阵位移法)", level=1)
p = doc.add_paragraph()
run = p.add_run(
"以下内力分析采用简化等效均布荷载(未考虑真实车道荷载、冲击系数、"
"多工况组合),承载力校核采用矩形应力图法并假定各片梁均匀分担整体弯矩,"
"仅用于方案演示参考,不能作为实际工程设计依据。"
)
run.bold = True
force_rows = [
[
f"第{r['span_index']}跨",
f"{r['span_m']:.1f}m",
f"{r['m_left_knm']:.1f}",
f"{r['m_mid_knm']:.1f}",
f"{r['m_right_knm']:.1f}",
f"{r['v_left_kn']:.1f} / {r['v_right_kn']:.1f}",
]
for r in force_results
]
_add_kv_table(
doc,
["跨号", "跨径", "左端弯矩(kN·m)", "跨中弯矩(kN·m)", "右端弯矩(kN·m)", "左/右端剪力(kN)"],
force_rows,
)
if capacity_results:
doc.add_paragraph("截面承载力校核(单片梁):")
cap_rows = [
[
f"第{i + 1}跨",
f"{c['m_demand_knm']:.1f}",
f"{c['mu_knm']:.1f}",
f"{c['utilization']:.2f}",
# overall_adequate 综合了"抗弯承载力"与"配筋净距是否过密"两个
# 维度,跟界面上的判断标准保持一致;旧数据没有这个字段时退回
# 只看抗弯承载力,不至于直接报错
"满足" if c.get("overall_adequate", c["is_adequate"]) else "不满足",
]
for i, c in enumerate(capacity_results)
]
_add_kv_table(
doc, ["跨号", "弯矩需求(kN·m)", "抗弯承载力Mu(kN·m)", "利用率", "是否满足"], cap_rows
)
doc.add_heading("五、工程合理性提示", level=1)
if warnings:
for w in warnings:
doc.add_paragraph(w, style="List Bullet")
else:
doc.add_paragraph("未发现明显的经验性不合理项(仅基于简化经验公式判断,不代表通过正式规范校核)。")
if ai_chat_history:
doc.add_heading("六、AI 辅助设计过程记录", level=1)
for msg in ai_chat_history:
role = "用户" if msg.get("role") == "user" else "AI"
doc.add_paragraph(f"【{role}】{msg.get('content', '')}")
buffer = io.BytesIO()
doc.save(buffer)
return buffer.getvalue()