Преглед на файлове

Merge branch 'feature/pref-1.0'

wuwenyi преди 2 дни
родител
ревизия
62e990cd5f

+ 0 - 36
src/main/java/com/qqflow/engine/common/config/HttpLoggingInterceptor.java

@@ -1,36 +0,0 @@
-package com.qqflow.engine.common.config;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.servlet.HandlerInterceptor;
-
-import java.util.stream.Collectors;
-
-/**
- * HTTP 请求/响应日志拦截器:记录每个请求的 URI、参数和响应状态
- */
-@Slf4j
-public class HttpLoggingInterceptor implements HandlerInterceptor {
-
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
-        String params = request.getParameterMap().isEmpty() ? ""
-                : "?" + request.getParameterMap().entrySet().stream()
-                    .map(e -> e.getKey() + "=" + String.join(",", e.getValue()))
-                    .collect(Collectors.joining("&"));
-        log.info("[HTTP] {} {}{} | ip={}", request.getMethod(), request.getRequestURI(), params, request.getRemoteAddr());
-        return true;
-    }
-
-    @Override
-    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
-                                Object handler, Exception ex) {
-        int status = response.getStatus();
-        if (status >= 400) {
-            log.warn("[HTTP] {} {} → {}", request.getMethod(), request.getRequestURI(), status);
-        } else {
-            log.info("[HTTP] {} {} → {}", request.getMethod(), request.getRequestURI(), status);
-        }
-    }
-}

+ 1 - 8
src/main/java/com/qqflow/engine/config/WebConfig.java

@@ -2,12 +2,10 @@ package com.qqflow.engine.config;
 
 import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
 import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
-import com.qqflow.engine.common.config.HttpLoggingInterceptor;
 import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import java.time.format.DateTimeFormatter;
@@ -34,12 +32,7 @@ public class WebConfig implements WebMvcConfigurer {
                 .maxAge(3600);
     }
 
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new HttpLoggingInterceptor())
-                .addPathPatterns("/**")
-                .excludePathPatterns("/static/**", "/swagger-ui/**", "/v3/api-docs/**", "/doc.html");
-    }
+    // HTTP 日志从 HttpLoggingFilter(@Component)统一处理,不在此处注册
 
     // 文件下载不再通过静态资源映射公开访问,统一走 FileDownloadController 做权限校验
 }

+ 3 - 2
src/main/java/com/qqflow/engine/domain/flow/controller/ApprovalTaskController.java

@@ -41,10 +41,11 @@ public class ApprovalTaskController {
             @RequestParam(defaultValue = "1") Integer pageNum,
             @RequestParam(defaultValue = "10") Integer pageSize,
             @RequestParam(required = false) String processName,
-            @RequestParam(required = false) String formFilters) {
+            @RequestParam(required = false) String formFilters,
+            @RequestParam(required = false) String currentNodeId) {
         Long assigneeId = SecurityUtils.getUserId();
         String assigneeType = requireLoginUser().getUserType();
-        return Result.ok(this.approvalTaskService.todoList(assigneeId, assigneeType, processName, formFilters, pageNum, pageSize));
+        return Result.ok(this.approvalTaskService.todoList(assigneeId, assigneeType, processName, formFilters, currentNodeId, pageNum, pageSize));
     }
 
     @GetMapping("/handled")

+ 4 - 4
src/main/java/com/qqflow/engine/domain/flow/controller/ProcessInstanceController.java

@@ -52,9 +52,9 @@ public class ProcessInstanceController {
             @RequestParam(required = false) Integer status,
             @RequestParam(required = false) Long processDefinitionId,
             @RequestParam(required = false) String definitionName,
-            @RequestParam(required = false) String currentNodeName,
+            @RequestParam(required = false) String currentNodeId,
             @RequestParam(required = false) String applicantName) {
-        return Result.ok(this.processInstanceService.list(null, status, processDefinitionId, definitionName, currentNodeName, applicantName, pageNum, pageSize));
+        return Result.ok(this.processInstanceService.list(null, status, processDefinitionId, definitionName, currentNodeId, applicantName, pageNum, pageSize));
     }
 
     @GetMapping("/mine")
@@ -64,9 +64,9 @@ public class ProcessInstanceController {
             @RequestParam(defaultValue = "10") Integer pageSize,
             @RequestParam(required = false) Integer status,
             @RequestParam(required = false) String definitionName,
-            @RequestParam(required = false) String currentNodeName) {
+            @RequestParam(required = false) String currentNodeId) {
         Long applicantId = SecurityUtils.getUserId();
-        return Result.ok(this.processInstanceService.list(applicantId, status, null, definitionName, currentNodeName, null, pageNum, pageSize));
+        return Result.ok(this.processInstanceService.list(applicantId, status, null, definitionName, currentNodeId, null, pageNum, pageSize));
     }
 
     @GetMapping("/{id}")

