| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- from __future__ import annotations
- from datetime import datetime, timedelta, timezone
- from sqlalchemy import select
- from sqlalchemy.orm import Session
- from app.db.base import new_id
- from app.db.models.diagnosis import DiagnosisRule
- from app.db.models.document import BusinessDocument, DocumentExtraction
- from app.db.models.evaluation import EvaluationIndicator
- from app.db.models.knowledge import KnowledgeItem
- from app.db.models.mine import Mine, MineArea, Roadway, WorkFace
- from app.db.models.monitoring import (
- DataSource,
- Sensor,
- SensorReading,
- VentilationFacility,
- )
- from app.db.models.work_order import Alarm, WorkOrder, WorkOrderEvent
- def seed_demo_data(db: Session) -> None:
- if db.scalar(select(Mine).where(Mine.code == "shangwan")):
- return
- now = datetime.now(timezone.utc)
- mine = Mine(
- id=new_id(),
- code="shangwan",
- name="上湾煤矿",
- short_name="上湾煤矿",
- province="内蒙古自治区",
- city="鄂尔多斯市",
- status="active",
- production_capacity=1600,
- design_capacity=1600,
- ventilation_method="中央并列式",
- description="通防智能管控平台示范矿井",
- settings={"coordinate_system": "CGCS2000"},
- is_default=True,
- )
- area = MineArea(
- id=new_id(),
- mine_id=mine.id,
- code="N",
- name="北翼采区",
- area_type="采区",
- depth=420,
- status="active",
- )
- face = WorkFace(
- id=new_id(),
- mine_id=mine.id,
- area_id=area.id,
- code="N1202",
- name="N1202 综采工作面",
- face_type="采煤工作面",
- status="active",
- planned_air_volume=1404,
- actual_air_volume=1286,
- gas_limit=0.8,
- dust_limit=4.0,
- location={"x": 1202, "y": 386, "z": -420},
- )
- return_roadway = Roadway(
- id=new_id(),
- mine_id=mine.id,
- area_id=area.id,
- code="N1202-R",
- name="N1202 回风巷",
- roadway_type="回风巷",
- start_node="N1202",
- end_node="北翼回风",
- length=1260,
- cross_section_area=18.6,
- resistance=2860,
- airflow=1286,
- status="warning",
- properties={"support_type": "锚网索"},
- )
- gas_source = DataSource(
- id=new_id(),
- mine_id=mine.id,
- code="KJ-SAFETY",
- name="KJ 安全监控系统",
- source_type="monitoring",
- protocol="OPC UA",
- endpoint="opc.tcp://10.20.16.28:4840",
- status="online",
- last_sync_at=now,
- point_count=1286,
- latency_ms=2400,
- config={},
- )
- video_source = DataSource(
- id=new_id(),
- mine_id=mine.id,
- code="VIDEO",
- name="工业视频平台",
- source_type="video",
- protocol="GB/T 28181",
- endpoint="10.20.18.10:5060",
- status="online",
- last_sync_at=now,
- point_count=218,
- latency_ms=820,
- config={"channels": 218},
- )
- gas_sensor = Sensor(
- id=new_id(),
- mine_id=mine.id,
- area_id=area.id,
- data_source_id=gas_source.id,
- code="CH4-N1202-01",
- name="N1202 回风巷瓦斯",
- sensor_type="gas",
- unit="%CH4",
- location="N1202 回风巷",
- status="online",
- warning_threshold=0.6,
- alarm_threshold=0.8,
- upper_bound=4,
- lower_bound=0,
- last_value=0.86,
- last_seen_at=now,
- properties={},
- )
- airflow_sensor = Sensor(
- id=new_id(),
- mine_id=mine.id,
- area_id=area.id,
- data_source_id=gas_source.id,
- code="AF-N1202-01",
- name="N1202 工作面风量",
- sensor_type="airflow",
- unit="m³/min",
- location="N1202 工作面",
- status="online",
- warning_threshold=1300,
- alarm_threshold=1200,
- upper_bound=1800,
- lower_bound=0,
- last_value=1286,
- last_seen_at=now,
- properties={},
- )
- dust_sensor = Sensor(
- id=new_id(),
- mine_id=mine.id,
- area_id=area.id,
- data_source_id=gas_source.id,
- code="DUST-S1302-01",
- name="S1302 粉尘",
- sensor_type="dust",
- unit="mg/m³",
- location="S1302 回风巷",
- status="online",
- warning_threshold=3.5,
- alarm_threshold=4.0,
- upper_bound=10,
- lower_bound=0,
- last_value=4.2,
- last_seen_at=now,
- properties={},
- )
- gate = VentilationFacility(
- id=new_id(),
- mine_id=mine.id,
- area_id=area.id,
- roadway_id=return_roadway.id,
- code="FG-002",
- name="2# 调节风门",
- facility_type="风门",
- location="北翼回风巷",
- status="warning",
- open_state="open",
- sensor_value=42,
- video_confidence=0.91,
- last_checked_at=now,
- properties={},
- )
- db.add_all(
- [
- mine,
- area,
- face,
- return_roadway,
- gas_source,
- video_source,
- gas_sensor,
- airflow_sensor,
- dust_sensor,
- gate,
- ]
- )
- db.flush()
- readings = []
- for sensor, base in (
- (gas_sensor, 0.46),
- (airflow_sensor, 1380),
- (dust_sensor, 3.1),
- ):
- for index in range(24):
- value = base + (index % 6) * (0.03 if sensor.sensor_type == "gas" else 8)
- readings.append(
- SensorReading(
- id=new_id(),
- sensor_id=sensor.id,
- measured_at=now - timedelta(hours=23 - index),
- value=round(value, 2),
- quality=100,
- is_alarm=sensor.sensor_type == "gas" and value >= 0.8,
- source="seed",
- meta={},
- )
- )
- db.add_all(readings)
- documents = [
- BusinessDocument(
- id=new_id(),
- mine_id=mine.id,
- code="TF-CS-2026-086",
- title="N1202 工作面通风安全技术措施",
- category="通风专业",
- subcategory="安全技术措施",
- file_name="N1202通风安全技术措施.pdf",
- file_path="data/uploads/N1202通风安全技术措施.pdf",
- file_ext=".pdf",
- file_size=2_936_012,
- page_count=42,
- owner_name="王强",
- department="通防科",
- version="V1.0",
- parse_status="completed",
- parse_progress=100,
- tags=["通风", "N1202", "安全措施"],
- summary="N1202 工作面通风方式、需风量和瓦斯管理要求。",
- metadata_json={},
- ),
- BusinessDocument(
- id=new_id(),
- mine_id=mine.id,
- code="TF-BB-2026-091",
- title="2026 年 9 月通风阻力测定报告",
- category="通风专业",
- subcategory="测定报告",
- file_name="通风阻力测定报告.docx",
- file_path="data/uploads/通风阻力测定报告.docx",
- file_ext=".docx",
- file_size=1_678_592,
- page_count=28,
- owner_name="赵磊",
- department="通防科",
- parse_status="completed",
- parse_progress=100,
- tags=["通风阻力", "月度报告"],
- summary="北翼回风系统阻力和主通风机工况分析。",
- metadata_json={},
- ),
- BusinessDocument(
- id=new_id(),
- mine_id=mine.id,
- code="TF-BB-2026-092",
- title="矿井测风记录日报表",
- category="监测监控",
- subcategory="台账报表",
- file_name="测风记录日报表.xlsx",
- file_path="data/uploads/测风记录日报表.xlsx",
- file_ext=".xlsx",
- file_size=876_544,
- row_count=1240,
- owner_name="刘伟",
- department="通防科",
- parse_status="processing",
- parse_progress=76,
- tags=["测风", "日报"],
- summary="各测风站风量和风速记录。",
- metadata_json={},
- ),
- BusinessDocument(
- id=new_id(),
- mine_id=mine.id,
- code="TF-SJ-2026-034",
- title="S1302 工作面综合防尘设计",
- category="粉尘防治",
- subcategory="专项设计",
- file_name="S1302综合防尘设计.pdf",
- file_path="data/uploads/S1302综合防尘设计.pdf",
- file_ext=".pdf",
- file_size=3_250_176,
- page_count=36,
- owner_name="陈晨",
- department="通防科",
- parse_status="pending",
- parse_progress=0,
- tags=["粉尘", "S1302"],
- summary="综合防尘设施和喷雾降尘设计。",
- metadata_json={},
- ),
- ]
- db.add_all(documents)
- db.flush()
- db.add_all(
- [
- DocumentExtraction(
- id=new_id(),
- document_id=documents[0].id,
- field_key="ventilation_method",
- field_name="通风方式",
- field_value="U 型通风",
- normalized_value="U型通风",
- confidence=0.968,
- page_no=8,
- verified=True,
- metadata_json={},
- ),
- DocumentExtraction(
- id=new_id(),
- document_id=documents[0].id,
- field_key="planned_air_volume",
- field_name="设计需风量",
- field_value="1404 m³/min",
- normalized_value="1404",
- unit="m³/min",
- confidence=0.942,
- page_no=12,
- verified=True,
- metadata_json={},
- ),
- ]
- )
- db.add_all(
- [
- KnowledgeItem(
- id=new_id(),
- mine_id=mine.id,
- document_id=documents[0].id,
- code="K-REG-001",
- title="瓦斯超限处置要求",
- knowledge_type="规程",
- category="瓦斯防治",
- source_type="document",
- source_ref="N1202 工作面通风安全技术措施",
- content="瓦斯浓度超限后应立即停止作业、切断电源、撤出人员,并核查局部通风和回风系统。",
- summary="明确瓦斯超限后的撤人、断电、检查和复测闭环要求。",
- tags=["瓦斯", "超限", "应急处置"],
- is_verified=True,
- verified_by="通防专家",
- metadata_json={},
- ),
- KnowledgeItem(
- id=new_id(),
- mine_id=mine.id,
- code="K-CASE-001",
- title="调节风门状态异常处置案例",
- knowledge_type="事故案例",
- category="通风专业",
- source_type="manual",
- source_ref="2024-026",
- content="视频判断风门未闭合但传感器反馈正常时,应优先现场复核闭锁装置、密封状态和传感器安装位置。",
- summary="说明视频与传感器冲突时的联合核查方法。",
- tags=["风门", "漏风", "视频识别"],
- is_verified=True,
- verified_by="通防专家",
- metadata_json={},
- ),
- KnowledgeItem(
- id=new_id(),
- mine_id=mine.id,
- code="K-RULE-001",
- title="局部通风机循环风判定要点",
- knowledge_type="专家经验",
- category="通风专业",
- source_type="expert",
- source_ref="专家规则 R-021",
- content="判定循环风应结合吸风口瓦斯浓度、风筒出口距离、巷道风流方向和风量变化综合判断。",
- summary="局部通风机循环风多因素判定方法。",
- tags=["局部通风", "循环风"],
- is_verified=True,
- verified_by="通防专家",
- metadata_json={},
- ),
- ]
- )
- db.add_all(
- [
- DiagnosisRule(
- id=new_id(),
- mine_id=mine.id,
- code="R-GAS-001",
- name="瓦斯浓度超限",
- scene="灾害防治",
- defect_type="瓦斯超限",
- severity="high",
- condition={"sensor_type": "gas", "operator": ">=", "field": "alarm_threshold"},
- threshold={"value": 0.8, "unit": "%CH4"},
- output_template="监测点瓦斯浓度超过报警阈值。",
- recommendation="停止作业、切断电源、撤出人员并核查通风系统。",
- knowledge_refs=["K-REG-001"],
- ),
- DiagnosisRule(
- id=new_id(),
- mine_id=mine.id,
- code="R-AF-001",
- name="工作面风量不足",
- scene="风量分配",
- defect_type="风量不足",
- severity="medium",
- condition={"actual_ratio": "<", "value": 0.9},
- threshold={"ratio": 0.9},
- output_template="实际风量低于计划风量的 90%。",
- recommendation="核查风窗、漏风点和巷道阻力,调整后复测。",
- ),
- DiagnosisRule(
- id=new_id(),
- mine_id=mine.id,
- code="R-FAC-001",
- name="通风设施状态异常",
- scene="通风设施",
- defect_type="设施状态异常",
- severity="medium",
- condition={"facility_status": "!=", "value": "normal"},
- threshold={},
- output_template="设施传感器或视频状态异常。",
- recommendation="安排现场复核设施开闭状态和传感器工作状态。",
- ),
- ]
- )
- indicator_rows = [
- ("SAFETY", "安全性", "安全性", 0.3, 1),
- ("RELIABILITY", "可靠性", "可靠性", 0.2, 2),
- ("ECONOMY", "经济性", "经济性", 0.15, 3),
- ("MANAGEMENT", "管理合规", "管理合规", 0.2, 4),
- ("DATA_QUALITY", "数据质量", "数据质量", 0.15, 5),
- ]
- for code, name, dimension, weight, sort_order in indicator_rows:
- db.add(
- EvaluationIndicator(
- id=new_id(),
- mine_id=mine.id,
- code=code,
- name=name,
- dimension=dimension,
- indicator_type="composite",
- weight=weight,
- weight_method="static",
- enabled=True,
- sort_order=sort_order,
- config={},
- )
- )
- alarm = Alarm(
- id=new_id(),
- mine_id=mine.id,
- sensor_id=gas_sensor.id,
- alarm_no="AL-20261008-001",
- alarm_type="gas_over_limit",
- level="high",
- title="N1202 回风巷瓦斯浓度超限",
- content="瓦斯浓度达到 0.86%,超过 0.80% 报警阈值。",
- value=0.86,
- threshold=0.8,
- status="open",
- occurred_at=now - timedelta(minutes=12),
- metadata_json={},
- )
- db.add(alarm)
- db.flush()
- order = WorkOrder(
- id=new_id(),
- mine_id=mine.id,
- alarm_id=alarm.id,
- order_no="WO-20261008-001",
- title="N1202 回风巷瓦斯超限处置",
- content="核查局部通风机、风筒和回风系统运行状态,完成复测后闭环。",
- priority="high",
- status="processing",
- assignee_name="王强",
- department="通防科",
- due_at=now + timedelta(hours=2),
- attachments=[],
- metadata_json={},
- )
- db.add(order)
- db.flush()
- db.add(
- WorkOrderEvent(
- id=new_id(),
- work_order_id=order.id,
- event_type="created",
- to_status="processing",
- operator_name="系统",
- comment="根据瓦斯超限告警自动创建",
- attachments=[],
- created_at=now - timedelta(minutes=10),
- )
- )
- db.commit()
|