From 76743b009ca5ea67557fcab597b332f8d1947813 Mon Sep 17 00:00:00 2001
From: dengzedong <dengzedong@email>
Date: 星期二, 24 十二月 2024 14:09:04 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java      |   13 +++
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java   |   13 +++
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java          |    6 +
 iailab-module-data/iailab-module-data-biz/src/main/resources/application.yaml                                                                                           |    2 
 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java                                                      |    5 +
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java                                  |    1 
 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/PointCollector.java                                                     |   24 +++++
 pom.xml                                                                                                                                                                 |    4 
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java               |    2 
 /dev/null                                                                                                                                                               |   43 ----------
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java            |    2 
 iailab-cloud/iailab-gateway/src/main/resources/application.yaml                                                                                                         |    2 
 iailab-module-infra/iailab-module-infra-biz/src/main/resources/application.yaml                                                                                         |    4 
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java |   13 +++
 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CumulateHandle.java                                             |   13 +++
 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java                                          |    2 
 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/MeasureHandle.java                                              |   16 +++-
 iailab-module-model/iailab-module-model-biz/src/main/resources/application.yml                                                                                          |    2 
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/controller/admin/task/BpmTaskController.java                                                |    6 +
 iailab-module-system/iailab-module-system-biz/src/main/resources/application.yaml                                                                                       |    4 
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/service/task/BpmTaskServiceImpl.java                                                        |    2 
 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CalculateHandle.java                                            |   30 +++++--
 22 files changed, 133 insertions(+), 76 deletions(-)

diff --git a/iailab-cloud/iailab-gateway/src/main/resources/application.yaml b/iailab-cloud/iailab-gateway/src/main/resources/application.yaml
index 600cd0a..3f5f03f 100644
--- a/iailab-cloud/iailab-gateway/src/main/resources/application.yaml
+++ b/iailab-cloud/iailab-gateway/src/main/resources/application.yaml
@@ -148,7 +148,7 @@
 
 logging:
   file:
-    name: @log.path@/logs/${spring.application.name}.log # 日志文件名,全路径
+    name: @log.path@/iailab-gateway/log/${spring.application.name}.log # 日志文件名,全路径
 
 knife4j:
   # 聚合 Swagger 文档,参考 https://doc.xiaominfo.com/docs/action/springcloud-gateway 文档
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/controller/admin/task/BpmTaskController.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/controller/admin/task/BpmTaskController.java
index cdd7713..865b26b 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/controller/admin/task/BpmTaskController.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/controller/admin/task/BpmTaskController.java
@@ -4,6 +4,7 @@
 import com.iailab.framework.common.pojo.CommonResult;
 import com.iailab.framework.common.pojo.PageResult;
 import com.iailab.framework.common.util.number.NumberUtils;
+import com.iailab.framework.datapermission.core.annotation.DataPermission;
 import com.iailab.module.bpm.controller.admin.task.vo.task.*;
 import com.iailab.module.bpm.convert.task.BpmTaskConvert;
 import com.iailab.module.bpm.dal.dataobject.definition.BpmFormDO;
@@ -60,6 +61,7 @@
     @GetMapping("todo-page")
     @Operation(summary = "获取 Todo 待办任务分页")
     @PreAuthorize("@ss.hasPermission('bpm:task:query')")
+    @DataPermission(enable = false) // 关闭数据权限,避免只查看自己时,查询不到部门。
     public CommonResult<PageResult<BpmTaskRespVO>> getTaskTodoPage(@Valid BpmTaskPageReqVO pageVO) {
         PageResult<Task> pageResult = taskService.getTaskTodoPage(getLoginUserId(), pageVO);
         if (CollUtil.isEmpty(pageResult.getList())) {
@@ -69,9 +71,11 @@
         // 拼接数据
         Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
                 convertSet(pageResult.getList(), Task::getProcessInstanceId));
+        // TODO 此处有bug
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                 convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
-        return success(BpmTaskConvert.INSTANCE.buildTodoTaskPage(pageResult, processInstanceMap, userMap));
+        PageResult<BpmTaskRespVO> bpmTaskRespVOPageResult = BpmTaskConvert.INSTANCE.buildTodoTaskPage(pageResult, processInstanceMap, userMap);
+        return success(bpmTaskRespVOPageResult);
     }
 
     @GetMapping("done-page")
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
index d368f77..a5d1d7f 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
@@ -4,6 +4,7 @@
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.iailab.framework.common.util.number.NumberUtils;
+import com.iailab.framework.datapermission.core.annotation.DataPermission;
 import com.iailab.module.bpm.enums.definition.BpmBoundaryEventType;
 import com.iailab.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
 import com.iailab.module.bpm.framework.flowable.core.util.BpmnModelUtils;
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java
index bef1ecf..bd827bb 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java
@@ -1,8 +1,12 @@
 package com.iailab.module.bpm.framework.flowable.core.listener.demo.exection;
 
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.flowable.bpmn.model.FieldExtension;
 import org.flowable.engine.delegate.DelegateExecution;
 import org.flowable.engine.delegate.JavaDelegate;