+ 3 - 0
src/main/java/com/qqflow/engine/domain/flow/dto/BatchTaskDTO.java

@@ -19,4 +19,7 @@ public class BatchTaskDTO {
 
     @Schema(description = "附件URL")
     private String attachmentUrls;
+
+    @Schema(description = "目标节点ID(存在多分支时必选)")
+    private String targetNodeId;
 }

+ 2 - 1
src/main/java/com/qqflow/engine/domain/flow/mapper/ApprovalTaskMapper.java

@@ -35,7 +35,8 @@ public interface ApprovalTaskMapper extends BaseMapper<ApprovalTask> {
             @Param("assigneeType") String assigneeType,
             @Param("roleIds") List<Long> roleIds,
             @Param("processName") String processName,
-            @Param("formFilters") Map<String, String> formFilters);
+            @Param("formFilters") Map<String, String> formFilters,
+            @Param("currentNodeId") String currentNodeId);
 
     com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> selectHandledList(
             com.baomidou.mybatisplus.extension.plugins.pagination.Page<ApprovalTask> page,

+ 1 - 1
src/main/java/com/qqflow/engine/domain/flow/mapper/ProcessInstanceMapper.java

@@ -13,7 +13,7 @@ public interface ProcessInstanceMapper extends BaseMapper<ProcessInstance> {
             @Param("applicantId") Long applicantId,
             @Param("status") Integer status,
             @Param("definitionName") String definitionName,
-            @Param("currentNodeName") String currentNodeName,
+            @Param("currentNodeId") String currentNodeId,
             @Param("applicantName") String applicantName,
             @Param("processDefinitionId") Long processDefinitionId);
 

+ 1 - 1
src/main/java/com/qqflow/engine/domain/flow/service/ApprovalTaskService.java

@@ -13,7 +13,7 @@ import java.util.List;
 
 public interface ApprovalTaskService {
 
-    PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String assigneeType, String processName, String formFilters, Integer pageNum, Integer pageSize);
+    PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String assigneeType, String processName, String formFilters, String currentNodeId, Integer pageNum, Integer pageSize);
 
     PageResult<ApprovalTaskDTO> handledList(Long assigneeId, String assigneeType, String processName, Integer pageNum, Integer pageSize);
 

+ 1 - 1
src/main/java/com/qqflow/engine/domain/flow/service/ProcessInstanceService.java

