Browse Source

策略管理初版

learshaw 4 months ago
parent
commit
15bd92b3c2
51 changed files with 3475 additions and 645 deletions
  1. 1 1
      common-cloud/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml
  2. 0 11
      ems/ems-application/ems-admin/src/main/java/com/ruoyi/web/controller/ems/DeviceController.java
  3. 1 1
      ems/ems-application/pom.xml
  4. 174 104
      ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/controller/OpEnergyStrategyController.java
  5. 0 15
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/EmsObjAbilityCallLog.java
  6. 0 12
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/EmsObjEventLog.java
  7. 0 16
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/EmsSubsystem.java
  8. 28 111
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategy.java
  9. 42 0
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyExecLog.java
  10. 25 120
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyStep.java
  11. 43 0
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyStepLog.java
  12. 61 0
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyTemplate.java
  13. 42 0
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyTrigger.java
  14. 0 10
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/PlantCarbonSink.java
  15. 49 0
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/StepExecutionResult.java
  16. 52 0
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/StrategyExecutionContext.java
  17. 69 0
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyExecLogMapper.java
  18. 32 24
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyMapper.java
  19. 62 0
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyStepLogMapper.java
  20. 35 19
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyStepMapper.java
  21. 61 0
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyTemplateMapper.java
  22. 84 0
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyTriggerMapper.java
  23. 76 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyExecLogService.java
  24. 32 25
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyService.java
  25. 61 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyStepLogService.java
  26. 42 19
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyStepService.java
  27. 61 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyTemplateService.java
  28. 77 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyTriggerService.java
  29. 38 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IStepExecutor.java
  30. 0 11
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/AbilityCallServiceImpl.java
  31. 74 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyExecLogServiceImpl.java
  32. 18 44
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyServiceImpl.java
  33. 59 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyStepLogServiceImpl.java
  34. 26 6
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyStepServiceImpl.java
  35. 97 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyTemplateServiceImpl.java
  36. 69 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyTriggerServiceImpl.java
  37. 122 0
      ems/ems-core/src/main/java/com/ruoyi/ems/strategy/evaluator/ConditionEvaluator.java
  38. 249 0
      ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/AbilityCallStepExecutor.java
  39. 51 0
      ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/ConditionStepExecutor.java
  40. 45 0
      ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/DelayStepExecutor.java
  41. 48 0
      ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/StepExecutorFactory.java
  42. 259 0
      ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/StrategyExecutor.java
  43. 118 0
      ems/ems-core/src/main/java/com/ruoyi/ems/strategy/listener/StrategyTriggerListener.java
  44. 107 0
      ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyExecLogMapper.xml
  45. 106 24
      ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyMapper.xml
  46. 114 0
      ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyStepLogMapper.xml
  47. 126 43
      ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyStepMapper.xml
  48. 127 0
      ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyTemplateMapper.xml
  49. 110 0
      ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyTriggerMapper.xml
  50. 295 28
      ems/sql/ems_server.sql
  51. 7 1
      ems/sql/ems_sys_data.sql

+ 1 - 1
common-cloud/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml

@@ -8,7 +8,7 @@ spring:
     name: ruoyi-gen
   profiles:
     # 环境配置
-    active: local
+    active: prod
   cloud:
     nacos:
       discovery:

+ 0 - 11
ems/ems-application/ems-admin/src/main/java/com/ruoyi/web/controller/ems/DeviceController.java

@@ -188,17 +188,6 @@ public class DeviceController extends BaseController {
     }
 
     /**
-     * 设备-设备状态统计
-     *
-     * @param areaCode
-     * @return
-     */
-    @GetMapping(value = "/status/cnt")
-    public AjaxResult getDeviceStatusCnt(@RequestParam("areaCode") String areaCode) {
-        return success(deviceService.cntDeviceStatus(areaCode));
-    }
-
-    /**
      * 设备-类型在线率
      *
      * @param areaCode

+ 1 - 1
ems/ems-application/pom.xml

@@ -12,7 +12,7 @@
     <description>华设能源管理系统-单体应用版</description>
 
     <modules>
-        <module>ems-admin</module>
+
     </modules>
     <packaging>pom</packaging>
 

+ 174 - 104
ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/controller/OpEnergyStrategyController.java

@@ -9,13 +9,21 @@ import com.ruoyi.common.log.annotation.Log;
 import com.ruoyi.common.log.enums.BusinessType;
 import com.ruoyi.common.security.annotation.RequiresPermissions;
 import com.ruoyi.ems.domain.OpEnergyStrategy;
+import com.ruoyi.ems.domain.OpEnergyStrategyExecLog;
 import com.ruoyi.ems.domain.OpEnergyStrategyParam;
 import com.ruoyi.ems.domain.OpEnergyStrategyStep;
-import com.ruoyi.ems.model.ParamOption;
+import com.ruoyi.ems.domain.OpEnergyStrategyStepLog;
+import com.ruoyi.ems.domain.OpEnergyStrategyTemplate;
+import com.ruoyi.ems.domain.OpEnergyStrategyTrigger;
+import com.ruoyi.ems.service.IOpEnergyStrategyExecLogService;
 import com.ruoyi.ems.service.IOpEnergyStrategyParamService;
 import com.ruoyi.ems.service.IOpEnergyStrategyService;
 import com.ruoyi.ems.service.IOpEnergyStrategyStepService;
+import com.ruoyi.ems.service.IOpEnergyStrategyTemplateService;
+import com.ruoyi.ems.service.IOpEnergyStrategyTriggerService;
+import com.ruoyi.ems.strategy.executor.StrategyExecutor;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -28,8 +36,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -49,30 +55,28 @@ public class OpEnergyStrategyController extends BaseController {
     private IOpEnergyStrategyService strategyService;
 
     @Autowired
+    private IOpEnergyStrategyTemplateService templateService;
+
+    @Autowired
     private IOpEnergyStrategyParamService paramService;
 
     @Autowired
     private IOpEnergyStrategyStepService stepService;
 
-    private static final Map<String, List<ParamOption>> PARAM_OPTIONS = new HashMap<>();
+    @Autowired
+    private IOpEnergyStrategyTriggerService triggerService;
 
-    static {
-        List<ParamOption> dcList = Arrays.asList(new ParamOption("maxPowerTrack", "最大功率点跟踪(MPPT)", "通过实时调整光伏阵列的工作状态,使光伏系统始终运行在最大功率点"),
-            new ParamOption("inverterControl", "逆变器控制", "通过光伏逆变器实施控制"),
-            new ParamOption("powerAndVoltage", "无功功率及电压控制", "根据电网需求,通过调节光伏系统输出的无功功率和电压,实现电压稳定和电力因素的优化"));
+    @Autowired
+    private IOpEnergyStrategyExecLogService execLogService;
 
-        PARAM_OPTIONS.put("default.controlMode", dcList);
+    @Autowired
+    private StrategyExecutor strategyExecutor;
 
-        List<ParamOption> diList = Arrays.asList(
-            new ParamOption("svpwm", "空间矢量控制(SVPWM)", "通过对逆变器开关状态的优化控制,实现并网电流的高精度控制"),
-            new ParamOption("dtc", "直流转矩控制", "以控制逆变器输出转矩和磁链为目标,快速响应"));
-
-        PARAM_OPTIONS.put("inverterControl.controlMode", diList);
-    }
 
     /**
      * 查询能源策略列表
      */
