|
@@ -2,6 +2,7 @@ package com.qunzhixinxi.hnqz.admin.controller.task;
|
|
|
|
|
|
import static com.qunzhixinxi.hnqz.common.core.util.R.ok;
|
|
import static com.qunzhixinxi.hnqz.common.core.util.R.ok;
|
|
|
|
|
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
import cn.hutool.core.text.StrPool;
|
|
import cn.hutool.core.text.StrPool;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
@@ -18,15 +19,23 @@ import com.qunzhixinxi.hnqz.common.core.util.R;
|
|
import com.qunzhixinxi.hnqz.common.log.annotation.SysLog;
|
|
import com.qunzhixinxi.hnqz.common.log.annotation.SysLog;
|
|
import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
|
|
import com.qunzhixinxi.hnqz.common.security.service.HnqzUser;
|
|
import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
|
|
import com.qunzhixinxi.hnqz.common.security.util.SecurityUtils;
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
|
+import java.util.HashMap;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashMap;
|
|
|
|
+import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
-import java.util.Objects;
|
|
|
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
import javax.validation.Valid;
|
|
import javax.validation.Valid;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.springframework.data.redis.core.RedisCallback;
|
|
|
|
+import org.springframework.data.redis.core.RedisOperations;
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
|
|
+import org.springframework.data.redis.core.ValueOperations;
|
|
import org.springframework.web.bind.annotation.GetMapping;
|
|
import org.springframework.web.bind.annotation.GetMapping;
|
|
import org.springframework.web.bind.annotation.PostMapping;
|
|
import org.springframework.web.bind.annotation.PostMapping;
|
|
import org.springframework.web.bind.annotation.RequestBody;
|
|
import org.springframework.web.bind.annotation.RequestBody;
|
|
@@ -49,6 +58,9 @@ public class WmTaskControllerV2 {
|
|
@Resource private RedisUtils redisUtils;
|
|
@Resource private RedisUtils redisUtils;
|
|
@Resource private TaskManager taskManager;
|
|
@Resource private TaskManager taskManager;
|
|
|
|
|
|
|
|
+ private static final ConcurrentHashMap<String, Object> PRETREATMENT_LOCK =
|
|
|
|
+ new ConcurrentHashMap<>();
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 获取当前操作人审核过的任务
|
|
* 获取当前操作人审核过的任务
|
|
*
|
|
*
|
|
@@ -171,6 +183,117 @@ public class WmTaskControllerV2 {
|
|
return ok(Boolean.TRUE);
|
|
return ok(Boolean.TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 清除批量审批预处理
|
|
|
|
+ *
|
|
|
|
+ * <p>用于筛选出正在审核任务,并对筛选结果锁定
|
|
|
|
+ *
|
|
|
|
+ * @param pretreatmentClear 预处理内容
|
|
|
|
+ * @return 预处理结果
|
|
|
|
+ */
|
|
|
|
+ @SysLog(value = "清除批量审批预处理")
|
|
|
|
+ @PostMapping(value = "/check/pretreatment/clear")
|
|
|
|
+ public R<Long> clearPretreatmentBatchCheck(
|
|
|
|
+ @Valid @RequestBody TaskReqVO.OnPretreatmentClear pretreatmentClear) {
|
|
|
|
+
|
|
|
|
+ synchronized (this) {
|
|
|
|
+
|
|
|
|
+ // 删除幂等token
|
|
|
|
+ String taskIdStr =
|
|
|
|
+ pretreatmentClear.getTaskIds().stream()
|
|
|
|
+ .sorted()
|
|
|
|
+ .collect(Collectors.joining(StrPool.COMMA));
|
|
|
|
+
|
|
|
|
+ boolean valid = redisUtils.validToken(pretreatmentClear.getToken(), taskIdStr);
|
|
|
|
+
|
|
|
|
+ if (!valid) {
|
|
|
|
+ throw new BizException("审核令牌无效,请刷新数据后重试");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ List<String> taskIds =
|
|
|
|
+ pretreatmentClear.getTaskIds().stream()
|
|
|
|
+ .map(tid -> "task_opt:check:" + tid)
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
+
|
|
|
|
+ return R.ok(redisTemplate.delete(taskIds));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 批量审批预处理
|
|
|
|
+ *
|
|
|
|
+ * <p>用于筛选出正在审核任务,并对筛选结果锁定
|
|
|
|
+ *
|
|
|
|
+ * @param pretreatment 预处理内容
|
|
|
|
+ * @return 预处理结果
|
|
|
|
+ */
|
|
|
|
+ @SysLog(value = "批量审核预处理")
|
|
|
|
+ @PostMapping(value = "/check/pretreatment")
|
|
|
|
+ public R<Map<String, Object>> pretreatmentBatchCheck(
|
|
|
|
+ @Valid @RequestBody TaskReqVO.OnPretreatment pretreatment) {
|
|
|
|
+
|
|
|
|
+ synchronized (this) {
|
|
|
|
+ HnqzUser user = SecurityUtils.getUser();
|
|
|
|
+
|
|
|
|
+ String lockInfo = String.format("【%s】已预留该服务", user.getRealName());
|
|
|
|
+
|
|
|
|
+ List<String> taskIds = pretreatment.getTaskIds();
|
|
|
|
+
|
|
|
|
+ ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
|
|
|
|
+ RedisOperations<String, Object> redisOperations = valueOperations.getOperations();
|
|
|
|
+
|
|
|
|
+ List<Map<String, String>> locked = new LinkedList<>();
|
|
|
|
+ List<Map<String, String>> available = new LinkedList<>();
|
|
|
|
+ List<String> availTaskIds = new LinkedList<>();
|
|
|
|
+
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
|
+ for (String taskId : taskIds) {
|
|
|
|
+
|
|
|
|
+ String lockKey = "task_opt:check:" + taskId;
|
|
|
|
+
|
|
|
|
+ // 不存在历史执行锁
|
|
|
|
+ if (Boolean.TRUE.equals(
|
|
|
|
+ valueOperations.setIfAbsent(lockKey, lockInfo, 3, TimeUnit.MINUTES))) {
|
|
|
|
+ Map<String, String> map = new HashMap<>(4);
|
|
|
|
+ map.put("status", "成功");
|
|
|
|
+ map.put("taskId", taskId);
|
|
|
|
+ map.put("lockInfo", lockInfo);
|
|
|
|
+ map.put("expireAt", formatter.format(now.plusMinutes(3)));
|
|
|
|
+ available.add(map);
|
|
|
|
+ availTaskIds.add(taskId);
|
|
|
|
+ }
|
|
|
|
+ // 存在历史执行锁
|
|
|
|
+ else {
|
|
|
|
+ Object object = valueOperations.get(lockKey);
|
|
|
|
+ Map<String, String> map = new HashMap<>(4);
|
|
|
|
+ map.put("status", "失败");
|
|
|
|
+ map.put("taskId", taskId);
|
|
|
|
+ map.put("lockInfo", object.toString());
|
|
|
|
+ Long expire = redisOperations.getExpire(lockKey);
|
|
|
|
+ map.put("expireAt", formatter.format(now.plusSeconds(expire)));
|
|
|
|
+ locked.add(map);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ List<Map<String, String>> total = new LinkedList<>();
|
|
|
|
+ total.addAll(available);
|
|
|
|
+ total.addAll(locked);
|
|
|
|
+ Map<String, Object> result = new HashMap<>(4);
|
|
|
|
+ result.put("total", total);
|
|
|
|
+ result.put("locked", locked);
|
|
|
|
+ result.put("available", available);
|
|
|
|
+ result.put(
|
|
|
|
+ "token",
|
|
|
|
+ CollUtil.isEmpty(available)
|
|
|
|
+ ? null
|
|
|
|
+ : redisUtils.generateToken(
|
|
|
|
+ availTaskIds.stream().sorted().collect(Collectors.joining(StrPool.COMMA))));
|
|
|
|
+
|
|
|
|
+ return R.ok(result);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 批量任务审核
|
|
* 批量任务审核
|
|
*
|
|
*
|
|
@@ -215,18 +338,14 @@ public class WmTaskControllerV2 {
|
|
lockKeys.put("task_opt:check:" + taskId, lockInfo);
|
|
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 + ",...),请刷新后重试");
|
|
|
|
- }
|
|
|
|
|
|
+ // 设置执行锁
|
|
|
|
+ redisTemplate.opsForValue().multiSet(lockKeys);
|
|
|
|
+ redisTemplate.executePipelined(
|
|
|
|
+ (RedisCallback<Object>)
|
|
|
|
+ connection -> {
|
|
|
|
+ lockKeys.forEach((k, v) -> connection.expire(k.getBytes(), 600));
|
|
|
|
+ return null;
|
|
|
|
+ });
|
|
|
|
|
|
// 发起审核
|
|
// 发起审核
|
|
try {
|
|
try {
|
|
@@ -237,4 +356,72 @@ public class WmTaskControllerV2 {
|
|
|
|
|
|
return ok(Boolean.TRUE);
|
|
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);
|
|
|
|
+ // }
|
|
}
|
|
}
|