@@ -15,7 +15,7 @@ public interface ProcessInstanceService {
     /** 从指定节点发起流程(导入时使用),前置节点自动跳过 */
     Long startProcessAtNode(StartProcessDTO dto, String nodeName);
 
-    PageResult<ProcessInstanceDTO> list(Long applicantId, Integer status, Long processDefinitionId, String definitionName, String currentNodeName, String applicantName, Integer pageNum, Integer pageSize);
+    PageResult<ProcessInstanceDTO> list(Long applicantId, Integer status, Long processDefinitionId, String definitionName, String currentNodeId, String applicantName, Integer pageNum, Integer pageSize);
 
     ProcessInstanceDTO getDetail(Long id);
 

+ 16 - 2
src/main/java/com/qqflow/engine/domain/flow/service/impl/ApprovalTaskServiceImpl.java

@@ -92,11 +92,11 @@ public class ApprovalTaskServiceImpl implements ApprovalTaskService {
     private final SysUserService sysUserService;
 
     @Override
-    public PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String assigneeType, String processName, String formFilters, Integer pageNum, Integer pageSize) {
+    public PageResult<ApprovalTaskDTO> todoList(Long assigneeId, String assigneeType, String processName, String formFilters, String currentNodeId, Integer pageNum, Integer pageSize) {
         List<Long> roleIds = loadRoleIdsIfSystemUser(assigneeId, assigneeType);
         Page<ApprovalTask> page = new Page<>(pageNum, pageSize);
         Map<String, String> filterMap = this.parseFormFilters(formFilters);
-        this.approvalTaskMapper.selectTodoList(page, assigneeId, assigneeType, roleIds, processName, filterMap);
+        this.approvalTaskMapper.selectTodoList(page, assigneeId, assigneeType, roleIds, processName, filterMap, currentNodeId);
         List<ApprovalTaskDTO> records = page.getRecords().stream()
                 .map(ApprovalTaskDTO::of)
                 .peek(this::fillUrgency)
@@ -172,11 +172,13 @@ public class ApprovalTaskServiceImpl implements ApprovalTaskService {
     @Override
     @Transactional
     public void batchApprove(BatchTaskDTO dto) {
+        this.validateSameInstanceAndNode(dto.getTaskIds());
         for (Long taskId : dto.getTaskIds()) {
             ApproveTaskDTO approveDto = new ApproveTaskDTO();
             approveDto.setTaskId(taskId);
             approveDto.setComment(dto.getComment());
             approveDto.setAttachmentUrls(dto.getAttachmentUrls());
+            approveDto.setTargetNodeId(dto.getTargetNodeId());
             this.approve(approveDto);
         }
     }
@@ -184,6 +186,7 @@ public class ApprovalTaskServiceImpl implements ApprovalTaskService {
     @Override
     @Transactional
     public void batchReject(BatchTaskDTO dto) {
+        this.validateSameInstanceAndNode(dto.getTaskIds());
         for (Long taskId : dto.getTaskIds()) {
             ApproveTaskDTO rejectDto = new ApproveTaskDTO();
             rejectDto.setTaskId(taskId);
@@ -193,6 +196,17 @@ public class ApprovalTaskServiceImpl implements ApprovalTaskService {
         }
     }
 
+    /** 校验所有任务属于同一个流程节点的任务(允许跨实例) */
+    private void validateSameInstanceAndNode(List<Long> taskIds) {
+        if (taskIds == null || taskIds.size() <= 1) return;
+        List<ApprovalTask> tasks = this.approvalTaskMapper.selectList(
+                new LambdaQueryWrapper<ApprovalTask>().in(ApprovalTask::getId, taskIds));
+        long distinctNodes = tasks.stream().map(ApprovalTask::getNodeId).distinct().count();
+        if (distinctNodes > 1) {
+            throw new BusinessException("选择流程处于多个节点,无法批量审批");
+        }
+    }
+
     @Override
     @Transactional
     public void returnTask(ApproveTaskDTO dto) {

+ 3 - 9
src/main/java/com/qqflow/engine/domain/flow/service/impl/ProcessInstanceServiceImpl.java

@@ -115,16 +115,10 @@ public class ProcessInstanceServiceImpl implements ProcessInstanceService {
     }
 
     @Override
-    public PageResult<ProcessInstanceDTO> list(Long applicantId, Integer status, Long processDefinitionId, String definitionName, String currentNodeName, String applicantName, Integer pageNum, Integer pageSize) {
+    public PageResult<ProcessInstanceDTO> list(Long applicantId, Integer status, Long processDefinitionId, String definitionName, String currentNodeId, String applicantName, Integer pageNum, Integer pageSize) {
         Page<ProcessInstance> page = new Page<>(pageNum, pageSize);
-        this.processInstanceMapper.selectInstanceList(page, applicantId, status, definitionName, currentNodeName, applicantName, processDefinitionId);
-        List<ProcessInstanceDTO> records = this.enrichInstanceDtos(page.getRecords());
-        if (currentNodeName != null && !currentNodeName.isBlank()) {
-            records = records.stream()
-                    .filter(r -> currentNodeName.equals(r.getCurrentNodeName()))
-                    .collect(Collectors.toList());
-        }
-        return PageResult.of(page.getTotal(), records);
+        this.processInstanceMapper.selectInstanceList(page, applicantId, status, definitionName, currentNodeId, applicantName, processDefinitionId);
+        return PageResult.of(page.getTotal(), this.enrichInstanceDtos(page.getRecords()));
     }
 
     @Override

+ 3 - 0
src/main/resources/mapper/flow/ApprovalTaskMapper.xml

@@ -61,6 +61,9 @@
                 </if>
             </foreach>
         </if>
+        <if test="currentNodeId != null and currentNodeId != ''">
+            AND pi.current_node_id = #{currentNodeId}
+        </if>
         ORDER BY t.create_time ASC
     </select>
 

+ 3 - 0
src/main/resources/mapper/flow/ProcessInstanceMapper.xml

@@ -43,6 +43,9 @@
         <if test="applicantName != null and applicantName != ''">
             AND (su.username LIKE CONCAT('%', #{applicantName}, '%') OR su.real_name LIKE CONCAT('%', #{applicantName}, '%'))
         </if>
+        <if test="currentNodeId != null and currentNodeId != ''">
+            AND pi.current_node_id = #{currentNodeId}
+        </if>
         ORDER BY pi.create_time DESC
     </select>