seed.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. from __future__ import annotations
  2. from datetime import datetime, timedelta, timezone
  3. from sqlalchemy import select
  4. from sqlalchemy.orm import Session
  5. from app.db.base import new_id
  6. from app.db.models.diagnosis import DiagnosisRule
  7. from app.db.models.document import BusinessDocument, DocumentExtraction
  8. from app.db.models.evaluation import EvaluationIndicator
  9. from app.db.models.knowledge import KnowledgeItem
  10. from app.db.models.mine import Mine, MineArea, Roadway, WorkFace
  11. from app.db.models.monitoring import (
  12. DataSource,
  13. Sensor,
  14. SensorReading,
  15. VentilationFacility,
  16. )
  17. from app.db.models.work_order import Alarm, WorkOrder, WorkOrderEvent
  18. def seed_demo_data(db: Session) -> None:
  19. if db.scalar(select(Mine).where(Mine.code == "shangwan")):
  20. return
  21. now = datetime.now(timezone.utc)
  22. mine = Mine(
  23. id=new_id(),
  24. code="shangwan",
  25. name="上湾煤矿",
  26. short_name="上湾煤矿",
  27. province="内蒙古自治区",
  28. city="鄂尔多斯市",
  29. status="active",
  30. production_capacity=1600,
  31. design_capacity=1600,
  32. ventilation_method="中央并列式",
  33. description="通防智能管控平台示范矿井",
  34. settings={"coordinate_system": "CGCS2000"},
  35. is_default=True,
  36. )
  37. area = MineArea(
  38. id=new_id(),
  39. mine_id=mine.id,
  40. code="N",
  41. name="北翼采区",
  42. area_type="采区",
  43. depth=420,
  44. status="active",
  45. )
  46. face = WorkFace(
  47. id=new_id(),
  48. mine_id=mine.id,
  49. area_id=area.id,
  50. code="N1202",
  51. name="N1202 综采工作面",
  52. face_type="采煤工作面",
  53. status="active",
  54. planned_air_volume=1404,
  55. actual_air_volume=1286,
  56. gas_limit=0.8,
  57. dust_limit=4.0,
  58. location={"x": 1202, "y": 386, "z": -420},
  59. )
  60. return_roadway = Roadway(
  61. id=new_id(),
  62. mine_id=mine.id,
  63. area_id=area.id,
  64. code="N1202-R",
  65. name="N1202 回风巷",
  66. roadway_type="回风巷",
  67. start_node="N1202",
  68. end_node="北翼回风",
  69. length=1260,
  70. cross_section_area=18.6,
  71. resistance=2860,
  72. airflow=1286,
  73. status="warning",
  74. properties={"support_type": "锚网索"},
  75. )
  76. gas_source = DataSource(
  77. id=new_id(),
  78. mine_id=mine.id,
  79. code="KJ-SAFETY",
  80. name="KJ 安全监控系统",
  81. source_type="monitoring",
  82. protocol="OPC UA",
  83. endpoint="opc.tcp://10.20.16.28:4840",
  84. status="online",
  85. last_sync_at=now,
  86. point_count=1286,
  87. latency_ms=2400,
  88. config={},
  89. )
  90. video_source = DataSource(
  91. id=new_id(),
  92. mine_id=mine.id,
  93. code="VIDEO",
  94. name="工业视频平台",
  95. source_type="video",
  96. protocol="GB/T 28181",
  97. endpoint="10.20.18.10:5060",
  98. status="online",
  99. last_sync_at=now,
  100. point_count=218,
  101. latency_ms=820,
  102. config={"channels": 218},
  103. )
  104. gas_sensor = Sensor(
  105. id=new_id(),
  106. mine_id=mine.id,
  107. area_id=area.id,
  108. data_source_id=gas_source.id,
  109. code="CH4-N1202-01",
  110. name="N1202 回风巷瓦斯",
  111. sensor_type="gas",
  112. unit="%CH4",
  113. location="N1202 回风巷",
  114. status="online",
  115. warning_threshold=0.6,
  116. alarm_threshold=0.8,
  117. upper_bound=4,
  118. lower_bound=0,
  119. last_value=0.86,
  120. last_seen_at=now,
  121. properties={},
  122. )
  123. airflow_sensor = Sensor(
  124. id=new_id(),
  125. mine_id=mine.id,
  126. area_id=area.id,
  127. data_source_id=gas_source.id,
  128. code="AF-N1202-01",
  129. name="N1202 工作面风量",
  130. sensor_type="airflow",
  131. unit="m³/min",
  132. location="N1202 工作面",
  133. status="online",
  134. warning_threshold=1300,
  135. alarm_threshold=1200,
  136. upper_bound=1800,
  137. lower_bound=0,
  138. last_value=1286,
  139. last_seen_at=now,
  140. properties={},
  141. )
  142. dust_sensor = Sensor(
  143. id=new_id(),
  144. mine_id=mine.id,
  145. area_id=area.id,
  146. data_source_id=gas_source.id,
  147. code="DUST-S1302-01",
  148. name="S1302 粉尘",
  149. sensor_type="dust",
  150. unit="mg/m³",
  151. location="S1302 回风巷",
  152. status="online",
  153. warning_threshold=3.5,
  154. alarm_threshold=4.0,
  155. upper_bound=10,
  156. lower_bound=0,
  157. last_value=4.2,
  158. last_seen_at=now,
  159. properties={},
  160. )
  161. gate = VentilationFacility(
  162. id=new_id(),
  163. mine_id=mine.id,
  164. area_id=area.id,
  165. roadway_id=return_roadway.id,
  166. code="FG-002",
  167. name="2# 调节风门",
  168. facility_type="风门",
  169. location="北翼回风巷",
  170. status="warning",
  171. open_state="open",
  172. sensor_value=42,
  173. video_confidence=0.91,
  174. last_checked_at=now,
  175. properties={},
  176. )
  177. db.add_all(
  178. [
  179. mine,
  180. area,
  181. face,
  182. return_roadway,
  183. gas_source,
  184. video_source,
  185. gas_sensor,
  186. airflow_sensor,
  187. dust_sensor,
  188. gate,
  189. ]
  190. )
  191. db.flush()
  192. readings = []
  193. for sensor, base in (
  194. (gas_sensor, 0.46),
  195. (airflow_sensor, 1380),
  196. (dust_sensor, 3.1),
  197. ):
  198. for index in range(24):
  199. value = base + (index % 6) * (0.03 if sensor.sensor_type == "gas" else 8)
  200. readings.append(
  201. SensorReading(
  202. id=new_id(),
  203. sensor_id=sensor.id,
  204. measured_at=now - timedelta(hours=23 - index),
  205. value=round(value, 2),
  206. quality=100,
  207. is_alarm=sensor.sensor_type == "gas" and value >= 0.8,
  208. source="seed",
  209. meta={},
  210. )
  211. )
  212. db.add_all(readings)
  213. documents = [
  214. BusinessDocument(
  215. id=new_id(),
  216. mine_id=mine.id,
  217. code="TF-CS-2026-086",
  218. title="N1202 工作面通风安全技术措施",
  219. category="通风专业",
  220. subcategory="安全技术措施",
  221. file_name="N1202通风安全技术措施.pdf",
  222. file_path="data/uploads/N1202通风安全技术措施.pdf",
  223. file_ext=".pdf",
  224. file_size=2_936_012,
  225. page_count=42,
  226. owner_name="王强",
  227. department="通防科",
  228. version="V1.0",
  229. parse_status="completed",
  230. parse_progress=100,
  231. tags=["通风", "N1202", "安全措施"],
  232. summary="N1202 工作面通风方式、需风量和瓦斯管理要求。",
  233. metadata_json={},
  234. ),
  235. BusinessDocument(
  236. id=new_id(),
  237. mine_id=mine.id,
  238. code="TF-BB-2026-091",
  239. title="2026 年 9 月通风阻力测定报告",
  240. category="通风专业",
  241. subcategory="测定报告",
  242. file_name="通风阻力测定报告.docx",
  243. file_path="data/uploads/通风阻力测定报告.docx",
  244. file_ext=".docx",
  245. file_size=1_678_592,
  246. page_count=28,
  247. owner_name="赵磊",
  248. department="通防科",
  249. parse_status="completed",
  250. parse_progress=100,
  251. tags=["通风阻力", "月度报告"],
  252. summary="北翼回风系统阻力和主通风机工况分析。",
  253. metadata_json={},
  254. ),
  255. BusinessDocument(
  256. id=new_id(),
  257. mine_id=mine.id,
  258. code="TF-BB-2026-092",
  259. title="矿井测风记录日报表",
  260. category="监测监控",
  261. subcategory="台账报表",
  262. file_name="测风记录日报表.xlsx",
  263. file_path="data/uploads/测风记录日报表.xlsx",
  264. file_ext=".xlsx",
  265. file_size=876_544,
  266. row_count=1240,
  267. owner_name="刘伟",
  268. department="通防科",
  269. parse_status="processing",
  270. parse_progress=76,
  271. tags=["测风", "日报"],
  272. summary="各测风站风量和风速记录。",
  273. metadata_json={},
  274. ),
  275. BusinessDocument(
  276. id=new_id(),
  277. mine_id=mine.id,
  278. code="TF-SJ-2026-034",
  279. title="S1302 工作面综合防尘设计",
  280. category="粉尘防治",
  281. subcategory="专项设计",
  282. file_name="S1302综合防尘设计.pdf",
  283. file_path="data/uploads/S1302综合防尘设计.pdf",
  284. file_ext=".pdf",
  285. file_size=3_250_176,
  286. page_count=36,
  287. owner_name="陈晨",
  288. department="通防科",
  289. parse_status="pending",
  290. parse_progress=0,
  291. tags=["粉尘", "S1302"],
  292. summary="综合防尘设施和喷雾降尘设计。",
  293. metadata_json={},
  294. ),
  295. ]
  296. db.add_all(documents)
  297. db.flush()
  298. db.add_all(
  299. [
  300. DocumentExtraction(
  301. id=new_id(),
  302. document_id=documents[0].id,
  303. field_key="ventilation_method",
  304. field_name="通风方式",
  305. field_value="U 型通风",
  306. normalized_value="U型通风",
  307. confidence=0.968,
  308. page_no=8,
  309. verified=True,
  310. metadata_json={},
  311. ),
  312. DocumentExtraction(
  313. id=new_id(),
  314. document_id=documents[0].id,
  315. field_key="planned_air_volume",
  316. field_name="设计需风量",
  317. field_value="1404 m³/min",
  318. normalized_value="1404",
  319. unit="m³/min",
  320. confidence=0.942,
  321. page_no=12,
  322. verified=True,
  323. metadata_json={},
  324. ),
  325. ]
  326. )
  327. db.add_all(
  328. [
  329. KnowledgeItem(
  330. id=new_id(),
  331. mine_id=mine.id,
  332. document_id=documents[0].id,
  333. code="K-REG-001",
  334. title="瓦斯超限处置要求",
  335. knowledge_type="规程",
  336. category="瓦斯防治",
  337. source_type="document",
  338. source_ref="N1202 工作面通风安全技术措施",
  339. content="瓦斯浓度超限后应立即停止作业、切断电源、撤出人员,并核查局部通风和回风系统。",
  340. summary="明确瓦斯超限后的撤人、断电、检查和复测闭环要求。",
  341. tags=["瓦斯", "超限", "应急处置"],
  342. is_verified=True,
  343. verified_by="通防专家",
  344. metadata_json={},
  345. ),
  346. KnowledgeItem(
  347. id=new_id(),
  348. mine_id=mine.id,
  349. code="K-CASE-001",
  350. title="调节风门状态异常处置案例",
  351. knowledge_type="事故案例",
  352. category="通风专业",
  353. source_type="manual",
  354. source_ref="2024-026",
  355. content="视频判断风门未闭合但传感器反馈正常时,应优先现场复核闭锁装置、密封状态和传感器安装位置。",
  356. summary="说明视频与传感器冲突时的联合核查方法。",
  357. tags=["风门", "漏风", "视频识别"],
  358. is_verified=True,
  359. verified_by="通防专家",
  360. metadata_json={},
  361. ),
  362. KnowledgeItem(
  363. id=new_id(),
  364. mine_id=mine.id,
  365. code="K-RULE-001",
  366. title="局部通风机循环风判定要点",
  367. knowledge_type="专家经验",
  368. category="通风专业",
  369. source_type="expert",
  370. source_ref="专家规则 R-021",
  371. content="判定循环风应结合吸风口瓦斯浓度、风筒出口距离、巷道风流方向和风量变化综合判断。",
  372. summary="局部通风机循环风多因素判定方法。",
  373. tags=["局部通风", "循环风"],
  374. is_verified=True,
  375. verified_by="通防专家",
  376. metadata_json={},
  377. ),
  378. ]
  379. )
  380. db.add_all(
  381. [
  382. DiagnosisRule(
  383. id=new_id(),
  384. mine_id=mine.id,
  385. code="R-GAS-001",
  386. name="瓦斯浓度超限",
  387. scene="灾害防治",
  388. defect_type="瓦斯超限",
  389. severity="high",
  390. condition={"sensor_type": "gas", "operator": ">=", "field": "alarm_threshold"},
  391. threshold={"value": 0.8, "unit": "%CH4"},
  392. output_template="监测点瓦斯浓度超过报警阈值。",
  393. recommendation="停止作业、切断电源、撤出人员并核查通风系统。",
  394. knowledge_refs=["K-REG-001"],
  395. ),
  396. DiagnosisRule(
  397. id=new_id(),
  398. mine_id=mine.id,
  399. code="R-AF-001",
  400. name="工作面风量不足",
  401. scene="风量分配",
  402. defect_type="风量不足",
  403. severity="medium",
  404. condition={"actual_ratio": "<", "value": 0.9},
  405. threshold={"ratio": 0.9},
  406. output_template="实际风量低于计划风量的 90%。",
  407. recommendation="核查风窗、漏风点和巷道阻力,调整后复测。",
  408. ),
  409. DiagnosisRule(
  410. id=new_id(),
  411. mine_id=mine.id,
  412. code="R-FAC-001",
  413. name="通风设施状态异常",
  414. scene="通风设施",
  415. defect_type="设施状态异常",
  416. severity="medium",
  417. condition={"facility_status": "!=", "value": "normal"},
  418. threshold={},
  419. output_template="设施传感器或视频状态异常。",
  420. recommendation="安排现场复核设施开闭状态和传感器工作状态。",
  421. ),
  422. ]
  423. )
  424. indicator_rows = [
  425. ("SAFETY", "安全性", "安全性", 0.3, 1),
  426. ("RELIABILITY", "可靠性", "可靠性", 0.2, 2),
  427. ("ECONOMY", "经济性", "经济性", 0.15, 3),
  428. ("MANAGEMENT", "管理合规", "管理合规", 0.2, 4),
  429. ("DATA_QUALITY", "数据质量", "数据质量", 0.15, 5),
  430. ]
  431. for code, name, dimension, weight, sort_order in indicator_rows:
  432. db.add(
  433. EvaluationIndicator(
  434. id=new_id(),
  435. mine_id=mine.id,
  436. code=code,
  437. name=name,
  438. dimension=dimension,
  439. indicator_type="composite",
  440. weight=weight,
  441. weight_method="static",
  442. enabled=True,
  443. sort_order=sort_order,
  444. config={},
  445. )
  446. )
  447. alarm = Alarm(
  448. id=new_id(),
  449. mine_id=mine.id,
  450. sensor_id=gas_sensor.id,
  451. alarm_no="AL-20261008-001",
  452. alarm_type="gas_over_limit",
  453. level="high",
  454. title="N1202 回风巷瓦斯浓度超限",
  455. content="瓦斯浓度达到 0.86%,超过 0.80% 报警阈值。",
  456. value=0.86,
  457. threshold=0.8,
  458. status="open",
  459. occurred_at=now - timedelta(minutes=12),
  460. metadata_json={},
  461. )
  462. db.add(alarm)
  463. db.flush()
  464. order = WorkOrder(
  465. id=new_id(),
  466. mine_id=mine.id,
  467. alarm_id=alarm.id,
  468. order_no="WO-20261008-001",
  469. title="N1202 回风巷瓦斯超限处置",
  470. content="核查局部通风机、风筒和回风系统运行状态,完成复测后闭环。",
  471. priority="high",
  472. status="processing",
  473. assignee_name="王强",
  474. department="通防科",
  475. due_at=now + timedelta(hours=2),
  476. attachments=[],
  477. metadata_json={},
  478. )
  479. db.add(order)
  480. db.flush()
  481. db.add(
  482. WorkOrderEvent(
  483. id=new_id(),
  484. work_order_id=order.id,
  485. event_type="created",
  486. to_status="processing",
  487. operator_name="系统",
  488. comment="根据瓦斯超限告警自动创建",
  489. attachments=[],
  490. created_at=now - timedelta(minutes=10),
  491. )
  492. )
  493. db.commit()