+    @RequiresPermissions("power-mgr:strategy:list")
     @GetMapping("/list")
     public TableDataInfo list(OpEnergyStrategy strategy) {
         startPage();
@@ -119,6 +123,22 @@ public class OpEnergyStrategyController extends BaseController {
     }
 
     /**
+     * 启用/停用策略
+     */
+    @PutMapping("/state/{strategyCode}/{state}")
+    @ApiOperation("启用/停用策略")
+    public AjaxResult changeState(@PathVariable String strategyCode, @PathVariable Integer state) {
+        OpEnergyStrategy strategy = strategyService.selectStrategyByCode(strategyCode);
+        if (strategy == null) {
+            return error("策略不存在");
+        }
+        strategy.setStrategyState(state);
+        return toAjax(strategyService.updateStrategy(strategy));
+    }
+
+    // ==================== 策略参数管理 ====================
+
+    /**
      * 获取能源策略参数
      *
      * @param strategyCode 策略编码
@@ -126,31 +146,52 @@ public class OpEnergyStrategyController extends BaseController {
      */
     @GetMapping(value = "/param")
     public AjaxResult getStrategyParam(@RequestParam(name = "strategyCode") String strategyCode) {
-        // 补充策略参数
         List<OpEnergyStrategyParam> paramList = paramService.selectParamByStrategyCode(strategyCode);
         return success(buildStrategyParams(paramList));
     }
 
     /**
-     * 修改能源策略
+     * 修改能源策略参数
      */
     @RequiresPermissions("power-mgr:strategy:edit")
     @Log(title = "能源策略参数", businessType = BusinessType.UPDATE)
     @PutMapping("/param")
     public AjaxResult editParam(@RequestBody OpEnergyStrategyParam strategyParam) {
-        AjaxResult result = null;
-
         try {
             int updateCnt = paramService.updateParamValue(strategyParam);
-            result = toAjax(updateCnt);
+            return toAjax(updateCnt);
+        } catch (BusinessException e) {
+            return error(e.getMessage());
         }
-        catch (BusinessException e) {
-            result = error(e.getMessage());
+    }
+
+    private Map<String, Map<String, JSONObject>> buildStrategyParams(List<OpEnergyStrategyParam> paramList) {
+        Map<String, Map<String, JSONObject>> params = new HashMap<>();
+
+        Map<String, List<OpEnergyStrategyParam>> groupedMap = paramList.stream()
+            .collect(Collectors.groupingBy(OpEnergyStrategyParam::getParamGroup, Collectors.toList()));
+
+        for (Map.Entry<String, List<OpEnergyStrategyParam>> entry : groupedMap.entrySet()) {
+            String groupName = entry.getKey();
+            List<OpEnergyStrategyParam> groupParams = entry.getValue();
+
+            Map<String, JSONObject> groupParamMap = new HashMap<>();
+            for (OpEnergyStrategyParam param : groupParams) {
+                JSONObject option = new JSONObject();
+                option.put("paramName", param.getParamName());
+                option.put("paramValue", param.getParamValue());
+                option.put("editEnable", param.getEditEnable());
+                option.put("paramValueFormat", param.getParamValueFormat());
+                groupParamMap.put(param.getParamKey(), option);
+            }
+            params.put(groupName, groupParamMap);
         }
 
-        return result;
+        return params;
     }
 
+    // ==================== 策略步骤管理 ====================
+
     /**
      * 获取能源策略执行步骤
      *
@@ -166,7 +207,7 @@ public class OpEnergyStrategyController extends BaseController {
      * 新增能源策略执行步骤
      *
      * @param strategyStep 策略步骤
-     * @return 步骤列表
+     * @return 执行结果
      */
     @PostMapping(value = "/step")
     public AjaxResult addStrategyStep(@RequestBody OpEnergyStrategyStep strategyStep) {
@@ -174,21 +215,10 @@ public class OpEnergyStrategyController extends BaseController {
     }
 
     /**
-     * 删除能源策略执行步骤
-     *
-     * @param strategyCode 策略代码
-     * @return 步骤列表
-     */
-    @DeleteMapping(value = "/step")
-    public AjaxResult delStrategyStep(@RequestParam(name = "strategyCode") String strategyCode) {
-        return toAjax(stepService.deleteStepByStrategyCode(strategyCode));
-    }
-
-    /**
      * 修改能源策略执行步骤
      *
      * @param strategyStep 策略步骤
-     * @return 步骤列表
+     * @return 执行结果
      */
     @PutMapping(value = "/step")
     public AjaxResult editStrategyStep(@RequestBody OpEnergyStrategyStep strategyStep) {
@@ -196,94 +226,134 @@ public class OpEnergyStrategyController extends BaseController {
     }
 
     /**
-     * 修改能源策略执行步骤
+     * 删除能源策略执行步骤
      *
-     * @param strategySteps 策略步骤
-     * @return 步骤列表
+     * @param id 步骤ID
+     * @return 执行结果
      */
-    @PutMapping(value = "/step/batch")
-    public AjaxResult editStrategyStep(List<OpEnergyStrategyStep> strategySteps) {
-        stepService.deleteStepByStrategyCode(strategySteps.get(0).getStrategyCode());
-        return toAjax(stepService.insertStepBatch(strategySteps));
+    @DeleteMapping(value = "/step/{id}")
+    public AjaxResult delStrategyStep(@PathVariable Long id) {
+        return toAjax(stepService.deleteStep(id));
     }
 
     /**
-     * 获取能源策略参数选项
+     * 批量修改能源策略执行步骤
      *
-     * @param strategyType 策略类型
-     * @param paramKey     参数键
-     * @return 选项
+     * @param strategySteps 策略步骤列表
+     * @return 执行结果
      */
-    @GetMapping(value = "/param/option")
-    public AjaxResult getStrategyParamOption(@RequestParam(name = "strategyType") int strategyType,
-        @RequestParam(name = "paramKey") String paramKey) {
-        List<ParamOption> options = null;
-
-        switch (strategyType) {
-            case 1:
-                options = getYwParamOption(paramKey);
-                break;
-            case 2:
-                options = getYhParamOption(paramKey);
-                break;
-            case 3:
-                options = getWcParamOption(paramKey);
-                break;
+    @PutMapping(value = "/step/batch")
+    public AjaxResult editStrategyStepBatch(@RequestBody List<OpEnergyStrategyStep> strategySteps) {
+        if (CollectionUtils.isEmpty(strategySteps)) {
+            return error("步骤列表不能为空");
         }
+        stepService.deleteStepByStrategyCode(strategySteps.get(0).getStrategyCode());
+        return toAjax(stepService.insertStepBatch(strategySteps));
+    }
 
-        return CollectionUtils.isNotEmpty(options) ? success(options) : success(new ArrayList<>());
+    // ==================== 触发器管理(新增) ====================
+
+    /**
+     * 获取策略触发器列表
+     */
+    @GetMapping("/trigger/{strategyCode}")
+    @ApiOperation("获取触发器列表")
+    public AjaxResult getTriggers(@PathVariable String strategyCode) {
+        List<OpEnergyStrategyTrigger> triggers = triggerService.selectByStrategyCode(strategyCode);
+        return success(triggers);
     }
 
-    private List<ParamOption> getYwParamOption(String paramKey) {
-        return PARAM_OPTIONS.get(paramKey);
+    /**
+     * 保存策略触发器
+     */
+    @PostMapping("/trigger")
+    @ApiOperation("保存触发器")
+    public AjaxResult saveTrigger(@RequestBody OpEnergyStrategyTrigger trigger) {
+        if (trigger.getId() == null) {
+            return toAjax(triggerService.insertTrigger(trigger));
+        } else {
+            return toAjax(triggerService.updateTrigger(trigger));
+        }
     }
 
-    private List<ParamOption> getYhParamOption(String paramKey) {
-        return null;
+    /**
+     * 删除触发器
+     */
+    @DeleteMapping("/trigger/{id}")
+    @ApiOperation("删除触发器")
+    public AjaxResult deleteTrigger(@PathVariable Long id) {
+        return toAjax(triggerService.deleteTrigger(id));
     }
 
-    private List<ParamOption> getWcParamOption(String paramKey) {
-        return null;
+    /**
+     * 策略模板
+     * @param template
+     * @return
+     */
+    @GetMapping("/template/list")
+    public AjaxResult listTemplate(OpEnergyStrategyTemplate template)
+    {
+        List<OpEnergyStrategyTemplate> list = templateService.selectTemplateList(template);
+        return success(list);
     }
 
-    private Map<String, Map<String, JSONObject>> buildStrategyParams(List<OpEnergyStrategyParam> paramList) {
-        Map<String, Map<String, JSONObject>> params = new HashMap<>();
 
-        Map<String, List<OpEnergyStrategyParam>> groupedMap = paramList.stream()
-            .collect(Collectors.groupingBy(OpEnergyStrategyParam::getParamGroup, Collectors.toList()));
+    /**
+     * 手动执行策略
+     */
+    @PostMapping("/execute/{strategyCode}")
+    @ApiOperation("手动执行策略")
+    public AjaxResult executeStrategy(@PathVariable String strategyCode,
+        @RequestBody(required = false) Map<String, Object> params) {
+        try {
+            if (params == null) {
+                params = new HashMap<>();
+            }
+            params.put("trigger_type", "MANUAL");
+            params.put("trigger_source", "USER");
 
-        for (Map.Entry<String, List<OpEnergyStrategyParam>> entry : groupedMap.entrySet()) {
-            String groupName = entry.getKey();
-            List<OpEnergyStrategyParam> groupParams = entry.getValue();
+            String execId = strategyExecutor.executeStrategy(strategyCode, params);
 
-            if (params.containsKey(groupName)) {
-                Map<String, JSONObject> groupParamMap = params.get(groupName);
-
-                for (OpEnergyStrategyParam param : groupParams) {
-                    JSONObject option = new JSONObject();
-                    option.put("paramName", param.getParamName());
-                    option.put("paramValue", param.getParamValue());
-                    option.put("editEnable", param.getEditEnable());
-                    option.put("paramValueFormat", param.getParamValueFormat());
-                    groupParamMap.put(param.getParamKey(), option);
-                }
-            }
-            else {
-                Map<String, JSONObject> groupParamMap = new HashMap<>();
-
-                for (OpEnergyStrategyParam param : groupParams) {
-                    JSONObject option = new JSONObject();
-                    option.put("paramName", param.getParamName());
-                    option.put("paramValue", param.getParamValue());
-                    option.put("editEnable", param.getEditEnable());
-                    option.put("paramValueFormat", param.getParamValueFormat());
-                    groupParamMap.put(param.getParamKey(), option);
-                }
-
-                params.put(groupName, groupParamMap);
-            }
+            Map<String, Object> result = new HashMap<>();
+            result.put("execId", execId);
+            result.put("message", "策略执行已启动");
+
+            return success(result);
+        } catch (Exception e) {
+            return error("策略执行失败: " + e.getMessage());
         }
+    }
 
-        return params;
+    // ==================== 执行日志(新增) ====================
+
+    /**
+     * 获取策略执行日志列表
+     */
+    @GetMapping("/execLog/list/{strategyCode}")
+    @ApiOperation("获取执行日志列表")
+    public AjaxResult getExecLogList(@PathVariable String strategyCode) {
+        List<OpEnergyStrategyExecLog> execLogs = execLogService.selectByStrategyCode(strategyCode);
+        return success(execLogs);
+    }
+
+    /**
+     * 获取策略执行日志详情
+     */
+    @GetMapping("/execLog/{execId}")
+    @ApiOperation("获取执行日志详情")
+    public AjaxResult getExecLog(@PathVariable String execId) {
+        OpEnergyStrategyExecLog execLog = execLogService.selectByExecId(execId);
+        if (execLog == null) {
+            return error("执行日志不存在");
+        }
+
+        // 获取步骤日志
+        List<OpEnergyStrategyStepLog> stepLogs = execLogService.selectStepLogsByExecId(execId);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("execLog", execLog);
+        result.put("stepLogs", stepLogs);
+
+        return success(result);
     }
-}
+}

+ 0 - 15
ems/ems-core/src/main/java/com/ruoyi/ems/domain/EmsObjAbilityCallLog.java

@@ -56,19 +56,4 @@ public class EmsObjAbilityCallLog extends BaseEntity
     private String resPayload;
 
     private transient List<String> modelCodes;
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("objCode", getObjCode())
-            .append("modelCode", getModelCode())
-            .append("abilityKey", getAbilityKey())
-            .append("callTime", getCallTime())
-            .append("callPayload", getCallPayload())
-            .append("callStatus", getCallStatus())
-            .append("resTime", getResTime())
-            .append("resPayload", getResPayload())
-            .toString();
-    }
 }

+ 0 - 12
ems/ems-core/src/main/java/com/ruoyi/ems/domain/EmsObjEventLog.java

@@ -60,16 +60,4 @@ public class EmsObjEventLog extends BaseEntity {
     private String eventDetail;
 
     private transient List<String> modelCodes;
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("objCode", getObjCode())
-            .append("modelCode", getModelCode())
-            .append("eventKey", getEventKey())
-            .append("eventName", getEventName())
-            .append("eventTime", getEventTime())
-            .append("eventDetail", getEventDetail()).toString();
-    }
 }

+ 0 - 16
ems/ems-core/src/main/java/com/ruoyi/ems/domain/EmsSubsystem.java

@@ -48,20 +48,4 @@ public class EmsSubsystem extends BaseEntity
 
     private String modelCode;
 
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("systemCode", getSystemCode())
-            .append("systemName", getSystemName())
-            .append("shortName", getShortName())
-            .append("manFacturer", getManFacturer())
-            .append("contactPerson", getContactPerson())
-            .append("contactNumber", getContactNumber())
-            .append("maintainerPerson", getMaintainerPerson())
-            .append("maintainerNumber", getMaintainerNumber())
-            .append("descr", getDescr())
-            .append("modelCode", getModelCode())
-            .toString();
-    }
 }

+ 28 - 111
ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategy.java

@@ -1,133 +1,50 @@
 package com.ruoyi.ems.domain;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.huashe.common.domain.BaseEntity;
+import lombok.Data;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 
+import java.util.Date;
+
 /**
  * 能源策略对象 adm_op_energy_strategy
  *
  * @author ruoyi
  * @date 2024-08-08
  */
+@Data
 public class OpEnergyStrategy extends BaseEntity
 {
-    private static final long serialVersionUID = 1L;
-
-    /** 序号 */
     private Long id;
-
-    /** 区域代码 */
     private String areaCode;
-
-    /** 策略代码 */
     private String strategyCode;
-
-    /** 策略名称 */
-
     private String strategyName;
-
-    /** 策略描述 */
-    private String strategyDesc;
-
-    /** 策略类型 */
-    private Integer strategyType;
-
-    /** 策略状态 */
+    private String sceneType;
+    private String strategyCategory;
+    private Integer triggerType;
+    private String triggerConfig;
     private Integer strategyState;
-
-    /** 执行模式 1:定时执行(cron)99:手动执行 */
+    private Integer priority;
+    private String strategyDesc;
     private Integer execMode;
-
-    /** 执行规则 */
     private String execRule;
-
-    public Long getId() {
-        return id;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public String getAreaCode() {
-        return areaCode;
-    }
-
-    public void setAreaCode(String areaCode) {
-        this.areaCode = areaCode;
-    }
-
-    public String getStrategyCode() {
-        return strategyCode;
-    }
-
-    public void setStrategyCode(String strategyCode) {
-        this.strategyCode = strategyCode;
-    }
-
-    public String getStrategyName() {
-        return strategyName;
-    }
-
-    public void setStrategyName(String strategyName) {
-        this.strategyName = strategyName;
-    }
-
-    public String getStrategyDesc() {
-        return strategyDesc;
-    }
-
-    public void setStrategyDesc(String strategyDesc) {
-        this.strategyDesc = strategyDesc;
-    }
-
-    public Integer getStrategyType() {
-        return strategyType;
-    }
-
-    public void setStrategyType(Integer strategyType) {
-        this.strategyType = strategyType;
-    }
-
-    public Integer getStrategyState() {
-        return strategyState;
-    }
-
-    public void setStrategyState(Integer strategyState) {
-        this.strategyState = strategyState;
-    }
-
-    public Integer getExecMode() {
-        return execMode;
-    }
-
-    public void setExecMode(Integer execMode) {
-        this.execMode = execMode;
-    }
-
-    public String getExecRule() {
-        return execRule;
-    }
-
-    public void setExecRule(String execRule) {
-        this.execRule = execRule;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("areaCode", getAreaCode())
-            .append("strategyCode", getStrategyCode())
-            .append("strategyName", getStrategyName())
-            .append("strategyDesc", getStrategyDesc())
-            .append("strategyType", getStrategyType())
-            .append("strategyState", getStrategyState())
-            .append("execMode", getExecMode())
-            .append("execRule", getExecRule())
-            .append("createTime", getCreateTime())
-            .append("updateTime", getUpdateTime())
-            .toString();
-    }
+    private Integer timeout;
+    private Integer retryTimes;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date lastExecTime;
+    private Integer lastExecResult;
+    private Integer execCount;
+    private Integer successCount;
+    private Integer failCount;
+    private Integer version;
+
+    private String createBy;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+    private String updateBy;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
 }

+ 42 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyExecLog.java

@@ -0,0 +1,42 @@
+/*
+ * 文 件 名:  OpEnergyStrategyExecLog
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.domain;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * OpEnergyStrategyExecLog
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class OpEnergyStrategyExecLog {
+    private Long id;
+    private String strategyCode;
+    private String execId;
+    private String triggerType;
+    private String triggerSource;
+    private Integer execStatus;
+    private Date startTime;
+    private Date endTime;
+    private Integer duration;
+    private String contextData;
+    private String resultData;
+    private String errorMessage;
+    private String execBy;
+    private Date createTime;
+}

+ 25 - 120
ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyStep.java

@@ -1,138 +1,43 @@
 package com.ruoyi.ems.domain;
 
+import lombok.Data;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 
+import java.util.Date;
+
 /**
  * 能源策略步骤对象 adm_op_energy_strategy_step
  * 
  * @author ruoyi
  * @date 2024-10-14
  */
+@Data
 public class OpEnergyStrategyStep
 {
-    /** 序号 */
     private Long id;
-
-    /** 策略代码 */
     private String strategyCode;
-
-    /** 步骤代码 */
     private String stepCode;
-
-    /** 步骤名称 */
     private String stepName;
-
-    /** 步骤顺序 */
-    private Long stepIndex;
-
-    /** 步骤处理 */
-    private String stepHandler;
-
-    /** 步骤参数 */
-    private String stepParam;
-
-    /** 目标设施 */
-    private String targetFacs;
-
-    /** 目标设备 */
-    private String targetDevice;
-
-    public void setId(Long id) 
-    {
-        this.id = id;
-    }
-
-    public Long getId() 
-    {
-        return id;
-    }
-
-    public void setStrategyCode(String strategyCode) 
-    {
-        this.strategyCode = strategyCode;
-    }
-
-    public String getStrategyCode() 
-    {
-        return strategyCode;
-    }
-    public void setStepCode(String stepCode) 
-    {
-        this.stepCode = stepCode;
-    }
-
-    public String getStepCode() 
-    {
-        return stepCode;
-    }
-    public void setStepName(String stepName) 
-    {
-        this.stepName = stepName;
-    }
-
-    public String getStepName() 
-    {
-        return stepName;
-    }
-    public void setStepIndex(Long stepIndex) 
-    {
-        this.stepIndex = stepIndex;
-    }
-
-    public Long getStepIndex() 
-    {
-        return stepIndex;
-    }
-    public void setStepHandler(String stepHandler) 
-    {
-        this.stepHandler = stepHandler;
-    }
-
-    public String getStepHandler() 
-    {
-        return stepHandler;
-    }
-    public void setStepParam(String stepParam) 
-    {
-        this.stepParam = stepParam;
-    }
-
-    public String getStepParam() 
-    {
-        return stepParam;
-    }
-    public void setTargetFacs(String targetFacs) 
-    {
-        this.targetFacs = targetFacs;
-    }
-
-    public String getTargetFacs() 
-    {
-        return targetFacs;
-    }
-    public void setTargetDevice(String targetDevice) 
-    {
-        this.targetDevice = targetDevice;
-    }
-
-    public String getTargetDevice() 
-    {
-        return targetDevice;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("strategyCode", getStrategyCode())
-            .append("stepCode", getStepCode())
-            .append("stepName", getStepName())
-            .append("stepIndex", getStepIndex())
-            .append("stepHandler", getStepHandler())
-            .append("stepParam", getStepParam())
-            .append("targetFacs", getTargetFacs())
-            .append("targetDevice", getTargetDevice())
-            .toString();
-    }
+    private String stepType;
+    private Integer stepIndex;
+    private String parentStepCode;
+    private String conditionExpr;
+    private Integer targetObjType;
+    private String targetObjCode;
+    private String targetModelCode;
+    private String abilityKey;
+    private String abilityParam;
+    private String paramSource;
+    private String paramMapping;
+    private Integer delaySeconds;
+    private Integer retryOnFail;
+    private Integer retryTimes;
+    private Integer retryInterval;
+    private Integer continueOnFail;
+    private Integer timeout;
+    private Integer enable;
+    private String remark;
+    private Date createTime;
+    private Date updateTime;
 }

+ 43 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyStepLog.java

@@ -0,0 +1,43 @@
+/*
+ * 文 件 名:  OpEnergyStrategyStepLog
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.domain;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * OpEnergyStrategyStepLog
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class OpEnergyStrategyStepLog {
+    private Long id;
+    private String execId;
+    private String strategyCode;
+    private String stepCode;
+    private String stepName;
+    private Integer stepIndex;
+    private Integer execStatus;
+    private Date startTime;
+    private Date endTime;
+    private Integer duration;
+    private String inputParam;
+    private String outputResult;
+    private String errorMessage;
+    private Integer retryCount;
+    private Date createTime;
+}

+ 61 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyTemplate.java

@@ -0,0 +1,61 @@
+package com.ruoyi.ems.domain;
+
+import com.huashe.common.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 策略模板对象 adm_op_energy_strategy_template
+ * 
+ * @author ruoyi
+ * @date 2025-12-01
+ */
+@Data
+public class OpEnergyStrategyTemplate extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 序号 */
+    private Long id;
+
+    /** 模板代码 */
+    private String templateCode;
+
+    /** 模板名称 */
+    private String templateName;
+
+    /** 场景类型 */
+    private String sceneType;
+
+    /** 模板描述 */
+    private String description;
+
+    /** 模板数据(JSON,包含触发器、步骤、上下文变量) */
+    private String templateData;
+
+    /** 图标 */
+    private String icon;
+
+    /** 封面图片 */
+    private String coverImage;
+
+    /** 标签(逗号分隔) */
+    private String tags;
+
+    /** 适用设备类型(逗号分隔) */
+    private String applicableDevices;
+
+    /** 排序 */
+    private Integer sortOrder;
+
+    /** 使用次数 */
+    private Integer useCount;
+
+    /** 是否系统预置:0-否,1-是 */
+    private Integer isSystem;
+
+    /** 是否公开:0-否,1-是 */
+    private Integer isPublic;
+
+    /** 状态:0-禁用,1-启用 */
+    private Integer status;
+}

+ 42 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/domain/OpEnergyStrategyTrigger.java

@@ -0,0 +1,42 @@
+/*
+ * 文 件 名:  OpEnergyStrategyTrigger
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.domain;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * OpEnergyStrategyTrigger
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class OpEnergyStrategyTrigger {
+    private Long id;
+    private String strategyCode;
+    private String triggerName;
+    private String triggerType;
+    private Integer sourceObjType;
+    private String sourceObjCode;
+    private String sourceModelCode;
+    private String eventKey;
+    private String attrKey;
+    private String conditionExpr;
+    private Integer enable;
+    private Integer priority;
+    private Date createTime;
+    private Date updateTime;
+}

+ 0 - 10
ems/ems-core/src/main/java/com/ruoyi/ems/domain/PlantCarbonSink.java

@@ -33,14 +33,4 @@ public class PlantCarbonSink extends BaseEntity
 
     /** 数据版本 */
     private String version;
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("plantMethod", getPlantMethod())
-            .append("carbonQuantity", getCarbonQuantity())
-            .append("version", getVersion())
-            .toString();
-    }
 }

+ 49 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/domain/StepExecutionResult.java

@@ -0,0 +1,49 @@
+/*
+ * 文 件 名:  StepExecutionResult
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.domain;
+
+import lombok.Data;
+
+/**
+ * StepExecutionResult
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class StepExecutionResult {
+    private boolean success;
+    private String stepCode;
+    private Object result;
+    private String errorMessage;
+    private long duration;
+
+    public static StepExecutionResult success(String stepCode, Object result, long duration) {
+        StepExecutionResult r = new StepExecutionResult();
+        r.setSuccess(true);
+        r.setStepCode(stepCode);
+        r.setResult(result);
+        r.setDuration(duration);
+        return r;
+    }
+
+    public static StepExecutionResult fail(String stepCode, String error, long duration) {
+        StepExecutionResult r = new StepExecutionResult();
+        r.setSuccess(false);
+        r.setStepCode(stepCode);
+        r.setErrorMessage(error);
+        r.setDuration(duration);
+        return r;
+    }
+}

+ 52 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/domain/StrategyExecutionContext.java

@@ -0,0 +1,52 @@
+/*
+ * 文 件 名:  StrategyExecutionContext
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.domain;
+
+import lombok.Data;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * StrategyExecutionContext
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Data
+public class StrategyExecutionContext {
+    private String execId;
+    private String strategyCode;
+    private String triggerType;
+    private String triggerSource;
+    private Map<String, Object> variables = new HashMap<>();
+    private Map<String, Object> stepResults = new HashMap<>();
+    private Long startTime;
+
+    public void setVariable(String key, Object value) {
+        variables.put(key, value);
+    }
+
+    public Object getVariable(String key) {
+        return variables.get(key);
+    }
+
+    public void setStepResult(String stepCode, Object result) {
+        stepResults.put(stepCode, result);
+    }
+
+    public Object getStepResult(String stepCode) {
+        return stepResults.get(stepCode);
+    }
+}

+ 69 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyExecLogMapper.java

@@ -0,0 +1,69 @@
+/*
+ * 文 件 名:  OpEnergyStrategyExecLogMapper
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.mapper;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyExecLog;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 策略执行日志Mapper接口
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface OpEnergyStrategyExecLogMapper {
+    /**
+     * 查询执行日志列表
+     * @param execLog 执行日志
+     * @return 执行日志列表
+     */
+    List<OpEnergyStrategyExecLog> selectExecLogList(OpEnergyStrategyExecLog execLog);
+
+    /**
+     * 根据执行ID查询执行日志
+     * @param execId 执行ID
+     * @return 执行日志
+     */
+    OpEnergyStrategyExecLog selectByExecId(@Param("execId") String execId);
+
+    /**
+     * 根据策略代码查询执行日志
+     * @param strategyCode 策略代码
+     * @return 执行日志列表
+     */
+    List<OpEnergyStrategyExecLog> selectByStrategyCode(@Param("strategyCode") String strategyCode);
+
+    /**
+     * 新增执行日志
+     * @param execLog 执行日志
+     * @return 结果
+     */
+    int insertExecLog(OpEnergyStrategyExecLog execLog);
+
+    /**
+     * 修改执行日志
+     * @param execLog 执行日志
+     * @return 结果
+     */
+    int updateExecLog(OpEnergyStrategyExecLog execLog);
+
+    /**
+     * 删除执行日志
+     * @param id 执行日志ID
+     * @return 结果
+     */
+    int deleteExecLog(@Param("id") Long id);
+}

+ 32 - 24
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyMapper.java

@@ -1,6 +1,7 @@
 package com.ruoyi.ems.mapper;
 
 import com.ruoyi.ems.domain.OpEnergyStrategy;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -12,50 +13,57 @@ import java.util.List;
  */
 public interface OpEnergyStrategyMapper {
     /**
-     * 查询能源策略
-     *
-     * @param id 能源策略主键
-     * @return 能源策略
+     * 查询策略列表
+     * @param strategy 策略
+     * @return 策略列表
      */
-    OpEnergyStrategy selectStrategyById(Long id);
+    List<OpEnergyStrategy> selectStrategyList(OpEnergyStrategy strategy);
 
     /**
-     * 查询能源策略列表
-     *
-     * @param strategy 能源策略
-     * @return 能源策略集合
+     * 查询策略详情(根据ID)
+     * @param id 策略ID
+     * @return 策略详情
      */
-    List<OpEnergyStrategy> selectStrategyList(OpEnergyStrategy strategy);
+    OpEnergyStrategy selectStrategyById(@Param("id") Long id);
+
+    /**
+     * 查询策略详情(根据代码)
+     * @param strategyCode 策略代码
+     * @return 策略详情
+     */
+    OpEnergyStrategy selectStrategyByCode(@Param("strategyCode") String strategyCode);
 
     /**
-     * 新增能源策略
-     *
-     * @param strategy 能源策略
+     * 新增策略
+     * @param strategy 策略
      * @return 结果
      */
     int insertStrategy(OpEnergyStrategy strategy);
 
     /**
-     * 修改能源策略
-     *
-     * @param strategy 能源策略
+     * 修改策略
+     * @param strategy 策略
      * @return 结果
      */
     int updateStrategy(OpEnergyStrategy strategy);
 
     /**
-     * 删除能源策略
-     *
-     * @param id 能源策略主键
+     * 删除策略
+     * @param id 策略ID
      * @return 结果
      */
-    int deleteStrategyById(Long id);
+    int deleteStrategyById(@Param("id") Long id);
 
     /**
-     * 批量删除能源策略
-     *
-     * @param ids 需要删除的数据主键集合
+     * 批量删除策略
+     * @param ids 策略ID数组
      * @return 结果
      */
-    int deleteStrategyByIds(Long[] ids);
+    int deleteStrategyByIds(@Param("ids") Long[] ids);
+
+    /**
+     * 查询定时调度策略
+     * @return 策略列表
+     */
+    List<OpEnergyStrategy> selectScheduledStrategies();
 }

+ 62 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyStepLogMapper.java

@@ -0,0 +1,62 @@
+/*
+ * 文 件 名:  OpEnergyStrategyStepLogMapper
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.mapper;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyStepLog;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 策略步骤日志Mapper接口
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface OpEnergyStrategyStepLogMapper {
+    /**
+     * 查询步骤日志列表
+     * @param stepLog 步骤日志
+     * @return 步骤日志列表
+     */
+    List<OpEnergyStrategyStepLog> selectStepLogList(OpEnergyStrategyStepLog stepLog);
+
+    /**
+     * 根据执行ID查询步骤日志
+     * @param execId 执行ID
+     * @return 步骤日志列表
+     */
+    List<OpEnergyStrategyStepLog> selectByExecId(@Param("execId") String execId);
+
+    /**
+     * 新增步骤日志
+     * @param stepLog 步骤日志
+     * @return 结果
+     */
+    int insertStepLog(OpEnergyStrategyStepLog stepLog);
+
+    /**
+     * 修改步骤日志
+     * @param stepLog 步骤日志
+     * @return 结果
+     */
+    int updateStepLog(OpEnergyStrategyStepLog stepLog);
+
+    /**
+     * 批量新增步骤日志
+     * @param stepLogs 步骤日志列表
+     * @return 结果
+     */
+    int insertStepLogBatch(@Param("list") List<OpEnergyStrategyStepLog> stepLogs);
+}

+ 35 - 19
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyStepMapper.java

@@ -13,42 +13,58 @@ import java.util.List;
  */
 public interface OpEnergyStrategyStepMapper {
     /**
-     * 查询能源策略步骤列表
-     *
-     * @param strategyCode 能源策略步骤code
-     * @return 能源策略步骤集合
+     * 查询策略步骤列表
+     * @param strategyCode 策略代码
+     * @return 步骤列表
      */
     List<OpEnergyStrategyStep> selectStepByStrategyCode(@Param("strategyCode") String strategyCode);
 
     /**
-     * 新增能源策略步骤
-     *
-     * @param strategyStep 能源策略步骤
+     * 查询步骤详情
+     * @param id 步骤ID
+     * @return 步骤详情
+     */
+    OpEnergyStrategyStep selectStepById(@Param("id") Long id);
+
+    /**
+     * 新增步骤
+     * @param step 步骤
      * @return 结果
      */
-    int insertStep(OpEnergyStrategyStep strategyStep);
+    int insertStep(OpEnergyStrategyStep step);
 
     /**
-     * 新增能源策略步骤
-     *
-     * @param list 能源策略步骤列表
+     * 修改步骤
+     * @param step 步骤
      * @return 结果
      */
-    int insertStepBatch(List<OpEnergyStrategyStep> list);
+    int updateStep(OpEnergyStrategyStep step);
 
     /**
-     * 修改能源策略步骤
-     *
-     * @param Step 能源策略步骤
+     * 删除步骤
+     * @param id 步骤ID
      * @return 结果
      */
-    int updateStep(OpEnergyStrategyStep Step);
+    int deleteStepById(@Param("id") Long id);
 
     /**
-     * 删除能源策略步骤
-     *
-     * @param strategyCode 能源策略步骤code
+     * 批量删除步骤
+     * @param ids 步骤ID数组
+     * @return 结果
+     */
+    int deleteStepByIds(@Param("ids") Long[] ids);
+
+    /**
+     * 根据策略代码删除步骤
+     * @param strategyCode 策略代码
      * @return 结果
      */
     int deleteStepByStrategyCode(@Param("strategyCode") String strategyCode);
+
+    /**
+     * 批量新增步骤
+     * @param steps 步骤列表
+     * @return 结果
+     */
+    int insertStepBatch(@Param("list") List<OpEnergyStrategyStep> steps);
 }

+ 61 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyTemplateMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.ems.mapper;
+
+import java.util.List;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyTemplate;
+
+/**
+ * 策略模板Mapper接口
+ *
+ * @author ruoyi
+ * @date 2025-12-01
+ */
+public interface OpEnergyStrategyTemplateMapper {
+    /**
+     * 查询策略模板
+     *
+     * @param id 策略模板主键
+     * @return 策略模板
+     */
+    OpEnergyStrategyTemplate selectTemplateById(Long id);
+
+    /**
+     * 查询策略模板列表
+     *
+     * @param template 策略模板
+     * @return 策略模板集合
+     */
+    List<OpEnergyStrategyTemplate> selectTemplateList(OpEnergyStrategyTemplate template);
+
+    /**
+     * 新增策略模板
+     *
+     * @param template 策略模板
+     * @return 结果
+     */
+    int insertTemplate(OpEnergyStrategyTemplate template);
+
+    /**
+     * 修改策略模板
+     *
+     * @param template 策略模板
+     * @return 结果
+     */
+    int updateTemplate(OpEnergyStrategyTemplate template);
+
+    /**
+     * 删除策略模板
+     *
+     * @param id 策略模板主键
+     * @return 结果
+     */
+    int deleteTemplateById(Long id);
+
+    /**
+     * 批量删除策略模板
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteTemplateByIds(Long[] ids);
+}

+ 84 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/OpEnergyStrategyTriggerMapper.java

@@ -0,0 +1,84 @@
+/*
+ * 文 件 名:  OpEnergyStrategyTriggerMapper
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.mapper;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyTrigger;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 能源策略触发器Mapper接口
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface OpEnergyStrategyTriggerMapper {
+    /**
+     * 查询策略触发器列表
+     * @param strategyCode 策略代码
+     * @return 触发器列表
+     */
+    List<OpEnergyStrategyTrigger> selectByStrategyCode(@Param("strategyCode") String strategyCode);
+
+    /**
+     * 根据源对象和事件查询触发器
+     * @param sourceObjCode 源对象代码
+     * @param eventKey 事件标识
+     * @return 触发器列表
+     */
+    List<OpEnergyStrategyTrigger> findBySourceAndEvent(
+        @Param("sourceObjCode") String sourceObjCode,
+        @Param("eventKey") String eventKey
+    );
+
+    /**
+     * 根据源对象和属性查询触发器
+     * @param sourceObjCode 源对象代码
+     * @param attrKey 属性标识
+     * @return 触发器列表
+     */
+    List<OpEnergyStrategyTrigger> findBySourceAndAttr(
+        @Param("sourceObjCode") String sourceObjCode,
+        @Param("attrKey") String attrKey
+    );
+
+    /**
+     * 新增触发器
+     * @param trigger 触发器
+     * @return 结果
+     */
+    int insertTrigger(OpEnergyStrategyTrigger trigger);
+
+    /**
+     * 修改触发器
+     * @param trigger 触发器
+     * @return 结果
+     */
+    int updateTrigger(OpEnergyStrategyTrigger trigger);
+
+    /**
+     * 删除触发器
+     * @param id 触发器ID
+     * @return 结果
+     */
+    int deleteTrigger(@Param("id") Long id);
+
+    /**
+     * 批量删除触发器
+     * @param ids 触发器ID数组
+     * @return 结果
+     */
+    int deleteTriggerByIds(@Param("ids") Long[] ids);
+}

+ 76 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyExecLogService.java

@@ -0,0 +1,76 @@
+/*
+ * 文 件 名:  IOpEnergyStrategyExecLogService
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyExecLog;
+import com.ruoyi.ems.domain.OpEnergyStrategyStepLog;
+
+import java.util.List;
+
+/**
+ * 策略执行日志Service接口
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface IOpEnergyStrategyExecLogService {
+    /**
+     * 查询执行日志列表
+     * @param execLog 执行日志
+     * @return 执行日志列表
+     */
+    List<OpEnergyStrategyExecLog> selectExecLogList(OpEnergyStrategyExecLog execLog);
+
+    /**
+     * 根据执行ID查询执行日志
+     * @param execId 执行ID
+     * @return 执行日志
+     */
+    OpEnergyStrategyExecLog selectByExecId(String execId);
+
+    /**
+     * 根据策略代码查询执行日志
+     * @param strategyCode 策略代码
+     * @return 执行日志列表
+     */
+    List<OpEnergyStrategyExecLog> selectByStrategyCode(String strategyCode);
+
+    /**
+     * 新增执行日志
+     * @param execLog 执行日志
+     * @return 结果
+     */
+    int insertExecLog(OpEnergyStrategyExecLog execLog);
+
+    /**
+     * 修改执行日志
+     * @param execLog 执行日志
+     * @return 结果
+     */
+    int updateExecLog(OpEnergyStrategyExecLog execLog);
+
+    /**
+     * 删除执行日志
+     * @param id 执行日志ID
+     * @return 结果
+     */
+    int deleteExecLog(Long id);
+
+    /**
+     * 根据执行ID查询步骤日志
+     * @param execId 执行ID
+     * @return 步骤日志列表
+     */
+    List<OpEnergyStrategyStepLog> selectStepLogsByExecId(String execId);
+}

