"""种子数据 - 天普园区设备信息、用户、告警规则、碳排放因子、报表模板、历史告警""" import asyncio import json import sys import os from datetime import datetime, timezone, timedelta sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "core", "backend")) from sqlalchemy import select from app.core.database import async_session, engine from app.core.security import hash_password from app.models.user import User, Role from app.models.device import Device, DeviceType, DeviceGroup from app.models.alarm import AlarmRule, AlarmEvent from app.models.carbon import EmissionFactor from app.models.report import ReportTemplate, ReportTask from app.models.energy import EnergyCategory from app.models.charging import ( ChargingMerchant, ChargingBrand, ChargingStation, ChargingPile, ChargingPriceStrategy, ChargingPriceParam, ChargingOrder, ) from app.models.quota import EnergyQuota from app.models.pricing import ElectricityPricing, PricingPeriod from app.models.maintenance import InspectionPlan, InspectionRecord, RepairOrder, DutySchedule from app.models.management import Regulation, Standard, ProcessDoc, EmergencyPlan async def seed(): async with async_session() as session: # ===================================================================== # 1. 角色 (6 roles with JSON permissions) # ===================================================================== roles_data = [ { "name": "admin", "display_name": "园区管理员", "description": "平台最高管理者,负责全局配置和用户管理", "permissions": json.dumps([ "user:read", "user:write", "user:delete", "device:read", "device:write", "device:delete", "energy:read", "energy:export", "alarm:read", "alarm:write", "alarm:acknowledge", "report:read", "report:write", "report:export", "carbon:read", "carbon:write", "system:config", "system:audit", ]), }, { "name": "energy_manager", "display_name": "能源主管", "description": "负责园区能源运行管理和优化决策", "permissions": json.dumps([ "device:read", "device:write", "energy:read", "energy:export", "alarm:read", "alarm:write", "alarm:acknowledge", "report:read", "report:write", "report:export", "carbon:read", "carbon:write", ]), }, { "name": "area_manager", "display_name": "区域负责人", "description": "负责特定区域或建筑的能源管理", "permissions": json.dumps([ "device:read", "energy:read", "energy:export", "alarm:read", "alarm:acknowledge", "report:read", "report:export", "carbon:read", ]), }, { "name": "operator", "display_name": "设备运维员", "description": "负责设备日常运维和故障处理", "permissions": json.dumps([ "device:read", "device:write", "energy:read", "alarm:read", "alarm:acknowledge", "report:read", ]), }, { "name": "analyst", "display_name": "财务分析员", "description": "负责能源成本分析和财务报表", "permissions": json.dumps([ "energy:read", "energy:export", "report:read", "report:write", "report:export", "carbon:read", ]), }, { "name": "visitor", "display_name": "普通访客", "description": "仅查看公开信息", "permissions": json.dumps([ "energy:read", "device:read", ]), }, ] roles = [Role(**r) for r in roles_data] session.add_all(roles) # ===================================================================== # 2. 用户 (admin + 2 demo users) # ===================================================================== users = [ User(username="admin", hashed_password=hash_password("admin123"), full_name="系统管理员", role="admin", email="admin@tianpu.com", phone="13800000001"), User(username="energy_mgr", hashed_password=hash_password("tianpu123"), full_name="张能源", role="energy_manager", email="energy@tianpu.com", phone="13800000002"), User(username="operator1", hashed_password=hash_password("tianpu123"), full_name="李运维", role="operator", email="op1@tianpu.com", phone="13800000003"), User(username="visitor", hashed_password=hash_password("visitor123"), full_name="访客", role="visitor", email=None, phone=None), ] session.add_all(users) # ===================================================================== # 3. 设备类型 (8 types) # ===================================================================== device_types = [ DeviceType(code="pv_inverter", name="光伏逆变器", icon="solar-panel", data_fields=["power", "daily_energy", "total_energy", "dc_voltage", "ac_voltage", "temperature", "fault_code"]), DeviceType(code="heat_pump", name="空气源热泵", icon="heat-pump", data_fields=["power", "cop", "inlet_temp", "outlet_temp", "flow_rate", "outdoor_temp", "mode"]), DeviceType(code="solar_thermal", name="光热集热器", icon="solar-thermal", data_fields=["heat_output", "collector_temp", "irradiance", "pump_status"]), DeviceType(code="battery", name="储能系统", icon="battery", data_fields=["power", "soc", "voltage", "current", "temperature", "cycle_count"]), DeviceType(code="meter", name="智能电表", icon="meter", data_fields=["power", "energy", "voltage", "current", "power_factor", "frequency"]), DeviceType(code="sensor", name="温湿度传感器", icon="sensor", data_fields=["temperature", "humidity"]), DeviceType(code="heat_meter", name="热量表", icon="heat-meter", data_fields=["heat_power", "heat_energy", "flow_rate", "supply_temp", "return_temp"]), DeviceType(code="water_meter", name="水表", icon="water-meter", data_fields=["flow_rate", "total_flow"]), ] session.add_all(device_types) # ===================================================================== # 4. 设备分组 (hierarchical: Campus -> subsystems) # ===================================================================== groups = [ DeviceGroup(id=1, name="天普大兴园区", location="北京市大兴区", description="园区总节点"), DeviceGroup(id=2, name="东楼", parent_id=1, location="天普大楼东侧"), DeviceGroup(id=3, name="西楼", parent_id=1, location="天普大楼西侧"), DeviceGroup(id=4, name="光伏系统", parent_id=1, location="天普大楼屋顶"), DeviceGroup(id=5, name="热泵系统", parent_id=1, location="天普大楼机房"), DeviceGroup(id=6, name="电力计量", parent_id=1, location="天普大楼配电室"), DeviceGroup(id=7, name="环境监测", parent_id=1, location="天普大楼各楼层"), ] session.add_all(groups) # Flush to satisfy FK constraints before inserting devices await session.flush() # ===================================================================== # 5. 天普实际设备 (19 devices total) # ===================================================================== devices = [ # --- 光伏逆变器 - 3台华为SUN2000-110KTL-M0 --- Device(name="东楼逆变器1", code="INV-01", device_type="pv_inverter", group_id=4, model="SUN2000-110KTL-M0", manufacturer="华为", rated_power=110, location="东楼屋顶", protocol="http_api", collect_interval=15, connection_params={"api_type": "fusionsolar", "station_code": "NE=12345"}), Device(name="东楼逆变器2", code="INV-02", device_type="pv_inverter", group_id=4, model="SUN2000-110KTL-M0", manufacturer="华为", rated_power=110, location="东楼屋顶", protocol="http_api", collect_interval=15), Device(name="西楼逆变器1", code="INV-03", device_type="pv_inverter", group_id=4, model="SUN2000-110KTL-M0", manufacturer="华为", rated_power=110, location="西楼屋顶", protocol="http_api", collect_interval=15), # --- 热泵机组 - 4台 --- Device(name="热泵机组1", code="HP-01", device_type="heat_pump", group_id=5, rated_power=35, location="大楼机房", protocol="modbus_rtu", collect_interval=15, connection_params={"dtu_id": "2225000009", "slave_id": 1}), Device(name="热泵机组2", code="HP-02", device_type="heat_pump", group_id=5, rated_power=35, location="大楼机房", protocol="modbus_rtu", collect_interval=15, connection_params={"dtu_id": "2225000009", "slave_id": 2}), Device(name="热泵机组3", code="HP-03", device_type="heat_pump", group_id=5, rated_power=35, location="大楼机房", protocol="modbus_rtu", collect_interval=15, connection_params={"dtu_id": "2225000009", "slave_id": 3}), Device(name="热泵机组4", code="HP-04", device_type="heat_pump", group_id=5, rated_power=35, location="大楼机房", protocol="modbus_rtu", collect_interval=15, connection_params={"dtu_id": "2225000009", "slave_id": 4}), # --- 电表 --- Device(name="关口电表(余电上网)", code="METER-GRID", device_type="meter", group_id=6, model="威胜", serial_number="3462847657", location="配电室", protocol="dlt645", collect_interval=60, connection_params={"dtu_id": "infrared", "ratio": 1000}), Device(name="并网电表(光伏总发电)", code="METER-PV", device_type="meter", group_id=6, model="杭州炬华", serial_number="3422994056", location="配电室", protocol="dlt645", collect_interval=60, connection_params={"dtu_id": "infrared", "ct_ratio": "600/5"}), Device(name="热泵电表", code="METER-HP", device_type="meter", group_id=6, location="机房热泵控制柜", protocol="modbus_rtu", collect_interval=60, connection_params={"dtu_id": "2225000003"}), Device(name="循环水泵电表", code="METER-PUMP", device_type="meter", group_id=6, location="机房水泵配电柜", protocol="modbus_rtu", collect_interval=60, connection_params={"dtu_id": "2225000002"}), # --- 热量表 --- Device(name="主管热量表", code="HM-01", device_type="heat_meter", group_id=5, location="机房中部主管", protocol="modbus_rtu", collect_interval=60, connection_params={"dtu_id": "2225000001"}), # --- 温湿度传感器 --- Device(name="一楼东厅温湿度", code="TH-01", device_type="sensor", group_id=7, location="大楼一楼东厅", protocol="mqtt", collect_interval=60, connection_params={"dtu_id": "2225000007"}, metadata_={"area": "一楼东展厅风管上"}), Device(name="一楼西厅温湿度", code="TH-02", device_type="sensor", group_id=7, location="大楼一楼西厅", protocol="mqtt", collect_interval=60, connection_params={"dtu_id": "2225000006"}, metadata_={"area": "一楼西厅中西风管上"}), Device(name="二楼西厅温湿度", code="TH-03", device_type="sensor", group_id=7, location="大楼二楼西厅", protocol="mqtt", collect_interval=60, connection_params={"dtu_id": "2225000005"}, metadata_={"area": "财务门口西侧"}), Device(name="二楼东厅温湿度", code="TH-04", device_type="sensor", group_id=7, location="大楼二楼东厅", protocol="mqtt", collect_interval=60, connection_params={"dtu_id": "2225000004"}, metadata_={"area": "英豪对过"}), Device(name="机房室外温湿度", code="TH-05", device_type="sensor", group_id=7, location="机房热泵控制柜", protocol="mqtt", collect_interval=60, connection_params={"dtu_id": "2225000008"}, metadata_={"area": "机房门口", "type": "outdoor"}), # --- 水表 --- Device(name="补水水表", code="WM-01", device_type="water_meter", group_id=5, location="机房软水器补水管", protocol="image", collect_interval=300, connection_params={"type": "smart_capture"}), ] session.add_all(devices) await session.flush() # ===================================================================== # 6. 告警规则 # ===================================================================== alarm_rules = [ AlarmRule( name="光伏功率过低告警", device_type="pv_inverter", data_type="power", condition="lt", threshold=5.0, duration=1800, severity="warning", notify_channels=["app", "wechat"], is_active=True, ), AlarmRule( name="热泵COP过低告警", device_type="heat_pump", data_type="cop", condition="lt", threshold=2.0, duration=600, severity="major", notify_channels=["app", "sms", "wechat"], is_active=True, ), AlarmRule( name="室内温度超限告警", device_type="sensor", data_type="temperature", condition="range_out", threshold_high=30.0, threshold_low=16.0, duration=300, severity="warning", notify_channels=["app"], is_active=True, ), AlarmRule( name="电表通信中断告警", device_type="meter", data_type="power", condition="eq", threshold=0.0, duration=3600, severity="critical", notify_channels=["app", "sms", "wechat", "email"], notify_targets={"emails": ["admin@tianpu.com", "energy@tianpu.com"]}, is_active=True, ), AlarmRule( name="热泵功率过载告警", device_type="heat_pump", data_type="power", condition="gt", threshold=38.0, duration=300, severity="critical", notify_channels=["app", "sms", "email"], notify_targets={"emails": ["admin@tianpu.com"]}, is_active=True, ), AlarmRule( name="光伏逆变器过温告警", device_type="pv_inverter", data_type="temperature", condition="gt", threshold=65.0, duration=120, severity="major", notify_channels=["app", "sms"], is_active=True, ), ] session.add_all(alarm_rules) # ===================================================================== # 7. 碳排放因子 # ===================================================================== factors = [ EmissionFactor(name="华北电网排放因子", energy_type="electricity", factor=0.8843, unit="kWh", scope=2, region="north_china", source="生态环境部2023", year=2023), EmissionFactor(name="天然气排放因子", energy_type="natural_gas", factor=2.162, unit="m³", scope=1, source="IPCC 2006", year=2006), EmissionFactor(name="柴油排放因子", energy_type="diesel", factor=2.63, unit="L", scope=1, source="IPCC 2006", year=2006), EmissionFactor(name="光伏减排因子", energy_type="pv_generation", factor=0.8843, unit="kWh", scope=2, region="north_china", source="等量替代电网电力", year=2023), EmissionFactor(name="热泵节能减排因子", energy_type="heat_pump_saving", factor=0.8843, unit="kWh", scope=2, region="north_china", source="相比电加热节省的电量", year=2023), ] session.add_all(factors) # ===================================================================== # 8. 预置报表模板 # ===================================================================== templates = [ ReportTemplate( name="日报", report_type="daily", is_system=True, description="每日能源运行日报,包含发用电量、自消纳率、热泵COP、碳排放", fields=[ {"key": "total_consumption", "label": "总用电量", "unit": "kWh"}, {"key": "pv_generation", "label": "光伏发电量", "unit": "kWh"}, {"key": "self_use_rate", "label": "自消纳率", "unit": "%"}, {"key": "heatpump_energy", "label": "热泵用电", "unit": "kWh"}, {"key": "avg_cop", "label": "平均COP"}, {"key": "carbon_emission", "label": "碳排放", "unit": "kgCO2"}, ], ), ReportTemplate( name="月报", report_type="monthly", is_system=True, description="每月能源运行月报,包含能耗趋势、电费、碳排放与减排", fields=[ {"key": "total_consumption", "label": "总用电量", "unit": "kWh"}, {"key": "pv_generation", "label": "光伏发电量", "unit": "kWh"}, {"key": "grid_import", "label": "电网购电", "unit": "kWh"}, {"key": "cost", "label": "电费", "unit": "元"}, {"key": "carbon_emission", "label": "碳排放", "unit": "tCO2"}, {"key": "carbon_reduction", "label": "碳减排", "unit": "tCO2"}, ], time_granularity="day", ), ReportTemplate( name="设备运行报告", report_type="custom", is_system=True, description="设备运行状态汇总,包含运行时长、能耗、告警统计", fields=[ {"key": "device_name", "label": "设备名称"}, {"key": "operating_hours", "label": "运行时长", "unit": "h"}, {"key": "energy_consumption", "label": "能耗", "unit": "kWh"}, {"key": "avg_power", "label": "平均功率", "unit": "kW"}, {"key": "alarm_count", "label": "告警次数"}, ], ), ] session.add_all(templates) await session.flush() # ===================================================================== # 8b. 定时报表任务 (daily report at 8am) # ===================================================================== report_tasks = [ ReportTask( template_id=1, # 日报模板 name="每日能源运行日报", schedule="0 8 * * *", recipients=["admin@tianpu.com"], export_format="xlsx", status="pending", is_active=True, created_by=1, ), ] session.add_all(report_tasks) await session.flush() # ===================================================================== # 9. 历史告警事件 (15 events over last 7 days) # ===================================================================== now = datetime.now(timezone.utc) # We need device IDs and rule IDs — query them back dev_result = await session.execute(select(Device)) all_devices = {d.code: d.id for d in dev_result.scalars().all()} rule_result = await session.execute(select(AlarmRule)) all_rules = {r.name: r for r in rule_result.scalars().all()} r_pv_low = all_rules["光伏功率过低告警"] r_hp_cop = all_rules["热泵COP过低告警"] r_temp = all_rules["室内温度超限告警"] r_meter = all_rules["电表通信中断告警"] r_hp_overload = all_rules["热泵功率过载告警"] r_pv_overtemp = all_rules["光伏逆变器过温告警"] alarm_events = [ # --- 7 days ago: PV low power (resolved) --- AlarmEvent( rule_id=r_pv_low.id, device_id=all_devices["INV-01"], severity="warning", title="光伏功率过低告警", description="当前值 2.3,阈值 5.0", value=2.3, threshold=5.0, status="resolved", resolve_note="云层过境后恢复正常", triggered_at=now - timedelta(days=7, hours=3), resolved_at=now - timedelta(days=7, hours=2, minutes=45), ), # --- 6 days ago: Heat pump COP low (resolved) --- AlarmEvent( rule_id=r_hp_cop.id, device_id=all_devices["HP-01"], severity="major", title="热泵COP过低告警", description="当前值 1.6,阈值 2.0", value=1.6, threshold=2.0, status="resolved", resolve_note="设备恢复正常", triggered_at=now - timedelta(days=6, hours=10), resolved_at=now - timedelta(days=6, hours=9, minutes=30), ), # --- 5 days ago: Temperature out of range (resolved) --- AlarmEvent( rule_id=r_temp.id, device_id=all_devices["TH-01"], severity="warning", title="室内温度超限告警", description="当前值 31.2,阈值 [16.0, 30.0]", value=31.2, threshold=30.0, status="resolved", resolve_note="已调节空调温度", triggered_at=now - timedelta(days=5, hours=14), resolved_at=now - timedelta(days=5, hours=13, minutes=20), ), # --- 5 days ago: Meter communication lost (resolved) --- AlarmEvent( rule_id=r_meter.id, device_id=all_devices["METER-HP"], severity="critical", title="电表通信中断告警", description="当前值 0.0,阈值 0.0", value=0.0, threshold=0.0, status="resolved", resolve_note="已派人检修,通信恢复", triggered_at=now - timedelta(days=5, hours=8), resolved_at=now - timedelta(days=5, hours=6), ), # --- 4 days ago: HP overload (resolved) --- AlarmEvent( rule_id=r_hp_overload.id, device_id=all_devices["HP-02"], severity="critical", title="热泵功率过载告警", description="当前值 40.2,阈值 38.0", value=40.2, threshold=38.0, status="resolved", resolve_note="负荷降低后自动恢复", triggered_at=now - timedelta(days=4, hours=16), resolved_at=now - timedelta(days=4, hours=15, minutes=40), ), # --- 4 days ago: PV overtemp (resolved) --- AlarmEvent( rule_id=r_pv_overtemp.id, device_id=all_devices["INV-01"], severity="major", title="光伏逆变器过温告警", description="当前值 68.5,阈值 65.0", value=68.5, threshold=65.0, status="resolved", resolve_note="自动恢复", triggered_at=now - timedelta(days=4, hours=13), resolved_at=now - timedelta(days=4, hours=12, minutes=45), ), # --- 3 days ago: PV low power again (resolved) --- AlarmEvent( rule_id=r_pv_low.id, device_id=all_devices["INV-03"], severity="warning", title="光伏功率过低告警", description="当前值 1.8,阈值 5.0", value=1.8, threshold=5.0, status="resolved", resolve_note="自动恢复", triggered_at=now - timedelta(days=3, hours=11), resolved_at=now - timedelta(days=3, hours=10, minutes=48), ), # --- 2 days ago: Temperature sensor (acknowledged) --- AlarmEvent( rule_id=r_temp.id, device_id=all_devices["TH-03"], severity="warning", title="室内温度超限告警", description="当前值 15.2,阈值 [16.0, 30.0]", value=15.2, threshold=16.0, status="resolved", resolve_note="供暖开启后恢复", triggered_at=now - timedelta(days=2, hours=7), acknowledged_at=now - timedelta(days=2, hours=6, minutes=50), resolved_at=now - timedelta(days=2, hours=5), ), # --- 2 days ago: HP COP low (acknowledged, then resolved) --- AlarmEvent( rule_id=r_hp_cop.id, device_id=all_devices["HP-03"], severity="major", title="热泵COP过低告警", description="当前值 1.4,阈值 2.0", value=1.4, threshold=2.0, status="resolved", resolve_note="已派人检修", triggered_at=now - timedelta(days=2, hours=15), acknowledged_at=now - timedelta(days=2, hours=14, minutes=30), resolved_at=now - timedelta(days=2, hours=12), ), # --- 1 day ago: PV overtemp (resolved) --- AlarmEvent( rule_id=r_pv_overtemp.id, device_id=all_devices["INV-02"], severity="major", title="光伏逆变器过温告警", description="当前值 67.1,阈值 65.0", value=67.1, threshold=65.0, status="resolved", resolve_note="设备恢复正常", triggered_at=now - timedelta(days=1, hours=14), resolved_at=now - timedelta(days=1, hours=13, minutes=30), ), # --- 1 day ago: HP overload (acknowledged, still active) --- AlarmEvent( rule_id=r_hp_overload.id, device_id=all_devices["HP-04"], severity="critical", title="热泵功率过载告警", description="当前值 39.5,阈值 38.0", value=39.5, threshold=38.0, status="acknowledged", triggered_at=now - timedelta(hours=18), acknowledged_at=now - timedelta(hours=17), ), # --- 12 hours ago: Meter communication (active) --- AlarmEvent( rule_id=r_meter.id, device_id=all_devices["METER-PUMP"], severity="critical", title="电表通信中断告警", description="当前值 0.0,阈值 0.0", value=0.0, threshold=0.0, status="active", triggered_at=now - timedelta(hours=12), ), # --- 6 hours ago: Temperature out of range (active) --- AlarmEvent( rule_id=r_temp.id, device_id=all_devices["TH-02"], severity="warning", title="室内温度超限告警", description="当前值 31.8,阈值 [16.0, 30.0]", value=31.8, threshold=30.0, status="active", triggered_at=now - timedelta(hours=6), ), # --- 2 hours ago: PV low (active) --- AlarmEvent( rule_id=r_pv_low.id, device_id=all_devices["INV-02"], severity="warning", title="光伏功率过低告警", description="当前值 3.1,阈值 5.0", value=3.1, threshold=5.0, status="active", triggered_at=now - timedelta(hours=2), ), # --- 30 min ago: HP COP low (active) --- AlarmEvent( rule_id=r_hp_cop.id, device_id=all_devices["HP-02"], severity="major", title="热泵COP过低告警", description="当前值 1.7,阈值 2.0", value=1.7, threshold=2.0, status="active", triggered_at=now - timedelta(minutes=30), ), ] session.add_all(alarm_events) await session.flush() # ===================================================================== # 10. 能耗分项类别 (5 categories) # ===================================================================== categories = [ EnergyCategory(name="暖通空调", code="hvac", sort_order=1, icon="fire", color="#FF6B6B"), EnergyCategory(name="照明", code="lighting", sort_order=2, icon="bulb", color="#FFD93D"), EnergyCategory(name="动力", code="power", sort_order=3, icon="thunderbolt", color="#6BCB77"), EnergyCategory(name="特殊", code="special", sort_order=4, icon="experiment", color="#4D96FF"), EnergyCategory(name="其他", code="other", sort_order=5, icon="more", color="#9B59B6"), ] session.add_all(categories) await session.flush() # Map category codes to IDs cat_map = {c.code: c.id for c in categories} # Assign categories to existing devices for code, dev_id in all_devices.items(): dev = await session.get(Device, dev_id) if code.startswith("HP-"): dev.category_id = cat_map["hvac"] elif code.startswith("METER-") or code.startswith("HM-"): dev.category_id = cat_map["power"] elif code.startswith("TH-") or code.startswith("WM-"): dev.category_id = cat_map["other"] elif code.startswith("INV-"): dev.category_id = cat_map["special"] await session.flush() # ===================================================================== # 11. 充电桩管理 (merchant, brands, stations, piles, pricing, orders) # ===================================================================== merchant = ChargingMerchant( name="天普充电运营", contact_person="张运营", phone="13800001111", email="charging@tianpu.com", status="active", settlement_type="postpaid", ) session.add(merchant) await session.flush() brand1 = ChargingBrand(brand_name="特来电", country="中国", description="国内领先充电桩品牌") brand2 = ChargingBrand(brand_name="星星充电", country="中国", description="新能源充电设备") session.add_all([brand1, brand2]) await session.flush() station1 = ChargingStation( name="A栋地下停车场充电站", merchant_id=merchant.id, type="public", address="天普大兴园区A栋B1", status="active", total_piles=4, available_piles=2, total_power_kw=480, operating_hours="00:00-24:00", created_by=1, ) station2 = ChargingStation( name="园区露天充电站", merchant_id=merchant.id, type="public", address="天普大兴园区南门", status="active", total_piles=2, available_piles=1, total_power_kw=240, operating_hours="06:00-23:00", created_by=1, ) session.add_all([station1, station2]) await session.flush() # 6 charging piles piles = [ ChargingPile(station_id=station1.id, encoding="CP-A1-01", name="A栋1号桩", type="DC_fast", brand="特来电", model="TLD-120", rated_power_kw=120, connector_type="GB_T", status="active", work_status="idle"), ChargingPile(station_id=station1.id, encoding="CP-A1-02", name="A栋2号桩", type="DC_fast", brand="特来电", model="TLD-120", rated_power_kw=120, connector_type="GB_T", status="active", work_status="charging"), ChargingPile(station_id=station1.id, encoding="CP-A1-03", name="A栋3号桩", type="AC_slow", brand="星星充电", model="XX-7", rated_power_kw=7, connector_type="GB_T", status="active", work_status="idle"), ChargingPile(station_id=station1.id, encoding="CP-A1-04", name="A栋4号桩", type="DC_superfast", brand="特来电", model="TLD-240", rated_power_kw=240, connector_type="GB_T", status="active", work_status="fault"), ChargingPile(station_id=station2.id, encoding="CP-S1-01", name="南门1号桩", type="DC_fast", brand="星星充电", model="XX-120", rated_power_kw=120, connector_type="GB_T", status="active", work_status="idle"), ChargingPile(station_id=station2.id, encoding="CP-S1-02", name="南门2号桩", type="DC_fast", brand="星星充电", model="XX-120", rated_power_kw=120, connector_type="GB_T", status="active", work_status="charging"), ] session.add_all(piles) await session.flush() # Charging price strategy with 4 time periods charge_strategy = ChargingPriceStrategy( strategy_name="园区充电分时电价", station_id=station1.id, bill_model="tou", description="按时段计费", status="active", ) session.add(charge_strategy) await session.flush() charge_periods = [ ChargingPriceParam(strategy_id=charge_strategy.id, start_time="10:00", end_time="15:00", period_mark="peak", elec_price=1.2, service_price=0.8), ChargingPriceParam(strategy_id=charge_strategy.id, start_time="18:00", end_time="21:00", period_mark="peak", elec_price=1.2, service_price=0.8), ChargingPriceParam(strategy_id=charge_strategy.id, start_time="07:00", end_time="10:00", period_mark="flat", elec_price=0.7, service_price=0.6), ChargingPriceParam(strategy_id=charge_strategy.id, start_time="23:00", end_time="07:00", period_mark="valley", elec_price=0.3, service_price=0.4), ] session.add_all(charge_periods) # 5 sample charging orders charging_orders = [ ChargingOrder( order_no="CHG20260401001", user_name="王先生", phone="13900001001", station_id=station1.id, station_name="A栋地下停车场充电站", pile_id=piles[0].id, pile_name="A栋1号桩", start_time=now - timedelta(days=2, hours=14), end_time=now - timedelta(days=2, hours=12, minutes=30), car_no="京A12345", charge_method="app", settle_type="normal", pay_type="wechat", settle_time=now - timedelta(days=2, hours=12, minutes=30), settle_price=45.60, paid_price=45.60, elec_amt=28.80, serve_amt=16.80, order_status="completed", charge_duration=5400, energy=38.0, start_soc=20.0, end_soc=85.0, order_source="miniprogram", ), ChargingOrder( order_no="CHG20260401002", user_name="李女士", phone="13900001002", station_id=station2.id, station_name="园区露天充电站", pile_id=piles[4].id, pile_name="南门1号桩", start_time=now - timedelta(days=1, hours=20), end_time=now - timedelta(days=1, hours=18), car_no="京B67890", charge_method="plug_and_charge", settle_type="normal", pay_type="alipay", settle_time=now - timedelta(days=1, hours=18), settle_price=52.30, paid_price=52.30, elec_amt=33.60, serve_amt=18.70, order_status="completed", charge_duration=7200, energy=48.0, start_soc=15.0, end_soc=92.0, order_source="app", ), ChargingOrder( order_no="CHG20260402001", user_name="赵工", phone="13900001003", station_id=station1.id, station_name="A栋地下停车场充电站", pile_id=piles[1].id, pile_name="A栋2号桩", start_time=now - timedelta(hours=2), car_no="京C11111", charge_method="app", order_status="charging", energy=12.5, start_soc=30.0, order_source="miniprogram", ), ChargingOrder( order_no="CHG20260402002", user_name="孙经理", phone="13900001004", station_id=station2.id, station_name="园区露天充电站", pile_id=piles[5].id, pile_name="南门2号桩", start_time=now - timedelta(hours=5), end_time=now - timedelta(hours=3), car_no="京D22222", charge_method="card", settle_type="delayed", settle_price=38.90, elec_amt=24.50, serve_amt=14.40, order_status="pending_pay", charge_duration=7200, energy=32.0, start_soc=25.0, end_soc=78.0, order_source="pc", ), ChargingOrder( order_no="CHG20260402003", user_name="周师傅", phone="13900001005", station_id=station1.id, station_name="A栋地下停车场充电站", pile_id=piles[3].id, pile_name="A栋4号桩", start_time=now - timedelta(hours=8), end_time=now - timedelta(hours=7, minutes=15), car_no="京E33333", charge_method="app", settle_type="abnormal", order_status="failed", charge_duration=2700, energy=5.2, start_soc=40.0, end_soc=45.0, abno_cause="充电桩故障,自动断电", order_source="miniprogram", ), ] session.add_all(charging_orders) await session.flush() # ===================================================================== # 12. 能源配额 (4 quotas) # ===================================================================== quotas = [ EnergyQuota(name="东楼月度用电定额", target_type="building", target_id=2, energy_type="electricity", period="monthly", quota_value=50000, unit="kWh", warning_threshold_pct=80, alert_threshold_pct=95, is_active=True, created_by=1), EnergyQuota(name="西楼月度用电定额", target_type="building", target_id=3, energy_type="electricity", period="monthly", quota_value=45000, unit="kWh", warning_threshold_pct=80, alert_threshold_pct=95, is_active=True, created_by=1), EnergyQuota(name="热泵系统月度用电定额", target_type="device_group", target_id=5, energy_type="electricity", period="monthly", quota_value=30000, unit="kWh", warning_threshold_pct=75, alert_threshold_pct=90, is_active=True, created_by=1), EnergyQuota(name="园区年度总用电定额", target_type="building", target_id=1, energy_type="electricity", period="yearly", quota_value=600000, unit="kWh", warning_threshold_pct=80, alert_threshold_pct=95, is_active=True, created_by=1), ] session.add_all(quotas) await session.flush() # ===================================================================== # 13. 电价策略 (1 TOU pricing with 4 periods) # ===================================================================== pricing = ElectricityPricing( name="2026年工商业分时电价", energy_type="electricity", pricing_type="tou", effective_from=datetime(2026, 1, 1, tzinfo=timezone.utc), is_active=True, created_by=1, ) session.add(pricing) await session.flush() pricing_periods = [ PricingPeriod(pricing_id=pricing.id, period_name="peak", start_time="10:00", end_time="15:00", price_per_unit=1.2), PricingPeriod(pricing_id=pricing.id, period_name="peak", start_time="18:00", end_time="21:00", price_per_unit=1.2), PricingPeriod(pricing_id=pricing.id, period_name="flat", start_time="07:00", end_time="10:00", price_per_unit=0.7), PricingPeriod(pricing_id=pricing.id, period_name="flat", start_time="15:00", end_time="18:00", price_per_unit=0.7), PricingPeriod(pricing_id=pricing.id, period_name="valley", start_time="23:00", end_time="07:00", price_per_unit=0.3), PricingPeriod(pricing_id=pricing.id, period_name="shoulder", start_time="21:00", end_time="23:00", price_per_unit=0.85), ] session.add_all(pricing_periods) await session.flush() # ===================================================================== # 14. 运维管理 (inspection plans, records, repair orders, duty schedules) # ===================================================================== plan1 = InspectionPlan( name="热泵日常巡检", description="检查热泵运行状态、温度、COP等关键参数", device_group_id=5, schedule_type="daily", inspector_id=3, checklist=json.dumps([ {"item": "检查运行温度", "type": "check", "required": True}, {"item": "检查COP值", "type": "check", "required": True}, {"item": "检查噪音振动", "type": "check", "required": True}, {"item": "检查管路密封", "type": "check", "required": False}, ]), is_active=True, next_run_at=now + timedelta(hours=8), created_by=1, ) plan2 = InspectionPlan( name="光伏系统周巡检", description="检查光伏板、逆变器、线缆等设备状态", device_group_id=4, schedule_type="weekly", inspector_id=3, checklist=json.dumps([ {"item": "检查光伏板清洁度", "type": "check", "required": True}, {"item": "检查逆变器运行状态", "type": "check", "required": True}, {"item": "检查线缆连接", "type": "check", "required": True}, {"item": "记录发电量数据", "type": "input", "required": True}, ]), is_active=True, next_run_at=now + timedelta(days=3), created_by=1, ) session.add_all([plan1, plan2]) await session.flush() # 3 inspection records inspection_records = [ InspectionRecord( plan_id=plan1.id, inspector_id=3, status="completed", findings=json.dumps([ {"item": "检查运行温度", "result": "正常", "note": "出水温度45℃"}, {"item": "检查COP值", "result": "正常", "note": "COP=3.8"}, {"item": "检查噪音振动", "result": "正常", "note": ""}, {"item": "检查管路密封", "result": "正常", "note": ""}, ]), started_at=now - timedelta(days=1, hours=9), completed_at=now - timedelta(days=1, hours=8, minutes=30), ), InspectionRecord( plan_id=plan1.id, inspector_id=3, status="issues_found", findings=json.dumps([ {"item": "检查运行温度", "result": "异常", "note": "出水温度偏高52℃"}, {"item": "检查COP值", "result": "异常", "note": "COP=1.9,低于正常值"}, {"item": "检查噪音振动", "result": "正常", "note": ""}, {"item": "检查管路密封", "result": "正常", "note": ""}, ]), started_at=now - timedelta(days=2, hours=9), completed_at=now - timedelta(days=2, hours=8, minutes=45), ), InspectionRecord( plan_id=plan2.id, inspector_id=3, status="pending", started_at=now - timedelta(hours=1), ), ] session.add_all(inspection_records) await session.flush() # 4 repair orders repair_orders = [ RepairOrder( code="WO-20260401-001", title="热泵机组2压缩机异响", description="巡检发现热泵机组2运行时有异常噪音,COP偏低,需检修", device_id=all_devices["HP-02"], priority="high", status="open", cost_estimate=5000.0, created_by=1, created_at=now - timedelta(days=2, hours=8), ), RepairOrder( code="WO-20260401-002", title="循环水泵电表通信故障", description="水泵电表持续12小时无数据上报,需现场检查通信模块", device_id=all_devices["METER-PUMP"], priority="critical", status="assigned", assigned_to=3, cost_estimate=800.0, created_by=1, created_at=now - timedelta(hours=12), assigned_at=now - timedelta(hours=11), ), RepairOrder( code="WO-20260402-001", title="A栋4号充电桩故障维修", description="充电桩充电中途自动断电,用户报修", device_id=None, priority="high", status="in_progress", assigned_to=3, cost_estimate=2000.0, created_by=1, created_at=now - timedelta(hours=7), assigned_at=now - timedelta(hours=6, minutes=30), ), RepairOrder( code="WO-20260330-001", title="西楼逆变器风扇更换", description="逆变器散热风扇老化,温度报警频繁,已更换新风扇", device_id=all_devices["INV-03"], priority="medium", status="completed", assigned_to=3, resolution="已更换散热风扇,测试运行正常", cost_estimate=1200.0, actual_cost=980.0, created_by=1, created_at=now - timedelta(days=4), assigned_at=now - timedelta(days=4), completed_at=now - timedelta(days=3, hours=16), ), ] session.add_all(repair_orders) # 7 duty schedules (this week, starting from Monday) # Calculate this week's Monday days_since_monday = now.weekday() this_monday = now - timedelta(days=days_since_monday) this_monday = this_monday.replace(hour=0, minute=0, second=0, microsecond=0) duty_schedules = [ DutySchedule(user_id=3, duty_date=this_monday, shift="day", area_id=1, notes="全区巡检"), DutySchedule(user_id=3, duty_date=this_monday + timedelta(days=1), shift="day", area_id=5, notes="热泵系统重点巡检"), DutySchedule(user_id=3, duty_date=this_monday + timedelta(days=2), shift="day", area_id=4, notes="光伏系统巡检"), DutySchedule(user_id=2, duty_date=this_monday + timedelta(days=2), shift="on_call", area_id=1, notes="值班备勤"), DutySchedule(user_id=3, duty_date=this_monday + timedelta(days=3), shift="day", area_id=6, notes="电力计量巡检"), DutySchedule(user_id=3, duty_date=this_monday + timedelta(days=4), shift="day", area_id=1, notes="全区巡检"), DutySchedule(user_id=2, duty_date=this_monday + timedelta(days=5), shift="on_call", area_id=1, notes="周末值班"), ] session.add_all(duty_schedules) await session.flush() # ===================================================================== # 15. 管理体系 (regulations, standards, process docs, emergency plans) # ===================================================================== regulations = [ Regulation(title="园区能源管理制度", category="operation", content="本制度适用于天普大兴园区所有能源设施的日常运行管理。各部门应严格执行节能措施,定期汇报能耗情况。", effective_date=datetime(2026, 1, 1, tzinfo=timezone.utc), status="active", created_by=1), Regulation(title="设备安全操作规程", category="safety", content="所有操作人员必须持证上岗。高压设备操作需两人以上。严禁带电作业。定期进行安全培训。", effective_date=datetime(2026, 1, 1, tzinfo=timezone.utc), status="active", created_by=1), Regulation(title="碳排放管理办法", category="environment", content="园区实行碳排放总量控制,每月核算碳排放量。光伏和热泵优先使用,减少电网购电。", effective_date=datetime(2026, 3, 1, tzinfo=timezone.utc), status="active", created_by=1), ] session.add_all(regulations) standards = [ Standard(name="能源管理体系", code="ISO 50001:2018", type="international", description="国际能源管理体系标准,系统化管理能源绩效", compliance_status="in_progress", review_date=datetime(2026, 6, 1, tzinfo=timezone.utc)), Standard(name="能源管理体系要求", code="GB/T 23331-2020", type="national", description="等同采用ISO 50001的国家标准", compliance_status="compliant", review_date=datetime(2026, 12, 1, tzinfo=timezone.utc)), Standard(name="公共建筑节能设计标准", code="GB 50189-2015", type="national", description="公共建筑节能设计的国家强制性标准", compliance_status="compliant", review_date=datetime(2026, 12, 1, tzinfo=timezone.utc)), ] session.add_all(standards) process_docs = [ ProcessDoc(title="热泵系统操作手册", category="operation", content="1. 开机前检查水压和电源;2. 设置目标温度;3. 启动压缩机;4. 监测运行参数;5. 记录运行日志。", version="2.0", approved_by="张能源", effective_date=datetime(2026, 1, 15, tzinfo=timezone.utc)), ProcessDoc(title="光伏系统维护流程", category="maintenance", content="1. 每月清洗光伏板;2. 检查逆变器运行状态;3. 检查线缆连接;4. 测量绝缘电阻;5. 记录发电数据对比。", version="1.5", approved_by="张能源", effective_date=datetime(2026, 2, 1, tzinfo=timezone.utc)), ] session.add_all(process_docs) emergency_plans = [ EmergencyPlan( title="停电应急预案", scenario="power_outage", steps=json.dumps([ {"step_number": 1, "action": "确认停电范围和原因", "responsible_person": "值班员", "contact": "13800000003"}, {"step_number": 2, "action": "启动储能系统供电", "responsible_person": "运维工程师", "contact": "13800000003"}, {"step_number": 3, "action": "通知园区各部门", "responsible_person": "园区管理员", "contact": "13800000001"}, {"step_number": 4, "action": "联系供电局抢修", "responsible_person": "能源主管", "contact": "13800000002"}, ]), responsible_person="张能源", review_date=datetime(2026, 7, 1, tzinfo=timezone.utc), is_active=True, ), EmergencyPlan( title="设备故障应急预案", scenario="equipment_failure", steps=json.dumps([ {"step_number": 1, "action": "立即切断故障设备电源", "responsible_person": "值班员", "contact": "13800000003"}, {"step_number": 2, "action": "评估影响范围并隔离", "responsible_person": "运维工程师", "contact": "13800000003"}, {"step_number": 3, "action": "启动备用设备", "responsible_person": "运维工程师", "contact": "13800000003"}, {"step_number": 4, "action": "联系厂家技术支持", "responsible_person": "能源主管", "contact": "13800000002"}, {"step_number": 5, "action": "填写故障报告", "responsible_person": "运维工程师", "contact": "13800000003"}, ]), responsible_person="李运维", review_date=datetime(2026, 7, 1, tzinfo=timezone.utc), is_active=True, ), ] session.add_all(emergency_plans) await session.commit() print("=" * 60) print("Seed data inserted successfully!") print("=" * 60) print(f" - {len(roles)} roles (with permissions)") print(f" - {len(users)} users (admin/admin123, energy_mgr/tianpu123, operator1/tianpu123)") print(f" - {len(device_types)} device types") print(f" - {len(groups)} device groups (hierarchical)") print(f" - {len(devices)} devices") print(f" - {len(alarm_rules)} alarm rules") print(f" - {len(factors)} emission factors") print(f" - {len(templates)} report templates") print(f" - {len(report_tasks)} report tasks (scheduled)") print(f" - {len(alarm_events)} alarm events (historical)") print(f" - {len(categories)} energy categories") print(f" - 1 charging merchant, {len([brand1, brand2])} brands") print(f" - {len([station1, station2])} charging stations, {len(piles)} piles") print(f" - {len(charging_orders)} charging orders") print(f" - {len(quotas)} energy quotas") print(f" - 1 electricity pricing with {len(pricing_periods)} periods") print(f" - {len([plan1, plan2])} inspection plans, {len(inspection_records)} records") print(f" - {len(repair_orders)} repair orders") print(f" - {len(duty_schedules)} duty schedules") print(f" - {len(regulations)} regulations, {len(standards)} standards") print(f" - {len(process_docs)} process docs, {len(emergency_plans)} emergency plans") await engine.dispose() if __name__ == "__main__": asyncio.run(seed())