+
+import java.util.List;
 
 /**
  * 类型为 class 的 ExecutionListener 监听器示例
@@ -14,8 +18,15 @@
 
     @Override
     public void execute(DelegateExecution execution) {
-        log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(),
+        log.info("[execute][execution({}) 执行监听器(类)被调用!变量有:{}]", execution.getId(),
                 execution.getCurrentFlowableListener().getFieldExtensions());
+        List<FieldExtension> fieldExtensions = execution.getCurrentFlowableListener().getFieldExtensions();
+        if(ObjectUtils.isNotEmpty(fieldExtensions)) {
+            fieldExtensions.stream().forEach(fieldExtension -> {
+                System.out.println(fieldExtension.getFieldName());
+                System.out.println(fieldExtension.getExpression());
+            });
+        }
     }
 
 }
\ No newline at end of file
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java
index 9836a6d..833e23e 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java
@@ -1,9 +1,13 @@
 package com.iailab.module.bpm.framework.flowable.core.listener.demo.exection;
 
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.flowable.bpmn.model.FieldExtension;
 import org.flowable.engine.delegate.DelegateExecution;
 import org.flowable.engine.delegate.JavaDelegate;
 import org.springframework.stereotype.Component;
+
+import java.util.List;
 
 /**
  * 类型为 delegateExpression 的 ExecutionListener 监听器示例
@@ -16,8 +20,15 @@
 
     @Override
     public void execute(DelegateExecution execution) {
-        log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(),
+        log.info("[execute][execution({}) 执行监听器(委托表达式被调用)!变量有:{}]", execution.getId(),
                 execution.getCurrentFlowableListener().getFieldExtensions());
+        List<FieldExtension> fieldExtensions = execution.getCurrentFlowableListener().getFieldExtensions();
+        if(ObjectUtils.isNotEmpty(fieldExtensions)) {
+            fieldExtensions.stream().forEach(fieldExtension -> {
+                System.out.println(fieldExtension.getFieldName());
+                System.out.println(fieldExtension.getStringValue());
+            });
+        }
     }
 
 }
\ No newline at end of file
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java
index ce35c3c..69d7665 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java
@@ -1,8 +1,12 @@
 package com.iailab.module.bpm.framework.flowable.core.listener.demo.exection;
 
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.flowable.bpmn.model.FieldExtension;
 import org.flowable.engine.delegate.DelegateExecution;
 import org.springframework.stereotype.Component;
+
+import java.util.List;
 
 /**
  * 类型为 expression 的 ExecutionListener 监听器示例
@@ -14,8 +18,15 @@
 public class DemoSpringExpressionExecutionListener {
 
     public void execute(DelegateExecution execution) {
-        log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(),
+        log.info("[execute][execution({}) 执行监听器(spring表达式)被调用!变量有:{}]", execution.getId(),
                 execution.getCurrentFlowableListener().getFieldExtensions());
+        List<FieldExtension> fieldExtensions = execution.getCurrentFlowableListener().getFieldExtensions();
+        if(ObjectUtils.isNotEmpty(fieldExtensions)) {
+            fieldExtensions.stream().forEach(fieldExtension -> {
+                System.out.println(fieldExtension.getFieldName());
+                System.out.println(fieldExtension.getExpression());
+            });
+        }
     }
 
 }
\ No newline at end of file
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java
index b82b7ec..bd6cf18 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java
@@ -14,7 +14,7 @@
 
     @Override
     public void notify(DelegateTask delegateTask) {
-        log.info("[execute][task({}) 被调用]", delegateTask.getId());
+        log.info("[execute][task({}) 任务监听器(类)被调用]", delegateTask.getId());
     }
 
 }
\ No newline at end of file
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java
index 37c7425..24e9d63 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionTaskListener.java
@@ -5,6 +5,8 @@
 import org.flowable.task.service.delegate.DelegateTask;
 import org.springframework.stereotype.Component;
 
+import java.util.Map;
+
 /**
  * 类型为 delegateExpression 的 TaskListener 监听器示例
  *
@@ -16,7 +18,9 @@
 
     @Override
     public void notify(DelegateTask delegateTask) {
-        log.info("[execute][task({}) 被调用]", delegateTask.getId());
+        log.info("[execute][task({}) 任务监听器(委托表达式)被调用]", delegateTask.getId());
+        Map<String, Object> variables = delegateTask.getVariables();
+        System.out.println(variables.toString());;
     }
 
 }
\ No newline at end of file
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java
index 15c71ea..9be3f72 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java
@@ -14,7 +14,7 @@
 public class DemoSpringExpressionTaskListener {
 
     public void notify(DelegateTask delegateTask) {
-        log.info("[execute][task({}) 被调用]", delegateTask.getId());
+        log.info("[execute][task({}) 任务监听器(spring表达式)被调用]", delegateTask.getId());
     }
 
 }
\ No newline at end of file
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/service/task/BpmTaskServiceImpl.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/service/task/BpmTaskServiceImpl.java
index 2a6a3a1..b63071e 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/service/task/BpmTaskServiceImpl.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -9,6 +9,7 @@
 import com.iailab.framework.common.util.number.NumberUtils;
 import com.iailab.framework.common.util.object.ObjectUtils;
 import com.iailab.framework.common.util.object.PageUtils;
+import com.iailab.framework.datapermission.core.annotation.DataPermission;
 import com.iailab.framework.web.core.util.WebFrameworkUtils;
 import com.iailab.module.bpm.controller.admin.task.vo.task.*;
 import com.iailab.module.bpm.convert.task.BpmTaskConvert;
@@ -1145,7 +1146,6 @@
                         }
                     }
                 }
-
                 AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())).getCheckedData();
                 messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
             }
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java
deleted file mode 100644
index f5266aa..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate;
-
-import cn.hutool.core.map.MapUtil;
-import com.iailab.framework.common.enums.CommonStatusEnum;
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import com.iailab.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateUserStrategy;
-import com.iailab.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
-import com.iailab.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
-import com.iailab.module.system.api.user.AdminUserApi;
-import com.iailab.module.system.api.user.dto.AdminUserRespDTO;
-import org.flowable.bpmn.model.UserTask;
-import org.flowable.engine.delegate.DelegateExecution;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Spy;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static com.iailab.framework.test.core.util.RandomUtils.randomPojo;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * {@link BpmTaskCandidateInvoker} 的单元测试
- *
- * @author iailab
- */
-public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidateInvoker taskCandidateInvoker;
-
-    @Mock
-    private AdminUserApi adminUserApi;
-    @Spy
-    private BpmTaskCandidateStrategy strategy = new BpmTaskCandidateUserStrategy();
-    @Spy
-    private List<BpmTaskCandidateStrategy> strategyList = Collections.singletonList(strategy);
-
-    @Test
-    public void testCalculateUsers() {
-        // 准备参数
-        String param = "1,2";
-        DelegateExecution execution = mock(DelegateExecution.class);
-        // mock 方法(DelegateExecution)
-        UserTask userTask = mock(UserTask.class);
-        when(execution.getCurrentFlowElement()).thenReturn(userTask);
-        when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)))
-                .thenReturn(BpmTaskCandidateStrategyEnum.USER.getStrategy().toString());
-        when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)))
-                .thenReturn(param);
-        // mock 方法(adminUserApi)
-        AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L)
-                .setStatus(CommonStatusEnum.ENABLE.getStatus()));
-        AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L)
-                .setStatus(CommonStatusEnum.ENABLE.getStatus()));
-        Map<Long, AdminUserRespDTO> userMap = MapUtil.builder(user1.getId(), user1)
-                .put(user2.getId(), user2).build();
-        when(adminUserApi.getUserMap(eq(asSet(1L, 2L)))).thenReturn(userMap);
-
-        // 调用
-        Set<Long> results = taskCandidateInvoker.calculateUsers(execution);
-        // 断言
-        assertEquals(asSet(1L, 2L), results);
-    }
-
-    @Test
-    public void testRemoveDisableUsers() {
-        // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到
-        Set<Long> assigneeUserIds = asSet(1L, 2L, 3L);
-        // mock 方法
-        AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L)
-                .setStatus(CommonStatusEnum.ENABLE.getStatus()));
-        AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L)
-                .setStatus(CommonStatusEnum.DISABLE.getStatus()));
-        Map<Long, AdminUserRespDTO> userMap = MapUtil.builder(user1.getId(), user1)
-                .put(user2.getId(), user2).build();
-        when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap);
-
-        // 调用
-        taskCandidateInvoker.removeDisableUsers(assigneeUserIds);
-        // 断言
-        assertEquals(asSet(1L), assigneeUserIds);
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java
deleted file mode 100644
index 469b898..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.expression;
-
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import com.iailab.module.bpm.service.task.BpmProcessInstanceService;
-import com.iailab.module.system.api.dept.DeptApi;
-import com.iailab.module.system.api.dept.dto.DeptRespDTO;
-import com.iailab.module.system.api.user.AdminUserApi;
-import com.iailab.module.system.api.user.dto.AdminUserRespDTO;
-import org.flowable.engine.delegate.DelegateExecution;
-import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import java.util.Set;
-
-import static com.iailab.framework.common.pojo.CommonResult.success;
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static com.iailab.framework.test.core.util.RandomUtils.randomPojo;
-import static com.iailab.framework.test.core.util.RandomUtils.randomString;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-public class BpmTaskAssignLeaderExpressionTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskAssignLeaderExpression expression;
-
-    @Mock
-    private AdminUserApi adminUserApi;
-    @Mock
-    private DeptApi deptApi;
-
-    @Mock
-    private BpmProcessInstanceService processInstanceService;
-
-    @Test
-    public void testCalculateUsers_noDept() {
-        // 准备参数
-        DelegateExecution execution = mockDelegateExecution(1L);
-        // mock 方法(startUser)
-        AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
-        when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser));
-        // mock 方法(getStartUserDept)没有部门
-        when(deptApi.getDept(eq(10L))).thenReturn(success(null));
-
-        // 调用
-        Set<Long> result = expression.calculateUsers(execution, 1);
-        // 断言
-        assertEquals(0, result.size());
-    }
-
-    @Test
-    public void testCalculateUsers_noParentDept() {
-        // 准备参数
-        DelegateExecution execution = mockDelegateExecution(1L);
-        // mock 方法(startUser)
-        AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
-        when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser));
-        DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
-                .setLeaderUserId(20L));
-        // mock 方法(getDept)
-        when(deptApi.getDept(eq(10L))).thenReturn(success(startUserDept));
-        when(deptApi.getDept(eq(100L))).thenReturn(success(null));
-
-        // 调用
-        Set<Long> result = expression.calculateUsers(execution, 2);
-        // 断言
-        assertEquals(asSet(20L), result);
-    }
-
-    @Test
-    public void testCalculateUsers_existParentDept() {
-        // 准备参数
-        DelegateExecution execution = mockDelegateExecution(1L);
-        // mock 方法(startUser)
-        AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
-        when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser));
-        DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
-                .setLeaderUserId(20L));
-        when(deptApi.getDept(eq(10L))).thenReturn(success(startUserDept));
-        // mock 方法(父 dept)
-        DeptRespDTO parentDept = randomPojo(DeptRespDTO.class, o -> o.setId(100L).setParentId(1000L)
-                .setLeaderUserId(200L));
-        when(deptApi.getDept(eq(100L))).thenReturn(success(parentDept));
-
-        // 调用
-        Set<Long> result = expression.calculateUsers(execution, 2);
-        // 断言
-        assertEquals(asSet(200L), result);
-    }
-
-    @SuppressWarnings("SameParameterValue")
-    private DelegateExecution mockDelegateExecution(Long startUserId) {
-        ExecutionEntityImpl execution = new ExecutionEntityImpl();
-        execution.setProcessInstanceId(randomString());
-        // mock 返回 startUserId
-        ExecutionEntityImpl processInstance = new ExecutionEntityImpl();
-        processInstance.setStartUserId(String.valueOf(startUserId));
-        when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId())))
-                .thenReturn(processInstance);
-        return execution;
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java
deleted file mode 100644
index b35a123..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.strategy;
-
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import com.iailab.module.system.api.dept.DeptApi;
-import com.iailab.module.system.api.dept.dto.DeptRespDTO;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import java.util.Set;
-
-import static com.iailab.framework.common.pojo.CommonResult.success;
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static com.iailab.framework.test.core.util.RandomUtils.randomPojo;
-import static java.util.Arrays.asList;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-public class BpmTaskCandidateDeptLeaderStrategyTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidateDeptLeaderStrategy strategy;
-
-    @Mock
-    private DeptApi deptApi;
-
-    @Test
-    public void testCalculateUsers() {
-        // 准备参数
-        String param = "1,2";
-        // mock 方法
-        DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L));
-        DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L));
-        when(deptApi.getDeptList(eq(asSet(1L, 2L)))).thenReturn(success(asList(dept1, dept2)));
-
-        // 调用
-        Set<Long> results = strategy.calculateUsers(null, param);
-        // 断言
-        assertEquals(asSet(11L, 22L), results);
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java
deleted file mode 100644
index 0dc7321..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.strategy;
-
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import com.iailab.module.system.api.user.AdminUserApi;
-import com.iailab.module.system.api.user.dto.AdminUserRespDTO;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import java.util.List;
-import java.util.Set;
-
-import static com.iailab.framework.common.pojo.CommonResult.success;
-import static com.iailab.framework.common.util.collection.CollectionUtils.convertList;
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-public class BpmTaskCandidateDeptMemberStrategyTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidateDeptMemberStrategy strategy;
-
-    @Mock
-    private AdminUserApi adminUserApi;
-
-    @Test
-    public void testCalculateUsers() {
-        // 准备参数
-        String param = "11,22";
-        // mock 方法
-        List<AdminUserRespDTO> users = convertList(asSet(11L, 22L),
-                id -> new AdminUserRespDTO().setId(id));
-        when(adminUserApi.getUserListByDeptIds(eq(asSet(11L, 22L)))).thenReturn(success(users));
-
-        // 调用
-        Set<Long> results = strategy.calculateUsers(null, param);
-        // 断言
-        assertEquals(asSet(11L, 22L), results);
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java
deleted file mode 100644
index 152e16c..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.strategy;
-
-import com.iailab.module.bpm.framework.flowable.core.util.FlowableUtils;
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import org.flowable.engine.delegate.DelegateExecution;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.MockedStatic;
-
-import java.util.Set;
-
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.*;
-
-public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidateExpressionStrategy strategy;
-
-    @Test
-    public void testCalculateUsers() {
-        try (MockedStatic<FlowableUtils> flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) {
-            // 准备参数
-            String param = "1,2";
-            DelegateExecution execution = mock(DelegateExecution.class);
-            // mock 方法
-            flowableUtilMockedStatic.when(() -> FlowableUtils.getExpressionValue(same(execution), eq(param)))
-                    .thenReturn(asSet(1L, 2L));
-
-            // 调用
-            Set<Long> results = strategy.calculateUsers(execution, param);
-            // 断言
-            assertEquals(asSet(1L, 2L), results);
-        }
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java
deleted file mode 100644
index d488f32..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.strategy;
-
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import com.iailab.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
-import com.iailab.module.bpm.service.definition.BpmUserGroupService;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import java.util.Arrays;
-import java.util.Set;
-
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static com.iailab.framework.test.core.util.RandomUtils.randomPojo;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidateGroupStrategy strategy;
-
-    @Mock
-    private BpmUserGroupService userGroupService;
-
-    @Test
-    public void testCalculateUsers() {
-        // 准备参数
-        String param = "1,2";
-        // mock 方法
-        BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setUserIds(asSet(11L, 12L)));
-        BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setUserIds(asSet(21L, 22L)));
-        when(userGroupService.getUserGroupList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(userGroup1, userGroup2));
-
-        // 调用
-        Set<Long> results = strategy.calculateUsers(null, param);
-        // 断言
-        assertEquals(asSet(11L, 12L, 21L, 22L), results);
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java
deleted file mode 100644
index 7a6f0e1..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.strategy;
-
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import com.iailab.module.system.api.dept.PostApi;
-import com.iailab.module.system.api.user.AdminUserApi;
-import com.iailab.module.system.api.user.dto.AdminUserRespDTO;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import java.util.List;
-import java.util.Set;
-
-import static com.iailab.framework.common.pojo.CommonResult.success;
-import static com.iailab.framework.common.util.collection.CollectionUtils.convertList;
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidatePostStrategy strategy;
-
-    @Mock
-    private PostApi postApi;
-    @Mock
-    private AdminUserApi adminUserApi;
-
-    @Test
-    public void testCalculateUsers() {
-        // 准备参数
-        String param = "1,2";
-        // mock 方法
-        List<AdminUserRespDTO> users = convertList(asSet(11L, 22L),
-                id -> new AdminUserRespDTO().setId(id));
-        when(adminUserApi.getUserListByPostIds(eq(asSet(1L, 2L)))).thenReturn(success(users));
-
-        // 调用
-        Set<Long> results = strategy.calculateUsers(null, param);
-        // 断言
-        assertEquals(asSet(11L, 22L), results);
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java
deleted file mode 100644
index 45d6cc2..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.strategy;
-
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import com.iailab.module.system.api.permission.PermissionApi;
-import com.iailab.module.system.api.permission.RoleApi;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import java.util.Set;
-
-import static com.iailab.framework.common.pojo.CommonResult.success;
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidateRoleStrategy strategy;
-
-    @Mock
-    private RoleApi roleApi;
-    @Mock
-    private PermissionApi permissionApi;
-
-    @Test
-    public void testCalculateUsers() {
-        // 准备参数
-        String param = "1,2";
-        // mock 方法
-        when(permissionApi.getUserRoleIdListByRoleIds(eq(asSet(1L, 2L))))
-            .thenReturn(success(asSet(11L, 22L)));
-
-        // 调用
-        Set<Long> results = strategy.calculateUsers(null, param);
-        // 断言
-        assertEquals(asSet(11L, 22L), results);
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java
deleted file mode 100644
index 2277eb5..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.iailab.module.bpm.framework.flowable.core.candidate.strategy;
-
-import com.iailab.framework.test.core.ut.BaseMockitoUnitTest;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-
-import java.util.Set;
-
-import static com.iailab.framework.common.util.collection.SetUtils.asSet;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private BpmTaskCandidateUserStrategy strategy;
-
-    @Test
-    public void testCalculateUsers() {
-        // 准备参数
-        String param = "1,2";
-
-        // 调用
-        Set<Long> results = strategy.calculateUsers(null, param);
-        // 断言
-        assertEquals(asSet(1L, 2L), results);
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/category/BpmCategoryServiceImplTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/category/BpmCategoryServiceImplTest.java
deleted file mode 100644
index d07e3b7..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/category/BpmCategoryServiceImplTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package com.iailab.module.bpm.service.category;
-
-import com.iailab.framework.common.enums.CommonStatusEnum;
-import com.iailab.framework.common.pojo.PageResult;
-import com.iailab.framework.test.core.ut.BaseDbUnitTest;
-import com.iailab.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO;
-import com.iailab.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO;
-import com.iailab.module.bpm.dal.dataobject.definition.BpmCategoryDO;
-import com.iailab.module.bpm.dal.mysql.category.BpmCategoryMapper;
-import com.iailab.module.bpm.service.definition.BpmCategoryServiceImpl;
-import org.junit.jupiter.api.Test;
-import org.springframework.context.annotation.Import;
-
-import javax.annotation.Resource;
-
-import static com.iailab.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
-import static com.iailab.framework.common.util.date.LocalDateTimeUtils.buildTime;
-import static com.iailab.framework.common.util.object.ObjectUtils.cloneIgnoreId;
-import static com.iailab.framework.test.core.util.AssertUtils.assertPojoEquals;
-import static com.iailab.framework.test.core.util.AssertUtils.assertServiceException;
-import static com.iailab.framework.test.core.util.RandomUtils.*;
-import static com.iailab.module.bpm.enums.ErrorCodeConstants.CATEGORY_NOT_EXISTS;
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * {@link BpmCategoryServiceImpl} 的单元测试类
- *
- * @author iailab
- */
-@Import(BpmCategoryServiceImpl.class)
-public class BpmCategoryServiceImplTest extends BaseDbUnitTest {
-
-    @Resource
-    private BpmCategoryServiceImpl categoryService;
-
-    @Resource
-    private BpmCategoryMapper categoryMapper;
-
-    @Test
-    public void testCreateCategory_success() {
-        // 准备参数
-        BpmCategorySaveReqVO createReqVO = randomPojo(BpmCategorySaveReqVO.class).setId(null)
-                .setStatus(randomCommonStatus());
-
-        // 调用
-        Long categoryId = categoryService.createCategory(createReqVO);
-        // 断言
-        assertNotNull(categoryId);
-        // 校验记录的属性是否正确
-        BpmCategoryDO category = categoryMapper.selectById(categoryId);
-        assertPojoEquals(createReqVO, category, "id");
-    }
-
-    @Test
-    public void testUpdateCategory_success() {
-        // mock 数据
-        BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class);
-        categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        BpmCategorySaveReqVO updateReqVO = randomPojo(BpmCategorySaveReqVO.class, o -> {
-            o.setId(dbCategory.getId()); // 设置更新的 ID
-            o.setStatus(randomCommonStatus());
-        });
-
-        // 调用
-        categoryService.updateCategory(updateReqVO);
-        // 校验是否更新正确
-        BpmCategoryDO category = categoryMapper.selectById(updateReqVO.getId()); // 获取最新的
-        assertPojoEquals(updateReqVO, category);
-    }
-
-    @Test
-    public void testUpdateCategory_notExists() {
-        // 准备参数
-        BpmCategorySaveReqVO updateReqVO = randomPojo(BpmCategorySaveReqVO.class);
-
-        // 调用, 并断言异常
-        assertServiceException(() -> categoryService.updateCategory(updateReqVO), CATEGORY_NOT_EXISTS);
-    }
-
-    @Test
-    public void testDeleteCategory_success() {
-        // mock 数据
-        BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class);
-        categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        Long id = dbCategory.getId();
-
-        // 调用
-        categoryService.deleteCategory(id);
-       // 校验数据不存在了
-       assertNull(categoryMapper.selectById(id));
-    }
-
-    @Test
-    public void testDeleteCategory_notExists() {
-        // 准备参数
-        Long id = randomLongId();
-
-        // 调用, 并断言异常
-        assertServiceException(() -> categoryService.deleteCategory(id), CATEGORY_NOT_EXISTS);
-    }
-
-    @Test
-    public void testGetCategoryPage() {
-       // mock 数据
-       BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class, o -> { // 等会查询到
-           o.setName("芋头");
-           o.setCode("xiaodun");
-           o.setStatus(CommonStatusEnum.ENABLE.getStatus());
-           o.setCreateTime(buildTime(2023, 2, 2));
-       });
-       categoryMapper.insert(dbCategory);
-       // 测试 name 不匹配
-       categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName("小盾")));
-       // 测试 code 不匹配
-       categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCode("tudou")));
-       // 测试 status 不匹配
-       categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
-       // 测试 createTime 不匹配
-       categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCreateTime(buildTime(2024, 2, 2))));
-       // 准备参数
-       BpmCategoryPageReqVO reqVO = new BpmCategoryPageReqVO();
-       reqVO.setName("芋");
-       reqVO.setCode("xiao");
-       reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
-       reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
-
-       // 调用
-       PageResult<BpmCategoryDO> pageResult = categoryService.getCategoryPage(reqVO);
-       // 断言
-       assertEquals(1, pageResult.getTotal());
-       assertEquals(1, pageResult.getList().size());
-       assertPojoEquals(dbCategory, pageResult.getList().get(0));
-    }
-
-}
\ No newline at end of file
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/definition/BpmFormServiceTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/definition/BpmFormServiceTest.java
deleted file mode 100644
index b465299..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/definition/BpmFormServiceTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.iailab.module.bpm.service.definition;
-
-import cn.hutool.core.util.RandomUtil;
-import com.iailab.framework.common.pojo.PageResult;
-import com.iailab.framework.common.util.json.JsonUtils;
-import com.iailab.framework.test.core.ut.BaseDbUnitTest;
-import com.iailab.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO;
-import com.iailab.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO;
-import com.iailab.module.bpm.dal.dataobject.definition.BpmFormDO;
-import com.iailab.module.bpm.dal.mysql.definition.BpmFormMapper;
-import com.iailab.module.bpm.service.definition.dto.BpmFormFieldRespDTO;
-import org.junit.jupiter.api.Test;
-import org.springframework.context.annotation.Import;
-
-import javax.annotation.Resource;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.iailab.framework.common.util.object.ObjectUtils.cloneIgnoreId;
-import static com.iailab.framework.test.core.util.AssertUtils.assertPojoEquals;
-import static com.iailab.framework.test.core.util.AssertUtils.assertServiceException;
-import static com.iailab.framework.test.core.util.RandomUtils.randomLongId;
-import static com.iailab.framework.test.core.util.RandomUtils.randomPojo;
-import static com.iailab.module.bpm.enums.ErrorCodeConstants.FORM_NOT_EXISTS;
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * {@link BpmFormServiceImpl} 的单元测试类
- *
- * @author iailab
- */
-@Import(BpmFormServiceImpl.class)
-public class BpmFormServiceTest extends BaseDbUnitTest {
-
-    @Resource
-    private BpmFormServiceImpl formService;
-
-    @Resource
-    private BpmFormMapper formMapper;
-
-    @Test
-    public void testCreateForm_success() {
-        // 准备参数
-        BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> {
-            o.setConf("{}");
-            o.setFields(randomFields());
-        });
-
-        // 调用
-        Long formId = formService.createForm(reqVO);
-        // 断言
-        assertNotNull(formId);
-        // 校验记录的属性是否正确
-        BpmFormDO form = formMapper.selectById(formId);
-        assertPojoEquals(reqVO, form);
-    }
-
-    @Test
-    public void testUpdateForm_success() {
-        // mock 数据
-        BpmFormDO dbForm = randomPojo(BpmFormDO.class, o -> {
-            o.setConf("{}");
-            o.setFields(randomFields());
-        });
-        formMapper.insert(dbForm);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> {
-            o.setId(dbForm.getId()); // 设置更新的 ID
-            o.setConf("{'iailab': 'yuanma'}");
-            o.setFields(randomFields());
-        });
-
-        // 调用
-        formService.updateForm(reqVO);
-        // 校验是否更新正确
-        BpmFormDO form = formMapper.selectById(reqVO.getId()); // 获取最新的
-        assertPojoEquals(reqVO, form);
-    }
-
-    @Test
-    public void testUpdateForm_notExists() {
-        // 准备参数
-        BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> {
-            o.setConf("{'iailab': 'yuanma'}");
-            o.setFields(randomFields());
-        });
-
-        // 调用, 并断言异常
-        assertServiceException(() -> formService.updateForm(reqVO), FORM_NOT_EXISTS);
-    }
-
-    @Test
-    public void testDeleteForm_success() {
-        // mock 数据
-        BpmFormDO dbForm = randomPojo(BpmFormDO.class);
-        formMapper.insert(dbForm);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        Long id = dbForm.getId();
-
-        // 调用
-        formService.deleteForm(id);
-        // 校验数据不存在了
-        assertNull(formMapper.selectById(id));
-    }
-
-    @Test
-    public void testDeleteForm_notExists() {
-        // 准备参数
-        Long id = randomLongId();
-
-        // 调用, 并断言异常
-        assertServiceException(() -> formService.deleteForm(id), FORM_NOT_EXISTS);
-    }
-
-    @Test
-    public void testGetFormPage() {
-        // mock 数据
-        BpmFormDO dbForm = randomPojo(BpmFormDO.class, o -> { // 等会查询到
-            o.setName("iailab");
-        });
-        formMapper.insert(dbForm);
-        // 测试 name 不匹配
-        formMapper.insert(cloneIgnoreId(dbForm, o -> o.setName("源码")));
-        // 准备参数
-        BpmFormPageReqVO reqVO = new BpmFormPageReqVO();
-        reqVO.setName("平台");
-
-        // 调用
-        PageResult<BpmFormDO> pageResult = formService.getFormPage(reqVO);
-        // 断言
-        assertEquals(1, pageResult.getTotal());
-        assertEquals(1, pageResult.getList().size());
-        assertPojoEquals(dbForm, pageResult.getList().get(0));
-    }
-
-    private List<String> randomFields() {
-        int size = RandomUtil.randomInt(1, 3);
-        return Stream.iterate(0, i -> i).limit(size)
-                .map(i -> JsonUtils.toJsonString(randomPojo(BpmFormFieldRespDTO.class)))
-                .collect(Collectors.toList());
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/definition/BpmUserGroupServiceTest.java b/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/definition/BpmUserGroupServiceTest.java
deleted file mode 100644
index 4dfa08d..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/java/com/iailab/module/bpm/service/definition/BpmUserGroupServiceTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package com.iailab.module.bpm.service.definition;
-
-import com.iailab.framework.common.enums.CommonStatusEnum;
-import com.iailab.framework.common.pojo.PageResult;
-import com.iailab.framework.test.core.ut.BaseDbUnitTest;
-import com.iailab.framework.test.core.util.AssertUtils;
-import com.iailab.framework.test.core.util.RandomUtils;
-import com.iailab.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO;
-import com.iailab.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO;
-import com.iailab.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
-import com.iailab.module.bpm.dal.mysql.definition.BpmUserGroupMapper;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.springframework.context.annotation.Import;
-
-import javax.annotation.Resource;
-import java.time.LocalDateTime;
-
-import static com.iailab.framework.common.util.date.LocalDateTimeUtils.buildTime;
-import static com.iailab.framework.common.util.object.ObjectUtils.cloneIgnoreId;
-import static com.iailab.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS;
-
-/**
- * {@link BpmUserGroupServiceImpl} 的单元测试类
- *
- * @author iailab
- */
-@Import(BpmUserGroupServiceImpl.class)
-public class BpmUserGroupServiceTest extends BaseDbUnitTest {
-
-    @Resource
-    private BpmUserGroupServiceImpl userGroupService;
-
-    @Resource
-    private BpmUserGroupMapper userGroupMapper;
-
-    @Test
-    public void testCreateUserGroup_success() {
-        // 准备参数
-        BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class);
-
-        // 调用
-        Long userGroupId = userGroupService.createUserGroup(reqVO);
-        // 断言
-        Assertions.assertNotNull(userGroupId);
-        // 校验记录的属性是否正确
-        BpmUserGroupDO userGroup = userGroupMapper.selectById(userGroupId);
-        AssertUtils.assertPojoEquals(reqVO, userGroup);
-    }
-
-    @Test
-    public void testUpdateUserGroup_success() {
-        // mock 数据
-        BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class);
-        userGroupMapper.insert(dbUserGroup);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class, o -> {
-            o.setId(dbUserGroup.getId()); // 设置更新的 ID
-        });
-
-        // 调用
-        userGroupService.updateUserGroup(reqVO);
-        // 校验是否更新正确
-        BpmUserGroupDO userGroup = userGroupMapper.selectById(reqVO.getId()); // 获取最新的
-        AssertUtils.assertPojoEquals(reqVO, userGroup);
-    }
-
-    @Test
-    public void testUpdateUserGroup_notExists() {
-        // 准备参数
-        BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class);
-
-        // 调用, 并断言异常
-        AssertUtils.assertServiceException(() -> userGroupService.updateUserGroup(reqVO), USER_GROUP_NOT_EXISTS);
-    }
-
-    @Test
-    public void testDeleteUserGroup_success() {
-        // mock 数据
-        BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class);
-        userGroupMapper.insert(dbUserGroup);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        Long id = dbUserGroup.getId();
-
-        // 调用
-        userGroupService.deleteUserGroup(id);
-       // 校验数据不存在了
-       Assertions.assertNull(userGroupMapper.selectById(id));
-    }
-
-    @Test
-    public void testDeleteUserGroup_notExists() {
-        // 准备参数
-        Long id = RandomUtils.randomLongId();
-
-        // 调用, 并断言异常
-        AssertUtils.assertServiceException(() -> userGroupService.deleteUserGroup(id), USER_GROUP_NOT_EXISTS);
-    }
-
-    @Test
-    public void testGetUserGroupPage() {
-       // mock 数据
-       BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class, o -> { // 等会查询到
-           o.setName("iailab");
-           o.setStatus(CommonStatusEnum.ENABLE.getStatus());
-           o.setCreateTime(buildTime(2021, 11, 11));
-       });
-       userGroupMapper.insert(dbUserGroup);
-       // 测试 name 不匹配
-       userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setName("平台")));
-       // 测试 status 不匹配
-       userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
-       // 测试 createTime 不匹配
-       userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setCreateTime(buildTime(2021, 12, 12))));
-       // 准备参数
-       BpmUserGroupPageReqVO reqVO = new BpmUserGroupPageReqVO();
-       reqVO.setName("源码");
-       reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
-       reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)}));
-
-       // 调用
-       PageResult<BpmUserGroupDO> pageResult = userGroupService.getUserGroupPage(reqVO);
-       // 断言
-       Assertions.assertEquals(1, pageResult.getTotal());
-       Assertions.assertEquals(1, pageResult.getList().size());
-       AssertUtils.assertPojoEquals(dbUserGroup, pageResult.getList().get(0));
-    }
-
-}
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/application-unit-test.yaml b/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/application-unit-test.yaml
deleted file mode 100644
index c457ceb..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/application-unit-test.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-spring:
-  main:
-    lazy-initialization: true # 开启懒加载,加快速度
-    banner-mode: off # 单元测试,禁用 Banner
-
---- #################### 数据库相关配置 ####################
-
-spring:
-  # 数据源配置项
-  datasource:
-    name: ruoyi-vue-pro
-    url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写
-    driver-class-name: org.h2.Driver
-    username: sa
-    password:
-    druid:
-      async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
-      initial-size: 1 # 单元测试,配置为 1,提升启动速度
-  sql:
-    init:
-      schema-locations: classpath:/sql/create_tables.sql
-
-mybatis-plus:
-  lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
-  type-aliases-package: ${iailab.info.base-package}.dal.dataobject
-  global-config:
-    db-config:
-      id-type: AUTO # H2 主键递增
-
---- #################### 定时任务相关配置 ####################
-
---- #################### 配置中心相关配置 ####################
-
---- #################### 服务保障相关配置 ####################
-
-# Lock4j 配置项(单元测试,禁用 Lock4j)
-
---- #################### 监控相关配置 ####################
-
---- #################### 平台相关配置 ####################
-
-# 平台配置项,设置当前项目所有自定义的配置
-iailab:
-  info:
-    base-package: com.iailab.module.bpm
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/logback.xml b/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/logback.xml
deleted file mode 100644
index daf756b..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/logback.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<configuration>
-    <!-- 引用 Spring Boot 的 logback 基础配置 -->
-    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
-</configuration>
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/sql/clean.sql b/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/sql/clean.sql
deleted file mode 100644
index d4f93bb..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/sql/clean.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-DELETE FROM "bpm_form";
-DELETE FROM "bpm_user_group";
-DELETE FROM "bpm_category";
diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/sql/create_tables.sql b/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/sql/create_tables.sql
deleted file mode 100644
index 1034962..0000000
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/test/resources/sql/create_tables.sql
+++ /dev/null
@@ -1,43 +0,0 @@
-CREATE TABLE IF NOT EXISTS "bpm_user_group" (
-    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    "name" varchar(63) NOT NULL,
-    "description" varchar(255) NOT NULL,
-    "status" tinyint NOT NULL,
-    "user_ids" varchar(255) NOT NULL,
-    "creator" varchar(64) DEFAULT '',
-    "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "updater" varchar(64) DEFAULT '',
-    "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "deleted" bit NOT NULL DEFAULT FALSE,
-    PRIMARY KEY ("id")
-) COMMENT '用户组';
-
-CREATE TABLE IF NOT EXISTS "bpm_category" (
-    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    "name" varchar(63) NOT NULL,
-    "code" varchar(63) NOT NULL,
-    "description" varchar(255) NOT NULL,
-    "status" tinyint NOT NULL,
-    "sort" int NOT NULL,
-    "creator" varchar(64) DEFAULT '',
-    "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "updater" varchar(64) DEFAULT '',
-    "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "deleted" bit NOT NULL DEFAULT FALSE,
-    PRIMARY KEY ("id")
-) COMMENT '分类';
-
-CREATE TABLE IF NOT EXISTS "bpm_form" (
-    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    "name" varchar(63) NOT NULL,
-    "status" tinyint NOT NULL,
-    "fields" varchar(255) NOT NULL,
-    "conf" varchar(255) NOT NULL,
-    "remark" varchar(255),
-    "creator" varchar(64) DEFAULT '',
-    "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "updater" varchar(64) DEFAULT '',
-    "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "deleted" bit NOT NULL DEFAULT FALSE,
-    PRIMARY KEY ("id")
-) COMMENT '动态表单';
diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/PointCollector.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/PointCollector.java
index 043d3bb..c7475c9 100644
--- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/PointCollector.java
+++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/PointCollector.java
@@ -3,6 +3,7 @@
 import com.iailab.module.data.common.enums.DataSourceType;
 import com.iailab.module.data.common.utils.R;
 import com.iailab.module.data.channel.kio.collector.KingIOCollector;
