Files
ems-core/backend/app/hooks/base.py
Du Wenbo 2b9797d61b feat: add customer hooks plugin system (v1.1.0)
New plugin architecture for customer-specific business logic:
- hooks/base.py: CustomerHooks base class with 12 hook points
  (on_alarm_created, on_alarm_resolved, on_energy_data_received,
   on_device_status_changed, on_quota_exceeded, on_work_order_created,
   on_work_order_completed, on_inspection_completed, on_report_generated,
   calculate_custom_kpis, on_charging_order_created/completed)
- hooks/loader.py: Dynamic loader that imports from customers/{CUSTOMER}/hooks/
- alarm_checker.py: calls on_alarm_created and on_alarm_resolved hooks
- quota_checker.py: calls on_quota_exceeded hook

Customers override hooks by creating customers/{name}/hooks/__init__.py
without modifying core code. Scales to 10-20+ customers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 18:30:53 +08:00

143 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""客户钩子基类 — 定义所有可扩展的业务事件钩子
每个客户项目可以继承 CustomerHooks 并重写需要的方法。
核心代码在关键业务节点调用这些钩子,客户无需修改核心代码即可注入自定义逻辑。
使用方式:
1. 在客户项目中创建 customers/{customer}/hooks/__init__.py
2. 继承 CustomerHooks重写需要的方法
3. 导出 hooks = YourCustomerHooks() 实例
"""
import logging
from typing import Any, Optional
logger = logging.getLogger("hooks")
class CustomerHooks:
"""客户钩子基类 — 所有方法默认为空操作,客户按需重写。"""
# =====================================================================
# 告警相关钩子
# =====================================================================
async def on_alarm_created(self, alarm_event, device, rule, db) -> None:
"""告警创建后触发。可用于:自动创建工单、发送微信通知、触发联动控制等。
Args:
alarm_event: AlarmEvent 实例已持久化有id
device: Device 实例(触发告警的设备)
rule: AlarmRule 实例(匹配的告警规则)
db: AsyncSession 数据库会话
"""
pass
async def on_alarm_resolved(self, alarm_event, device, db) -> None:
"""告警恢复后触发。可用于:关闭关联工单、发送恢复通知等。
Args:
alarm_event: AlarmEvent 实例已更新为resolved状态
device: Device 实例
db: AsyncSession
"""
pass
# =====================================================================
# 能耗数据钩子
# =====================================================================
async def on_energy_data_received(self, device, data_point, db) -> None:
"""新能耗数据入库后触发。可用于:自定义数据校验、派生计算、异常检测等。
Args:
device: Device 实例
data_point: EnergyData 实例
db: AsyncSession
"""
pass
# =====================================================================
# 设备状态钩子
# =====================================================================
async def on_device_status_changed(self, device, old_status: str, new_status: str, db) -> None:
"""设备状态变更后触发。可用于:离线告警、自动重启、通知运维人员等。
Args:
device: Device 实例
old_status: 旧状态 (online/offline/alarm/maintenance)
new_status: 新状态
db: AsyncSession
"""
pass
# =====================================================================
# 定额钩子
# =====================================================================
async def on_quota_exceeded(self, quota, usage, db) -> None:
"""定额超限后触发。可用于:邮件通知楼宇负责人、限电策略、上报管理层等。
Args:
quota: EnergyQuota 实例
usage: QuotaUsage 实例(包含使用率)
db: AsyncSession
"""
pass
# =====================================================================
# 工单钩子
# =====================================================================
async def on_work_order_created(self, order, db) -> None:
"""维修工单创建后触发。可用于:通知维修人员、同步到外部系统等。"""
pass
async def on_work_order_completed(self, order, db) -> None:
"""维修工单完成后触发。可用于:生成维修报告、更新设备状态等。"""
pass
# =====================================================================
# 巡检钩子
# =====================================================================
async def on_inspection_completed(self, record, db) -> None:
"""巡检完成后触发。可用于:生成合规报告、发现问题自动创建工单等。"""
pass
# =====================================================================
# 报表钩子
# =====================================================================
async def on_report_generated(self, report_task, file_path: str, db) -> None:
"""报表生成后触发。可用于自动邮件发送、上传到FTP/OSS、自定义格式转换等。"""
pass
# =====================================================================
# 自定义KPI钩子
# =====================================================================
async def calculate_custom_kpis(self, period: str, db) -> dict:
"""Dashboard加载时调用返回客户自定义KPI。
Args:
period: 统计周期 ("today", "month", "year")
db: AsyncSession
Returns:
dict: 自定义KPI字典{"solar_efficiency": 0.85, "grid_independence": 0.72}
"""
return {}
# =====================================================================
# 充电桩钩子
# =====================================================================
async def on_charging_order_created(self, order, db) -> None:
"""充电订单创建时触发。可用于:自定义计费规则、用户验证等。"""
pass
async def on_charging_order_completed(self, order, db) -> None:
"""充电订单完成时触发。可用于:结算通知、积分奖励等。"""
pass