Bläddra i källkod

feat: 添加统计柱形图

wuwenyi 2 veckor sedan
förälder
incheckning
82f3dc09df

+ 8 - 0
src/main/java/com/qqflow/engine/domain/flow/controller/AnalysisController.java

@@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 流程数据分析看板
@@ -75,6 +76,13 @@ public class AnalysisController {
         return Result.ok(analysisService.inProgressByNode(processDefinitionId));
     }
 
+    @GetMapping("/node-count")
+    @Operation(summary = "各节点流程实例数量统计")
+    public Result<List<Map<String, Object>>> nodeCount(
+            @RequestParam Long processDefinitionId) {
+        return Result.ok(analysisService.nodeCountByDefinition(processDefinitionId));
+    }
+
     @GetMapping("/stuck-instances")
     @Operation(summary = "节点下钻明细(卡住流程实例)")
     public Result<PageResult<StuckInstanceDTO>> stuckInstances(

+ 4 - 0
src/main/java/com/qqflow/engine/domain/flow/service/AnalysisService.java

@@ -10,6 +10,7 @@ import com.qqflow.engine.domain.flow.dto.analysis.TrendDTO;
 
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 流程数据分析服务
@@ -74,4 +75,7 @@ public interface AnalysisService {
      * @return 趋势列表
      */
     List<TrendDTO> trend(Long processDefinitionId);
+
+    /** 各节点流程实例数量统计 */
+    List<Map<String, Object>> nodeCountByDefinition(Long processDefinitionId);
 }

+ 55 - 0
src/main/java/com/qqflow/engine/domain/flow/service/impl/AnalysisServiceImpl.java

@@ -8,8 +8,16 @@ import com.qqflow.engine.domain.flow.dto.analysis.ProcessEfficiencyDTO;
 import com.qqflow.engine.domain.flow.dto.analysis.StuckInstanceDTO;
 import com.qqflow.engine.domain.flow.dto.analysis.StatusDistributionDTO;
 import com.qqflow.engine.domain.flow.dto.analysis.TrendDTO;
+import com.qqflow.engine.common.exception.BusinessException;
 import com.qqflow.engine.domain.flow.mapper.AnalysisMapper;
+import com.qqflow.engine.domain.flow.mapper.ProcessDefinitionMapper;
+import com.qqflow.engine.domain.flow.mapper.ProcessInstanceMapper;
+import com.qqflow.engine.domain.flow.model.FlowModel;
+import com.qqflow.engine.domain.flow.model.FlowNode;
+import com.qqflow.engine.domain.flow.po.ProcessDefinition;
+import com.qqflow.engine.domain.flow.po.ProcessInstance;
 import com.qqflow.engine.domain.flow.service.AnalysisService;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
@@ -18,6 +26,7 @@ import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -32,6 +41,8 @@ public class AnalysisServiceImpl implements AnalysisService {
 
     private final AnalysisMapper analysisMapper;
     private final RedisCache redisCache;
+    private final ProcessDefinitionMapper processDefinitionMapper;
+    private final ProcessInstanceMapper processInstanceMapper;
 
     private static final String KEY_COMPLETED_EFFICIENCY = "analysis:completed-efficiency:%s:%s:%s";
     private static final String KEY_IN_PROGRESS_BY_NODE = "analysis:in-progress-by-node:%s";
@@ -178,4 +189,48 @@ public class AnalysisServiceImpl implements AnalysisService {
             default -> "未知";
         };
     }
+
+    @Override
+    public List<Map<String, Object>> nodeCountByDefinition(Long processDefinitionId) {
+        ProcessDefinition def = this.processDefinitionMapper.selectById(processDefinitionId);
+        if (def == null || def.getModelJson() == null) {
+            throw new BusinessException("流程定义不存在");
+        }
+        try {
+            FlowModel model = new ObjectMapper().readValue(def.getModelJson(), FlowModel.class);
+            Map<String, String> nodeNameMap = new HashMap<>();
+            if (model.getNodes() != null) {
+                for (FlowNode node : model.getNodes()) {
+                    nodeNameMap.put(node.getId(), node.getName());
+                }
+            }
+            // 查询该流程下所有实例,按当前节点分组统计
+            List<ProcessInstance> instances = this.processInstanceMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProcessInstance>()
+                            .eq(ProcessInstance::getProcessDefinitionId, processDefinitionId)
+                            .eq(ProcessInstance::getDeleted, 0));
+            Map<String, Long> countMap = new HashMap<>();
+            for (ProcessInstance pi : instances) {
+                if (pi.getCurrentNodeId() != null) {
+                    countMap.merge(pi.getCurrentNodeId(), 1L, Long::sum);
+                }
+            }
+            List<Map<String, Object>> result = new ArrayList<>();
+            if (model.getNodes() != null) {
+                for (FlowNode node : model.getNodes()) {
+                    String type = node.getType();
+                    if ("start".equals(type) || "end".equals(type) || "condition".equals(type) || "cc".equals(type)) {
+                        continue;
+                    }
+                    Map<String, Object> item = new LinkedHashMap<>();
+                    item.put("nodeName", node.getName());
+                    item.put("count", countMap.getOrDefault(node.getId(), 0L));
+                    result.add(item);
+                }
+            }
+            return result;
+        } catch (Exception e) {
+            throw new BusinessException("流程模型解析失败");
+        }
+    }
 }