+import com.iailab.module.data.influxdb.pojo.InfluxPointValueBoolPOJO;
 import com.iailab.module.data.influxdb.pojo.InfluxPointValueDigPOJO;
 import com.iailab.module.data.influxdb.pojo.InfluxPointValueSimPOJO;
 import com.iailab.module.data.point.collection.handler.CalculateHandle;
@@ -23,6 +24,7 @@
 import javax.annotation.Resource;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
@@ -68,6 +70,13 @@
     @Autowired
     private DaPointCollectStatusService daPointCollectStatusService;
 
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+    public static final String PV = "PV_";
+
+    public static final int offset = 60 * 3;
+
     /**
      * 采集
      *
@@ -95,9 +104,22 @@
             List<DaPointDTO> pointCumulateList = daPointService.getCumulatePoint(minfreq);
             pointValues.addAll(cumulateHandle.handle(collectTime, pointCumulateList));
 
-            log.info("存入数据库");
+            log.info("存入时序库");
             influxDBService.asyncWritePointValues(pointValues);
 
+            log.info("存入缓存");
+            for (InfluxPointValuePOJO pointValue : pointValues) {
+                if (pointValue instanceof InfluxPointValueSimPOJO) {
+                    InfluxPointValueSimPOJO simPOJO = (InfluxPointValueSimPOJO) pointValue;
+                    redisTemplate.opsForValue().set(PV + simPOJO.getPoint(), simPOJO.getValue(), offset);
+                } else if (pointValue instanceof InfluxPointValueDigPOJO) {
+                    InfluxPointValueDigPOJO digPOJO = (InfluxPointValueDigPOJO) pointValue;
+                    redisTemplate.opsForValue().set(PV + digPOJO.getPoint(), digPOJO.getValue(), offset);
+                } else if (pointValue instanceof InfluxPointValueBoolPOJO) {
+                    InfluxPointValueBoolPOJO boolPOJO = (InfluxPointValueBoolPOJO) pointValue;
+                    redisTemplate.opsForValue().set(PV + boolPOJO.getPoint(), boolPOJO.getValue(), offset);
+                }
+            }
             log.info("更新采集状态");
             daPointCollectStatusService.recordStatusList(pointValues, collectTime);
             log.info("采集完成");
diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CalculateHandle.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CalculateHandle.java
index c45c633..699ea60 100644
--- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CalculateHandle.java
+++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CalculateHandle.java
@@ -1,8 +1,10 @@
 package com.iailab.module.data.point.collection.handler;
 
+import com.iailab.module.data.common.enums.CommonConstant;
 import com.iailab.module.data.common.enums.DataTypeEnum;
 import com.iailab.module.data.common.enums.JsErrorCode;
 import com.iailab.module.data.common.utils.JavaScriptHandler;
+import com.iailab.module.data.point.collection.PointCollector;
 import com.iailab.module.data.point.collection.utils.GenInfluxPointValueUtils;
 import com.iailab.module.data.point.dto.DaPointDTO;
 import com.iailab.module.data.point.service.DaPointService;
@@ -10,6 +12,9 @@
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import javax.annotation.Resource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
@@ -38,6 +43,9 @@
 
     @Resource
     private JavaScriptHandler javaScriptHandler;
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
 
     public static final String regex = "[+\\-\\*/()\\&\\|\\>\\<]";
 
