From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-flowable/jnpf-flowable-biz/src/main/java/jnpf/flowable/job/AutoTransferJob.java |  242 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 242 insertions(+), 0 deletions(-)

diff --git a/jnpf-flowable/jnpf-flowable-biz/src/main/java/jnpf/flowable/job/AutoTransferJob.java b/jnpf-flowable/jnpf-flowable-biz/src/main/java/jnpf/flowable/job/AutoTransferJob.java
new file mode 100644
index 0000000..0a3b85e
--- /dev/null
+++ b/jnpf-flowable/jnpf-flowable-biz/src/main/java/jnpf/flowable/job/AutoTransferJob.java
@@ -0,0 +1,242 @@
+package jnpf.flowable.job;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import jnpf.base.ActionResult;
+import jnpf.base.UserInfo;
+import jnpf.config.ConfigValueUtil;
+import jnpf.database.util.TenantDataSourceUtil;
+import jnpf.flowable.entity.OperatorEntity;
+import jnpf.flowable.entity.RecordEntity;
+import jnpf.flowable.entity.TaskEntity;
+import jnpf.flowable.enums.OperatorEnum;
+import jnpf.flowable.enums.OperatorStateEnum;
+import jnpf.flowable.model.task.FlowModel;
+import jnpf.flowable.model.templatenode.nodejson.NodeModel;
+import jnpf.flowable.model.templatenode.nodejson.TemplateJsonModel;
+import jnpf.flowable.model.templatenode.nodejson.TimeConfig;
+import jnpf.flowable.model.time.FlowTimeModel;
+import jnpf.flowable.service.OperatorService;
+import jnpf.flowable.service.TaskService;
+import jnpf.flowable.util.*;
+import jnpf.permission.entity.UserEntity;
+import jnpf.util.AuthUtil;
+import jnpf.util.RedisUtil;
+import jnpf.util.StringUtil;
+import jnpf.util.UserProvider;
+import jnpf.util.context.SpringContext;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * 绫荤殑鎻忚堪
+ *
+ * @author JNPF@YinMai Info. Co., Ltd
+ * @version 5.0.x
+ * @since 2024/12/10 9:17
+ */
+@Slf4j
+public class AutoTransferJob extends QuartzJobBean {
+    private static RedisUtil redisUtil;
+    private static ConfigValueUtil configValueUtil;
+    private static OperatorService operatorService;
+    private static TaskService taskService;
+    private static ServiceUtil serviceUtil;
+    private static FlowUtil flowUtil;
+    private static RedisLock redisLock;
+    private static OperatorUtil operatorUtil;
+
+    static {
+        redisUtil = SpringContext.getBean(RedisUtil.class);
+        configValueUtil = SpringContext.getBean(ConfigValueUtil.class);
+        operatorService = SpringContext.getBean(OperatorService.class);
+        taskService = SpringContext.getBean(TaskService.class);
+        serviceUtil = SpringContext.getBean(ServiceUtil.class);
+        flowUtil = SpringContext.getBean(FlowUtil.class);
+        redisLock = SpringContext.getBean(RedisLock.class);
+        operatorUtil = SpringContext.getBean(OperatorUtil.class);
+    }
+
+    @Override
+    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
+        List<FlowTimeModel> list = FlowJobUtil.getTransfer(redisUtil);
+        if (CollUtil.isNotEmpty(list)) {
+            Set<String> nodeCodes = new TreeSet<>();
+            for (FlowTimeModel timeModel : list) {
+                FlowModel flowModel = timeModel.getFlowModel();
+
+                UserInfo userInfo = flowModel.getUserInfo();
+                if (configValueUtil.isMultiTenancy()) {
+                    TenantDataSourceUtil.switchTenant(userInfo.getTenantId());
+                }
+
+                String operatorId = timeModel.getOperatorId();
+
+                boolean lock = redisLock.lock("transfer-" + operatorId, operatorId, 5, TimeUnit.SECONDS);
+                if (lock) {
+
+
+                    String nodeCode = flowModel.getNodeCode();
+
+                    Map<String, Object> formData = flowModel.getFormData();
+                    Map<String, NodeModel> nodes = flowModel.getNodes();
+
+                    NodeModel nodeModel = nodes.get(nodeCode);
+                    TimeConfig config = nodeModel.getOverTimeConfig();
+
+                    OperatorEntity operator = operatorService.getById(operatorId);
+                    if (null == operator || operator.getHandleStatus() != null) {
+                        TimeUtil.deleteJob(timeModel.getId());
+                        FlowJobUtil.remove(timeModel, redisUtil);
+                        continue;
+                    }
+                    boolean next = true;
+                    if (ObjectUtil.equals(config.getOverTimeType(), OperatorEnum.NOMINATOR.getCode()) || ObjectUtil.equals(config.getOverTimeType(), OperatorEnum.SERVE.getCode())) {
+                        if (nodeCodes.contains(flowModel.getNodeCode())) {
+                            log.info("鑷姩杞澶辫触锛岃缁忓姙宸插鐞嗭紙id锛�" + operatorId + "锛宑ode锛�" + nodeCode + "锛�");
+                            FlowJobUtil.removeTransfer(timeModel, redisUtil);
+                            next = false;
+                        }
+                        nodeCodes.add(nodeCode);
+                    }
+
+                    if (ObjectUtil.equals(operator.getStatus(), OperatorStateEnum.TRANSFER.getCode())) {
+                        log.info("杞鐘舵�佺殑缁忓姙锛屼笉鎵ц: " + operator.getId());
+                        FlowJobUtil.removeTransfer(timeModel, redisUtil);
+                        next = false;
+                    }
+                    // 鎸囨淳绫诲瀷鐨勮浆瀹★紝鍒ゆ柇鏁翠釜鑺傜偣 鏄惁瀛樺湪杞绫诲瀷鐨勭粡鍔�
+                    if (ObjectUtil.equals(config.getOverTimeType(), OperatorEnum.NOMINATOR.getCode()) || ObjectUtil.equals(config.getOverTimeType(), OperatorEnum.SERVE.getCode())) {
+                        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
+                        queryWrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId()).eq(OperatorEntity::getNodeId, operator.getNodeId())
+                                .eq(OperatorEntity::getStatus, OperatorStateEnum.TRANSFER.getCode());
+                        long count = operatorService.count(queryWrapper);
+                        if (count > 0) {
+                            log.info("鑺傜偣瀛樺湪杞鐘舵�佺殑缁忓姙锛屼笉鎵ц: " + operator.getId() + " " + operator.getNodeId());
+                            FlowJobUtil.removeTransfer(timeModel, redisUtil);
+                            next = false;
+                        }
+                    }
+
+
+                    String userId = operator.getHandleId();
+                    UserEntity user = serviceUtil.getUserInfo(userId);
+                    if (null != user) {
+                        String token = AuthUtil.loginTempUser(userId, userInfo.getTenantId());
+                        userInfo.setUserId(user.getId());
+                        userInfo.setUserName(user.getRealName());
+                        userInfo.setUserAccount(user.getAccount());
+                        userInfo.setToken(token);
+                        UserProvider.setLoginUser(userInfo);
+                        UserProvider.setLocalLoginUser(userInfo);
+                    }
+
+                    try {
+                        if (next) {
+                            TaskEntity taskEntity = taskService.getById(operator.getTaskId());
+                            if (null == taskEntity) {
+                                taskEntity = flowModel.getTaskEntity();
+                            }
+                            String handleIds = null;
+                            if (ObjectUtil.equals(config.getOverTimeType(), OperatorEnum.NOMINATOR.getCode())) {
+                                // 鎸囧畾浜哄憳
+                                // 349057407209541--user
+                                if (CollUtil.isNotEmpty(config.getReApprovers())) {
+                                    String handleId = config.getReApprovers().get(0).split("--")[0];
+                                    UserEntity userEntity = serviceUtil.getUserInfo(handleId);
+                                    if (!ObjectUtil.equals(userId, handleId) && null != userEntity && ObjectUtil.equals(userEntity.getEnabledMark(), 1)) {
+                                        handleIds = handleId;
+                                    }
+                                }
+                                if (StringUtil.isNotEmpty(handleIds)) {
+                                    flowModel.setHandleIds(handleIds);
+                                    flowModel.setAutoTransferFlag(true);
+                                    taskService.assign(operator.getTaskId(), flowModel);
+                                    this.delete(timeModel);
+                                }
+                            } else if (ObjectUtil.equals(config.getOverTimeType(), OperatorEnum.SERVE.getCode())) {
+                                // 鎺ュ彛
+                                String interfaceId = config.getInterfaceId();
+                                List<TemplateJsonModel> templateJson = config.getTemplateJson();
+                                if (StringUtil.isNotEmpty(interfaceId)) {
+                                    RecordEntity recordEntity = new RecordEntity();
+                                    recordEntity.setTaskId(taskEntity.getId());
+                                    recordEntity.setNodeCode(operator.getNodeCode());
+                                    recordEntity.setHandleId(operator.getHandleId());
+                                    FlowModel parameterModel = new FlowModel();
+                                    parameterModel.setFormData(formData);
+                                    parameterModel.setRecordEntity(recordEntity);
+                                    parameterModel.setTaskEntity(taskEntity);
+                                    Map<String, String> parameterMap = flowUtil.parameterMap(parameterModel, templateJson);
+                                    ActionResult<Object> result = serviceUtil.infoToId(interfaceId, parameterMap);
+                                    if (Objects.equals(200, result.getCode())) {
+                                        Object data = result.getData();
+                                        if (data instanceof Map) {
+                                            JSONObject map = new JSONObject((Map) data);
+                                            List<String> handleId = StringUtil.isNotEmpty(map.getString("handleId")) ? Arrays.asList(map.getString("handleId").split(",")) : new ArrayList<>();
+                                            handleId = serviceUtil.getUserName(handleId, true)
+                                                    .stream().map(UserEntity::getId).filter(e -> !ObjectUtil.equals(userId, e)).sorted().collect(Collectors.toList());
+                                            handleIds = CollUtil.isNotEmpty(handleId) ? handleId.get(0) : null;
+                                        }
+                                    }
+                                    if (StringUtil.isNotEmpty(handleIds)) {
+                                        flowModel.setHandleIds(handleIds);
+                                        flowModel.setAutoTransferFlag(true);
+                                        taskService.assign(operator.getTaskId(), flowModel);
+                                        this.delete(timeModel);
+                                    }
+                                }
+                            } else {
+                                // 瓒呮椂瀹℃壒浜猴紝2.鍚屼竴閮ㄩ棬 7.鍚屼竴瑙掕壊 3.鍚屼竴宀椾綅 8.鍚屼竴鍒嗙粍
+                                UserEntity userEntity = serviceUtil.getUserInfo(userId);
+                                if (null != userEntity) {
+                                    Integer overTimeExtraRule = config.getOverTimeExtraRule();
+                                    List<String> userIds = new ArrayList<>();
+                                    operatorUtil.getByRule(userIds, userEntity, overTimeExtraRule);
+                                    userIds = serviceUtil.getUserName(userIds, true)
+                                            .stream().map(UserEntity::getId).filter(e -> !ObjectUtil.equals(userId, e)).sorted().collect(Collectors.toList());
+                                    if (CollUtil.isNotEmpty(userIds)) {
+                                        handleIds = userIds.get(0);
+                                    }
+                                }
+                                if (StringUtil.isNotEmpty(handleIds)) {
+                                    flowModel.setHandleIds(handleIds);
+                                    if (operator.getSignTime() == null) {
+                                        operator.setSignTime(new Date());
+                                    }
+                                    if (operator.getStartHandleTime() == null) {
+                                        operator.setStartHandleTime(new Date());
+                                    }
+                                    operatorService.updateById(operator);
+                                    flowModel.setAutoTransferFlag(true);
+                                    operatorService.transfer(operatorId, flowModel);
+                                    this.delete(timeModel);
+                                    operatorUtil.handleOperator();
+                                    operatorUtil.launchTrigger(flowModel);
+                                }
+                            }
+                        }
+                    } catch (Exception e) {
+                        log.error("瓒呮椂鑷姩杞寮傚父", e);
+                        this.delete(timeModel);
+                    } finally {
+                        FlowJobUtil.removeTransfer(timeModel, redisUtil);
+                    }
+                }
+            }
+        }
+    }
+
+    private void delete(FlowTimeModel timeModel) {
+        TimeUtil.deleteJob(timeModel.getId());
+        FlowJobUtil.remove(timeModel, redisUtil);
+    }
+}

--
Gitblit v1.8.0