+ 32 - 25
ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyService.java

@@ -12,50 +12,57 @@ import java.util.List;
  */
 public interface IOpEnergyStrategyService {
     /**
-     * 查询能源策略
-     *
-     * @param id 能源策略主键
-     * @return 能源策略
+     * 查询策略列表
+     * @param strategy 策略
+     * @return 策略列表
+     */
+    List<OpEnergyStrategy> selectStrategyList(OpEnergyStrategy strategy);
+
+    /**
+     * 查询策略详情(根据ID)
+     * @param id 策略ID
+     * @return 策略详情
      */
     OpEnergyStrategy selectStrategyById(Long id);
 
     /**
-     * 查询能源策略列表
-     *
-     * @param opEnergyStrategy 能源策略
-     * @return 能源策略集合
+     * 查询策略详情(根据代码)
+     * @param strategyCode 策略代码
+     * @return 策略详情
      */
-    List<OpEnergyStrategy> selectStrategyList(OpEnergyStrategy opEnergyStrategy);
+    OpEnergyStrategy selectStrategyByCode(String strategyCode);
 
     /**
-     * 新增能源策略
-     *
-     * @param opEnergyStrategy 能源策略
+     * 新增策略
+     * @param strategy 策略
      * @return 结果
      */
-    int insertStrategy(OpEnergyStrategy opEnergyStrategy);
+    int insertStrategy(OpEnergyStrategy strategy);
 
     /**
-     * 修改能源策略
-     *
-     * @param opEnergyStrategy 能源策略
+     * 修改策略
+     * @param strategy 策略
      * @return 结果
      */
-    int updateStrategy(OpEnergyStrategy opEnergyStrategy);
+    int updateStrategy(OpEnergyStrategy strategy);
 
     /**
-     * 批量删除能源策略
-     *
-     * @param ids 需要删除的能源策略主键集合
+     * 删除策略
+     * @param id 策略ID
      * @return 结果
      */
-    int deleteStrategyByIds(Long[] ids);
+    int deleteStrategyById(Long id);
 
     /**
-     * 删除能源策略信息
-     *
-     * @param id 能源策略主键
+     * 批量删除策略
+     * @param ids 策略ID数组
      * @return 结果
      */
-    int deleteStrategyById(Long id);
+    int deleteStrategyByIds(Long[] ids);
+
+    /**
+     * 查询定时调度策略
+     * @return 策略列表
+     */
+    List<OpEnergyStrategy> selectScheduledStrategies();
 }

+ 61 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyStepLogService.java

@@ -0,0 +1,61 @@
+/*
+ * 文 件 名:  IOpEnergyStrategyStepLogService
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyStepLog;
+
+import java.util.List;
+
+/**
+ * 策略步骤日志Service接口
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface IOpEnergyStrategyStepLogService {
+    /**
+     * 查询步骤日志列表
+     * @param stepLog 步骤日志
+     * @return 步骤日志列表
+     */
+    List<OpEnergyStrategyStepLog> selectStepLogList(OpEnergyStrategyStepLog stepLog);
+
+    /**
+     * 根据执行ID查询步骤日志
+     * @param execId 执行ID
+     * @return 步骤日志列表
+     */
+    List<OpEnergyStrategyStepLog> selectByExecId(String execId);
+
+    /**
+     * 新增步骤日志
+     * @param stepLog 步骤日志
+     * @return 结果
+     */
+    int insertStepLog(OpEnergyStrategyStepLog stepLog);
+
+    /**
+     * 修改步骤日志
+     * @param stepLog 步骤日志
+     * @return 结果
+     */
+    int updateStepLog(OpEnergyStrategyStepLog stepLog);
+
+    /**
+     * 批量新增步骤日志
+     * @param stepLogs 步骤日志列表
+     * @return 结果
+     */
+    int insertStepLogBatch(List<OpEnergyStrategyStepLog> stepLogs);
+}

+ 42 - 19
ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyStepService.java

@@ -12,42 +12,65 @@ import java.util.List;
  */
 public interface IOpEnergyStrategyStepService {
     /**
-     * 查询能源策略步骤列表
-     *
-     * @param strategyCode 能源策略步骤
-     * @return 能源策略步骤集合
+     * 查询策略步骤列表(按策略代码)
+     * @param strategyCode 策略代码
+     * @return 步骤列表
+     */
+    List<OpEnergyStrategyStep> selectStepsByStrategyCode(String strategyCode);
+
+    /**
+     * 查询策略步骤列表(按策略代码)- 别名方法
+     * @param strategyCode 策略代码
+     * @return 步骤列表
      */
     List<OpEnergyStrategyStep> selectStepByStrategyCode(String strategyCode);
 
     /**
-     * 新增能源策略步骤
-     *
-     * @param strategyStep 能源策略步骤
+     * 查询策略步骤详情
+     * @param id 步骤ID
+     * @return 步骤详情
+     */
+    OpEnergyStrategyStep selectStepById(Long id);
+
+    /**
+     * 新增策略步骤
+     * @param step 步骤
+     * @return 结果
+     */
+    int insertStep(OpEnergyStrategyStep step);
+
+    /**
+     * 修改策略步骤
+     * @param step 步骤
      * @return 结果
      */
-    int insertStep(OpEnergyStrategyStep strategyStep);
+    int updateStep(OpEnergyStrategyStep step);
 
     /**
-     * 新增能源策略步骤
-     *
-     * @param strategySteps 能源策略步骤列表
+     * 删除策略步骤
+     * @param id 步骤ID
      * @return 结果
      */
-    int insertStepBatch(List<OpEnergyStrategyStep> strategySteps);
+    int deleteStep(Long id);
 
     /**
-     * 修改能源策略步骤
-     *
-     * @param strategyStep 能源策略步骤
+     * 批量删除策略步骤
+     * @param ids 步骤ID数组
      * @return 结果
      */
-    int updateStep(OpEnergyStrategyStep strategyStep);
+    int deleteStepByIds(Long[] ids);
 
     /**
-     * 删除能源策略步骤信息
-     *
-     * @param strategyCode 能源策略步骤code
+     * 根据策略代码删除步骤
+     * @param strategyCode 策略代码
      * @return 结果
      */
     int deleteStepByStrategyCode(String strategyCode);
+
+    /**
+     * 批量新增步骤
+     * @param steps 步骤列表
+     * @return 结果
+     */
+    int insertStepBatch(List<OpEnergyStrategyStep> steps);
 }

+ 61 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyTemplateService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.ems.service;
+
+import java.util.List;
+import com.ruoyi.ems.domain.OpEnergyStrategyTemplate;
+
+/**
+ * 策略模板Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-12-01
+ */
+public interface IOpEnergyStrategyTemplateService 
+{
+    /**
+     * 查询策略模板
+     * 
+     * @param id 策略模板主键
+     * @return 策略模板
+     */
+     OpEnergyStrategyTemplate selectTemplateById(Long id);
+
+    /**
+     * 查询策略模板列表
+     * 
+     * @param template 策略模板
+     * @return 策略模板集合
+     */
+     List<OpEnergyStrategyTemplate> selectTemplateList(OpEnergyStrategyTemplate template);
+
+    /**
+     * 新增策略模板
+     * 
+     * @param template 策略模板
+     * @return 结果
+     */
+     int insertTemplate(OpEnergyStrategyTemplate template);
+
+    /**
+     * 修改策略模板
+     * 
+     * @param template 策略模板
+     * @return 结果
+     */
+     int updateTemplate(OpEnergyStrategyTemplate template);
+
+    /**
+     * 批量删除策略模板
+     * 
+     * @param ids 需要删除的策略模板主键集合
+     * @return 结果
+     */
+     int deleteTemplateByIds(Long[] ids);
+
+    /**
+     * 删除策略模板信息
+     * 
+     * @param id 策略模板主键
+     * @return 结果
+     */
+     int deleteTemplateById(Long id);
+}

+ 77 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/IOpEnergyStrategyTriggerService.java

@@ -0,0 +1,77 @@
+/*
+ * 文 件 名:  IOpEnergyStrategyTriggerService
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyTrigger;
+
+import java.util.List;
+
+/**
+ * 能源策略触发器Service接口
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface IOpEnergyStrategyTriggerService {
+    /**
+     * 查询策略触发器列表
+     * @param strategyCode 策略代码
+     * @return 触发器列表
+     */
+    List<OpEnergyStrategyTrigger> selectByStrategyCode(String strategyCode);
+
+    /**
+     * 根据源对象和事件查询触发器
+     * @param sourceObjCode 源对象代码
+     * @param eventKey 事件标识
+     * @return 触发器列表
+     */
+    List<OpEnergyStrategyTrigger> findBySourceAndEvent(String sourceObjCode, String eventKey);
+
+    /**
+     * 根据源对象和属性查询触发器
+     * @param sourceObjCode 源对象代码
+     * @param attrKey 属性标识
+     * @return 触发器列表
+     */
+    List<OpEnergyStrategyTrigger> findBySourceAndAttr(String sourceObjCode, String attrKey);
+
+    /**
+     * 新增触发器
+     * @param trigger 触发器
+     * @return 结果
+     */
+    int insertTrigger(OpEnergyStrategyTrigger trigger);
+
+    /**
+     * 修改触发器
+     * @param trigger 触发器
+     * @return 结果
+     */
+    int updateTrigger(OpEnergyStrategyTrigger trigger);
+
+    /**
+     * 删除触发器
+     * @param id 触发器ID
+     * @return 结果
+     */
+    int deleteTrigger(Long id);
+
+    /**
+     * 批量删除触发器
+     * @param ids 触发器ID数组
+     * @return 结果
+     */
+    int deleteTriggerByIds(Long[] ids);
+}

+ 38 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/IStepExecutor.java

@@ -0,0 +1,38 @@
+/*
+ * 文 件 名:  IStepExecutor
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyStep;
+import com.ruoyi.ems.domain.StrategyExecutionContext;
+
+/**
+ * 步骤执行器接口
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface IStepExecutor {
+    /**
+     * 执行步骤
+     * @param step 步骤配置
+     * @param context 执行上下文
+     * @return 执行结果
+     */
+    Object execute(OpEnergyStrategyStep step, StrategyExecutionContext context) throws Exception;
+
+    /**
+     * 支持的步骤类型
+     */
+    String getSupportedType();
+}

+ 0 - 11
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/AbilityCallServiceImpl.java

@@ -14,17 +14,12 @@ import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
 import com.huashe.common.exception.Assert;
 import com.huashe.common.exception.BusinessException;
-import com.ruoyi.ems.domain.EmsDevice;
 import com.ruoyi.ems.domain.EmsObjAbility;
 import com.ruoyi.ems.domain.EmsObjModel;
-import com.ruoyi.ems.domain.EmsSubsystem;
-import com.ruoyi.ems.enums.DevObjType;
 import com.ruoyi.ems.model.AbilityPayload;
 import com.ruoyi.ems.model.CallResponse;
 import com.ruoyi.ems.service.IAbilityCallService;
-import com.ruoyi.ems.service.IEmsDeviceService;
 import com.ruoyi.ems.service.IEmsObjModelService;