@@ -86,7 +94,7 @@
         String result = javaScriptHandler.eval(expression);
         log.info("result=" + result);
         if (result == null) {
-            return null;
+            return CommonConstant.BAD_VALUE;
         } else if (result.contains(JsErrorCode.Infinity.name()) ||
                 result.contains(JsErrorCode.NaN.name())) {
             log.info("计算异常,使用默认值");
@@ -95,7 +103,7 @@
             if (DataTypeEnum.INT.getCode().equals(dto.getDataType())) {
                 return new BigDecimal(result).intValue();
             } else if (DataTypeEnum.FLOAT.getCode().equals(dto.getDataType())) {
-                return new BigDecimal(result).setScale(10, BigDecimal.ROUND_UP).doubleValue();
+                return new BigDecimal(result).setScale(4, BigDecimal.ROUND_UP).doubleValue();
             } else if (DataTypeEnum.BOOLEAN.getCode().equals(dto.getDataType())) {
                 return Boolean.parseBoolean(result);
             }
@@ -110,12 +118,19 @@
             return data;
         }
         pointMathList.forEach(item -> {
-            data.put(item.getPointNo(), singleCompute(item));
+            Object value = CommonConstant.BAD_VALUE;
+            if (redisTemplate.hasKey(PointCollector.PV + item.getPointNo())) {
+                value = redisTemplate.opsForValue().get(PointCollector.PV + item.getPointNo());
+            } else {
+                value = singleCompute(item);
+            }
+            data.put(item.getPointNo(), value);
         });
         return data;
     }
 
     private Object singleCompute(DaPointDTO dto) {
+        String result = CommonConstant.BAD_VALUE.toString();
         Map<String, Object> dataMap = new HashMap<>();
         String expression = dto.getExpression();
         String[] arr = expression.split(regex);
@@ -135,19 +150,18 @@
         expression = expression.replace("False", "false");
         expression = expression.replace("True", "true");
         log.info("PointNo=" + dto.getPointNo() + ";expression=" + expression);
-        String result = javaScriptHandler.eval(expression);
+        result = javaScriptHandler.eval(expression);
         log.info("result=" + result);
         if (result == null) {
-            return null;
-        } else if (result.contains(JsErrorCode.Infinity.name()) ||
-                result.contains(JsErrorCode.NaN.name())) {
+            return CommonConstant.BAD_VALUE;
+        } else if (result.contains(JsErrorCode.Infinity.name()) || result.contains(JsErrorCode.NaN.name())) {
             log.info("计算异常,使用默认值");
             return dto.getDefaultValue() == null ? BigDecimal.ZERO : dto.getDefaultValue();
         } else {
             if (DataTypeEnum.INT.getCode().equals(dto.getDataType())) {
                 return new BigDecimal(result).intValue();
             } else if (DataTypeEnum.FLOAT.getCode().equals(dto.getDataType())) {
-                return new BigDecimal(result).setScale(10, BigDecimal.ROUND_UP).doubleValue();
+                return new BigDecimal(result).setScale(2, BigDecimal.ROUND_UP).doubleValue();
             } else if (DataTypeEnum.BOOLEAN.getCode().equals(dto.getDataType())) {
                 return Boolean.parseBoolean(result);
             }
diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CumulateHandle.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CumulateHandle.java
index e2baacc..23a3287 100644
--- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CumulateHandle.java
+++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/CumulateHandle.java
@@ -7,12 +7,14 @@
 import com.iailab.module.data.common.enums.CommonConstant;
 import com.iailab.module.data.enums.DataPointFreqEnum;
 import com.iailab.module.data.influxdb.pojo.InfluxPointValuePOJO;
+import com.iailab.module.data.point.collection.PointCollector;
 import com.iailab.module.data.point.collection.utils.GenInfluxPointValueUtils;
 import com.iailab.module.data.point.dto.DaPointDTO;
 import com.iailab.module.data.point.service.DaPointService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
@@ -37,6 +39,9 @@
     @Autowired
     @Lazy
     private DataPointApi dataPointApi;
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
 
     public List<InfluxPointValuePOJO> handle(Date collectTime, List<DaPointDTO> dtos) {
         List<InfluxPointValuePOJO> result = new ArrayList<>();
@@ -73,7 +78,13 @@
         Calendar calendar = Calendar.getInstance();
         calendar.set(Calendar.MILLISECOND, 0);
         pointMathList.forEach(item -> {
-            data.put(item.getPointNo(), singleCompute(item, calendar.getTime()));
+            Object value = CommonConstant.BAD_VALUE;
+            if (redisTemplate.hasKey(PointCollector.PV + item.getPointNo())) {
+                value = redisTemplate.opsForValue().get(PointCollector.PV + item.getPointNo());
+            } else {
+                value = singleCompute(item, calendar.getTime());
+            }
+            data.put(item.getPointNo(), value);
         });
         return data;
     }
diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/MeasureHandle.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/MeasureHandle.java
index c97aa8b..bd0a697 100644
--- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/MeasureHandle.java
+++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/point/collection/handler/MeasureHandle.java
@@ -10,6 +10,7 @@
 import com.iailab.module.data.channel.kio.collector.KingIOCollector;
 import com.iailab.module.data.channel.modbus.collector.ModBusCollector;
 import com.iailab.module.data.channel.opcua.collector.OpcUaCollector;
+import com.iailab.module.data.point.collection.PointCollector;
 import com.iailab.module.data.point.collection.utils.GenInfluxPointValueUtils;
 import com.iailab.module.data.point.common.PointDataTypeEnum;
 import com.iailab.module.data.point.dto.DaPointDTO;
@@ -19,6 +20,7 @@
 import javax.annotation.Resource;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
@@ -57,6 +59,9 @@
 
     @Resource
     private DaPointService daPointService;
+
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
 
     public List<InfluxPointValuePOJO> handle(Date collectTime, List<DaPointDTO> dtos, Map<String, Object> dataMap) {
         log.info("测量点处理开始");
@@ -178,7 +183,9 @@
                 item -> {
                     try {
                         Object value = CommonConstant.BAD_VALUE;
-                        if (DataSourceType.OPCUA.getCode().equals(item.getSourceType())) {
+                        if (redisTemplate.hasKey(PointCollector.PV + item.getPointNo())) {
+                            value = redisTemplate.opsForValue().get(PointCollector.PV + item.getPointNo());
+                        } else if (DataSourceType.OPCUA.getCode().equals(item.getSourceType())) {
                             value = opcUaCollector.getTagValue(item.getSourceId(), item.getTagNo());
                         } else if (DataSourceType.ModBus.getCode().equals(item.getSourceType())) {
                             value = modBusCollector.getTagValue(item.getSourceId(), item.getTagNo());
@@ -186,12 +193,13 @@
                             value = kingIOCollector.getTagValue(item.getSourceId(), item.getTagNo());
                         } else if (DataSourceType.HTTP.getCode().equals(item.getSourceType())) {
                             value = httpCollectorForIhd.getTagValue(item.getSourceId(), item.getTagNo(), item.getDimension(), item.getValueType());
+                            // 存入缓存
+                            redisTemplate.opsForValue().set(PointCollector.PV + item.getPointNo(), value, PointCollector.offset);
                         } else {
                             log.info("没有匹配的TagNo=" + item.getTagNo());
                         }
-                        log.info("没有匹配的TagNo=" + item.getTagNo());
-                        log.info("valueStr=" + value.toString());
-                        log.info("DataType=" + item.getDataType());
+
+                        log.info("TagNo=" + item.getTagNo() + ",value=" + value.toString());
                         if (!PointDataTypeEnum.BOOLEAN.getCode().equals(item.getDataType())) {
                             BigDecimal decValue =  new BigDecimal(value.toString());
                             if (PointDataTypeEnum.FLOAT.getCode().equals(item.getDataType())) {
diff --git a/iailab-module-data/iailab-module-data-biz/src/main/resources/application.yaml b/iailab-module-data/iailab-module-data-biz/src/main/resources/application.yaml
index b155a20..1aa2d73 100644
--- a/iailab-module-data/iailab-module-data-biz/src/main/resources/application.yaml
+++ b/iailab-module-data/iailab-module-data-biz/src/main/resources/application.yaml
@@ -61,7 +61,7 @@
 
 logging:
   file:
-    name: @log.path@/logs/${spring.application.name}.log # 日志文件名,全路径
+    name: @log.path@/iailab-data/log/${spring.application.name}.log # 日志文件名,全路径
   level:
     org:
       springframework:
diff --git a/iailab-module-infra/iailab-module-infra-biz/src/main/resources/application.yaml b/iailab-module-infra/iailab-module-infra-biz/src/main/resources/application.yaml
index d28c4c9..c460931 100644
--- a/iailab-module-infra/iailab-module-infra-biz/src/main/resources/application.yaml
+++ b/iailab-module-infra/iailab-module-infra-biz/src/main/resources/application.yaml
@@ -11,7 +11,7 @@
       username: @nacos.username@
       password: @nacos.password@
       discovery: # 【配置中心】配置项
-        ip: @deploy.server@
+#        ip: @deploy.server@
         namespace: @profiles.active@
         group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
         metadata:
@@ -58,7 +58,7 @@
 
 logging:
   file:
-    name: D:/DLUT/IailabPlat/webapp/infra/logs/${spring.application.name}.log # 日志文件名,全路径
+    name: @log.path@/iailab-infra/log/${spring.application.name}.log # 日志文件名,全路径
 
 --- #################### 接口文档配置 ####################
 
diff --git a/iailab-module-model/iailab-module-model-biz/src/main/resources/application.yml b/iailab-module-model/iailab-module-model-biz/src/main/resources/application.yml
index 9883f9f..8ef4a92 100644
--- a/iailab-module-model/iailab-module-model-biz/src/main/resources/application.yml
+++ b/iailab-module-model/iailab-module-model-biz/src/main/resources/application.yml
@@ -58,7 +58,7 @@
 
 logging:
   file:
-    name: @log.path@/logs/${spring.application.name}.log # 日志文件名,全路径
+    name: @log.path@/iailab-model/log/${spring.application.name}.log # 日志文件名,全路径
   level:
     org:
       springframework:
diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java
index d2a3342..2fcd758 100644
--- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java
+++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java
@@ -253,7 +253,7 @@
                     menu.setParentId(parentMenu.getId());
                     tempChildren.add(parentMenu);
                 } else if(menu.getType().equals(MenuTypeEnum.DIR.getType())) {
-                    // 为应用菜单二级目录前增加“/”
+                    // 为应用菜单二级目录前增加“/” (不处理外链菜单path)
                     if(!menu.getPath().contains("http:") && !menu.getPath().contains("https:")) {
                         menu.setPath("/" + menu.getPath());
                     }
diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java
index 9aab0a7..5315a17 100644
--- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java
+++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java
@@ -208,7 +208,10 @@
         List<AuthPermissionInfoRespVO.MenuVO> menuVOS = filterList(treeNodeMap.values(), node -> id.equals(node.getParentId()));
         if(type == 0) {
             menuVOS.stream().forEach(menuVO -> {
-                menuVO.setPath((parentPath + "/" + menuVO.getPath()).replace("//", "/"));
+                // 不处理外链菜单path
+                if(!menuVO.getPath().contains("http:") && !menuVO.getPath().contains("https:")) {
+                    menuVO.setPath((parentPath + "/" + menuVO.getPath()).replace("//", "/"));
+                }
             });
         }
         return menuVOS;
diff --git a/iailab-module-system/iailab-module-system-biz/src/main/resources/application.yaml b/iailab-module-system/iailab-module-system-biz/src/main/resources/application.yaml
index ea07602..77c72e9 100644
--- a/iailab-module-system/iailab-module-system-biz/src/main/resources/application.yaml
+++ b/iailab-module-system/iailab-module-system-biz/src/main/resources/application.yaml
@@ -58,7 +58,7 @@
 
 logging:
   file:
-    name: @log.path@/logs/${spring.application.name}.log # 日志文件名,全路径
+    name: @log.path@/iailab-system/log/${spring.application.name}.log # 日志文件名,全路径
 
 --- #################### 接口文档配置 ####################
 
@@ -225,4 +225,4 @@
     begin-code: 9999 # 这里配置 9999 的原因是,测试方便。
     end-code: 9999 # 这里配置 9999 的原因是,测试方便。
 
-debug: false
+debug: true
diff --git a/pom.xml b/pom.xml
index 2cb73e5..5914503 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,7 +122,7 @@
                 <nacos.metadata.version>1.0.0</nacos.metadata.version>
                 <log.path>D:\DLUT\iailab-plat</log.path>
                 <logstash.address>127.0.0.1:4560</logstash.address>
-                <deploy.server>192.168.56.1</deploy.server>
+                <deploy.server>172.16.216.132</deploy.server>
             </properties>
             <activation>
                 <!-- 默认环境 -->
@@ -156,7 +156,7 @@
                 <nacos.username>nacos</nacos.username>
                 <nacos.password>nacos</nacos.password>
                 <nacos.metadata.version>1.0.0</nacos.metadata.version>
-                <log.path>D:\iailab\logs</log.path>
+                <log.path>D:\iailab</log.path>
                 <logstash.address>127.0.0.1:4560</logstash.address>
                 <deploy.server>10.88.4.131</deploy.server>
             </properties>

--
Gitblit v1.9.3