Ver código fonte

feat: task batch check

shc 5 meses atrás
pai
commit
95e35c5815

+ 74 - 4
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/task/WmTaskControllerV2.java

@@ -12,9 +12,13 @@ import com.qunzhixinxi.hnqz.admin.util.RedisUtils;
 import com.qunzhixinxi.hnqz.admin.util.RedisUtils.Token;
 import com.qunzhixinxi.hnqz.common.core.exception.BizException;
 import com.qunzhixinxi.hnqz.common.core.util.R;
+import com.qunzhixinxi.hnqz.common.log.annotation.SysLog;
 import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
 import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
-import java.util.concurrent.TimeUnit;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 import javax.annotation.Resource;
 import javax.validation.Valid;
@@ -73,14 +77,14 @@ public class WmTaskControllerV2 {
    * @return 审核结果
    */
   //  @Inner(value = false)
-  //  @SysLog(value = "单一任务审核")
+  @SysLog(value = "单一任务审核")
   @PostMapping(value = "/check/single")
   public R<Boolean> doSingleCheck(@Valid @RequestBody TaskReqVO.OnSingleCheck checkReq) {
 
     // 删除幂等token
     boolean valid = redisUtils.validToken(checkReq.getToken(), checkReq.getTaskId());
     if (!valid) {
-      throw new BizException("令牌无效,请刷新数据后重试");
+      throw new BizException("审核令牌无效,请刷新数据后重试");
     }
 
     // 校验参数
@@ -97,7 +101,7 @@ public class WmTaskControllerV2 {
 
     String lockKey = "task_opt:check:" + checkReq.getTaskId();
     Boolean locked =
-        redisTemplate.opsForValue().setIfAbsent(lockKey, lockInfo, 10, TimeUnit.MINUTES);
+        redisTemplate.opsForValue().setIfAbsent(lockKey, lockInfo /*, 10, TimeUnit.MINUTES*/);
 
     if (Boolean.FALSE.equals(locked)) {
       throw new BizException(
@@ -117,4 +121,70 @@ public class WmTaskControllerV2 {
 
     return ok(Boolean.TRUE);
   }
+
+  /**
+   * 批量任务审核
+   *
+   * @param checkReq 审核信息
+   * @return 审核结果
+   */
+  @SysLog(value = "批量任务审核")
+  @PostMapping(value = "/check/batch")
+  public R<Boolean> doBatchCheck(@Valid @RequestBody TaskReqVO.OnBatchCheck checkReq) {
+
+    // 删除幂等token
+    String taskIdStr = checkReq.getTaskIds().stream().sorted().collect(Collectors.joining(StrPool.COMMA));
+
+    boolean valid = redisUtils.validToken(checkReq.getToken(), taskIdStr);
+
+    if (!valid) {
+      throw new BizException("审核令牌无效,请刷新数据后重试");
+    }
+
+    // 校验参数
+    if (!checkReq.getCheckResult() && StrUtil.isBlank(checkReq.getCheckMessage())) {
+      throw new BizException("拒绝时,【审核意见】必填");
+    }
+
+    List<String> taskIds =
+        checkReq.getTaskIds().stream().distinct().sorted().collect(Collectors.toList());
+    if (taskIds.size() != checkReq.getTaskIds().size()) {
+      throw new BizException("批量请求中存在重复的服务ID");
+    }
+
+    // 添加执行锁
+    HnqzUser user = SecurityUtils.getUser();
+
+    String lockInfo =
+        String.format(
+            "【%s】正在进行服务【%s】", user.getRealName(), checkReq.getCheckResult() ? "通过" : "拒绝");
+
+    Map<String, String> lockKeys = new LinkedHashMap<>(taskIds.size());
+
+    for (String taskId : taskIds) {
+      lockKeys.put("task_opt:check:" + taskId, lockInfo);
+    }
+
+    Boolean locked = redisTemplate.opsForValue().multiSetIfAbsent(lockKeys);
+
+    if (Boolean.FALSE.equals(locked)) {
+
+      Object object =
+          Objects.requireNonNull(redisTemplate.opsForValue().multiGet(lockKeys.keySet())).stream()
+              .filter(Objects::nonNull)
+              .findFirst()
+              .get();
+
+      throw new BizException("当前批量操作中包含至少一条在途审批(" + object + ",...),请刷新后重试");
+    }
+
+    // 发起审核
+    try {
+      taskManager.doBatchCheck(checkReq, user);
+    } finally {
+      redisTemplate.delete(lockKeys.keySet());
+    }
+
+    return ok(Boolean.TRUE);
+  }
 }

+ 20 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/controller/task/vo/TaskReqVO.java

@@ -6,6 +6,7 @@ import java.util.List;
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
 import lombok.AccessLevel;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -76,6 +77,25 @@ public final class TaskReqVO {
     private String checkMessage;
   }
 
+  @Data
+  public static class OnBatchCheck {
+
+    @NotBlank(message = "请求令牌不能为空")
+    private String token;
+
+    @NotEmpty(message = "批量任务ID必填")
+    @Size(min = 1, max = 500, message = "批量审核任务数量范围为{min}-{max}")
+    private List<String> taskIds;
+
+    @NotNull(message = "审核节点必填")
+    private Integer nodeId;
+
+    @NotNull(message = "审核结果必填")
+    private Boolean checkResult;
+
+    private String checkMessage;
+  }
+
   @Data
   public static class OnToken {
 

+ 212 - 15
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/manager/TaskManager.java

@@ -1,7 +1,6 @@
 package com.qunzhixinxi.hnqz.admin.manager;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -10,6 +9,7 @@ import com.qunzhixinxi.hnqz.admin.api.constant.UpmsState.TaskState;
 import com.qunzhixinxi.hnqz.admin.api.constant.UpmsType.AreaType;
 import com.qunzhixinxi.hnqz.admin.api.constant.enums.PackageStatusEnum;
 import com.qunzhixinxi.hnqz.admin.api.dto.SysCheckChainNodeCheckHistoryDTO;
+import com.qunzhixinxi.hnqz.admin.api.dto.SysCheckChainNodeCheckHistoryDTO.OnCreate;
 import com.qunzhixinxi.hnqz.admin.api.entity.SysCheckChainNodeCheckHistory;
 import com.qunzhixinxi.hnqz.admin.api.entity.SysDept;
 import com.qunzhixinxi.hnqz.admin.api.entity.SysUser;
@@ -25,6 +25,7 @@ import com.qunzhixinxi.hnqz.admin.mapper.WmTaskV2Mapper;
 import com.qunzhixinxi.hnqz.admin.service.SysUserAreaService;
 import com.qunzhixinxi.hnqz.admin.service.WmScorePackageService;
 import com.qunzhixinxi.hnqz.admin.service.WmScorePackageStatusService;
+import com.qunzhixinxi.hnqz.admin.service.WmTaskService;
 import com.qunzhixinxi.hnqz.common.core.constant.CacheConstants;
 import com.qunzhixinxi.hnqz.common.core.constant.CommonConstants;
 import com.qunzhixinxi.hnqz.common.core.exception.BizException;
@@ -37,6 +38,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import javax.annotation.Resource;
@@ -57,6 +59,7 @@ public class TaskManager {
 
   @Resource private RedisTemplate redisTemplate;
   @Resource private WmTaskV2Mapper taskMapper;
+  @Resource private WmTaskService taskService;
   @Resource private SysUserAreaService userAreaService;
   @Resource private WmScorePackageService scorePackageService;
   @Resource private SysCheckChainManager checkChainManager;
@@ -141,11 +144,10 @@ public class TaskManager {
       nodeSum.add(28);
     }
     // 其他
-    else{
-       throw new BizException("当前角色不存在绑定审批节点");
+    else {
+      throw new BizException("当前角色不存在绑定审批节点");
     }
 
-
     return nodeSum;
   }
 
@@ -201,13 +203,13 @@ public class TaskManager {
     Map<String, WmDaDrugEntDrugtable> drugtableMap =
         drugs.stream().collect(Collectors.toMap(WmDaDrugEntDrugtable::getId, Function.identity()));
 
-    List<Integer> taskIds =
-        records.stream()
-            .mapToInt(ToDirectCheck::getTaskId)
-            .distinct()
-            .sorted()
-            .boxed()
-            .collect(Collectors.toList());
+    //    List<Integer> taskIds =
+    //        records.stream()
+    //            .mapToInt(ToDirectCheck::getTaskId)
+    //            .distinct()
+    //            .sorted()
+    //            .boxed()
+    //            .collect(Collectors.toList());
 
     //    List<Map<String, Object>> taskCheckHis =
     //        checkChainNodeCheckHistoryMapper.listTaskCheckHis(taskIds);
@@ -305,6 +307,7 @@ public class TaskManager {
     return Integer.parseInt(quarterStr) * 3 - 2;
   }
 
+  // ~单一审核=======================================================================================
   // 任务单一审核
   @Transactional(rollbackFor = Exception.class)
   public void doSingleCheck(@Valid TaskReqVO.OnSingleCheck checkReq, HnqzUser user) {
@@ -445,7 +448,7 @@ public class TaskManager {
         .findAny()
         .ifPresent(
             h -> {
-              throw new BizException("当前务已被同节点审核完毕, 请刷新数据,查看最新信息");
+              throw new BizException("当前务已被同节点审核完毕, 请刷新数据,查看最新信息");
             });
 
     histories.stream()
@@ -453,18 +456,212 @@ public class TaskManager {
         .findAny()
         .ifPresent(
             h -> {
-              throw new BizException("当前务已被其他节点【拒绝】, 请刷新数据,查看最新信息");
+              throw new BizException("当前务已被其他节点【拒绝】, 请刷新数据,查看最新信息");
             });
   }
 
   private void validateTaskDetails(WmTask task) {
 
     if (task == null) {
-      throw new BizException("为查询到该ID的任务");
+      throw new BizException("未查询到该ID的服务");
     }
 
     if (!TaskState.PASSED.getState().equals(task.getTaskStatus())) {
-      throw new BizException("当前任务状态不支持,审核操作,请刷新数据");
+      throw new BizException("当前服务状态不支持,审核操作,请刷新数据");
+    }
+  }
+
+  // ~批量审核=======================================================================================
+  // 批量审核
+  @Transactional(rollbackFor = Exception.class)
+  public void doBatchCheck(@Valid TaskReqVO.OnBatchCheck checkReq, HnqzUser user) {
+
+    Boolean checkResult = checkReq.getCheckResult();
+    String checkMessage = checkReq.getCheckMessage();
+    List<String> taskIds =
+        checkReq.getTaskIds().stream().distinct().sorted().collect(Collectors.toList());
+    LocalDateTime now = LocalDateTime.now();
+
+    // 获取任务
+    List<WmTask> tasks =
+        taskMapper.selectList(Wrappers.<WmTask>lambdaQuery().in(WmTask::getId, taskIds));
+
+    // 校验任务
+    validateTaskDetails1(tasks, taskIds);
+
+    // 校验任务审核记录
+    validateTaskCheckHis1(taskIds, checkReq.getNodeId());
+
+    // 获取包信息
+    Map<String, List<WmTask>> pkgId2TasksMap =
+        tasks.stream().collect(Collectors.groupingBy(WmTask::getScorePackageId));
+
+    List<String> pkgIds =
+        pkgId2TasksMap.keySet().stream().distinct().sorted().collect(Collectors.toList());
+
+    List<WmScorePackage> scorePackage = scorePackageService.listByIds(pkgIds);
+
+    // 校验包信息
+    validatePackage1(scorePackage, pkgIds);
+
+    // 获取领取信息
+    List<WmScorePackageStatus> picked =
+        scorePackageStatusService.list(
+            Wrappers.<WmScorePackageStatus>lambdaQuery()
+                .eq(WmScorePackageStatus::getStatus, PackageStatusEnum.APPROVED.val())
+                .in(WmScorePackageStatus::getPackageId, pkgIds));
+
+    // 校验领取信息
+    validatePicked1(picked, pkgIds);
+
+    // 更新任务审核信息
+    String userIdStr = user.getId().toString();
+    List<WmTask> updates =
+        taskIds.stream()
+            .map(
+                tid -> {
+                  WmTask updateTask = new WmTask();
+                  updateTask.setId(tid);
+
+                  if (!checkResult) {
+                    updateTask.setTaskStatus(TaskState.REJECTED.getState());
+                  }
+
+                  updateTask.setUpdateUser(userIdStr);
+                  updateTask.setUpdateTime(now);
+                  return updateTask;
+                })
+            .collect(Collectors.toList());
+
+    taskService.updateBatchById(updates);
+
+    // 创建审批节点
+    List<OnCreate> checkHis =
+        taskIds.stream()
+            .map(
+                tid -> {
+                  OnCreate res = new OnCreate();
+                  res.setNodeId(checkReq.getNodeId());
+                  res.setTargetId(Integer.parseInt(tid));
+                  res.setCheckResult(checkResult);
+                  res.setCheckMessage(checkMessage);
+                  return res;
+                })
+            .collect(Collectors.toList());
+
+    checkChainManager.doCheck(checkHis, user);
+
+    // 最后一层审核通过
+    if (checkResult && checkReq.getNodeId() == 6) {
+
+      Map<String, WmScorePackage> id2EntityMap =
+          scorePackage.stream()
+              .collect(Collectors.toMap(WmScorePackage::getId, Function.identity()));
+
+      Integer userId = user.getId();
+      pkgId2TasksMap.forEach(
+          (k, v) -> {
+            // 查询已提交的任务(除去审核不通过的任务)& 统计判断任务累计积分是否达到积分包的预设值
+            Map<String, Integer> stat = calcTotalScoreAndCount(k);
+            //      int tot = stat.get("tot");
+            int passed = stat.get("passed");
+
+            int sum = v.stream().mapToInt(WmTask::getScore).sum();
+
+            boolean finished = (passed + sum) >= id2EntityMap.get(k).getScore();
+
+            // 更新包信息
+            scorePackageService.update(
+                Wrappers.<WmScorePackage>lambdaUpdate()
+                    .set(finished, WmScorePackage::getTaskAddFlag, AddTaskState.DISABLE.getState())
+                    .set(finished, WmScorePackage::getPackageFinishTime, now)
+                    .set(WmScorePackage::getUpdateTime, now)
+                    .set(WmScorePackage::getUpdateUser, userId)
+                    .eq(WmScorePackage::getId, k));
+
+            // 更新领取信息
+            scorePackageStatusService.update(
+                Wrappers.<WmScorePackageStatus>lambdaUpdate()
+                    .set(
+                        finished,
+                        WmScorePackageStatus::getTaskAddFlag,
+                        AddTaskState.DISABLE.getState())
+                    .set(WmScorePackageStatus::getUpdateTime, now)
+                    .set(WmScorePackageStatus::getUpdateUser, userId)
+                    .eq(WmScorePackageStatus::getPackageId, k));
+          });
+    }
+  }
+
+  private void validateTaskDetails1(List<WmTask> tasks, List<String> targetIds) {
+
+    if (CollUtil.isEmpty(tasks) || (tasks.size() != targetIds.size())) {
+      throw new BizException("未查询到的全部服务");
+    }
+
+    tasks.stream()
+        .filter(t -> !TaskState.PASSED.getState().equals(t.getTaskStatus()))
+        .findAny()
+        .ifPresent(
+            t -> {
+              throw new BizException("存在服务状态不支持审核操作,请刷新数据");
+            });
+  }
+
+  private void validateTaskCheckHis1(List<String> taskIds, Integer nodeId) {
+    List<SysCheckChainNodeCheckHistory> histories =
+        checkChainNodeCheckHistoryMapper.selectList(
+            Wrappers.<SysCheckChainNodeCheckHistory>lambdaQuery()
+                .in(
+                    SysCheckChainNodeCheckHistory::getTargetId,
+                    taskIds.stream().map(Integer::parseInt).collect(Collectors.toList())));
+
+    if (CollUtil.isEmpty(histories)) {
+      return;
     }
+
+    Map<Integer, List<SysCheckChainNodeCheckHistory>> collect =
+        histories.stream()
+            .collect(Collectors.groupingBy(SysCheckChainNodeCheckHistory::getTargetId));
+
+    collect.forEach(
+        (k, v) -> {
+          histories.stream()
+              .filter(h -> h.getNodeId().equals(nodeId))
+              .findAny()
+              .ifPresent(
+                  h -> {
+                    throw new BizException("服务(ID:" + k + ")已被同节点审核完毕, 请刷新数据,查看最新信息");
+                  });
+
+          histories.stream()
+              .filter(h -> !h.getCheckResult())
+              .findAny()
+              .ifPresent(
+                  h -> {
+                    throw new BizException("服务(ID:" + k + ")已被其他节点【拒绝】, 请刷新数据,查看最新信息");
+                  });
+        });
+  }
+
+  private void validatePackage1(List<WmScorePackage> scorePackage, List<String> targetIds) {
+    if (CollUtil.isEmpty(scorePackage) || (scorePackage.size() != targetIds.size())) {
+      throw new BizException("未获取到全部的执行包");
+    }
+
+    //    if (AddTaskState.DISABLE.getState().equals(scorePackage.getTaskAddFlag())) {
+    //      //      throw new BizException("当前包已经关闭,不能追加新服务记录");
+    //    }
+  }
+
+  private void validatePicked1(List<WmScorePackageStatus> picked, List<String> targetIds) {
+
+    if (CollUtil.isEmpty(picked) || (picked.size() != targetIds.size())) {
+      throw new BizException("未获取到全部的执行包领取记录");
+    }
+
+    //    if (AddTaskState.DISABLE.getState().equals(picked.getTaskAddFlag())) {
+    //      //      throw new BizException("当前包已经关闭,不能追加新服务记录");
+    //    }
   }
 }

+ 4 - 0
hnqz-upms/hnqz-upms-biz/src/main/java/com/qunzhixinxi/hnqz/admin/mapper/WmTaskV2Mapper.java

@@ -9,6 +9,7 @@ import java.time.LocalDateTime;
 import java.util.List;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * 任务mapper
@@ -34,4 +35,7 @@ public interface WmTaskV2Mapper extends BaseMapper<WmTask> {
       @Param("nodeIds") List<Integer> nodeIds,
       @Param("taskStatus") String taskStatus
       );
+
+
+  List<WmTask> selectByIds(@Param("ids") List<Long> ids);
 }