-import com.ruoyi.ems.service.IEmsSubsystemService;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
@@ -54,12 +49,6 @@ public class AbilityCallServiceImpl implements IAbilityCallService {
     private static final Logger log = LoggerFactory.getLogger(AbilityCallServiceImpl.class);
 
     @Autowired
-    private IEmsDeviceService deviceService;
-
-    @Autowired
-    private IEmsSubsystemService subsystemService;
-
-    @Autowired
     private IEmsObjModelService objModelService;
 
     @Override

+ 74 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyExecLogServiceImpl.java

@@ -0,0 +1,74 @@
+/*
+ * 文 件 名:  OpEnergyStrategyExecLogServiceImpl
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service.impl;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyExecLog;
+import com.ruoyi.ems.domain.OpEnergyStrategyStepLog;
+import com.ruoyi.ems.mapper.OpEnergyStrategyExecLogMapper;
+import com.ruoyi.ems.mapper.OpEnergyStrategyStepLogMapper;
+import com.ruoyi.ems.service.IOpEnergyStrategyExecLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 策略执行日志Service实现
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Service
+public class OpEnergyStrategyExecLogServiceImpl implements IOpEnergyStrategyExecLogService {
+    @Autowired
+    private OpEnergyStrategyExecLogMapper execLogMapper;
+
+    @Autowired
+    private OpEnergyStrategyStepLogMapper stepLogMapper;
+
+    @Override
+    public List<OpEnergyStrategyExecLog> selectExecLogList(OpEnergyStrategyExecLog execLog) {
+        return execLogMapper.selectExecLogList(execLog);
+    }
+
+    @Override
+    public OpEnergyStrategyExecLog selectByExecId(String execId) {
+        return execLogMapper.selectByExecId(execId);
+    }
+
+    @Override
+    public List<OpEnergyStrategyExecLog> selectByStrategyCode(String strategyCode) {
+        return execLogMapper.selectByStrategyCode(strategyCode);
+    }
+
+    @Override
+    public int insertExecLog(OpEnergyStrategyExecLog execLog) {
+        return execLogMapper.insertExecLog(execLog);
+    }
+
+    @Override
+    public int updateExecLog(OpEnergyStrategyExecLog execLog) {
+        return execLogMapper.updateExecLog(execLog);
+    }
+
+    @Override
+    public int deleteExecLog(Long id) {
+        return execLogMapper.deleteExecLog(id);
+    }
+
+    @Override
+    public List<OpEnergyStrategyStepLog> selectStepLogsByExecId(String execId) {
+        return stepLogMapper.selectByExecId(execId);
+    }
+}

+ 18 - 44
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyServiceImpl.java

@@ -19,69 +19,43 @@ public class OpEnergyStrategyServiceImpl implements IOpEnergyStrategyService {
     @Autowired
     private OpEnergyStrategyMapper strategyMapper;
 
-    /**
-     * 查询能源策略
-     *
-     * @param id 能源策略主键
-     * @return 能源策略
-     */
+    @Override
+    public List<OpEnergyStrategy> selectStrategyList(OpEnergyStrategy strategy) {
+        return strategyMapper.selectStrategyList(strategy);
+    }
+
     @Override
     public OpEnergyStrategy selectStrategyById(Long id) {
         return strategyMapper.selectStrategyById(id);
     }
 
-    /**
-     * 查询能源策略列表
-     *
-     * @param admOpEnergyStrategy 能源策略
-     * @return 能源策略
-     */
     @Override
-    public List<OpEnergyStrategy> selectStrategyList(OpEnergyStrategy admOpEnergyStrategy) {
-        return strategyMapper.selectStrategyList(admOpEnergyStrategy);
+    public OpEnergyStrategy selectStrategyByCode(String strategyCode) {
+        return strategyMapper.selectStrategyByCode(strategyCode);
+    }
+
+    @Override
+    public int insertStrategy(OpEnergyStrategy strategy) {
+        return strategyMapper.insertStrategy(strategy);
     }
 
-    /**
-     * 新增能源策略
-     *
-     * @param admOpEnergyStrategy 能源策略
-     * @return 结果
-     */
     @Override
-    public int insertStrategy(OpEnergyStrategy admOpEnergyStrategy) {
-        return strategyMapper.insertStrategy(admOpEnergyStrategy);
+    public int updateStrategy(OpEnergyStrategy strategy) {
+        return strategyMapper.updateStrategy(strategy);
     }
 
-    /**
-     * 修改能源策略
-     *
-     * @param admOpEnergyStrategy 能源策略
-     * @return 结果
-     */
     @Override
-    public int updateStrategy(OpEnergyStrategy admOpEnergyStrategy) {
-        return strategyMapper.updateStrategy(admOpEnergyStrategy);
+    public int deleteStrategyById(Long id) {
+        return strategyMapper.deleteStrategyById(id);
     }
 
-    /**
-     * 批量删除能源策略
-     *
-     * @param ids 需要删除的能源策略主键
-     * @return 结果
-     */
     @Override
     public int deleteStrategyByIds(Long[] ids) {
         return strategyMapper.deleteStrategyByIds(ids);
     }
 
-    /**
-     * 删除能源策略信息
-     *
-     * @param id 能源策略主键
-     * @return 结果
-     */
     @Override
-    public int deleteStrategyById(Long id) {
-        return strategyMapper.deleteStrategyById(id);
+    public List<OpEnergyStrategy> selectScheduledStrategies() {
+        return strategyMapper.selectScheduledStrategies();
     }
 }

+ 59 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyStepLogServiceImpl.java

@@ -0,0 +1,59 @@
+/*
+ * 文 件 名:  OpEnergyStrategyStepLogServiceImpl
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service.impl;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyStepLog;
+import com.ruoyi.ems.mapper.OpEnergyStrategyStepLogMapper;
+import com.ruoyi.ems.service.IOpEnergyStrategyStepLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 策略步骤日志Service实现
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Service
+public class OpEnergyStrategyStepLogServiceImpl implements IOpEnergyStrategyStepLogService {
+    @Autowired
+    private OpEnergyStrategyStepLogMapper stepLogMapper;
+
+    @Override
+    public List<OpEnergyStrategyStepLog> selectStepLogList(OpEnergyStrategyStepLog stepLog) {
+        return stepLogMapper.selectStepLogList(stepLog);
+    }
+
+    @Override
+    public List<OpEnergyStrategyStepLog> selectByExecId(String execId) {
+        return stepLogMapper.selectByExecId(execId);
+    }
+
+    @Override
+    public int insertStepLog(OpEnergyStrategyStepLog stepLog) {
+        return stepLogMapper.insertStepLog(stepLog);
+    }
+
+    @Override
+    public int updateStepLog(OpEnergyStrategyStepLog stepLog) {
+        return stepLogMapper.updateStepLog(stepLog);
+    }
+
+    @Override
+    public int insertStepLogBatch(List<OpEnergyStrategyStepLog> stepLogs) {
+        return stepLogMapper.insertStepLogBatch(stepLogs);
+    }
+}

+ 26 - 6
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyStepServiceImpl.java

@@ -20,27 +20,47 @@ public class OpEnergyStrategyStepServiceImpl implements IOpEnergyStrategyStepSer
     private OpEnergyStrategyStepMapper stepMapper;
 
     @Override
+    public List<OpEnergyStrategyStep> selectStepsByStrategyCode(String strategyCode) {
+        return stepMapper.selectStepByStrategyCode(strategyCode);
+    }
+
+    @Override
     public List<OpEnergyStrategyStep> selectStepByStrategyCode(String strategyCode) {
         return stepMapper.selectStepByStrategyCode(strategyCode);
     }
 
     @Override
-    public int insertStep(OpEnergyStrategyStep strategyStep) {
-        return stepMapper.insertStep(strategyStep);
+    public OpEnergyStrategyStep selectStepById(Long id) {
+        return stepMapper.selectStepById(id);
+    }
+
+    @Override
+    public int insertStep(OpEnergyStrategyStep step) {
+        return stepMapper.insertStep(step);
     }
 
     @Override
-    public int insertStepBatch(List<OpEnergyStrategyStep> strategySteps) {
-        return stepMapper.insertStepBatch(strategySteps);
+    public int updateStep(OpEnergyStrategyStep step) {
+        return stepMapper.updateStep(step);
     }
 
     @Override
-    public int updateStep(OpEnergyStrategyStep strategyStep) {
-        return stepMapper.updateStep(strategyStep);
+    public int deleteStep(Long id) {
+        return stepMapper.deleteStepById(id);
+    }
+
+    @Override
+    public int deleteStepByIds(Long[] ids) {
+        return stepMapper.deleteStepByIds(ids);
     }
 
     @Override
     public int deleteStepByStrategyCode(String strategyCode) {
         return stepMapper.deleteStepByStrategyCode(strategyCode);
     }
+
+    @Override
+    public int insertStepBatch(List<OpEnergyStrategyStep> steps) {
+        return stepMapper.insertStepBatch(steps);
+    }
 }

+ 97 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyTemplateServiceImpl.java

@@ -0,0 +1,97 @@
+package com.ruoyi.ems.service.impl;
+
+import com.huashe.common.utils.DateUtils;
+import com.ruoyi.ems.domain.OpEnergyStrategyTemplate;
+import com.ruoyi.ems.mapper.OpEnergyStrategyTemplateMapper;
+import com.ruoyi.ems.service.IOpEnergyStrategyTemplateService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 策略模板Service业务层处理
+ * 
+ * @author ruoyi
+ * @date 2025-12-01
+ */
+@Service
+public class OpEnergyStrategyTemplateServiceImpl implements IOpEnergyStrategyTemplateService 
+{
+    @Autowired
+    private OpEnergyStrategyTemplateMapper opTemplateMapper;
+
+    /**
+     * 查询策略模板
+     * 
+     * @param id 策略模板主键
+     * @return 策略模板
+     */
+    @Override
+    public OpEnergyStrategyTemplate selectTemplateById(Long id)
+    {
+        return opTemplateMapper.selectTemplateById(id);
+    }
+
+    /**
+     * 查询策略模板列表
+     * 
+     * @param template 策略模板
+     * @return 策略模板
+     */
+    @Override
+    public List<OpEnergyStrategyTemplate> selectTemplateList(OpEnergyStrategyTemplate template)
+    {
+        return opTemplateMapper.selectTemplateList(template);
+    }
+
+    /**
+     * 新增策略模板
+     * 
+     * @param template 策略模板
+     * @return 结果
+     */
+    @Override
+    public int insertTemplate(OpEnergyStrategyTemplate template)
+    {
+        template.setCreateTime(DateUtils.getNowDate());
+        return opTemplateMapper.insertTemplate(template);
+    }
+
+    /**
+     * 修改策略模板
+     * 
+     * @param template 策略模板
+     * @return 结果
+     */
+    @Override
+    public int updateTemplate(OpEnergyStrategyTemplate template)
+    {
+        template.setUpdateTime(DateUtils.getNowDate());
+        return opTemplateMapper.updateTemplate(template);
+    }
+
+    /**
+     * 批量删除策略模板
+     * 
+     * @param ids 需要删除的策略模板主键
+     * @return 结果
+     */
+    @Override
+    public int deleteTemplateByIds(Long[] ids)
+    {
+        return opTemplateMapper.deleteTemplateByIds(ids);
+    }
+
+    /**
+     * 删除策略模板信息
+     * 
+     * @param id 策略模板主键
+     * @return 结果
+     */
+    @Override
+    public int deleteTemplateById(Long id)
+    {
+        return opTemplateMapper.deleteTemplateById(id);
+    }
+}

+ 69 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/OpEnergyStrategyTriggerServiceImpl.java

@@ -0,0 +1,69 @@
+/*
+ * 文 件 名:  OpEnergyStrategyTriggerServiceImpl
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service.impl;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyTrigger;
+import com.ruoyi.ems.mapper.OpEnergyStrategyTriggerMapper;
+import com.ruoyi.ems.service.IOpEnergyStrategyTriggerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 能源策略触发器Service实现
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Service
+public class OpEnergyStrategyTriggerServiceImpl implements IOpEnergyStrategyTriggerService {
+    @Autowired
+    private OpEnergyStrategyTriggerMapper triggerMapper;
+
+    @Override
+    public List<OpEnergyStrategyTrigger> selectByStrategyCode(String strategyCode) {
+        return triggerMapper.selectByStrategyCode(strategyCode);
+    }
+
+    @Override
+    public List<OpEnergyStrategyTrigger> findBySourceAndEvent(String sourceObjCode, String eventKey) {
+        return triggerMapper.findBySourceAndEvent(sourceObjCode, eventKey);
+    }
+
+    @Override
+    public List<OpEnergyStrategyTrigger> findBySourceAndAttr(String sourceObjCode, String attrKey) {
+        return triggerMapper.findBySourceAndAttr(sourceObjCode, attrKey);
+    }
+
+    @Override
+    public int insertTrigger(OpEnergyStrategyTrigger trigger) {
+        return triggerMapper.insertTrigger(trigger);
+    }
+
+    @Override
+    public int updateTrigger(OpEnergyStrategyTrigger trigger) {
+        return triggerMapper.updateTrigger(trigger);
+    }
+
+    @Override
+    public int deleteTrigger(Long id) {
+        return triggerMapper.deleteTrigger(id);
+    }
+
+    @Override
+    public int deleteTriggerByIds(Long[] ids) {
+        return triggerMapper.deleteTriggerByIds(ids);
+    }
+}

+ 122 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/strategy/evaluator/ConditionEvaluator.java

@@ -0,0 +1,122 @@
+/*
+ * 文 件 名:  ConditionEvaluator
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.strategy.evaluator;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 条件表达式求值器
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@Component
+public class ConditionEvaluator {
+    /**
+     * 评估条件表达式
+     * @param conditionExpr 条件表达式JSON
+     * @param context 上下文变量
+     * @return 是否满足条件
+     */
+    public boolean evaluate(String conditionExpr, Map<String, Object> context) {
+        if (conditionExpr == null || conditionExpr.trim().isEmpty()) {
+            return true;
+        }
+
+        try {
+            JSONObject condition = JSON.parseObject(conditionExpr);
+            return evaluateCondition(condition, context);
+        } catch (Exception e) {
+            log.error("条件表达式解析失败: {}", conditionExpr, e);
+            return false;
+        }
+    }
+
+    private boolean evaluateCondition(JSONObject condition, Map<String, Object> context) {
+        String operator = condition.getString("operator");
+
+        if ("AND".equals(operator)) {
+            return condition.getJSONArray("conditions").stream()
+                .allMatch(c -> evaluateCondition((JSONObject) c, context));
+        } else if ("OR".equals(operator)) {
+            return condition.getJSONArray("conditions").stream()
+                .anyMatch(c -> evaluateCondition((JSONObject) c, context));
+        } else {
+            return evaluateSimpleCondition(condition, context);
+        }
+    }
+
+    private boolean evaluateSimpleCondition(JSONObject condition, Map<String, Object> context) {
+        String field = condition.getString("field");
+        String operator = condition.getString("operator");
+        Object expectedValue = condition.get("value");
+
+        Object actualValue = getValueFromContext(field, context);
+
+        return compare(actualValue, operator, expectedValue);
+    }
+
+    private Object getValueFromContext(String field, Map<String, Object> context) {
+        if (field.contains(".")) {
+            String[] parts = field.split("\\.");
+            Object current = context;
+            for (String part : parts) {
+                if (current instanceof Map) {
+                    current = ((Map<?, ?>) current).get(part);
+                } else {
+                    return null;
+                }
+            }
+            return current;
+        }
+        return context.get(field);
+    }
+
+    private boolean compare(Object actual, String operator, Object expected) {
+        if (actual == null) return false;
+
+        switch (operator) {
+            case "==":
+                return actual.equals(expected);
+            case "!=":
+                return !actual.equals(expected);
+            case ">":
+                return compareNumeric(actual, expected) > 0;
+            case ">=":
+                return compareNumeric(actual, expected) >= 0;
+            case "<":
+                return compareNumeric(actual, expected) < 0;
+            case "<=":
+                return compareNumeric(actual, expected) <= 0;
+            case "contains":
+                return actual.toString().contains(expected.toString());
+            case "in":
+                return expected.toString().contains(actual.toString());
+            default:
+                return false;
+        }
+    }
+
+    private int compareNumeric(Object a, Object b) {
+        double va = Double.parseDouble(a.toString());
+        double vb = Double.parseDouble(b.toString());
+        return Double.compare(va, vb);
+    }
+}

+ 249 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/AbilityCallStepExecutor.java

@@ -0,0 +1,249 @@
+/*
+ * 文 件 名:  AbilityCallStepExecutor
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.strategy.executor;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.ems.domain.OpEnergyStrategyStep;
+import com.ruoyi.ems.domain.StrategyExecutionContext;
+import com.ruoyi.ems.model.AbilityPayload;
+import com.ruoyi.ems.service.IAbilityCallService;
+import com.ruoyi.ems.service.IEmsObjAttrValueService;
+import com.ruoyi.ems.service.IStepExecutor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ *  能力调用执行器
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@Component
+public class AbilityCallStepExecutor implements IStepExecutor {
+    @Autowired
+    private IAbilityCallService abilityCallService;
+
+    @Autowired(required = false)
+    private IEmsObjAttrValueService attrValueService;
+
+    @Override
+    public Object execute(OpEnergyStrategyStep step, StrategyExecutionContext context) throws Exception {
+        // 构建能力调用载荷
+        AbilityPayload payload = new AbilityPayload();
+        payload.setObjCode(step.getTargetObjCode());
+        payload.setObjType(step.getTargetObjType());
+        payload.setModelCode(step.getTargetModelCode());
+        payload.setAbilityKey(step.getAbilityKey());
+
+        // 解析能力参数(支持多种参数来源)
+        String abilityParam = parseParam(step, context);
+        payload.setAbilityParam(abilityParam);
+
+        log.info("策略步骤[{}]执行能力调用: {}", step.getStepCode(), payload);
+
+        // 调用设备能力服务
+        String result = abilityCallService.devAbilityCall(payload);
+
+        log.info("策略步骤[{}]能力调用完成, 结果: {}", step.getStepCode(), result);
+
+        return result;
+    }
+
+    /**
+     * 解析能力参数(支持静态、上下文、属性值三种来源)
+     */
+    private String parseParam(OpEnergyStrategyStep step, StrategyExecutionContext context) {
+        String paramSource = step.getParamSource();
+
+        if (paramSource == null) {
+            paramSource = "STATIC";
+        }
+
+        switch (paramSource) {
+            case "STATIC":
+                // 静态参数:直接使用配置的参数值
+                return step.getAbilityParam();
+
+            case "CONTEXT":
+                // 上下文参数:从执行上下文中获取动态值
+                return parseContextParam(step, context);
+
+            case "ATTR":
+                // 属性参数:从设备属性中获取实时值
+                return parseAttrParam(step, context);
+
+            default:
+                log.warn("未知的参数来源类型: {}, 使用静态参数", paramSource);
+                return step.getAbilityParam();
+        }
+    }
+
+    /**
+     * 从上下文解析参数
+     * paramMapping格式: {"brightness": "context.lightLevel", "mode": "context.workMode"}
+     */
+    private String parseContextParam(OpEnergyStrategyStep step, StrategyExecutionContext context) {
+        String paramMapping = step.getParamMapping();
+
+        if (paramMapping == null || paramMapping.trim().isEmpty()) {
+            log.warn("上下文参数映射配置为空,使用静态参数");
+            return step.getAbilityParam();
+        }
+
+        try {
+            JSONObject mapping = JSON.parseObject(paramMapping);
+            JSONObject resultParams = new JSONObject();
+
+            // 遍历映射配置,从上下文中获取值
+            mapping.forEach((paramKey, contextPath) -> {
+                String path = contextPath.toString();
+                Object value = getValueFromContext(path, context);
+                if (value != null) {
+                    resultParams.put(paramKey, value);
+                } else {
+                    log.warn("上下文路径 {} 未找到值", path);
+                }
+            });
+
+            // 如果没有映射到任何值,返回静态参数
+            if (resultParams.isEmpty()) {
+                return step.getAbilityParam();
+            }
+
+            return resultParams.toJSONString();
+        } catch (Exception e) {
+            log.error("解析上下文参数失败: {}", e.getMessage(), e);
+            return step.getAbilityParam();
+        }
+    }
+
+    /**
+     * 从设备属性解析参数
+     * paramMapping格式: {"targetTemp": "deviceCode.temperature", "mode": "deviceCode.workMode"}
+     */
+    private String parseAttrParam(OpEnergyStrategyStep step, StrategyExecutionContext context) {
+        if (attrValueService == null) {
+            log.warn("属性值服务未注入,无法获取设备属性,使用静态参数");
+            return step.getAbilityParam();
+        }
+
+        String paramMapping = step.getParamMapping();
+
+        if (paramMapping == null || paramMapping.trim().isEmpty()) {
+            log.warn("属性参数映射配置为空,使用静态参数");
+            return step.getAbilityParam();
+        }
+
+        try {
+            JSONObject mapping = JSON.parseObject(paramMapping);
+            JSONObject resultParams = new JSONObject();
+
+            // 遍历映射配置,从设备属性中获取值
+            mapping.forEach((paramKey, attrPath) -> {
+                String path = attrPath.toString();
+                String[] parts = path.split("\\.");
+
+                if (parts.length == 2) {
+                    String deviceCode = parts[0];
+                    String attrKey = parts[1];
+
+                    // 调用属性查询服务获取设备属性值
+                    Object attrValue = queryDeviceAttr(step.getTargetModelCode(), deviceCode, attrKey);
+                    if (attrValue != null) {
+                        resultParams.put(paramKey, attrValue);
+                    } else {
+                        log.warn("设备 {} 的属性 {} 未找到值", deviceCode, attrKey);
+                    }
+                } else {
+                    log.warn("属性路径格式错误: {}, 应为 deviceCode.attrKey", path);
+                }
+            });
+
+            // 如果没有映射到任何值,返回静态参数
+            if (resultParams.isEmpty()) {
+                return step.getAbilityParam();
+            }
+
+            return resultParams.toJSONString();
+        } catch (Exception e) {
+            log.error("解析属性参数失败: {}", e.getMessage(), e);
+            return step.getAbilityParam();
+        }
+    }
+
+    /**
+     * 从上下文中获取值(支持嵌套路径)
+     * 例如: "context.lightLevel" 或 "stepResult.STEP_001.value"
+     */
+    private Object getValueFromContext(String path, StrategyExecutionContext context) {
+        if (path == null || path.trim().isEmpty()) {
+            return null;
+        }
+
+        // 移除 "context." 前缀
+        if (path.startsWith("context.")) {
+            path = path.substring(8);
+        }
+
+        // 支持嵌套路径
+        String[] parts = path.split("\\.");
+        Object current = null;
+
+        if ("stepResult".equals(parts[0])) {
+            // 从步骤结果中获取
+            if (parts.length >= 2) {
+                current = context.getStepResult(parts[1]);
+                // 继续处理后续路径
+                for (int i = 2; i < parts.length && current != null; i++) {
+                    if (current instanceof JSONObject) {
+                        current = ((JSONObject) current).get(parts[i]);
+                    }
+                }
+            }
+        } else {
+            // 从变量中获取
+            current = context.getVariable(parts[0]);
+            // 继续处理后续路径
+            for (int i = 1; i < parts.length && current != null; i++) {
+                if (current instanceof JSONObject) {
+                    current = ((JSONObject) current).get(parts[i]);
+                }
+            }
+        }
+
+        return current;
+    }
+
+    /**
+     * 查询设备属性值
+     */
+    private Object queryDeviceAttr(String modelCode, String deviceCode, String attrKey) {
+        try {
+            if (attrValueService != null) {
+                return attrValueService.selectObjAttrValue(modelCode, deviceCode, attrKey);
+            }
+        } catch (Exception e) {
+            log.error("查询设备属性失败: deviceCode={}, attrKey={}", deviceCode, attrKey, e);
+        }
+        return null;
+    }
+
+    @Override
+    public String getSupportedType() {
+        return "ABILITY";
+    }
+}

+ 51 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/ConditionStepExecutor.java

@@ -0,0 +1,51 @@
+/*
+ * 文 件 名:  ConditionStepExecutor
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.strategy.executor;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyStep;
+import com.ruoyi.ems.domain.StrategyExecutionContext;
+import com.ruoyi.ems.service.IStepExecutor;
+import com.ruoyi.ems.strategy.evaluator.ConditionEvaluator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 条件判断执行器
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@Component
+public class ConditionStepExecutor implements IStepExecutor {
+    @Autowired
+    private ConditionEvaluator conditionEvaluator;
+
+    @Override
+    public Object execute(OpEnergyStrategyStep step, StrategyExecutionContext context) throws Exception {
+        boolean result = conditionEvaluator.evaluate(step.getConditionExpr(), context.getVariables());
+        log.info("条件判断结果: {}", result);
+
+        // 将结果保存到上下文
+        context.setVariable(step.getStepCode() + "_result", result);
+
+        return result;
+    }
+
+    @Override
+    public String getSupportedType() {
+        return "CONDITION";
+    }
+}

+ 45 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/DelayStepExecutor.java

@@ -0,0 +1,45 @@
+/*
+ * 文 件 名:  DelayStepExecutor
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.strategy.executor;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyStep;
+import com.ruoyi.ems.domain.StrategyExecutionContext;
+import com.ruoyi.ems.service.IStepExecutor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 延时执行器
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@Component
+public class DelayStepExecutor implements IStepExecutor {
+    @Override
+    public Object execute(OpEnergyStrategyStep step, StrategyExecutionContext context) throws Exception {
+        int delaySeconds = step.getDelaySeconds();
+        log.info("延时等待: {} 秒", delaySeconds);
+
+        Thread.sleep(delaySeconds * 1000L);
+
+        return "延时完成: " + delaySeconds + "秒";
+    }
+
+    @Override
+    public String getSupportedType() {
+        return "DELAY";
+    }
+}

+ 48 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/StepExecutorFactory.java

@@ -0,0 +1,48 @@
+/*
+ * 文 件 名:  StepExecutorFactory
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.strategy.executor;
+
+import com.ruoyi.ems.service.IStepExecutor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 步骤执行器工厂
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Component
+public class StepExecutorFactory {
+    private final Map<String, IStepExecutor> executorMap = new ConcurrentHashMap<>();
+
+    @Autowired
+    public void setExecutors(List<IStepExecutor> executors) {
+        executors.forEach(executor ->
+            executorMap.put(executor.getSupportedType(), executor)
+        );
+    }
+
+    public IStepExecutor getExecutor(String stepType) {
+        IStepExecutor executor = executorMap.get(stepType);
+        if (executor == null) {
+            throw new IllegalArgumentException("不支持的步骤类型: " + stepType);
+        }
+        return executor;
+    }
+}

+ 259 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/strategy/executor/StrategyExecutor.java

@@ -0,0 +1,259 @@
+/*
+ * 文 件 名:  StrategyExecutor
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.strategy.executor;
+
+import com.alibaba.fastjson2.JSON;
+import com.ruoyi.ems.domain.OpEnergyStrategy;
+import com.ruoyi.ems.domain.OpEnergyStrategyExecLog;
+import com.ruoyi.ems.domain.OpEnergyStrategyStep;
+import com.ruoyi.ems.domain.OpEnergyStrategyStepLog;
+import com.ruoyi.ems.domain.StepExecutionResult;
+import com.ruoyi.ems.domain.StrategyExecutionContext;
+import com.ruoyi.ems.service.IOpEnergyStrategyExecLogService;
+import com.ruoyi.ems.service.IOpEnergyStrategyService;
+import com.ruoyi.ems.service.IOpEnergyStrategyStepLogService;
+import com.ruoyi.ems.service.IOpEnergyStrategyStepService;
+import com.ruoyi.ems.service.IStepExecutor;
+import com.ruoyi.ems.strategy.evaluator.ConditionEvaluator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
+/**
+ * 策略执行器
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@Component
+public class StrategyExecutor {
+    @Autowired
+    private IOpEnergyStrategyService strategyService;
+
+    @Autowired
+    private IOpEnergyStrategyStepService stepService;
+
+    @Autowired
+    private IOpEnergyStrategyExecLogService execLogService;
+
+    @Autowired
+    private IOpEnergyStrategyStepLogService stepLogService;
+
+    @Autowired
+    private ConditionEvaluator conditionEvaluator;
+
+    @Autowired
+    private StepExecutorFactory stepExecutorFactory;
+
+    private final ExecutorService executorService = Executors.newFixedThreadPool(10);
+
+    /**
+     * 执行策略
+     */
+    public String executeStrategy(String strategyCode, Map<String, Object> triggerData) {
+        String execId = UUID.randomUUID().toString();
+
+        // 查询策略
+        OpEnergyStrategy strategy = strategyService.selectStrategyByCode(strategyCode);
+        if (strategy == null) {
+            log.error("策略不存在: {}", strategyCode);
+            return null;
+        }
+
+        if (strategy.getStrategyState() != 1) {
+            log.warn("策略未启用: {}", strategyCode);
+            return null;
+        }
+
+        // 创建执行上下文
+        StrategyExecutionContext context = new StrategyExecutionContext();
+        context.setExecId(execId);
+        context.setStrategyCode(strategyCode);
+        context.setStartTime(System.currentTimeMillis());
+        if (triggerData != null) {
+            context.getVariables().putAll(triggerData);
+        }
+
+        // 记录执行日志
+        OpEnergyStrategyExecLog execLog = new OpEnergyStrategyExecLog();
+        execLog.setExecId(execId);
+        execLog.setStrategyCode(strategyCode);
+        execLog.setTriggerType(context.getTriggerType());
+        execLog.setTriggerSource(context.getTriggerSource());
+        execLog.setExecStatus(0); // 执行中
+        execLog.setStartTime(new Date());
+        execLog.setContextData(JSON.toJSONString(context.getVariables()));
+        execLogService.insertExecLog(execLog);
+
+        // 异步执行策略
+        executorService.submit(() -> {
+            try {
+                executeStrategySteps(strategy, context, execLog);
+            } catch (Exception e) {
+                log.error("策略执行异常: {}", strategyCode, e);
+                updateExecLogFailed(execLog, e.getMessage());
+            }
+        });
+
+        return execId;
+    }
+
+    private void executeStrategySteps(OpEnergyStrategy strategy,
+        StrategyExecutionContext context,
+        OpEnergyStrategyExecLog execLog) {
+        List<OpEnergyStrategyStep> steps = stepService.selectStepsByStrategyCode(strategy.getStrategyCode());
+
+        // 按步骤顺序排序
+        steps = steps.stream()
+            .sorted(Comparator.comparingInt(OpEnergyStrategyStep::getStepIndex))
+            .collect(Collectors.toList());
+
+        boolean allSuccess = true;
+
+        for (OpEnergyStrategyStep step : steps) {
+            if (step.getEnable() != 1) {
+                continue;
+            }
+
+            // 评估执行条件
+            if (step.getConditionExpr() != null && !step.getConditionExpr().isEmpty()) {
+                boolean conditionMet = conditionEvaluator.evaluate(
+                    step.getConditionExpr(),
+                    context.getVariables()
+                );
+                if (!conditionMet) {
+                    log.info("步骤条件不满足,跳过: {}", step.getStepCode());
+                    recordStepSkipped(context.getExecId(), step);
+                    continue;
+                }
+            }
+
+            // 执行步骤
+            StepExecutionResult result = executeStep(step, context);
+
+            if (!result.isSuccess()) {
+                allSuccess = false;
+                if (step.getContinueOnFail() != 1) {
+                    log.error("步骤执行失败,终止策略: {}", step.getStepCode());
+                    break;
+                }
+            }
+
+            // 保存步骤结果到上下文
+            context.setStepResult(step.getStepCode(), result.getResult());
+        }
+
+        // 更新执行日志
+        long duration = System.currentTimeMillis() - context.getStartTime();
+        execLog.setEndTime(new Date());
+        execLog.setDuration((int) duration);
+        execLog.setExecStatus(allSuccess ? 1 : 2);
+        execLog.setResultData(JSON.toJSONString(context.getStepResults()));
+        execLogService.updateExecLog(execLog);
+
+        // 更新策略统计
+        updateStrategyStats(strategy, allSuccess);
+    }
+
+    private StepExecutionResult executeStep(OpEnergyStrategyStep step,
+        StrategyExecutionContext context) {
+        long startTime = System.currentTimeMillis();
+
+        // 记录步骤开始
+        OpEnergyStrategyStepLog stepLog = new OpEnergyStrategyStepLog();
+        stepLog.setExecId(context.getExecId());
+        stepLog.setStrategyCode(step.getStrategyCode());
+        stepLog.setStepCode(step.getStepCode());
+        stepLog.setStepName(step.getStepName());
+        stepLog.setStepIndex(step.getStepIndex());
+        stepLog.setExecStatus(0);
+        stepLog.setStartTime(new Date());
+        stepLogService.insertStepLog(stepLog);
+
+        try {
+            // 根据步骤类型获取执行器
+            IStepExecutor executor = stepExecutorFactory.getExecutor(step.getStepType());
+
+            // 执行步骤
+            Object result = executor.execute(step, context);
+
+            long duration = System.currentTimeMillis() - startTime;
+
+            // 更新步骤日志
+            stepLog.setExecStatus(1);
+            stepLog.setEndTime(new Date());
+            stepLog.setDuration((int) duration);
+            stepLog.setOutputResult(JSON.toJSONString(result));
+            stepLogService.updateStepLog(stepLog);
+
+            return StepExecutionResult.success(step.getStepCode(), result, duration);
+
+        } catch (Exception e) {
+            long duration = System.currentTimeMillis() - startTime;
+            log.error("步骤执行失败: {}", step.getStepCode(), e);
+
+            // 更新步骤日志
+            stepLog.setExecStatus(2);
+            stepLog.setEndTime(new Date());
+            stepLog.setDuration((int) duration);
+            stepLog.setErrorMessage(e.getMessage());
+            stepLogService.updateStepLog(stepLog);
+
+            return StepExecutionResult.fail(step.getStepCode(), e.getMessage(), duration);
+        }
+    }
+
+    private void recordStepSkipped(String execId, OpEnergyStrategyStep step) {
+        OpEnergyStrategyStepLog stepLog = new OpEnergyStrategyStepLog();
+        stepLog.setExecId(execId);
+        stepLog.setStrategyCode(step.getStrategyCode());
+        stepLog.setStepCode(step.getStepCode());
+        stepLog.setStepName(step.getStepName());
+        stepLog.setStepIndex(step.getStepIndex());
+        stepLog.setExecStatus(3); // 跳过
+        stepLog.setStartTime(new Date());
+        stepLog.setEndTime(new Date());
+        stepLogService.insertStepLog(stepLog);
+    }
+
+    private void updateExecLogFailed(OpEnergyStrategyExecLog execLog, String error) {
+        execLog.setExecStatus(2);
+        execLog.setEndTime(new Date());
+        execLog.setErrorMessage(error);
+        execLogService.updateExecLog(execLog);
+    }
+
+    private void updateStrategyStats(OpEnergyStrategy strategy, boolean success) {
+        strategy.setExecCount(strategy.getExecCount() + 1);
+        if (success) {
+            strategy.setSuccessCount(strategy.getSuccessCount() + 1);
+            strategy.setLastExecResult(0);
+        } else {
+            strategy.setFailCount(strategy.getFailCount() + 1);
+            strategy.setLastExecResult(1);
+        }
+        strategy.setLastExecTime(new Date());
+        strategyService.updateStrategy(strategy);
+    }
+}

+ 118 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/strategy/listener/StrategyTriggerListener.java

@@ -0,0 +1,118 @@
+/*
+ * 文 件 名:  StrategyTriggerListener
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/11/27
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.strategy.listener;
+
+import com.ruoyi.ems.domain.OpEnergyStrategyTrigger;
+import com.ruoyi.ems.service.IOpEnergyStrategyTriggerService;
+import com.ruoyi.ems.strategy.evaluator.ConditionEvaluator;
+import com.ruoyi.ems.strategy.executor.StrategyExecutor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 事件监听器
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/11/27]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Slf4j
+@Component
+public class StrategyTriggerListener {
+    @Autowired
+    private IOpEnergyStrategyTriggerService triggerService;
+
+    @Autowired
+    private ConditionEvaluator conditionEvaluator;
+
+    @Autowired
+    private StrategyExecutor strategyExecutor;
+
+    /**
+     * 处理设备事件
+     */
+    public void handleDeviceEvent(String deviceCode, String eventKey, Map<String, Object> eventData) {
+        log.info("接收到设备事件: device={}, event={}", deviceCode, eventKey);
+
+        // 查询匹配的触发器
+        List<OpEnergyStrategyTrigger> triggers = triggerService.findBySourceAndEvent(deviceCode, eventKey);
+
+        for (OpEnergyStrategyTrigger trigger : triggers) {
+            if (trigger.getEnable() != 1) {
+                continue;
+            }
+
+            // 评估触发条件
+            boolean shouldTrigger = true;
+            if (trigger.getConditionExpr() != null && !trigger.getConditionExpr().isEmpty()) {
+                shouldTrigger = conditionEvaluator.evaluate(trigger.getConditionExpr(), eventData);
+            }
+
+            if (shouldTrigger) {
+                log.info("触发策略: {}", trigger.getStrategyCode());
+
+                // 准备触发数据
+                Map<String, Object> triggerData = new HashMap<>(eventData);
+                triggerData.put("trigger_type", "EVENT");
+                triggerData.put("trigger_source", deviceCode);
+                triggerData.put("event_key", eventKey);
+
+                // 执行策略
+                strategyExecutor.executeStrategy(trigger.getStrategyCode(), triggerData);
+            }
+        }
+    }
+
+    /**
+     * 处理属性变化
+     */
+    public void handleAttrChange(String objCode, String attrKey, Object oldValue, Object newValue) {
+        log.info("接收到属性变化: obj={}, attr={}, old={}, new={}", objCode, attrKey, oldValue, newValue);
+
+        // 查询匹配的触发器
+        List<OpEnergyStrategyTrigger> triggers = triggerService.findBySourceAndAttr(objCode, attrKey);
+
+        for (OpEnergyStrategyTrigger trigger : triggers) {
+            if (trigger.getEnable() != 1) {
+                continue;
+            }
+
+            // 构建上下文数据
+            Map<String, Object> context = new HashMap<>();
+            context.put("objCode", objCode);
+            context.put("attrKey", attrKey);
+            context.put("oldValue", oldValue);
+            context.put("newValue", newValue);
+
+            // 评估触发条件
+            boolean shouldTrigger = true;
+            if (trigger.getConditionExpr() != null && !trigger.getConditionExpr().isEmpty()) {
+                shouldTrigger = conditionEvaluator.evaluate(trigger.getConditionExpr(), context);
+            }
+
+            if (shouldTrigger) {
+                log.info("触发策略: {}", trigger.getStrategyCode());
+
+                context.put("trigger_type", "ATTR_CHANGE");
+                context.put("trigger_source", objCode);
+
+                strategyExecutor.executeStrategy(trigger.getStrategyCode(), context);
+            }
+        }
+    }
+}

+ 107 - 0
ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyExecLogMapper.xml

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.ems.mapper.OpEnergyStrategyExecLogMapper">
+
+    <resultMap type="com.ruoyi.ems.domain.OpEnergyStrategyExecLog" id="ExecLogResult">
+        <result property="id" column="id"/>
+        <result property="strategyCode" column="strategy_code"/>
+        <result property="execId" column="exec_id"/>
+        <result property="triggerType" column="trigger_type"/>
+        <result property="triggerSource" column="trigger_source"/>
+        <result property="execStatus" column="exec_status"/>
+        <result property="startTime" column="start_time"/>
+        <result property="endTime" column="end_time"/>
+        <result property="duration" column="duration"/>
+        <result property="contextData" column="context_data"/>
+        <result property="resultData" column="result_data"/>
+        <result property="errorMessage" column="error_message"/>
+        <result property="execBy" column="exec_by"/>
+        <result property="createTime" column="create_time"/>
+    </resultMap>
+
+    <sql id="selectExecLogVo">
+        select id, strategy_code, exec_id, trigger_type, trigger_source, exec_status,
+               start_time, end_time, duration, context_data, result_data, error_message,
+               exec_by, create_time
+        from adm_op_energy_strategy_exec_log
+    </sql>
+
+    <select id="selectExecLogList" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyExecLog" resultMap="ExecLogResult">
+        <include refid="selectExecLogVo"/>
+        <where>
+            <if test="strategyCode != null and strategyCode != ''">
+                and strategy_code = #{strategyCode}
+            </if>
+            <if test="execStatus != null">
+                and exec_status = #{execStatus}
+            </if>
+            <if test="startTime != null">
+                and start_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null">
+                and end_time &lt;= #{endTime}
+            </if>
+        </where>
+        order by start_time desc
+    </select>
+
+    <select id="selectByExecId" parameterType="String" resultMap="ExecLogResult">
+        <include refid="selectExecLogVo"/>
+        where exec_id = #{execId}
+    </select>
+
+    <select id="selectByStrategyCode" parameterType="String" resultMap="ExecLogResult">
+        <include refid="selectExecLogVo"/>
+        where strategy_code = #{strategyCode}
+        order by start_time desc
+        limit 100
+    </select>
+
+    <insert id="insertExecLog" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyExecLog" useGeneratedKeys="true" keyProperty="id">
+        insert into adm_op_energy_strategy_exec_log
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="strategyCode != null and strategyCode != ''">strategy_code,</if>
+            <if test="execId != null and execId != ''">exec_id,</if>
+            <if test="triggerType != null">trigger_type,</if>
+            <if test="triggerSource != null">trigger_source,</if>
+            <if test="execStatus != null">exec_status,</if>
+            <if test="startTime != null">start_time,</if>
+            <if test="endTime != null">end_time,</if>
+            <if test="duration != null">duration,</if>
+            <if test="contextData != null">context_data,</if>
+            <if test="resultData != null">result_data,</if>
+            <if test="errorMessage != null">error_message,</if>
+            <if test="execBy != null">exec_by,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="strategyCode != null and strategyCode != ''">#{strategyCode},</if>
+            <if test="execId != null and execId != ''">#{execId},</if>
+            <if test="triggerType != null">#{triggerType},</if>
+            <if test="triggerSource != null">#{triggerSource},</if>
+            <if test="execStatus != null">#{execStatus},</if>
+            <if test="startTime != null">#{startTime},</if>
+            <if test="endTime != null">#{endTime},</if>
+            <if test="duration != null">#{duration},</if>
+            <if test="contextData != null">#{contextData},</if>
+            <if test="resultData != null">#{resultData},</if>
+            <if test="errorMessage != null">#{errorMessage},</if>
+            <if test="execBy != null">#{execBy},</if>
+        </trim>
+    </insert>
+
+    <update id="updateExecLog" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyExecLog">
+        update adm_op_energy_strategy_exec_log
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="execStatus != null">exec_status = #{execStatus},</if>
+            <if test="endTime != null">end_time = #{endTime},</if>
+            <if test="duration != null">duration = #{duration},</if>
+            <if test="resultData != null">result_data = #{resultData},</if>
+            <if test="errorMessage != null">error_message = #{errorMessage},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteExecLog" parameterType="Long">
+        delete from adm_op_energy_strategy_exec_log where id = #{id}
+    </delete>
+</mapper>

+ 106 - 24
ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyMapper.xml

@@ -5,30 +5,71 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 <mapper namespace="com.ruoyi.ems.mapper.OpEnergyStrategyMapper">
 
     <resultMap type="com.ruoyi.ems.domain.OpEnergyStrategy" id="StrategyResult">
-        <result property="id"    column="id"    />
-        <result property="areaCode"        column="area_code"    />
-        <result property="strategyCode"    column="strategy_code"    />
-        <result property="strategyName"    column="strategy_name"    />
-        <result property="strategyDesc"    column="strategy_desc"    />
-        <result property="strategyType"    column="strategy_type"    />
-        <result property="strategyState"   column="strategy_state"    />
-        <result property="execMode"        column="exec_mode"    />
-        <result property="execRule"        column="exec_rule"    />
+        <result property="id" column="id"/>
+        <result property="areaCode" column="area_code"/>
+        <result property="strategyCode" column="strategy_code"/>
+        <result property="strategyName" column="strategy_name"/>
+        <result property="strategyDesc" column="strategy_desc"/>
+        <result property="sceneType" column="scene_type"/>
+        <result property="strategyCategory" column="strategy_category"/>
+        <result property="triggerType" column="trigger_type"/>
+        <result property="triggerConfig" column="trigger_config"/>
+        <result property="strategyState" column="strategy_state"/>
+        <result property="priority" column="priority"/>
+        <result property="execMode" column="exec_mode"/>
+        <result property="execRule" column="exec_rule"/>
+        <result property="timeout" column="timeout"/>
+        <result property="retryTimes" column="retry_times"/>
+        <result property="lastExecTime" column="last_exec_time"/>
+        <result property="lastExecResult" column="last_exec_result"/>
+        <result property="execCount" column="exec_count"/>
+        <result property="successCount" column="success_count"/>
+        <result property="failCount" column="fail_count"/>
+        <result property="version" column="version"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
     </resultMap>
 
     <sql id="selectStrategyVo">
-        select s.id, s.area_code, s.strategy_code, s.strategy_name, s.strategy_desc, s.strategy_type, s.strategy_state, s.exec_mode, s.exec_rule from adm_op_energy_strategy s
+        select id, area_code, strategy_code, strategy_name, strategy_desc, scene_type,
+               strategy_category, trigger_type, trigger_config, strategy_state, priority,
+               exec_mode, exec_rule, timeout, retry_times, last_exec_time, last_exec_result,
+               exec_count, success_count, fail_count, version,
+               create_by, create_time, update_by, update_time
+        from adm_op_energy_strategy
     </sql>
 
     <select id="selectStrategyList" parameterType="com.ruoyi.ems.domain.OpEnergyStrategy" resultMap="StrategyResult">
         <include refid="selectStrategyVo"/>
         <where>
-            <if test="areaCode != null and areaCode != '' and areaCode != '-1'"> and area_code = #{areaCode}</if>
-            <if test="strategyCode != null and strategyCode != ''"> and strategy_code = #{strategyCode}</if>
-            <if test="strategyType != null "> and strategy_type = #{strategyType}</if>
-            <if test="execMode != null "> and exec_mode = #{execMode}</if>
-            <if test="strategyName != null  and strategyName != ''"> and strategy_name like concat('%', #{strategyName}, '%')</if>
+            <if test="areaCode != null and areaCode != '' and areaCode != '-1'">
+                and area_code = #{areaCode}
+            </if>
+            <if test="strategyCode != null and strategyCode != ''">
+                and strategy_code = #{strategyCode}
+            </if>
+            <if test="sceneType != null">
+                and scene_type = #{sceneType}
+            </if>
+            <if test="strategyCategory != null and strategyCategory != ''">
+                and strategy_category = #{strategyCategory}
+            </if>
+            <if test="triggerType != null">
+                and trigger_type = #{triggerType}
+            </if>
+            <if test="execMode != null">
+                and exec_mode = #{execMode}
+            </if>
+            <if test="strategyState != null">
+                and strategy_state = #{strategyState}
+            </if>
+            <if test="strategyName != null and strategyName != ''">
+                and strategy_name like concat('%', #{strategyName}, '%')
+            </if>
         </where>
+        order by priority desc, create_time desc
     </select>
 
     <select id="selectStrategyById" parameterType="Long" resultMap="StrategyResult">
@@ -36,6 +77,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where id = #{id}
     </select>
 
+    <select id="selectStrategyByCode" parameterType="String" resultMap="StrategyResult">
+        <include refid="selectStrategyVo"/>
+        where strategy_code = #{strategyCode}
+    </select>
+
+    <select id="selectScheduledStrategies" resultMap="StrategyResult">
+        <include refid="selectStrategyVo"/>
+        where strategy_state = 1
+        and trigger_type = 2
+        and exec_rule is not null
+        and exec_rule != ''
+        order by priority desc
+    </select>
+
     <insert id="insertStrategy" parameterType="com.ruoyi.ems.domain.OpEnergyStrategy" useGeneratedKeys="true" keyProperty="id">
         insert into adm_op_energy_strategy
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -43,35 +98,62 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="strategyCode != null and strategyCode != ''">strategy_code,</if>
             <if test="strategyName != null and strategyName != ''">strategy_name,</if>
             <if test="strategyDesc != null">strategy_desc,</if>
-            <if test="strategyType != null">strategy_type,</if>
+            <if test="sceneType != null">scene_type,</if>
+            <if test="strategyCategory != null">strategy_category,</if>
+            <if test="triggerType != null">trigger_type,</if>
+            <if test="triggerConfig != null">trigger_config,</if>
             <if test="strategyState != null">strategy_state,</if>
+            <if test="priority != null">priority,</if>
             <if test="execMode != null">exec_mode,</if>
             <if test="execRule != null">exec_rule,</if>
-         </trim>
+            <if test="timeout != null">timeout,</if>
+            <if test="retryTimes != null">retry_times,</if>
+            <if test="version != null">version,</if>
+            <if test="createBy != null">create_by,</if>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="areaCode != null and areaCode != ''">#{areaCode},</if>
             <if test="strategyCode != null and strategyCode != ''">#{strategyCode},</if>
             <if test="strategyName != null and strategyName != ''">#{strategyName},</if>
             <if test="strategyDesc != null">#{strategyDesc},</if>
-            <if test="strategyType != null">#{strategyType},</if>
+            <if test="sceneType != null">#{sceneType},</if>
+            <if test="strategyCategory != null">#{strategyCategory},</if>
+            <if test="triggerType != null">#{triggerType},</if>
+            <if test="triggerConfig != null">#{triggerConfig},</if>
             <if test="strategyState != null">#{strategyState},</if>
+            <if test="priority != null">#{priority},</if>
             <if test="execMode != null">#{execMode},</if>
             <if test="execRule != null">#{execRule},</if>
-         </trim>
+            <if test="timeout != null">#{timeout},</if>
+            <if test="retryTimes != null">#{retryTimes},</if>
+            <if test="version != null">#{version},</if>
+            <if test="createBy != null">#{createBy},</if>
+        </trim>
     </insert>
 
     <update id="updateStrategy" parameterType="com.ruoyi.ems.domain.OpEnergyStrategy">
         update adm_op_energy_strategy
         <trim prefix="SET" suffixOverrides=",">
             <if test="areaCode != null and areaCode != ''">area_code = #{areaCode},</if>
-            <if test="strategyCode != null and strategyCode != ''">strategy_code = #{strategyCode},</if>
-            <if test="strategyCode != null and strategyCode != ''">strategy_code = #{strategyCode},</if>
             <if test="strategyName != null and strategyName != ''">strategy_name = #{strategyName},</if>
             <if test="strategyDesc != null">strategy_desc = #{strategyDesc},</if>
-            <if test="strategyType != null">strategy_type = #{strategyType},</if>
+            <if test="sceneType != null"> scene_type = #{sceneType},</if>
+            <if test="strategyCategory != null">strategy_category = #{strategyCategory},</if>
+            <if test="triggerType != null">trigger_type = #{triggerType},</if>
+            <if test="triggerConfig != null">trigger_config = #{triggerConfig},</if>
             <if test="strategyState != null">strategy_state = #{strategyState},</if>
+            <if test="priority != null">priority = #{priority},</if>
             <if test="execMode != null">exec_mode = #{execMode},</if>
             <if test="execRule != null">exec_rule = #{execRule},</if>
+            <if test="timeout != null">timeout = #{timeout},</if>
+            <if test="retryTimes != null">retry_times = #{retryTimes},</if>
+            <if test="lastExecTime != null">last_exec_time = #{lastExecTime},</if>
+            <if test="lastExecResult != null">last_exec_result = #{lastExecResult},</if>
+            <if test="execCount != null">exec_count = #{execCount},</if>
+            <if test="successCount != null">success_count = #{successCount},</if>
+            <if test="failCount != null">fail_count = #{failCount},</if>
+            <if test="version != null">version = #{version},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
         </trim>
         where id = #{id}
     </update>
@@ -80,9 +162,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         delete from adm_op_energy_strategy where id = #{id}
     </delete>
 
-    <delete id="deleteStrategyByIds" parameterType="String">
+    <delete id="deleteStrategyByIds">
         delete from adm_op_energy_strategy where id in
-        <foreach item="id" collection="array" open="(" separator="," close=")">
+        <foreach item="id" collection="ids" open="(" separator="," close=")">
             #{id}
         </foreach>
     </delete>

+ 114 - 0
ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyStepLogMapper.xml

@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.ems.mapper.OpEnergyStrategyStepLogMapper">
+
+    <resultMap type="com.ruoyi.ems.domain.OpEnergyStrategyStepLog" id="StepLogResult">
+        <result property="id" column="id"/>
+        <result property="execId" column="exec_id"/>
+        <result property="strategyCode" column="strategy_code"/>
+        <result property="stepCode" column="step_code"/>
+        <result property="stepName" column="step_name"/>
+        <result property="stepIndex" column="step_index"/>
+        <result property="execStatus" column="exec_status"/>
+        <result property="startTime" column="start_time"/>
+        <result property="endTime" column="end_time"/>
+        <result property="duration" column="duration"/>
+        <result property="inputParam" column="input_param"/>
+        <result property="outputResult" column="output_result"/>
+        <result property="errorMessage" column="error_message"/>
+        <result property="retryCount" column="retry_count"/>
+        <result property="createTime" column="create_time"/>
+    </resultMap>
+
+    <sql id="selectStepLogVo">
+        select id, exec_id, strategy_code, step_code, step_name, step_index, exec_status,
+               start_time, end_time, duration, input_param, output_result, error_message,
+               retry_count, create_time
+        from adm_op_energy_strategy_step_log
+    </sql>
+
+    <select id="selectStepLogList" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyStepLog" resultMap="StepLogResult">
+        <include refid="selectStepLogVo"/>
+        <where>
+            <if test="execId != null and execId != ''">
+                and exec_id = #{execId}
+            </if>
+            <if test="strategyCode != null and strategyCode != ''">
+                and strategy_code = #{strategyCode}
+            </if>
+            <if test="stepCode != null and stepCode != ''">
+                and step_code = #{stepCode}
+            </if>
+            <if test="execStatus != null">
+                and exec_status = #{execStatus}
+            </if>
+        </where>
+        order by step_index
+    </select>
+
+    <select id="selectByExecId" parameterType="String" resultMap="StepLogResult">
+        <include refid="selectStepLogVo"/>
+        where exec_id = #{execId}
+        order by step_index
+    </select>
+
+    <insert id="insertStepLog" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyStepLog" useGeneratedKeys="true" keyProperty="id">
+        insert into adm_op_energy_strategy_step_log
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="execId != null and execId != ''">exec_id,</if>
+            <if test="strategyCode != null and strategyCode != ''">strategy_code,</if>
+            <if test="stepCode != null and stepCode != ''">step_code,</if>
+            <if test="stepName != null and stepName != ''">step_name,</if>
+            <if test="stepIndex != null">step_index,</if>
+            <if test="execStatus != null">exec_status,</if>
+            <if test="startTime != null">start_time,</if>
+            <if test="endTime != null">end_time,</if>
+            <if test="duration != null">duration,</if>
+            <if test="inputParam != null">input_param,</if>
+            <if test="outputResult != null">output_result,</if>
+            <if test="errorMessage != null">error_message,</if>
+            <if test="retryCount != null">retry_count,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="execId != null and execId != ''">#{execId},</if>
+            <if test="strategyCode != null and strategyCode != ''">#{strategyCode},</if>
+            <if test="stepCode != null and stepCode != ''">#{stepCode},</if>
+            <if test="stepName != null and stepName != ''">#{stepName},</if>
+            <if test="stepIndex != null">#{stepIndex},</if>
+            <if test="execStatus != null">#{execStatus},</if>
+            <if test="startTime != null">#{startTime},</if>
+            <if test="endTime != null">#{endTime},</if>
+            <if test="duration != null">#{duration},</if>
+            <if test="inputParam != null">#{inputParam},</if>
+            <if test="outputResult != null">#{outputResult},</if>
+            <if test="errorMessage != null">#{errorMessage},</if>
+            <if test="retryCount != null">#{retryCount},</if>
+        </trim>
+    </insert>
+
+    <update id="updateStepLog" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyStepLog">
+        update adm_op_energy_strategy_step_log
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="execStatus != null">exec_status = #{execStatus},</if>
+            <if test="endTime != null">end_time = #{endTime},</if>
+            <if test="duration != null">duration = #{duration},</if>
+            <if test="outputResult != null">output_result = #{outputResult},</if>
+            <if test="errorMessage != null">error_message = #{errorMessage},</if>
+            <if test="retryCount != null">retry_count = #{retryCount},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <insert id="insertStepLogBatch">
+        insert into adm_op_energy_strategy_step_log
+        (exec_id, strategy_code, step_code, step_name, step_index, exec_status,
+        start_time, end_time, duration, input_param, output_result, error_message, retry_count)
+        values
+        <foreach collection="list" item="item" separator=",">
+            (#{item.execId}, #{item.strategyCode}, #{item.stepCode}, #{item.stepName},
+            #{item.stepIndex}, #{item.execStatus}, #{item.startTime}, #{item.endTime},
+            #{item.duration}, #{item.inputParam}, #{item.outputResult}, #{item.errorMessage},
+            #{item.retryCount})
+        </foreach>
+    </insert>
+</mapper>

+ 126 - 43
ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyStepMapper.xml

@@ -1,79 +1,162 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.ems.mapper.OpEnergyStrategyStepMapper">
-    
-    <resultMap type="com.ruoyi.ems.domain.OpEnergyStrategyStep" id="opEnergyStrategyStepResult">
-        <result property="id"    column="id"    />
-        <result property="strategyCode"    column="strategy_code"    />
-        <result property="stepCode"    column="step_code"    />
-        <result property="stepName"    column="step_name"    />
-        <result property="stepIndex"    column="step_index"    />
-        <result property="stepHandler"    column="step_handler"    />
-        <result property="stepParam"    column="step_param"    />
-        <result property="targetFacs"    column="target_facs"    />
-        <result property="targetDevice"    column="target_device"    />
+
+    <resultMap type="com.ruoyi.ems.domain.OpEnergyStrategyStep" id="StepResult">
+        <result property="id" column="id"/>
+        <result property="strategyCode" column="strategy_code"/>
+        <result property="stepCode" column="step_code"/>
+        <result property="stepName" column="step_name"/>
+        <result property="stepType" column="step_type"/>
+        <result property="stepIndex" column="step_index"/>
+        <result property="parentStepCode" column="parent_step_code"/>
+        <result property="conditionExpr" column="condition_expr"/>
+        <result property="targetObjType" column="target_obj_type"/>
+        <result property="targetObjCode" column="target_obj_code"/>
+        <result property="targetModelCode" column="target_model_code"/>
+        <result property="abilityKey" column="ability_key"/>
+        <result property="abilityParam" column="ability_param"/>
+        <result property="paramSource" column="param_source"/>
+        <result property="paramMapping" column="param_mapping"/>
+        <result property="delaySeconds" column="delay_seconds"/>
+        <result property="retryOnFail" column="retry_on_fail"/>
+        <result property="retryTimes" column="retry_times"/>
+        <result property="retryInterval" column="retry_interval"/>
+        <result property="continueOnFail" column="continue_on_fail"/>
+        <result property="timeout" column="timeout"/>
+        <result property="enable" column="enable"/>
+        <result property="remark" column="remark"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateTime" column="update_time"/>
     </resultMap>
 
     <sql id="selectStepVo">
-        select id, strategy_code, step_code, step_name, step_index, step_handler, step_param, target_facs, target_device from adm_op_energy_strategy_step
+        select id, strategy_code, step_code, step_name, step_type, step_index, parent_step_code,
+               condition_expr, target_obj_type, target_obj_code, target_model_code, ability_key,
+               ability_param, param_source, param_mapping, delay_seconds, retry_on_fail, retry_times,
+               retry_interval, continue_on_fail, timeout, enable, remark, create_time, update_time
+        from adm_op_energy_strategy_step
     </sql>
 
-    <select id="selectStepByStrategyCode" parameterType="java.lang.String" resultMap="opEnergyStrategyStepResult">
+    <select id="selectStepByStrategyCode" parameterType="String" resultMap="StepResult">
         <include refid="selectStepVo"/>
         where strategy_code = #{strategyCode}
+        order by step_index
+    </select>
+
+    <select id="selectStepById" parameterType="Long" resultMap="StepResult">
+        <include refid="selectStepVo"/>
+        where id = #{id}
     </select>
-        
+
     <insert id="insertStep" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyStep" useGeneratedKeys="true" keyProperty="id">
         insert into adm_op_energy_strategy_step
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="strategyCode != null and strategyCode != ''">strategy_code,</if>
             <if test="stepCode != null and stepCode != ''">step_code,</if>
             <if test="stepName != null and stepName != ''">step_name,</if>
+            <if test="stepType != null and stepType != ''">step_type,</if>
             <if test="stepIndex != null">step_index,</if>
-            <if test="stepHandler != null and stepHandler != ''">step_handler,</if>
-            <if test="stepParam != null">step_param,</if>
-            <if test="targetFacs != null">target_facs,</if>
-            <if test="targetDevice != null">target_device,</if>
-         </trim>
+            <if test="parentStepCode != null">parent_step_code,</if>
+            <if test="conditionExpr != null">condition_expr,</if>
+            <if test="targetObjType != null">target_obj_type,</if>
+            <if test="targetObjCode != null">target_obj_code,</if>
+            <if test="targetModelCode != null">target_model_code,</if>
+            <if test="abilityKey != null">ability_key,</if>
+            <if test="abilityParam != null">ability_param,</if>
+            <if test="paramSource != null">param_source,</if>
+            <if test="paramMapping != null">param_mapping,</if>
+            <if test="delaySeconds != null">delay_seconds,</if>
+            <if test="retryOnFail != null">retry_on_fail,</if>
+            <if test="retryTimes != null">retry_times,</if>
+            <if test="retryInterval != null">retry_interval,</if>
+            <if test="continueOnFail != null">continue_on_fail,</if>
+            <if test="timeout != null">timeout,</if>
+            <if test="enable != null">enable,</if>
+            <if test="remark != null">remark,</if>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="strategyCode != null and strategyCode != ''">#{strategyCode},</if>
             <if test="stepCode != null and stepCode != ''">#{stepCode},</if>
             <if test="stepName != null and stepName != ''">#{stepName},</if>
+            <if test="stepType != null and stepType != ''">#{stepType},</if>
             <if test="stepIndex != null">#{stepIndex},</if>
-            <if test="stepHandler != null and stepHandler != ''">#{stepHandler},</if>
-            <if test="stepParam != null">#{stepParam},</if>
-            <if test="targetFacs != null">#{targetFacs},</if>
-            <if test="targetDevice != null">#{targetDevice},</if>
-         </trim>
-    </insert>
-
-    <insert id="insertStepBatch" parameterType="java.util.List">
-        insert into adm_op_energy_strategy_step (strategy_code, step_code, step_name, step_index, step_handler, step_param, target_facs, target_device)
-        values
-        <foreach collection="list" item="item" index="index" separator=",">
-            (#{item.strategyCode}, #{item.stepCode}, #{item.stepName}, #{item.stepIndex}, #{item.stepHandler}, #{item.stepParam}, #{item.targetFacs}, #{item.targetDevice})
-        </foreach>
+            <if test="parentStepCode != null">#{parentStepCode},</if>
+            <if test="conditionExpr != null">#{conditionExpr},</if>
+            <if test="targetObjType != null">#{targetObjType},</if>
+            <if test="targetObjCode != null">#{targetObjCode},</if>
+            <if test="targetModelCode != null">#{targetModelCode},</if>
+            <if test="abilityKey != null">#{abilityKey},</if>
+            <if test="abilityParam != null">#{abilityParam},</if>
+            <if test="paramSource != null">#{paramSource},</if>
+            <if test="paramMapping != null">#{paramMapping},</if>
+            <if test="delaySeconds != null">#{delaySeconds},</if>
+            <if test="retryOnFail != null">#{retryOnFail},</if>
+            <if test="retryTimes != null">#{retryTimes},</if>
+            <if test="retryInterval != null">#{retryInterval},</if>
+            <if test="continueOnFail != null">#{continueOnFail},</if>
+            <if test="timeout != null">#{timeout},</if>
+            <if test="enable != null">#{enable},</if>
+            <if test="remark != null">#{remark},</if>
+        </trim>
     </insert>
 
-
     <update id="updateStep" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyStep">
         update adm_op_energy_strategy_step
         <trim prefix="SET" suffixOverrides=",">
-            <if test="strategyCode != null and strategyCode != ''">strategy_code = #{strategyCode},</if>
-            <if test="stepCode != null and stepCode != ''">step_code = #{stepCode},</if>
             <if test="stepName != null and stepName != ''">step_name = #{stepName},</if>
+            <if test="stepType != null and stepType != ''">step_type = #{stepType},</if>
             <if test="stepIndex != null">step_index = #{stepIndex},</if>
-            <if test="stepHandler != null and stepHandler != ''">step_handler = #{stepHandler},</if>
-            <if test="stepParam != null">step_param = #{stepParam},</if>
-            <if test="targetFacs != null">target_facs = #{targetFacs},</if>
-            <if test="targetDevice != null">target_device = #{targetDevice},</if>
+            <if test="parentStepCode != null">parent_step_code = #{parentStepCode},</if>
+            <if test="conditionExpr != null">condition_expr = #{conditionExpr},</if>
+            <if test="targetObjType != null">target_obj_type = #{targetObjType},</if>
+            <if test="targetObjCode != null">target_obj_code = #{targetObjCode},</if>
+            <if test="targetModelCode != null">target_model_code = #{targetModelCode},</if>
+            <if test="abilityKey != null">ability_key = #{abilityKey},</if>
+            <if test="abilityParam != null">ability_param = #{abilityParam},</if>
+            <if test="paramSource != null">param_source = #{paramSource},</if>
+            <if test="paramMapping != null">param_mapping = #{paramMapping},</if>
+            <if test="delaySeconds != null">delay_seconds = #{delaySeconds},</if>
+            <if test="retryOnFail != null">retry_on_fail = #{retryOnFail},</if>
+            <if test="retryTimes != null">retry_times = #{retryTimes},</if>
+            <if test="retryInterval != null">retry_interval = #{retryInterval},</if>
+            <if test="continueOnFail != null">continue_on_fail = #{continueOnFail},</if>
+            <if test="timeout != null">timeout = #{timeout},</if>
+            <if test="enable != null">enable = #{enable},</if>
+            <if test="remark != null">remark = #{remark},</if>
         </trim>
         where id = #{id}
     </update>
 
-    <delete id="deleteStepByStrategyCode" parameterType="java.lang.String">
+    <delete id="deleteStepById" parameterType="Long">
+        delete from adm_op_energy_strategy_step where id = #{id}
+    </delete>
+
+    <delete id="deleteStepByIds">
+        delete from adm_op_energy_strategy_step where id in
+        <foreach item="id" collection="ids" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <delete id="deleteStepByStrategyCode" parameterType="String">
         delete from adm_op_energy_strategy_step where strategy_code = #{strategyCode}
     </delete>
+
+    <insert id="insertStepBatch">
+        insert into adm_op_energy_strategy_step
+        (strategy_code, step_code, step_name, step_type, step_index, parent_step_code,
+        condition_expr, target_obj_type, target_obj_code, target_model_code, ability_key,
+        ability_param, param_source, param_mapping, delay_seconds, retry_on_fail, retry_times,
+        retry_interval, continue_on_fail, timeout, enable, remark)
+        values
+        <foreach collection="list" item="item" separator=",">
+            (#{item.strategyCode}, #{item.stepCode}, #{item.stepName}, #{item.stepType},
+            #{item.stepIndex}, #{item.parentStepCode}, #{item.conditionExpr}, #{item.targetObjType},
+            #{item.targetObjCode}, #{item.targetModelCode}, #{item.abilityKey}, #{item.abilityParam},
+            #{item.paramSource}, #{item.paramMapping}, #{item.delaySeconds}, #{item.retryOnFail},
+            #{item.retryTimes}, #{item.retryInterval}, #{item.continueOnFail}, #{item.timeout},
+            #{item.enable}, #{item.remark})
+        </foreach>
+    </insert>
 </mapper>

+ 127 - 0
ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyTemplateMapper.xml

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.ems.mapper.OpEnergyStrategyTemplateMapper">
+    
+    <resultMap type="com.ruoyi.ems.domain.OpEnergyStrategyTemplate" id="OpEnergyStrategyTemplateResult">
+        <result property="id"    column="id"    />
+        <result property="templateCode"    column="template_code"    />
+        <result property="templateName"    column="template_name"    />
+        <result property="sceneType"    column="scene_type"    />
+        <result property="description"    column="description"    />
+        <result property="templateData"    column="template_data"    />
+        <result property="icon"    column="icon"    />
+        <result property="coverImage"    column="cover_image"    />
+        <result property="tags"    column="tags"    />
+        <result property="applicableDevices"    column="applicable_devices"    />
+        <result property="sortOrder"    column="sort_order"    />
+        <result property="useCount"    column="use_count"    />
+        <result property="isSystem"    column="is_system"    />
+        <result property="isPublic"    column="is_public"    />
+        <result property="status"    column="status"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectTemplateVo">
+        select id, template_code, template_name, scene_type, description, template_data, icon, cover_image, tags, applicable_devices, sort_order, use_count, is_system, is_public, status, create_by, create_time, update_by, update_time from adm_op_energy_strategy_template
+    </sql>
+
+    <select id="selectTemplateList" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyTemplate" resultMap="OpEnergyStrategyTemplateResult">
+        <include refid="selectTemplateVo"/>
+        <where>  
+            <if test="templateCode != null  and templateCode != ''"> and template_code = #{templateCode}</if>
+            <if test="templateName != null  and templateName != ''"> and template_name like concat('%', #{templateName}, '%')</if>
+            <if test="sceneType != null  and sceneType != ''"> and scene_type = #{sceneType}</if>
+            <if test="status != null"> and `status` = #{status}</if>
+        </where>
+    </select>
+    
+    <select id="selectTemplateById" parameterType="Long" resultMap="OpEnergyStrategyTemplateResult">
+        <include refid="selectTemplateVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertTemplate" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyTemplate" useGeneratedKeys="true" keyProperty="id">
+        insert into adm_op_energy_strategy_template
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="templateCode != null and templateCode != ''">template_code,</if>
+            <if test="templateName != null and templateName != ''">template_name,</if>
+            <if test="sceneType != null and sceneType != ''">scene_type,</if>
+            <if test="description != null">`description`,</if>
+            <if test="templateData != null">template_data,</if>
+            <if test="icon != null">icon,</if>
+            <if test="coverImage != null">cover_image,</if>
+            <if test="tags != null">tags,</if>
+            <if test="applicableDevices != null">applicable_devices,</if>
+            <if test="sortOrder != null">sort_order,</if>
+            <if test="useCount != null">use_count,</if>
+            <if test="isSystem != null">is_system,</if>
+            <if test="isPublic != null">is_public,</if>
+            <if test="status != null">`status`,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="templateCode != null and templateCode != ''">#{templateCode},</if>
+            <if test="templateName != null and templateName != ''">#{templateName},</if>
+            <if test="sceneType != null and sceneType != ''">#{sceneType},</if>
+            <if test="description != null">#{description},</if>
+            <if test="templateData != null">#{templateData},</if>
+            <if test="icon != null">#{icon},</if>
+            <if test="coverImage != null">#{coverImage},</if>
+            <if test="tags != null">#{tags},</if>
+            <if test="applicableDevices != null">#{applicableDevices},</if>
+            <if test="sortOrder != null">#{sortOrder},</if>
+            <if test="useCount != null">#{useCount},</if>
+            <if test="isSystem != null">#{isSystem},</if>
+            <if test="isPublic != null">#{isPublic},</if>
+            <if test="status != null">#{status},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateTemplate" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyTemplate">
+        update adm_op_energy_strategy_template
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="templateCode != null and templateCode != ''">template_code = #{templateCode},</if>
+            <if test="templateName != null and templateName != ''">template_name = #{templateName},</if>
+            <if test="sceneType != null and sceneType != ''">scene_type = #{sceneType},</if>
+            <if test="description != null">`description` = #{description},</if>
+            <if test="templateData != null">template_data = #{templateData},</if>
+            <if test="icon != null">icon = #{icon},</if>
+            <if test="coverImage != null">cover_image = #{coverImage},</if>
+            <if test="tags != null">tags = #{tags},</if>
+            <if test="applicableDevices != null">applicable_devices = #{applicableDevices},</if>
+            <if test="sortOrder != null">sort_order = #{sortOrder},</if>
+            <if test="useCount != null">use_count = #{useCount},</if>
+            <if test="isSystem != null">is_system = #{isSystem},</if>
+            <if test="isPublic != null">is_public = #{isPublic},</if>
+            <if test="status != null">`status` = #{status},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteTemplateById" parameterType="Long">
+        delete from adm_op_energy_strategy_template where id = #{id}
+    </delete>
+
+    <delete id="deleteTemplateByIds" parameterType="String">
+        delete from adm_op_energy_strategy_template where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 110 - 0
ems/ems-core/src/main/resources/mapper/ems/OpEnergyStrategyTriggerMapper.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.ems.mapper.OpEnergyStrategyTriggerMapper">
+
+    <resultMap type="com.ruoyi.ems.domain.OpEnergyStrategyTrigger" id="TriggerResult">
+        <result property="id" column="id"/>
+        <result property="strategyCode" column="strategy_code"/>
+        <result property="triggerName" column="trigger_name"/>
+        <result property="triggerType" column="trigger_type"/>
+        <result property="sourceObjType" column="source_obj_type"/>
+        <result property="sourceObjCode" column="source_obj_code"/>
+        <result property="sourceModelCode" column="source_model_code"/>
+        <result property="eventKey" column="event_key"/>
+        <result property="attrKey" column="attr_key"/>
+        <result property="conditionExpr" column="condition_expr"/>
+        <result property="enable" column="enable"/>
+        <result property="priority" column="priority"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+    <sql id="selectTriggerVo">
+        select id, strategy_code, trigger_name, trigger_type, source_obj_type, source_obj_code,
+               source_model_code, event_key, attr_key, condition_expr, enable, priority,
+               create_time, update_time
+        from adm_op_energy_strategy_trigger
+    </sql>
+
+    <select id="selectByStrategyCode" parameterType="String" resultMap="TriggerResult">
+        <include refid="selectTriggerVo"/>
+        where strategy_code = #{strategyCode}
+        order by priority desc, id
+    </select>
+
+    <select id="findBySourceAndEvent" resultMap="TriggerResult">
+        <include refid="selectTriggerVo"/>
+        where source_obj_code = #{sourceObjCode}
+        and trigger_type = 'EVENT'
+        and event_key = #{eventKey}
+        and enable = 1
+        order by priority desc
+    </select>
+
+    <select id="findBySourceAndAttr" resultMap="TriggerResult">
+        <include refid="selectTriggerVo"/>
+        where source_obj_code = #{sourceObjCode}
+        and trigger_type = 'ATTR'
+        and attr_key = #{attrKey}
+        and enable = 1
+        order by priority desc
+    </select>
+
+    <insert id="insertTrigger" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyTrigger" useGeneratedKeys="true" keyProperty="id">
+        insert into adm_op_energy_strategy_trigger
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="strategyCode != null and strategyCode != ''">strategy_code,</if>
+            <if test="triggerName != null and triggerName != ''">trigger_name,</if>
+            <if test="triggerType != null and triggerType != ''">trigger_type,</if>
+            <if test="sourceObjType != null">source_obj_type,</if>
+            <if test="sourceObjCode != null and sourceObjCode != ''">source_obj_code,</if>
+            <if test="sourceModelCode != null and sourceModelCode != ''">source_model_code,</if>
+            <if test="eventKey != null">event_key,</if>
+            <if test="attrKey != null">attr_key,</if>
+            <if test="conditionExpr != null">condition_expr,</if>
+            <if test="enable != null">enable,</if>
+            <if test="priority != null">priority,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="strategyCode != null and strategyCode != ''">#{strategyCode},</if>
+            <if test="triggerName != null and triggerName != ''">#{triggerName},</if>
+            <if test="triggerType != null and triggerType != ''">#{triggerType},</if>
+            <if test="sourceObjType != null">#{sourceObjType},</if>
+            <if test="sourceObjCode != null and sourceObjCode != ''">#{sourceObjCode},</if>
+            <if test="sourceModelCode != null and sourceModelCode != ''">#{sourceModelCode},</if>
+            <if test="eventKey != null">#{eventKey},</if>
+            <if test="attrKey != null">#{attrKey},</if>
+            <if test="conditionExpr != null">#{conditionExpr},</if>
+            <if test="enable != null">#{enable},</if>
+            <if test="priority != null">#{priority},</if>
+        </trim>
+    </insert>
+
+    <update id="updateTrigger" parameterType="com.ruoyi.ems.domain.OpEnergyStrategyTrigger">
+        update adm_op_energy_strategy_trigger
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="triggerName != null and triggerName != ''">trigger_name = #{triggerName},</if>
+            <if test="triggerType != null and triggerType != ''">trigger_type = #{triggerType},</if>
+            <if test="sourceObjType != null">source_obj_type = #{sourceObjType},</if>
+            <if test="sourceObjCode != null and sourceObjCode != ''">source_obj_code = #{sourceObjCode},</if>
+            <if test="sourceModelCode != null and sourceModelCode != ''">source_model_code = #{sourceModelCode},</if>
+            <if test="eventKey != null">event_key = #{eventKey},</if>
+            <if test="attrKey != null">attr_key = #{attrKey},</if>
+            <if test="conditionExpr != null">condition_expr = #{conditionExpr},</if>
+            <if test="enable != null">enable = #{enable},</if>
+            <if test="priority != null">priority = #{priority},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteTrigger" parameterType="Long">
+        delete from adm_op_energy_strategy_trigger where id = #{id}
+    </delete>
+
+    <delete id="deleteTriggerByIds">
+        delete from adm_op_energy_strategy_trigger where id in
+        <foreach item="id" collection="ids" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 295 - 28
ems/sql/ems_server.sql

@@ -883,21 +883,198 @@ create table adm_ems_flow_rel  (
 -- 能源策略表
 -- ----------------------------
 drop table if exists adm_op_energy_strategy;
-create table adm_op_energy_strategy  (
-  `id`                bigint(20)      not null auto_increment      comment '序号',
-  `area_code`         varchar(32)     not null                     comment '地块代码',
-  `strategy_code`     varchar(16)     not null                     comment '策略代码',
-  `strategy_name`     varchar(32)     not null                     comment '策略名称',
-  `strategy_type`     int             not null                     comment '1:源网协调,2:源荷互动, 3:网储互动,4:其他',
-  `strategy_state`    int             default null                 comment '0:关闭 1:启动',
-  `strategy_desc`     varchar(128)    default null                 comment '策略描述',
-  `exec_mode`         int             default null                 comment '1:定时执行(cron)99:手动执行',
-  `exec_rule`         varchar(64)     default null                 comment '执行规则',
-  `create_time`       datetime        default CURRENT_TIMESTAMP    comment '创建时间',
-  `update_time`       datetime        default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间',
-  primary key (`id`),
-  unique key ux_op_energy_strategy_code(`strategy_code`)
-) engine=innodb auto_increment=1 comment = '能源策略表';
+CREATE TABLE adm_op_energy_strategy (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '序号',
+  `area_code` VARCHAR(32) NOT NULL COMMENT '地块代码',
+  `strategy_code` VARCHAR(16) NOT NULL COMMENT '策略代码',
+  `strategy_name` VARCHAR(64) NOT NULL COMMENT '策略名称',
+  `scene_type` VARCHAR(32) DEFAULT NULL COMMENT '场景类型:PV_ESS-光储协同,DEMAND_RESP-需求响应,PEAK_VALLEY-削峰填谷,EMERGENCY-应急保供,ENERGY_SAVE-节能优化',
+  `strategy_category` VARCHAR(32) DEFAULT NULL COMMENT '策略分类:AUTO-自动,MANUAL-手动,SCHEDULE-定时,EVENT-事件',
+  `trigger_type` INT DEFAULT NULL COMMENT '触发类型:1-事件触发,2-定时触发,3-手动触发,4-条件触发',
+  `trigger_config` TEXT DEFAULT NULL COMMENT '触发配置(JSON)',
+  `strategy_state` INT DEFAULT 0 COMMENT '策略状态:0-停用,1-启用,2-调试',
+  `priority` INT DEFAULT 50 COMMENT '优先级:0-100,数值越大优先级越高',
+  `strategy_desc` VARCHAR(256) DEFAULT NULL COMMENT '策略描述',
+  `exec_mode` INT DEFAULT NULL COMMENT '执行模式:1-串行,2-并行,99-手动',
+  `exec_rule` VARCHAR(128) DEFAULT NULL COMMENT 'CRON表达式',
+  `timeout` INT DEFAULT 300 COMMENT '超时时间(秒)',
+  `retry_times` INT DEFAULT 0 COMMENT '失败重试次数',
+  `last_exec_time` DATETIME DEFAULT NULL COMMENT '最后执行时间',
+  `last_exec_result` INT DEFAULT NULL COMMENT '最后执行结果:0-成功,1-失败',
+  `exec_count` INT DEFAULT 0 COMMENT '执行次数',
+  `success_count` INT DEFAULT 0 COMMENT '成功次数',
+  `fail_count` INT DEFAULT 0 COMMENT '失败次数',
+  `version` INT DEFAULT 1 COMMENT '版本号',
+  `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `ux_strategy_code` (`strategy_code`),
+  KEY `idx_area_code` (`area_code`),
+  KEY `idx_trigger_type` (`trigger_type`),
+  KEY `idx_strategy_state` (`strategy_state`)
+) ENGINE=INNODB AUTO_INCREMENT=1 COMMENT='能源策略表';
+
+-- ----------------------------
+-- 能源策略模板表
+-- ----------------------------
+DROP TABLE IF EXISTS adm_op_energy_strategy_template;
+CREATE TABLE adm_op_energy_strategy_template (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '序号',
+  `template_code` VARCHAR(32) NOT NULL COMMENT '模板代码',
+  `template_name` VARCHAR(64) NOT NULL COMMENT '模板名称',
+  `scene_type` VARCHAR(32) NOT NULL COMMENT '场景类型',
+  `description` VARCHAR(512) DEFAULT NULL COMMENT '模板描述',
+  `template_data` LONGTEXT NOT NULL COMMENT '模板数据(JSON,包含触发器、步骤、上下文变量)',
+  `icon` VARCHAR(64) DEFAULT NULL COMMENT '图标',
+  `cover_image` VARCHAR(256) DEFAULT NULL COMMENT '封面图片',
+  `tags` VARCHAR(256) DEFAULT NULL COMMENT '标签(逗号分隔)',
+  `applicable_devices` VARCHAR(512) DEFAULT NULL COMMENT '适用设备类型(逗号分隔)',
+  `sort_order` INT DEFAULT 0 COMMENT '排序',
+  `use_count` INT DEFAULT 0 COMMENT '使用次数',
+  `is_system` INT DEFAULT 0 COMMENT '是否系统预置:0-否,1-是',
+  `is_public` INT DEFAULT 1 COMMENT '是否公开:0-否,1-是',
+  `status` INT DEFAULT 1 COMMENT '状态:0-禁用,1-启用',
+  `create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `ux_template_code` (`template_code`),
+  KEY `idx_scene_type` (`scene_type`),
+  KEY `idx_is_system` (`is_system`),
+  KEY `idx_status` (`status`)
+) ENGINE=INNODB AUTO_INCREMENT=1 COMMENT='策略模板表';
+
+-- 策略预置模板
+-- ----------------------------------------
+INSERT INTO adm_op_energy_strategy_template
+(template_code, template_name, scene_type, description, template_data, icon, tags, applicable_devices, sort_order, is_system, status)
+VALUES
+-- 光储联动模板
+('TPL_PV_ESS_BASIC', '光储联动-基础模板', 'PV_ESS',
+ '当光伏发电功率超过负荷需求时,自动将多余电量存入储能;当光伏发电不足时,从储能放电补充。',
+ '{
+   "triggers": [
+     {"triggerType": "ATTR", "triggerName": "光伏功率变化", "sourceObjType": 2, "attrKey": "activePower", "conditionExpr": "{\"left\":\"activePower\",\"op\":\">\",\"right\":0}"}
+   ],
+   "steps": [
+     {"stepType": "CONDITION", "stepName": "判断光伏功率", "stepIndex": 1, "conditionExpr": "{\"left\":\"pv.activePower\",\"op\":\">\",\"right\":\"load.activePower\"}"},
+     {"stepType": "ABILITY", "stepName": "储能充电", "stepIndex": 2, "abilityKey": "charge", "paramSource": "CONTEXT"},
+     {"stepType": "ABILITY", "stepName": "储能放电", "stepIndex": 3, "abilityKey": "discharge", "paramSource": "CONTEXT"}
+   ],
+   "context": [
+     {"varKey": "pvPower", "varName": "光伏功率", "varType": "INPUT", "dataType": "NUMBER"},
+     {"varKey": "loadPower", "varName": "负荷功率", "varType": "INPUT", "dataType": "NUMBER"},
+     {"varKey": "essSoc", "varName": "储能SOC", "varType": "INPUT", "dataType": "NUMBER"}
+   ]
+ }',
+ 'el-icon-sunny', '光伏,储能,联动', 'PV,ESS', 1, 1, 1),
+
+-- 削峰填谷模板
+('TPL_PEAK_VALLEY', '削峰填谷-定时调度', 'PEAK_VALLEY',
+ '根据电价时段自动调度储能充放电:低谷时段充电,高峰时段放电,实现电费优化。',
+ '{
+   "triggers": [
+     {"triggerType": "TIME", "triggerName": "谷时充电", "conditionExpr": "{\"cron\":\"0 0 23 * * ?\"}"},
+     {"triggerType": "TIME", "triggerName": "峰时放电", "conditionExpr": "{\"cron\":\"0 0 10 * * ?\"}"}
+   ],
+   "steps": [
+     {"stepType": "CONDITION", "stepName": "检查SOC", "stepIndex": 1, "conditionExpr": "{\"left\":\"ess.soc\",\"op\":\"<\",\"right\":90}"},
+     {"stepType": "ABILITY", "stepName": "储能充电", "stepIndex": 2, "abilityKey": "charge", "abilityParam": "{\"power\": 100}"},
+     {"stepType": "DELAY", "stepName": "等待充电完成", "stepIndex": 3, "delaySeconds": 3600}
+   ],
+   "context": [
+     {"varKey": "targetSoc", "varName": "目标SOC", "varType": "INPUT", "dataType": "NUMBER", "defaultValue": "90"},
+     {"varKey": "chargePower", "varName": "充电功率", "varType": "INPUT", "dataType": "NUMBER", "defaultValue": "100"}
+   ]
+ }',
+ 'el-icon-data-analysis', '削峰填谷,电价优化,储能', 'ESS', 2, 1, 1),
+
+-- 需求响应模板
+('TPL_DEMAND_RESP', '需求响应-负荷控制', 'DEMAND_RESP',
+ '当收到电网需求响应信号时,自动降低非关键负荷用电,并启动储能放电支撑。',
+ '{
+   "triggers": [
+     {"triggerType": "EVENT", "triggerName": "需求响应信号", "sourceObjType": 3, "eventKey": "demandResponse"}
+   ],
+   "steps": [
+     {"stepType": "PARALLEL", "stepName": "并行执行", "stepIndex": 1},
+     {"stepType": "ABILITY", "stepName": "降低空调负荷", "stepIndex": 2, "parentStepCode": "STEP_1", "abilityKey": "setTemperature", "abilityParam": "{\"temp\": 26}"},
+     {"stepType": "ABILITY", "stepName": "调暗照明", "stepIndex": 3, "parentStepCode": "STEP_1", "abilityKey": "dim", "abilityParam": "{\"level\": 60}"},
+     {"stepType": "ABILITY", "stepName": "储能放电", "stepIndex": 4, "abilityKey": "discharge", "paramSource": "STATIC"}
+   ],
+   "context": [
+     {"varKey": "responseLevel", "varName": "响应级别", "varType": "INPUT", "dataType": "NUMBER"},
+     {"varKey": "duration", "varName": "响应时长", "varType": "INPUT", "dataType": "NUMBER"}
+   ]
+ }',
+ 'el-icon-s-marketing', '需求响应,负荷控制,电网互动', 'ESS,HVAC,LIGHT', 3, 1, 1),
+
+-- 应急保供模板
+('TPL_EMERGENCY', '应急保供-电网故障切换', 'EMERGENCY',
+ '当检测到电网故障时,自动切换到储能供电模式,保障关键负荷持续运行。',
+ '{
+   "triggers": [
+     {"triggerType": "EVENT", "triggerName": "电网故障", "sourceObjType": 2, "eventKey": "gridFault"}
+   ],
+   "steps": [
+     {"stepType": "ABILITY", "stepName": "切断非关键负荷", "stepIndex": 1, "abilityKey": "disconnect"},
+     {"stepType": "DELAY", "stepName": "等待切换", "stepIndex": 2, "delaySeconds": 2},
+     {"stepType": "ABILITY", "stepName": "启动储能放电", "stepIndex": 3, "abilityKey": "discharge", "abilityParam": "{\"mode\": \"island\"}"},
+     {"stepType": "ABILITY", "stepName": "发送告警通知", "stepIndex": 4, "abilityKey": "sendAlert"}
+   ],
+   "context": [
+     {"varKey": "gridStatus", "varName": "电网状态", "varType": "INPUT", "dataType": "STRING"},
+     {"varKey": "essAvailable", "varName": "储能可用", "varType": "INPUT", "dataType": "BOOLEAN"}
+   ]
+ }',
+ 'el-icon-warning-outline', '应急,故障切换,保供', 'ESS,GRID', 4, 1, 1),
+
+-- 节能优化模板
+('TPL_ENERGY_SAVE', '节能优化-智能照明', 'ENERGY_SAVE',
+ '根据环境光照和人员存在情况,自动调节照明亮度,实现节能优化。',
+ '{
+   "triggers": [
+     {"triggerType": "ATTR", "triggerName": "光照变化", "sourceObjType": 2, "attrKey": "illuminance"},
+     {"triggerType": "ATTR", "triggerName": "人员检测", "sourceObjType": 2, "attrKey": "occupancy"}
+   ],
+   "steps": [
+     {"stepType": "CONDITION", "stepName": "检查人员存在", "stepIndex": 1, "conditionExpr": "{\"left\":\"sensor.occupancy\",\"op\":\"==\",\"right\":true}"},
+     {"stepType": "CONDITION", "stepName": "检查光照不足", "stepIndex": 2, "conditionExpr": "{\"left\":\"sensor.illuminance\",\"op\":\"<\",\"right\":300}"},
+     {"stepType": "ABILITY", "stepName": "开启照明", "stepIndex": 3, "abilityKey": "setLevel", "abilityParam": "{\"level\": 80}"}
+   ],
+   "context": [
+     {"varKey": "targetIlluminance", "varName": "目标照度", "varType": "INPUT", "dataType": "NUMBER", "defaultValue": "500"}
+   ]
+ }',
+ 'el-icon-odometer', '节能,照明,智能控制', 'LIGHT,SENSOR', 5, 1, 1);
+
+-- ----------------------------
+-- 策略触发条件表
+-- ----------------------------
+drop table if exists adm_op_energy_strategy_trigger;
+CREATE TABLE adm_op_energy_strategy_trigger (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '序号',
+  `strategy_code` VARCHAR(16) NOT NULL COMMENT '策略代码',
+  `trigger_name` VARCHAR(64) NOT NULL COMMENT '触发器名称',
+  `trigger_type` VARCHAR(32) NOT NULL COMMENT '触发类型:EVENT-事件,ATTR-属性变化,TIME-时间,CONDITION-条件',
+  `source_obj_type` INT DEFAULT NULL COMMENT '源对象类型:2-设备,3-系统',
+  `source_obj_code` VARCHAR(64) DEFAULT NULL COMMENT '源对象代码',
+  `source_model_code` VARCHAR(64) DEFAULT NULL COMMENT '源对象模型代码',
+  `event_key` VARCHAR(128) DEFAULT NULL COMMENT '事件标识',
+  `attr_key` VARCHAR(128) DEFAULT NULL COMMENT '属性标识',
+  `condition_expr` TEXT DEFAULT NULL COMMENT '条件表达式(JSON)',
+  `enable` INT DEFAULT 1 COMMENT '是否启用',
+  `priority` INT DEFAULT 50 COMMENT '优先级',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  KEY `idx_strategy_code` (`strategy_code`),
+  KEY `idx_source_obj` (`source_obj_code`),
+  KEY `idx_event_key` (`event_key`)
+) ENGINE=INNODB AUTO_INCREMENT=1 COMMENT='策略触发条件表';
 
 
 -- ----------------------------
@@ -922,19 +1099,109 @@ create table adm_op_energy_strategy_param  (
 -- 能源策略步骤
 -- ----------------------------
 drop table if exists adm_op_energy_strategy_step;
-create table adm_op_energy_strategy_step  (
-  `id`                bigint(20)      not null auto_increment      comment '序号',
-  `strategy_code`     varchar(16)     not null                     comment '策略代码',
-  `step_code`         varchar(16)     not null                     comment '步骤代码',
-  `step_name`         varchar(32)     not null                     comment '步骤名称',
-  `step_index`        int             not null                     comment '步骤顺序',
-  `step_handler`      varchar(128)    not null                     comment '步骤处理',
-  `step_param`        varchar(256)    default null                 comment '步骤参数',
-  `target_facs`       varchar(16)     default null                 comment '目标设施',
-  `target_device`     varchar(16)     default null                 comment '目标设备',
-  primary key (`id`),
-  unique key ux_op_energy_strategy_step_key(`strategy_code`,`step_code`,`step_index`)
-) engine=innodb auto_increment=1 comment = '能源策略步骤';
+CREATE TABLE adm_op_energy_strategy_step (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '序号',
+  `strategy_code` VARCHAR(16) NOT NULL COMMENT '策略代码',
+  `step_code` VARCHAR(32) NOT NULL COMMENT '步骤代码',
+  `step_name` VARCHAR(64) NOT NULL COMMENT '步骤名称',
+  `step_type` VARCHAR(32) NOT NULL COMMENT '步骤类型:ABILITY-能力调用,DELAY-延时,CONDITION-条件判断,PARALLEL-并行,LOOP-循环',
+  `step_index` INT NOT NULL COMMENT '步骤顺序',
+  `parent_step_code` VARCHAR(32) DEFAULT NULL COMMENT '父步骤代码(用于嵌套)',
+  `condition_expr` TEXT DEFAULT NULL COMMENT '执行条件(JSON表达式)',
+  `target_obj_type` INT DEFAULT NULL COMMENT '目标对象类型:2-设备,3-系统',
+  `target_obj_code` VARCHAR(64) DEFAULT NULL COMMENT '目标对象代码',
+  `target_model_code` VARCHAR(64) DEFAULT NULL COMMENT '目标模型代码',
+  `ability_key` VARCHAR(128) DEFAULT NULL COMMENT '能力标识',
+  `ability_param` TEXT DEFAULT NULL COMMENT '能力参数(JSON)',
+  `param_source` VARCHAR(32) DEFAULT 'STATIC' COMMENT '参数来源:STATIC-静态,CONTEXT-上下文,ATTR-属性值',
+  `param_mapping` TEXT DEFAULT NULL COMMENT '参数映射配置(JSON)',
+  `delay_seconds` INT DEFAULT 0 COMMENT '延时秒数',
+  `retry_on_fail` INT DEFAULT 0 COMMENT '失败是否重试',
+  `retry_times` INT DEFAULT 0 COMMENT '重试次数',
+  `retry_interval` INT DEFAULT 5 COMMENT '重试间隔(秒)',
+  `continue_on_fail` INT DEFAULT 0 COMMENT '失败是否继续',
+  `timeout` INT DEFAULT 60 COMMENT '超时时间(秒)',
+  `enable` INT DEFAULT 1 COMMENT '是否启用',
+  `remark` VARCHAR(256) DEFAULT NULL COMMENT '备注',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `ux_strategy_step` (`strategy_code`, `step_code`),
+  KEY `idx_step_index` (`strategy_code`, `step_index`),
+  KEY `idx_parent_step` (`parent_step_code`)
+) ENGINE=INNODB AUTO_INCREMENT=1 COMMENT='能源策略步骤表';
+
+-- ----------------------------
+-- 策略执行日志表
+-- ----------------------------
+drop table if exists adm_op_energy_strategy_exec_log;
+CREATE TABLE adm_op_energy_strategy_exec_log (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '序号',
+  `strategy_code` VARCHAR(16) NOT NULL COMMENT '策略代码',
+  `exec_id` VARCHAR(64) NOT NULL COMMENT '执行ID(UUID)',
+  `trigger_type` VARCHAR(32) DEFAULT NULL COMMENT '触发类型',
+  `trigger_source` VARCHAR(128) DEFAULT NULL COMMENT '触发源',
+  `exec_status` INT NOT NULL COMMENT '执行状态:0-执行中,1-成功,2-失败,3-超时',
+  `start_time` DATETIME NOT NULL COMMENT '开始时间',
+  `end_time` DATETIME DEFAULT NULL COMMENT '结束时间',
+  `duration` INT DEFAULT NULL COMMENT '执行时长(毫秒)',
+  `context_data` TEXT DEFAULT NULL COMMENT '执行上下文(JSON)',
+  `result_data` TEXT DEFAULT NULL COMMENT '执行结果(JSON)',
+  `error_message` TEXT DEFAULT NULL COMMENT '错误信息',
+  `exec_by` VARCHAR(64) DEFAULT NULL COMMENT '执行人',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `ux_exec_id` (`exec_id`),
+  KEY `idx_strategy_code` (`strategy_code`),
+  KEY `idx_start_time` (`start_time`),
+  KEY `idx_exec_status` (`exec_status`)
+) ENGINE=INNODB AUTO_INCREMENT=1 COMMENT='策略执行日志表';
+
+
+-- ----------------------------
+-- 策略步骤执行日志表
+-- ----------------------------
+drop table if exists adm_op_energy_strategy_step_log;
+CREATE TABLE adm_op_energy_strategy_step_log (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '序号',
+  `exec_id` VARCHAR(64) NOT NULL COMMENT '策略执行ID',
+  `strategy_code` VARCHAR(16) NOT NULL COMMENT '策略代码',
+  `step_code` VARCHAR(32) NOT NULL COMMENT '步骤代码',
+  `step_name` VARCHAR(64) NOT NULL COMMENT '步骤名称',
+  `step_index` INT NOT NULL COMMENT '步骤顺序',
+  `exec_status` INT NOT NULL COMMENT '执行状态:0-执行中,1-成功,2-失败,3-跳过',
+  `start_time` DATETIME NOT NULL COMMENT '开始时间',
+  `end_time` DATETIME DEFAULT NULL COMMENT '结束时间',
+  `duration` INT DEFAULT NULL COMMENT '执行时长(毫秒)',
+  `input_param` TEXT DEFAULT NULL COMMENT '输入参数',
+  `output_result` TEXT DEFAULT NULL COMMENT '输出结果',
+  `error_message` TEXT DEFAULT NULL COMMENT '错误信息',
+  `retry_count` INT DEFAULT 0 COMMENT '重试次数',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`),
+  KEY `idx_exec_id` (`exec_id`),
+  KEY `idx_strategy_step` (`strategy_code`, `step_code`)
+) ENGINE=INNODB AUTO_INCREMENT=1 COMMENT='策略步骤执行日志表';
+
+
+-- ----------------------------
+-- 策略上下文变量表
+-- ----------------------------
+drop table if exists adm_op_energy_strategy_context;
+CREATE TABLE adm_op_energy_strategy_context (
+  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '序号',
+  `strategy_code` VARCHAR(16) NOT NULL COMMENT '策略代码',
+  `var_key` VARCHAR(64) NOT NULL COMMENT '变量键',
+  `var_name` VARCHAR(128) NOT NULL COMMENT '变量名称',
+  `var_type` VARCHAR(32) NOT NULL COMMENT '变量类型:INPUT-输入,OUTPUT-输出,TEMP-临时',
+  `data_type` VARCHAR(32) DEFAULT 'STRING' COMMENT '数据类型:STRING,NUMBER,BOOLEAN,OBJECT',
+  `default_value` TEXT DEFAULT NULL COMMENT '默认值',
+  `value_source` VARCHAR(64) DEFAULT NULL COMMENT '值来源:设备代码.属性键',
+  `description` VARCHAR(256) DEFAULT NULL COMMENT '描述',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `ux_strategy_var` (`strategy_code`, `var_key`)
+) ENGINE=INNODB AUTO_INCREMENT=1 COMMENT='策略上下文变量表';
 
 
 -- ----------------------------

+ 7 - 1
ems/sql/ems_sys_data.sql

@@ -42,7 +42,7 @@ insert into sys_menu values ('113',  '负荷',            '2',    '3',  'strateg
 insert into sys_menu values ('114',  '配电',            '2',    '4',  'powerdist',          'mgr/powerdist',             '', 1, 0, 'C', '0', '1',   'power-mgr:dist',         'powerdist',      'admin', sysdate(), '', null, '配电监控');
 insert into sys_menu values ('115',  '充电桩',          '2',    '5',  'charging-pile',      'mgr/chargingpile',          '', 1, 0, 'C', '0', '0',   'power-mgr:chargingpile', 'chargingpile',   'admin', sysdate(), '', null, '充电桩');
 insert into sys_menu values ('116',  '计费',            '2',    '6',  'charging',           'mgr/charging',              '', 1, 0, 'C', '0', '0',   'power-mgr:charging',     'charging',       'admin', sysdate(), '', null, '计费');
-insert into sys_menu values ('117',  '策略',            '2',    '7',  'strategy-mgr',       'mgr/strategy',              '', 1, 0, 'C', '0', '0',   'power-mgr:strategy',     'strategy',       'admin', sysdate(), '', null, '管能策略');
+insert into sys_menu values ('117',  '策略',            '2', '7',     'strategy-mgr',        null,                       '', 1, 0, 'M', '0', '0',   'power-mgr:strategy',     'strategy',       'admin', sysdate(), '', null, '策略');
 
 insert into sys_menu values ('126',  '产能分析',       '3',    '1',  'power-prod',         'analysis/power/prod',       '', 1, 0, 'C', '0', '0',    'analysis:power:prod',    'energyprod',     'admin', sysdate(), '', null, '产能分析');
 insert into sys_menu values ('127',  '储能分析',       '3',    '2',  'power-store',        'analysis/power/store',      '', 1, 0, 'C', '0', '0',    'analysis:power:store',   'energystore',    'admin', sysdate(), '', null, '储能分析');
@@ -80,6 +80,12 @@ insert into sys_menu values ('178',  '日志管理',       '7',   '9',  'log',
 insert into sys_menu values ('179',  '在线用户',       '7',   '10', 'online',             'monitor/online/index',   '', 1, 0, 'C', '0', '0',   'monitor:online:list',    'online',         'admin', sysdate(), '', null, '在线用户菜单');
 INSERT INTO sys_menu VALUES ('180',  '任务调度',       '7',   '10', 'task/job',           'monitor/job/index',      '', 1, 0, 'C', '0', '0',   'monitor:job',            'date-range',     'admin', sysdate(), '', NULL, '任务调度');
 
+insert into sys_menu values ('1170',  '策略中心',       '117',   '1',  'strategy-index',     'mgr/strategy/index',       '', 1, 0, 'C', '0', '0',   'power-mgr:strategy:list',     'system',       'admin', sysdate(), '', null, '能耗监测');
+insert into sys_menu values ('1171',  '策略编排',       '117',   '2',  'strategy-editor',    'mgr/strategy/editor',      '', 1, 0, 'C', '0', '0',   'power-mgr:strategy:edit',     'system',        'admin', sysdate(), '', null, '智慧照明');
+insert into sys_menu values ('1172',  '策略模板',       '117',   '3',  'strategy-template',  'mgr/strategy/template',    '', 1, 0, 'C', '0', '0',   'power-mgr:strategy:list',     'system',        'admin', sysdate(), '', null, '智慧照明');
+insert into sys_menu values ('1173',  '策略日志',       '117',   '4',  'strategy-log',       'mgr/strategy/log',          '', 1, 0, 'C', '0', '0',   'power-mgr:strategy:list',     'system',        'admin', sysdate(), '', null, '智慧照明');
+
+
 insert into sys_menu values ('1550',  '楼控能耗',       '155',   '1',  'adapter-nhjc',       'adapter/nhjc/index',    '', 1, 0, 'C', '0', '0',   'adapter:devc:list',     'system',       'admin', sysdate(), '', null, '能耗监测');
 insert into sys_menu values ('1551',  '智慧照明',       '155',   '2',  'adapter-zm',         'adapter/zm/index',      '', 1, 0, 'C', '0', '0',   'adapter:devc:list',     'system',        'admin', sysdate(), '', null, '智慧照明');
 insert into sys_menu values ('1552',  '电力监控',       '155',   '3',  'adapter-dljk',       'adapter/dljk/index',    '', 1, 0, 'C', '0', '0',   'adapter:devc:list',     'system',        'admin', sysdate(), '', null, '智慧照明');