package com.yunzhupaas.flowable.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.collect.ImmutableList;
import com.yunzhupaas.base.model.flow.FlowFormDataModel;
import com.yunzhupaas.base.service.SuperServiceImpl;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.flowable.entity.*;
import com.yunzhupaas.flowable.enums.NodeEnum;
import com.yunzhupaas.flowable.enums.OperatorStateEnum;
import com.yunzhupaas.flowable.enums.RecordEnum;
import com.yunzhupaas.flowable.enums.TaskStatusEnum;
import com.yunzhupaas.flowable.job.FlowJobUtil;
import com.yunzhupaas.flowable.mapper.OperatorMapper;
import com.yunzhupaas.flowable.model.candidates.CandidateCheckFo;
import com.yunzhupaas.flowable.model.candidates.CandidateCheckVo;
import com.yunzhupaas.flowable.model.flowable.*;
import com.yunzhupaas.flowable.model.message.FlowMsgModel;
import com.yunzhupaas.flowable.model.operator.*;
import com.yunzhupaas.flowable.model.record.NodeRecordModel;
import com.yunzhupaas.flowable.model.task.AuditModel;
import com.yunzhupaas.flowable.model.task.FlowMethod;
import com.yunzhupaas.flowable.model.task.FlowModel;
import com.yunzhupaas.flowable.model.task.TaskPagination;
import com.yunzhupaas.flowable.model.templatejson.TemplateJsonInfoVO;
import com.yunzhupaas.flowable.model.templatenode.BackNodeModel;
import com.yunzhupaas.flowable.model.templatenode.FlowErrorModel;
import com.yunzhupaas.flowable.model.templatenode.nodejson.NodeModel;
import com.yunzhupaas.flowable.model.util.FlowContextHolder;
import com.yunzhupaas.flowable.model.util.FlowNature;
import com.yunzhupaas.flowable.model.util.SystemAuditHolder;
import com.yunzhupaas.flowable.model.util.SystemAuditModel;
import com.yunzhupaas.flowable.service.*;
import com.yunzhupaas.flowable.util.*;
import com.yunzhupaas.model.FlowWorkListVO;
import com.yunzhupaas.model.FlowWorkModel;
import com.yunzhupaas.permission.entity.UserEntity;
import com.yunzhupaas.permission.model.user.WorkHandoverModel;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.RedisUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 类的描述
 *
 * @author YUNZHUPAASYUNZHUPAAS开发组
 * @version 5.0.x
 * @since 2024/4/18 15:30
 */
@Service
public class OperatorServiceImpl extends SuperServiceImpl<OperatorMapper, OperatorEntity> implements OperatorService {
    @Autowired
    private FlowAbleUrl flowAbleUrl;
    @Autowired
    private TaskUtil taskUtil;
    @Autowired
    private TaskService taskService;
    @Autowired
    private ServiceUtil serviceUtil;
    @Autowired
    private OperatorUtil operatorUtil;
    @Autowired
    private ConditionService conditionService;
    @Autowired
    private TemplateNodeService templateNodeService;
    @Autowired
    private TemplateJsonService templateJsonService;
    @Autowired
    private RecordUtil recordUtil;
    @Autowired
    private CirculateUtil circulateUtil;
    @Autowired
    private CandidatesService candidatesService;
    @Autowired
    private MsgUtil msgUtil;
    @Autowired
    private RejectDataService rejectDataService;
    @Autowired
    private RecordService recordService;
    @Autowired
    private LaunchUserService launchUserService;
    @Autowired
    private DelegateService delegateService;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private ButtonUtil buttonUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private NodeRecordService nodeRecordService;
    @Autowired
    private TaskLineService taskLineService;
    @Autowired
    private RevokeService revokeService;

    @Override
    public OperatorEntity getInfo(String id) throws WorkFlowException {
        if (StringUtil.isBlank(id)) {
            return null;
        }
        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OperatorEntity::getId, id);
        OperatorEntity operator = this.getOne(queryWrapper);
        if (null == operator) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        return operator;
    }

    @Override
    public List<OperatorEntity> getList(String taskId) {
        if (StringUtil.isBlank(taskId)) {
            return new ArrayList<>();
        }
        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OperatorEntity::getTaskId, taskId).orderByDesc(OperatorEntity::getCreatorTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<OperatorVo> getList(TaskPagination pagination) {
        String loginUserId = StringUtil.isNotEmpty(pagination.getUserId()) ? pagination.getUserId()
                : UserProvider.getLoginUserId();
        List<Integer> statusList = ImmutableList.of(1, 2);
        MPJLambdaWrapper<OperatorEntity> wrapper = JoinWrappers.lambda(OperatorEntity.class)
                .selectAll(OperatorEntity.class)
                .selectAs(OperatorEntity::getStatus, OperatorVo::getStatus)
                .selectAs(OperatorEntity::getNodeName, OperatorVo::getCurrentNodeName)
                .selectAs(TaskEntity::getCreatorUserId, OperatorVo::getCreatorUserId)
                .selectAs(TaskEntity::getUrgent, OperatorVo::getFlowUrgent)
                .selectAs(TaskEntity::getFullName, OperatorVo::getFullName)
                .selectAs(TaskEntity::getFlowName, OperatorVo::getFlowName)
                .selectAs(TaskEntity::getStartTime, OperatorVo::getStartTime)
                .selectAs(TaskEntity::getFlowId, OperatorVo::getFlowId)
                .selectAs(TaskEntity::getFlowVersion, OperatorVo::getFlowVersion)
                .selectAs(TaskEntity::getFlowCategory, OperatorVo::getFlowCategory)
                .leftJoin(TaskEntity.class, TaskEntity::getId, OperatorEntity::getTaskId)
                .leftJoin(TemplateEntity.class, TemplateEntity::getId, TaskEntity::getTemplateId)
                .in(TemplateEntity::getStatus, statusList)
                .eq(OperatorEntity::getCompletion, 0)
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Futility.getCode())
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Waiting.getCode())
                .ne(TaskEntity::getStatus, TaskStatusEnum.CANCEL.getCode())
                .ne(TaskEntity::getStatus, TaskStatusEnum.REVOKED.getCode());

        Integer status = pagination.getStatus();
        switch (pagination.getCategory()) {
            case "0": // 待签
                wrapper.isNull(OperatorEntity::getSignTime).isNull(OperatorEntity::getStartHandleTime)
                        .isNull(OperatorEntity::getHandleStatus);
                break;
            case "1": // 待办
                wrapper.isNotNull(OperatorEntity::getSignTime).isNull(OperatorEntity::getStartHandleTime)
                        .isNull(OperatorEntity::getHandleStatus);
                break;
            case "2": // 在办
                wrapper.isNotNull(OperatorEntity::getSignTime).isNotNull(OperatorEntity::getStartHandleTime)
                        .isNull(OperatorEntity::getHandleStatus);
                break;
            case "5": // 批量在办
                wrapper.isNotNull(OperatorEntity::getSignTime).isNotNull(OperatorEntity::getStartHandleTime)
                        .isNull(OperatorEntity::getHandleStatus)
                        .ne(OperatorEntity::getStatus, OperatorStateEnum.Assist.getCode())
                        .ne(OperatorEntity::getStatus, OperatorStateEnum.AddSign.getCode());
        }
        if (null != status) {
            if (status == -2) {// 超时
                wrapper.isNotNull(OperatorEntity::getDuedate);
            } else {// 7.协办 5.退回
                wrapper.eq(OperatorEntity::getStatus, status);
            }
        }
        // 版本
        String flowId = pagination.getFlowId();
        if (ObjectUtil.isNotEmpty(flowId)) {
            wrapper.eq(TaskEntity::getFlowId, flowId);
        }
        String nodeCode = pagination.getNodeCode();
        if (StringUtil.isNotBlank(nodeCode)) {
            wrapper.eq(OperatorEntity::getNodeCode, nodeCode);
        }

        Boolean delegateType = pagination.getDelegateType();
        Map<String, String[]> delegateListAll = new HashMap<>();
        List<String> handleId = new ArrayList<>();
        // 是否委托
        if (delegateType) {
            List<DelegateEntity> delegateList = delegateService.getByToUserId(loginUserId);
            for (DelegateEntity delegate : delegateList) {
                if (StringUtil.isNotEmpty(delegate.getFlowId())) {
                    String[] flowIds = delegate.getFlowId().split(",");
                    delegateListAll.put(delegate.getUserId(), flowIds);
                } else {
                    handleId.add(delegate.getUserId());
                }
            }
        }
        wrapper.and(t -> {
            t.eq(OperatorEntity::getHandleId, loginUserId);
            if (!handleId.isEmpty()) {
                t.or(t1 -> t1.in(OperatorEntity::getHandleId, handleId).ne(OperatorEntity::getStatus,
                        OperatorStateEnum.Assist.getCode()));
            }
            if (delegateType) {
                for (String key : delegateListAll.keySet()) {
                    t.or(tw -> tw.in(TaskEntity::getTemplateId, delegateListAll.get(key))
                            .eq(OperatorEntity::getHandleId, key)
                            .ne(OperatorEntity::getStatus, OperatorStateEnum.Assist.getCode()));
                }
            }
        });
        // 关键字
        String keyWord = pagination.getKeyword();
        if (ObjectUtil.isNotEmpty(keyWord)) {
            wrapper.and(t -> t.like(TaskEntity::getEnCode, keyWord).or().like(TaskEntity::getFullName, keyWord));
        }
        // 所属分类
        String category = pagination.getFlowCategory();
        if (ObjectUtil.isNotEmpty(category)) {
            List<String> categoryList = Arrays.stream(category.split(",")).collect(Collectors.toList());
            wrapper.in(TaskEntity::getFlowCategory, categoryList);
        }
        // 所属流程
        String templateId = pagination.getTemplateId();
        if (ObjectUtil.isNotEmpty(templateId)) {
            wrapper.eq(TaskEntity::getTemplateId, templateId);
        }
        // 紧急程度
        Integer flowUrgent = pagination.getFlowUrgent();
        if (ObjectUtil.isNotEmpty(flowUrgent)) {
            wrapper.eq(TaskEntity::getUrgent, flowUrgent);
        }
        // 发起人员
        String creatorUserId = pagination.getCreatorUserId();
        if (ObjectUtil.isNotEmpty(creatorUserId)) {
            wrapper.eq(TaskEntity::getCreatorUserId, creatorUserId);
        }
        // 日期范围（近7天、近1月、近3月、自定义）
        if (ObjectUtil.isNotEmpty(pagination.getStartTime()) && ObjectUtil.isNotEmpty(pagination.getEndTime())) {
            wrapper.between(TaskEntity::getStartTime, new Date(pagination.getStartTime()),
                    new Date(pagination.getEndTime()));
        }
        wrapper.orderByDesc(OperatorEntity::getCreatorTime);

        Page<OperatorVo> page = new Page<>(pagination.getCurrentPage(), pagination.getPageSize());
        IPage<OperatorVo> operatorVoPage = this.selectJoinListPage(page, OperatorVo.class, wrapper);

        for (OperatorVo record : operatorVoPage.getRecords()) {
            boolean isUser = record.getHandleId().equals(loginUserId);
            record.setDelegateUser(!isUser ? record.getCreatorUserId() : null);
            // 待签状态
            if (pagination.getCategory().equals("0")) {
                record.setStatus(0);
            }
        }
        return pagination.setData(operatorVoPage.getRecords(), page.getTotal());
    }

    @Override
    public List<OperatorEntity> handleOperator(FlowModel flowModel) throws Exception {
        TaskEntity taskEntity = flowModel.getTaskEntity();
        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
        Map<String, NodeModel> nodes = flowModel.getNodes();
        Map<String, Object> formData = flowModel.getFormData();
        String instanceId = taskEntity.getInstanceId();
        String deploymentId = flowModel.getDeploymentId();
        NodeModel global = nodes.get(NodeEnum.global.getType());
        OperatorEntity operatorEntity = flowModel.getOperatorEntity();
        // 最终要返回一个所有节点下的审批人的集合
        List<OperatorEntity> list = new ArrayList<>();

        // 原来的当前节点
        List<String> srcCurrentList = StringUtil.isNotEmpty(taskEntity.getCurrentNodeCode())
                ? Arrays.stream(taskEntity.getCurrentNodeCode().split(",")).collect(Collectors.toList())
                : new ArrayList<>();

        // 获取引擎当前任务
        List<FlowableTaskModel> taskModelList = flowAbleUrl.getCurrentTask(instanceId);
        if (CollectionUtil.isEmpty(taskModelList)) {
            return list;
        }
        taskUtil.updateCurrentNode(taskModelList, nodes, taskEntity);
        List<String> types = ImmutableList.of(NodeEnum.subFlow.getType(), NodeEnum.approver.getType(),
                NodeEnum.processing.getType());
        List<FlowErrorModel> errorList = new ArrayList<>();

        // 生成经办
        for (FlowableTaskModel model : taskModelList) {
            // 当前节点已存在，跳过
            if (CollectionUtil.isNotEmpty(srcCurrentList) && srcCurrentList.contains(model.getTaskKey())) {
                continue;
            }
            // 获取对应的节点信息
            TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                    .filter(e -> e.getNodeCode().equals(model.getTaskKey())).findFirst().orElse(null);
            if (null == nodeEntity) {
                continue;
            }
            NodeModel nodeModel = JsonUtil.getJsonToBean(nodeEntity.getNodeJson(), NodeModel.class);
            if (nodeModel == null) {
                continue;
            }
            // 不是审批、子流程节点
            if (!types.contains(nodeModel.getType())) {
                continue;
            }
            // 流程参数
            taskUtil.updateGlobalParam(taskEntity, nodeModel, global, flowModel.getFormData());
            flowModel.setFlowableTaskId(model.getTaskId());
            // 处理子流程节点，传递表单数据
            if (nodeModel.getType().equals(NodeEnum.subFlow.getType())) {
                if (StringUtil.isEmpty(taskEntity.getRejectDataId())
                        && CollectionUtil.isEmpty(flowModel.getErrorRuleUserList())) {
                    FlowMethod method = new FlowMethod();
                    method.setDeploymentId(flowModel.getDeploymentId());
                    method.setNodeCode(nodeModel.getNodeId());
                    method.setNodes(flowModel.getNodes());
                    method.setFormData(flowModel.getFormData());
                    List<NodeModel> nextApprover = taskUtil.getNextApprover(method);
                    int nextError = taskUtil.checkNextError(flowModel, nextApprover, true, true, true);
                    if (nextError == 3) {
                        errorList.addAll(flowModel.getErrorList());
                        flowModel.setErrorList(new ArrayList<>());
                        continue;
                    } else if (nextError == 2) {
                        throw new WorkFlowException(MsgCode.WF061.get());
                    }
                }
                flowModel.setOperatorEntity(operatorEntity);
                operatorUtil.handleSubFlow(nodeEntity, flowModel);
                continue;
            }
            FlowMethod flowMethod = new FlowMethod();
            flowMethod.setTaskEntity(taskEntity);
            flowMethod.setNodeEntity(nodeEntity);
            flowMethod.setNodeEntityList(nodeEntityList);
            flowMethod.setFlowModel(flowModel);
            flowMethod.setIsAssign(true);
            flowMethod.setIsData(true);
            taskUtil.dataTransfer(flowMethod);
            flowMethod.setNodeModel(nodeModel);
            flowMethod.setFormData(formData);
            flowMethod.setDeploymentId(deploymentId);
            flowMethod.setNodeCode(nodeEntity.getNodeCode());
            flowMethod.setNodes(nodes);
            // 节点自动审批
            if (taskEntity.getRejectDataId() == null) {
                int flag = operatorUtil.checkAuto(flowMethod);
                if (flag == 1 || flag == 2) {
                    // 判断下一级是否存在候选人，存在候选人返回false
                    List<NodeModel> nextApprover;
                    boolean mark = true;
                    try {
                        nextApprover = taskUtil.getNextApprover(flowMethod);
                    } catch (WorkFlowException e) {
                        nextApprover = null;
                        mark = false;
                    }
                    Map<String, Boolean> resMap = conditionService.handleCondition(flowMethod);
                    try {
                        conditionService.checkCondition(resMap, nodes);
                    } catch (WorkFlowException e) {
                        mark = false;
                    }
                    // 下一节点的条件判断不满足，不触发系统审批
                    if (mark) {
                        boolean isBranch = taskUtil.checkBranch(nodeModel);
                        int nextError = taskUtil.checkNextError(flowModel, nextApprover, false, false);
                        if (!isBranch && taskUtil.checkNextCandidates(nextApprover) && nextError == 0) {
                            flowModel.setHandleOpinion("系统审批");
                            flowModel.setSignImg(null);
                            flowModel.setFileList(null);
                            flowModel.setHandleStatus(
                                    flag == 1 ? FlowNature.AuditCompletion : FlowNature.RejectCompletion);
                            flowMethod.setFlowModel(JsonUtil.getJsonToBean(flowModel, FlowModel.class));
                            flowMethod.setNodeModel(nodeModel);
                            OperatorEntity operator = operatorUtil.saveSystemOperator(flowMethod);
                            SystemAuditModel systemAuditModel = new SystemAuditModel();
                            systemAuditModel.setOperator(operator);
                            systemAuditModel.setFlowModel(flowMethod.getFlowModel());
                            SystemAuditHolder.add(systemAuditModel);
                            continue;
                        }
                    }
                }
            }

            // 获取审批人
            flowMethod.setErrorRule(true);
            flowMethod.setExtraRule(true);
            List<String> userIds = taskUtil.userListAll(flowMethod);
            // 获取正常的用户
            List<UserEntity> users = serviceUtil.getUserName(userIds, true);
            // 全局异常处理
            if (users.isEmpty()) {
                // 自动通过
                Integer pass = flowMethod.getPass();
                if (pass > 0) {
                    // 自动审批 要判断候选人等
                    boolean mark = true;
                    List<NodeModel> nextApprover;
                    try {
                        nextApprover = taskUtil.getNextApprover(flowMethod);
                    } catch (WorkFlowException e) {
                        // 异常节点（默认通过）下条件不满足、候选人，走admin兜底方案
                        nextApprover = null;
                        mark = false;
                    }
                    Map<String, Boolean> resMap = conditionService.handleCondition(flowMethod);
                    try {
                        conditionService.checkCondition(resMap, nodes);
                    } catch (WorkFlowException e) {
                        mark = false;
                    }
                    if (mark && !taskUtil.checkBranch(nodeModel) && taskUtil.checkNextCandidates(nextApprover)) {
                        flowModel.setHandleOpinion(
                                ObjectUtil.equals(nodeModel.getType(), NodeEnum.processing.getType()) ? "默认办理通过"
                                        : "默认审批通过");
                        flowModel.setSignImg(null);
                        flowModel.setFileList(null);
                        flowModel.setHandleStatus(FlowNature.AuditCompletion);
                        flowMethod.setFlowModel(JsonUtil.getJsonToBean(flowModel, FlowModel.class));
                        flowMethod.setNodeModel(nodeModel);
                        OperatorEntity operator = operatorUtil.saveSystemOperator(flowMethod);
                        SystemAuditModel systemAuditModel = new SystemAuditModel();
                        systemAuditModel.setOperator(operator);
                        systemAuditModel.setFlowModel(flowMethod.getFlowModel());
                        SystemAuditHolder.add(systemAuditModel);
                        continue;
                    } else {
                        String admin = serviceUtil.getAdmin();
                        UserEntity userEntity = serviceUtil.getUserInfo(admin);
                        users.add(userEntity);
                    }
                }
                // 上一节点审批人指定处理人
                Integer node = flowMethod.getNode();
                if (node > 0) {
                    operatorUtil.handleErrorRule(nodeModel, errorList);
                }
                // 无法提交
                Integer notSubmit = flowMethod.getNotSubmit();
                if (notSubmit > 0) {
                    throw new WorkFlowException(MsgCode.WF061.get());
                }
            }
            userIds = users.stream().map(UserEntity::getId).collect(Collectors.toList());
            flowMethod.setNodeModel(nodeModel);
            flowMethod.setUserIds(userIds);
            flowMethod.setFlowModel(flowModel);
            List<OperatorEntity> operator = operatorUtil.createOperator(flowMethod);
            list.addAll(operator);
        }

        if (!errorList.isEmpty()) {
            AuditModel model = new AuditModel();
            model.setErrorCodeList(errorList);
            throw new WorkFlowException(200, JsonUtil.getObjectToString(model));
        }
        flowModel.setList(list);
        return list;
    }

    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public void auditWithCheck(String id, FlowModel flowModel) throws Exception {
        this.audit(id, flowModel);
    }

    @Override
    public void audit(String id, FlowModel flowModel) throws Exception {
        OperatorEntity operator = operatorUtil.checkOperator(id);
        taskUtil.setFlowModel(operator.getTaskId(), flowModel);
        TaskEntity taskEntity = flowModel.getTaskEntity();
        String handleOpinion = flowModel.getHandleOpinion();
        String signId = flowModel.getSignId();
        String signImg = flowModel.getSignImg();
        Boolean useSignNext = flowModel.getUseSignNext();
        Map<String, Object> formData = flowModel.getFormData();
        Map<String, NodeModel> nodes = flowModel.getNodes();
        NodeModel global = nodes.get(NodeEnum.global.getType());
        NodeModel nodeModel = nodes.get(operator.getNodeCode());
        TemplateJsonEntity jsonEntity = flowModel.getJsonEntity();
        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
        TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                .filter(e -> StringUtil.equals(e.getNodeCode(), operator.getNodeCode())).findFirst().orElse(null);
        String formId = null != nodeEntity ? nodeEntity.getFormId() : "";
        // 获取流程参数
        taskUtil.getGlobalParam(taskEntity, nodeModel, global, formData);
        flowModel.setTaskEntity(taskEntity);
        RevokeEntity revokeEntity = revokeService.getRevokeTask(taskEntity.getId());
        if (CollectionUtil.isNotEmpty(formData) && null == revokeEntity) {
            FlowFormDataModel model = new FlowFormDataModel();
            model.setFormId(formId);
            model.setId(taskEntity.getId());
            model.setFormOperates(nodeModel.getFormOperates());
            model.setMap(formData);
            model.setFlowId(jsonEntity.getId());
            serviceUtil.saveOrUpdateFormData(model);
        }
        formData = serviceUtil.infoData(formId, taskEntity.getId());
        // 表单
        if (CollectionUtil.isNotEmpty(formData)) {
            flowModel.setFormData(formData);
            // 保存表单到线程
            FlowContextHolder.addChildData(taskEntity.getId(), formId, formData, nodeModel.getFormOperates(), false);
        }
        this.audit(operator, flowModel);
        if (useSignNext) {
            serviceUtil.updateSign(signId, signImg);
        }
        serviceUtil.addCommonWordsNum(handleOpinion);
        // 保存表单数据
        // FlowContextHolder.delete(taskEntity.getId(), formId);
        FlowContextHolder.deleteFormOperator();
        serviceUtil.handleFormData(taskEntity.getFlowId(), true);
    }

    @Override
    public void audit(OperatorEntity operator, FlowModel flowModel) throws Exception {
        TaskEntity taskEntity = flowModel.getTaskEntity();
        // 判断是否审批过
        if (null != operator.getHandleStatus()) {
            return;
        }
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);

        if (null == flowModel.getUserInfo()) {
            flowModel.setUserInfo(UserProvider.getUser());
        }
        RevokeEntity revokeEntity = revokeService.getRevokeTask(taskEntity.getId());
        if (null != revokeEntity) {
            // 处理撤销的经办
            operatorUtil.handleRevoke(flowModel, operator, revokeEntity);
            return;
        }

        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
        TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                .filter(e -> StringUtil.equals(e.getNodeCode(), operator.getNodeCode())).findFirst().orElse(null);
        if (nodeEntity == null) {
            throw new WorkFlowException(MsgCode.WF076.get());
        }
        flowModel.setNodeEntity(nodeEntity);
        String deploymentId = flowModel.getDeploymentId();
        Map<String, NodeModel> nodes = flowModel.getNodes();
        NodeModel nodeModel = nodes.get(operator.getNodeCode());
        // 全局节点
        TemplateNodeEntity globalEntity = nodeEntityList.stream()
                .filter(e -> StringUtil.equals(NodeEnum.global.getType(), e.getNodeType())).findFirst()
                .orElse(new TemplateNodeEntity());
        NodeModel global = JsonUtil.getJsonToBean(globalEntity.getNodeJson(), NodeModel.class);

        // 表单
        Map<String, Object> formData = flowModel.getFormData();

        if (CollectionUtil.isNotEmpty(flowModel.getCandidateList())) {
            // 或签，删除其他人选择的候选人
            if (ObjectUtil.equals(nodeModel.getCounterSign(), 0)) {
                NextOrPrevFo nextOrPrevFo = new NextOrPrevFo();
                nextOrPrevFo.setDeploymentId(flowModel.getDeploymentId());
                nextOrPrevFo.setTaskKey(operator.getNodeCode());
                List<FlowableNodeModel> nextModels = flowAbleUrl.getNext(nextOrPrevFo);
                List<String> nextCodes = nextModels.stream().map(FlowableNodeModel::getId).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(nextCodes)) {
                    candidatesService.deleteByCodes(operator.getTaskId(), nextCodes);
                }
            }
        }
        // 保存候选人、异常人
        candidatesService.create(flowModel, operator.getTaskId(), nodeEntityList, operator);

        // 流程参数
        taskUtil.updateGlobalParam(taskEntity, nodeModel, global, flowModel.getFormData());
        flowModel.setTaskEntity(taskEntity);

        FlowMethod flowMethod = new FlowMethod();
        Integer handleStatus = flowModel.getHandleStatus();
        if (handleStatus.equals(FlowNature.AuditCompletion)) {
            operator.setHandleStatus(FlowNature.AuditCompletion);
            flowMethod.setType(RecordEnum.audit.getCode());
            flowModel.setEventStatus(4);
        } else {
            operator.setHandleStatus(FlowNature.RejectCompletion);
            flowMethod.setType(RecordEnum.reject.getCode());
            flowModel.setEventStatus(5);
        }

        // 同意、拒绝
        operator.setHandleTime(new Date());
        operator.setCompletion(1);
        this.updateById(operator);
        if (StringUtil.isNotBlank(operator.getDraftData())) {
            // 清除草稿数据
            UpdateWrapper<OperatorEntity> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(OperatorEntity::getId, operator.getId())
                    .set(OperatorEntity::getDraftData, null);
            this.update(updateWrapper);
        }
        // 记录
        flowMethod.setFlowModel(flowModel);
        flowMethod.setOperatorEntity(operator);
        recordUtil.createRecord(flowMethod);

        flowMethod.setTaskEntity(taskEntity);
        flowMethod.setNodeEntity(nodeEntity);
        flowMethod.setNodeEntityList(nodeEntityList);
        flowMethod.setDeploymentId(deploymentId);
        flowMethod.setFormData(formData);
        flowMethod.setNodes(nodes);
        flowMethod.setNodeCode(operator.getNodeCode());
        flowMethod.setNodeModel(nodeModel);
        flowMethod.setHandleStatus(handleStatus);
        // 抄送
        List<CirculateEntity> circulateList = new ArrayList<>();
        if (flowModel.getCopyMsgFlag()) {
            circulateList = circulateUtil.circulateList(flowMethod);
        }
        flowMethod.setCirculateList(circulateList);

        // 判断加签比例
        if (!StringUtil.equals(operator.getParentId(), "0")) {
            operatorUtil.handleAddCounterSign(operator, flowModel);
            FlowMsgModel flowMsgModel = new FlowMsgModel();
            flowMsgModel.setNodeList(nodeEntityList);
            flowMsgModel.setCirculateList(circulateList);
            flowMsgModel.setFlowModel(flowModel);
            flowMsgModel.setTaskEntity(taskEntity);
            flowMsgModel.setNodeCode(nodeEntity.getNodeCode());
            flowMsgModel.setWait(false);
            flowMsgModel.setCopy(true);
            flowMsgModel.setFormData(FlowContextHolder.getAllData());
            msgUtil.message(flowMsgModel);
            return;
        }
        // 选择分支
        candidatesService.createBranch(flowModel.getBranchList(), operator);

        // 指派的经办无需计算比例，或系统审批
        if (!ObjectUtil.equals(operator.getStatus(), OperatorStateEnum.Assigned.getCode())
                || ObjectUtil.equals(operator.getHandleId(), FlowNature.SYSTEM_CODE)) {
            // 判断比例
            boolean auditRes = operatorUtil.checkAudit(flowMethod);
            if (!auditRes) {
                return;
            }
        }
        operatorUtil.addEvent(flowModel);
        Integer tempStatus = flowMethod.getHandleStatus() != null ? flowMethod.getHandleStatus() : handleStatus;
        // 判断拒绝后是否继续流转
        if (FlowNature.RejectCompletion.equals(tempStatus) && !global.getHasContinueAfterReject()) {
            flowMethod.setOperatorEntity(operator);
            flowMethod.setFlowModel(flowModel);
            taskUtil.handleEndTask(flowMethod);
            return;
        }
        flowModel.setOperatorEntity(operator);
        boolean isRejectDataId = taskEntity.getRejectDataId() != null;
        if (isRejectDataId) {
            operatorUtil.handleRejectData(flowModel);
        } else {
            List<String> branchList = candidatesService.getBranch(operator.getTaskId(), operator.getNodeCode());
            Map<String, Boolean> resMap;
            if (branchList.isEmpty()) {
                resMap = conditionService.handleCondition(flowMethod);
                conditionService.checkCondition(resMap, nodes);
            } else {
                resMap = conditionService.getForBranch(flowMethod, branchList);
            }
            taskLineService.create(taskEntity.getId(), resMap);

            // 完成
            CompleteFo fo = new CompleteFo();
            fo.setTaskId(operator.getNodeId());
            fo.setVariables(new HashMap<>(resMap));
            flowAbleUrl.complete(fo);
        }
        // 节点记录
        NodeRecordModel nodeRecordModel = new NodeRecordModel();
        nodeRecordModel.setTaskId(operator.getTaskId());
        nodeRecordModel.setNodeId(operator.getNodeId());
        nodeRecordModel.setNodeCode(operator.getNodeCode());
        nodeRecordModel.setNodeName(operator.getNodeName());
        nodeRecordModel
                .setNodeStatus(ObjectUtil.equals(flowMethod.getHandleStatus(), FlowNature.AuditCompletion) ? 2 : 3);
        nodeRecordService.create(nodeRecordModel);

        // 生成下一节点
        List<OperatorEntity> entityList = this.handleOperator(flowModel);
        // 删除选择分支
        candidatesService.deleteBranch(operator.getTaskId(), operator.getNodeCode());

        if (!isRejectDataId) {
            boolean isProcessing = ObjectUtil.equals(nodeEntity.getNodeType(), NodeEnum.processing.getType());
            flowModel
                    .setAction(ObjectUtil.equals(handleStatus, FlowNature.RejectCompletion) ? 2 : isProcessing ? 4 : 1);
            operatorUtil.handleTrigger(operator, flowModel);
        }

        // 判断任务是否结束
        flowModel.setHandleStatus(flowMethod.getHandleStatus() != null ? flowMethod.getHandleStatus() : handleStatus);
        taskUtil.isFinished(flowModel);

        // 消息
        FlowMsgModel flowMsgModel = new FlowMsgModel();
        flowMsgModel.setNodeList(nodeEntityList);
        flowMsgModel.setCirculateList(circulateList);
        flowMsgModel.setFlowModel(flowModel);
        flowMsgModel.setTaskEntity(taskEntity);
        flowMsgModel.setNodeCode(nodeEntity.getNodeCode());
        flowMsgModel.setOperatorList(entityList);
        if (flowModel.getCopyMsgFlag()) {
            flowMsgModel.setCopy(true);
        }
        if (flowModel.getHandleStatus().equals(FlowNature.AuditCompletion)) {
            flowMsgModel.setApprove(true);
        } else {
            flowMsgModel.setReject(true);
        }
        flowMsgModel.setFormData(FlowContextHolder.getAllData());
        msgUtil.message(flowMsgModel);

        // 系统审批
        operatorUtil.systemAudit();
    }

    @Override
    public void sign(FlowModel flowModel) throws WorkFlowException {
        UpdateWrapper<OperatorEntity> updateWrapper = new UpdateWrapper<>();
        if (CollectionUtil.isNotEmpty(flowModel.getIds())) {
            List<String> ids = new ArrayList<>();
            if (flowModel.getType().equals(0)) {
                operatorUtil.checkBatch(flowModel.getIds(), ids, false);
                List<String> list = new ArrayList<>();
                operatorUtil.checkCancel(ids, list);
                // 签收
                updateWrapper.lambda().in(OperatorEntity::getId, list)
                        .set(OperatorEntity::getSignTime, new Date());
            } else {
                operatorUtil.checkBatch(flowModel.getIds(), ids, true);
                List<String> list = new ArrayList<>();
                operatorUtil.checkCancel(ids, list);
                // 退签
                updateWrapper.lambda().in(OperatorEntity::getId, list)
                        .set(OperatorEntity::getSignTime, null);
            }
            this.update(updateWrapper);
        }
    }

    @Override
    public void startHandle(FlowModel flowModel) throws WorkFlowException {
        List<String> ids = new ArrayList<>();
        operatorUtil.checkBatch(flowModel.getIds(), ids, false);
        List<String> list = new ArrayList<>();
        operatorUtil.checkCancel(ids, list);

        UpdateWrapper<OperatorEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().in(OperatorEntity::getId, list)
                .set(OperatorEntity::getStartHandleTime, new Date());
        this.update(updateWrapper);
    }

    @Override
    public void saveAudit(String id, FlowModel flowModel) throws WorkFlowException {
        OperatorEntity entity = this.getById(id);
        if (null == entity) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        TaskEntity taskEntity = taskService.getInfo(entity.getTaskId());
        taskUtil.checkTemplateHide(taskEntity.getTemplateId());
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);
        entity.setDraftData(JsonUtil.getObjectToString(flowModel.getFormData()));
        this.updateById(entity);
    }

    @DSTransactional
    @Override
    public void addSign(String id, FlowModel flowModel) throws Exception {
        OperatorEntity operator = operatorUtil.checkOperator(id);
        List<OperatorEntity> childList = operatorUtil.getChildList(operator.getId());
        childList = childList.stream()
                .filter(e -> ObjectUtil.equals(e.getCompletion(), 0) && !ObjectUtil.equals(e.getStatus(), -1))
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(childList)) {
            throw new WorkFlowException(MsgCode.WF081.get());
        }
        AddSignModel parameter = flowModel.getAddSignParameter();
        List<String> idList = parameter.getAddSignUserIdList();
        buttonUtil.checkAddSign(operator, parameter);
        // 保存选择分支
        List<String> branchList = flowModel.getBranchList();
        if (CollectionUtil.isNotEmpty(branchList)) {
            candidatesService.createBranch(branchList, operator);
        }
        if (idList.isEmpty() || operator.getStatus().equals(OperatorStateEnum.Transfer.getCode())
                || operator.getStatus().equals(OperatorStateEnum.Assist.getCode())) {
            throw new WorkFlowException(MsgCode.WF081.get());
        }
        String userId = UserProvider.getLoginUserId();
        if (idList.contains(userId)) {
            throw new WorkFlowException(MsgCode.WF106.get());
        }
        if (!ObjectUtil.equals(operator.getHandleId(), userId)) {
            List<DelegateEntity> delegateList = delegateService.getByToUserId(userId);
            List<String> userIds = delegateList.stream().map(DelegateEntity::getUserId).distinct()
                    .collect(Collectors.toList());
            List<String> filterList = userIds.stream().filter(idList::contains).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(filterList)) {
                throw new WorkFlowException(MsgCode.WF116.get());
            }
        }
        // 将之前的加签经办作废
        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId()).eq(OperatorEntity::getParentId, id)
                .and(i -> i.eq(OperatorEntity::getStatus, OperatorStateEnum.AddSign.getCode())
                        .or().eq(OperatorEntity::getStatus, OperatorStateEnum.Recall.getCode()));
        List<OperatorEntity> list = this.list(queryWrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            list.forEach(e -> e.setStatus(OperatorStateEnum.Futility.getCode()));
            this.updateBatchById(list);
        }
        taskUtil.setFlowModel(operator.getTaskId(), flowModel);
        TaskEntity taskEntity = flowModel.getTaskEntity();
        taskUtil.checkTemplateHide(taskEntity.getTemplateId());
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);
        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
        Map<String, Object> formData = flowModel.getFormData();
        // 表单
        if (CollectionUtil.isNotEmpty(formData)) {
            TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                    .filter(e -> StringUtil.equals(e.getNodeCode(), operator.getNodeCode())).findFirst().orElse(null);
            if (null != nodeEntity) {
                NodeModel nodeModel = JsonUtil.getJsonToBean(nodeEntity.getNodeJson(), NodeModel.class);
                // 保存表单到线程
                FlowContextHolder.addChildData(taskEntity.getId(), nodeEntity.getFormId(), formData,
                        nodeModel.getFormOperates(), true);
            }
        }
        // 保存候选人、异常人
        candidatesService.create(flowModel, operator.getTaskId(), nodeEntityList, operator);
        // 更新经办信息
        operator.setHandleParameter(JsonUtil.getObjectToString(parameter));
        if (parameter.getAddSignType().equals(2)) {
            operator.setHandleStatus(FlowNature.AuditCompletion);
        }
        operator.setCompletion(1);
        if (this.updateById(operator)) {
            TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                    .filter(e -> e.getNodeCode().equals(operator.getNodeCode())).findFirst().orElse(null);
            if (null == nodeEntity) {
                throw new WorkFlowException(MsgCode.WF076.get());
            }

            NodeModel nodeModel = JsonUtil.getJsonToBean(nodeEntity.getNodeJson(), NodeModel.class);
            // 全局节点
            TemplateNodeEntity globalEntity = nodeEntityList.stream()
                    .filter(e -> StringUtil.equals(NodeEnum.global.getType(), e.getNodeType())).findFirst()
                    .orElse(new TemplateNodeEntity());
            NodeModel global = JsonUtil.getJsonToBean(globalEntity.getNodeJson(), NodeModel.class);
            Date date = new Date();
            // 后加签默认同意的记录
            if (parameter.getAddSignType().equals(2)) {
                FlowMethod flowMethod = new FlowMethod();
                flowMethod.setType(RecordEnum.audit.getCode());
                flowMethod.setFlowModel(flowModel);
                operator.setHandleTime(date);
                flowMethod.setOperatorEntity(operator);
                recordUtil.createRecord(flowMethod);
            }
            // 生成加签的经办
            List<OperatorEntity> entityList = new ArrayList<>();
            for (String handleId : idList) {
                FlowMethod flowMethod = new FlowMethod();
                flowMethod.setTaskEntity(taskEntity);
                flowMethod.setNodeEntity(nodeEntity);
                flowMethod.setNodeModel(nodeModel);
                flowMethod.setSignFor(global.getHasSignFor());
                flowMethod.setFlowableTaskId(operator.getNodeId());
                OperatorEntity entity = operatorUtil.createOperatorEntity(flowMethod);
                entity.setHandleId(handleId);
                entity.setParentId(operator.getId());
                entity.setStatus(OperatorStateEnum.AddSign.getCode());
                entityList.add(entity);
                if (ObjectUtil.equals(parameter.getCounterSign(), 2)) {
                    break;
                }
            }
            // 加签记录
            FlowMethod flowMethod = new FlowMethod();
            flowMethod.setFlowModel(flowModel);
            operator.setHandleTime(date);
            flowMethod.setOperatorEntity(operator);
            Integer type = RecordEnum.addSign.getCode();
            flowMethod.setType(type);
            flowMethod.setUserId(String.join(",", idList));
            recordUtil.createRecord(flowMethod);
            if (CollectionUtil.isNotEmpty(entityList)) {
                this.saveBatch(entityList);
                // 消息
                FlowMsgModel flowMsgModel = new FlowMsgModel();
                flowMsgModel.setOperatorList(entityList);
                flowMsgModel.setNodeList(nodeEntityList);
                flowMsgModel.setFlowModel(flowModel);
                flowMsgModel.setTaskEntity(taskEntity);
                flowMsgModel.setNodeCode(operator.getNodeCode());
                flowMsgModel.setFormData(FlowContextHolder.getAllData());
                msgUtil.message(flowMsgModel);
                // 超时
                TimeUtil.timeModel(entityList, flowModel, redisUtil);
            }
        }
        serviceUtil.handleFormData(taskEntity.getFlowId(), false);
    }

    @Override
    public List<ReduceUserModel> getReduceList(String id, ReducePagination pagination) throws WorkFlowException {
        RecordEntity record = recordService.getInfo(id);
        if (null == record) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        OperatorEntity operator = this.getById(record.getOperatorId());
        if (null == operator) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        if (null == operator.getHandleParameter()) {
            throw new WorkFlowException(MsgCode.WF082.get());
        }
        pagination.setOperator(operator);

        AddSignModel model = JsonUtil.getJsonToBean(operator.getHandleParameter(), AddSignModel.class);

        List<ReduceUserModel> list = new ArrayList<>();

        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId())
                .eq(OperatorEntity::getParentId, operator.getId())
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Futility.getCode())
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Assist.getCode());
        List<OperatorEntity> entityList = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(entityList)) {
            return list;
        }

        // 获取未审批的加签经办
        List<OperatorEntity> todoList = entityList.stream().filter(e -> null == e.getHandleStatus()
                && ObjectUtil.equals(e.getCompletion(), 0)).collect(Collectors.toList());

        // 依次审批，获取未创建经办的人员
        if (ObjectUtil.equals(model.getCounterSign(), 2) && CollectionUtil.isNotEmpty(todoList)) {
            List<String> idList = model.getAddSignUserIdList();
            OperatorEntity operatorEntity = todoList.get(0);
            int index = idList.indexOf(operatorEntity.getHandleId());
            if (index < idList.size() - 1) {
                for (int i = index + 1; i < idList.size(); i++) {
                    OperatorEntity op = new OperatorEntity();
                    op.setHandleId(idList.get(i));
                    todoList.add(op);
                }
            }
        }

        return operatorUtil.getReduceUsers(todoList, pagination);
    }

    // 减签
    @Override
    @DSTransactional
    public void reduce(String id, FlowModel flowModel) throws WorkFlowException {
        List<String> ids = flowModel.getIds();
        RecordEntity record = recordService.getInfo(id);
        if (null == record) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        OperatorEntity operator = this.getById(record.getOperatorId());
        if (null == operator) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }

        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId())
                .eq(OperatorEntity::getParentId, operator.getId())
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Futility.getCode())
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Assist.getCode());
        List<OperatorEntity> list = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(list)) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        if (CollectionUtil.isNotEmpty(ids)) {
            String userId = ids.get(0);
            OperatorEntity operatorEntity = list.stream()
                    .filter(e -> ObjectUtil.equals(e.getHandleId(), userId) && e.getHandleTime() != null).findFirst()
                    .orElse(null);
            if (null != operatorEntity && null != operatorEntity.getHandleStatus()) {
                throw new WorkFlowException(MsgCode.WF128.get());
            }
        }
        AddSignModel model = JsonUtil.getJsonToBean(operator.getHandleParameter(), AddSignModel.class);
        boolean inTurn = ObjectUtil.equals(model.getCounterSign(), 2);

        List<OperatorEntity> unApproved = list.stream()
                .filter(e -> ObjectUtil.equals(e.getCompletion(), 0) && e.getHandleTime() == null)
                .collect(Collectors.toList());
        if (inTurn) {
            // 依次审批的处理
            List<String> idList = model.getAddSignUserIdList();
            OperatorEntity entity = unApproved.stream().filter(e -> ids.contains(e.getHandleId())).findFirst()
                    .orElse(null);
            if (null != entity) {
                taskUtil.setFlowModel(operator.getTaskId(), flowModel);
                Map<String, NodeModel> nodes = flowModel.getNodes();
                NodeModel global = nodes.get(NodeEnum.global.getType());

                int index = idList.indexOf(entity.getHandleId());
                if (index == idList.size() - 1) {
                    throw new WorkFlowException(MsgCode.WF109.get());
                }
                String handleId = idList.get(index + 1);
                // 创建下一个经办
                OperatorEntity newOperator = operatorUtil.createOperator(entity, OperatorStateEnum.AddSign.getCode(),
                        handleId, global);
                this.save(newOperator);
                FlowMethod flowMethod = new FlowMethod();
                flowMethod.setFlowModel(flowModel);
                flowMethod.setAddSignModel(model);
                flowMethod.setOperatorEntity(operator);
                flowMethod.setTaskEntity(flowModel.getTaskEntity());
                List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
                flowMethod.setNodeEntityList(nodeEntityList);
                TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                        .filter(e -> ObjectUtil.equals(e.getNodeCode(), operator.getNodeCode()))
                        .findFirst().orElse(null);
                flowMethod.setNodeEntity(nodeEntity);
                operatorUtil.improperApproverMessage(flowMethod, newOperator);
                // 删除需要减签的经办
                this.removeById(entity);
            }
            // 更新handleParameter
            idList.removeAll(ids);
            model.setAddSignUserIdList(idList);
            operator.setHandleParameter(JsonUtil.getObjectToString(model));
            this.updateById(operator);
        } else {
            if (unApproved.size() == 1) {
                throw new WorkFlowException(MsgCode.WF109.get());
            }
        }
        // 记录
        FlowMethod flowMethod = new FlowMethod();
        flowMethod.setFlowModel(flowModel);
        flowMethod.setOperatorEntity(operator);
        Integer type = RecordEnum.subtractSign.getCode();
        flowMethod.setType(type);
        flowMethod.setUserId(String.join(",", ids));
        recordUtil.createRecord(flowMethod);

        if (inTurn) {
            return;
        }

        List<String> handleIds = list.stream().map(OperatorEntity::getHandleId).collect(Collectors.toList());

        handleIds.removeAll(ids);

        if (handleIds.isEmpty()) {
            // 全部减签
            this.removeByIds(list);
            // 还原经办
            UpdateWrapper<OperatorEntity> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(OperatorEntity::getId, operator.getId())
                    .set(OperatorEntity::getCompletion, 0)
                    .set(OperatorEntity::getHandleParameter, null);
            this.update(updateWrapper);
        } else {
            List<OperatorEntity> collect = list.stream().filter(t -> ids.contains(t.getHandleId()))
                    .collect(Collectors.toList());
            this.removeByIds(collect);
        }
    }

    // 获取可退回的节点
    @Override
    public List<BackNodeModel> getFallbacks(String id) throws WorkFlowException {
        OperatorEntity operator = this.getInfo(id);
        if (null == operator) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        TaskEntity taskEntity = taskService.getInfo(operator.getTaskId());
        if (null == taskEntity) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }
        TemplateJsonEntity jsonEntity = templateJsonService.getInfo(taskEntity.getFlowId());
        List<TemplateNodeEntity> nodeEntityList = templateNodeService.getList(taskEntity.getFlowId());
        Map<String, NodeModel> nodes = new HashMap<>();
        for (TemplateNodeEntity nodeEntity : nodeEntityList) {
            nodes.put(nodeEntity.getNodeCode(), JsonUtil.getJsonToBean(nodeEntity.getNodeJson(), NodeModel.class));
        }

        NodeModel nodeModel = nodes.get(operator.getNodeCode());
        List<BackNodeModel> list = new ArrayList<>();

        // 获取经办过滤
        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId());
        List<OperatorEntity> operatorEntityList = this.list(queryWrapper);
        List<String> nodeList = operatorEntityList.stream().map(OperatorEntity::getNodeCode).distinct()
                .collect(Collectors.toList());

        TemplateNodeEntity start = nodeEntityList.stream().filter(e -> e.getNodeType().equals(NodeEnum.start.getType()))
                .findFirst().orElse(null);
        if (null == start) {
            throw new WorkFlowException(MsgCode.WF076.get());
        }
        NodeModel startModel = JsonUtil.getJsonToBean(start.getNodeJson(), NodeModel.class);
        if (ObjectUtil.equals(nodeModel.getBackNodeCode(), FlowNature.START)) {
            BackNodeModel model = new BackNodeModel();
            model.setNodeName(startModel.getNodeName());
            model.setNodeCode(startModel.getNodeId());
            list.add(model);
        } else if (ObjectUtil.equals(nodeModel.getBackNodeCode(), FlowNature.UP)) {
            List<String> resList = new ArrayList<>();
            List<String> nodeCodeList = new ArrayList<>();
            taskUtil.prevNode(jsonEntity.getFlowableId(), operator.getNodeCode(), nodeEntityList, nodeCodeList);

            List<String> nodeCodes = operatorUtil.getList(taskEntity.getId()).stream()
                    .filter(e -> !e.getStatus().equals(OperatorStateEnum.Futility.getCode()))
                    .map(OperatorEntity::getNodeCode).distinct().collect(Collectors.toList());
            nodeCodes.add(start.getNodeCode());

            for (String nodeCode : nodeCodeList) {
                NodeModel node = nodes.get(nodeCode);
                // 退回节点包含子流程
                if (null != node && ObjectUtil.equals(node.getType(), NodeEnum.subFlow.getType())) {
                    throw new WorkFlowException(MsgCode.WF046.get());
                }
                if (!nodeCodes.contains(nodeCode)) {
                    continue;
                }
                resList.add(nodeCode);
            }

            if (resList.isEmpty()) {
                resList.addAll(nodeCodeList);
            }

            BackNodeModel model = new BackNodeModel();
            model.setNodeName("上级审批节点");
            model.setNodeCode(String.join(",", resList));
            list.add(model);
        } else if (ObjectUtil.equals(nodeModel.getBackNodeCode(), FlowNature.Reject)) {
            List<String> fallbacks = flowAbleUrl.getFallbacks(operator.getNodeId());
            nodeList.add(start.getNodeCode());
            fallbacks = fallbacks.stream().filter(nodeList::contains).collect(Collectors.toList());
            // 获取经办进行过滤
            List<String> nodeCodeList = operatorUtil.getList(taskEntity.getId()).stream()
                    .filter(e -> !e.getStatus().equals(OperatorStateEnum.Futility.getCode()))
                    .map(OperatorEntity::getNodeCode).distinct().collect(Collectors.toList());
            nodeCodeList.add(start.getNodeCode());

            for (String nodeCode : fallbacks) {
                // 过滤没有走过的点
                if (!nodeCodeList.contains(nodeCode) || ObjectUtil.equals(nodeCode, operator.getNodeCode())) {
                    continue;
                }
                NodeModel node = nodes.get(nodeCode);
                BackNodeModel model = new BackNodeModel();
                model.setNodeName(node.getNodeName());
                model.setNodeCode(node.getNodeId());
                list.add(model);
            }
        } else {
            NodeModel optional = nodes.get(nodeModel.getBackNodeCode());
            if (null != optional) {
                BackNodeModel model = new BackNodeModel();
                model.setNodeName(optional.getNodeName());
                model.setNodeCode(nodeModel.getBackNodeCode());
                list.add(model);
            }
        }
        return list;
    }

    // 退回
    @DSTransactional
    @Override
    public void back(String id, FlowModel flowModel) throws Exception {
        OperatorEntity operator = operatorUtil.checkOperator(id);

        taskUtil.setFlowModel(operator.getTaskId(), flowModel);
        TaskEntity taskEntity = flowModel.getTaskEntity();
        taskUtil.checkTemplateHide(taskEntity.getTemplateId());
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);
        if (null != taskEntity.getRejectDataId()) {
            throw new WorkFlowException(MsgCode.WF083.get());
        }
        Map<String, NodeModel> nodes = flowModel.getNodes();
        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
        String deploymentId = flowModel.getDeploymentId();

        NodeModel nodeModel = nodes.get(operator.getNodeCode());
        TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                .filter(e -> ObjectUtil.equals(e.getNodeCode(), operator.getNodeCode())).findFirst().orElse(null);
        flowModel.setNodeEntity(nodeEntity);

        TemplateNodeEntity start = nodeEntityList.stream().filter(e -> e.getNodeType().equals(NodeEnum.start.getType()))
                .findFirst().orElse(null);
        if (null == start) {
            throw new WorkFlowException(MsgCode.WF076.get());
        }

        Integer backType = flowModel.getBackType();
        String backStep = flowModel.getBackNodeCode();
        List<String> stepList = new ArrayList<>();
        if (FlowNature.START.equals(backStep)) {
            stepList.add(start.getNodeCode());
        } else {
            stepList = StringUtil.isNotEmpty(backStep) ? Arrays.stream(backStep.split(",")).collect(Collectors.toList())
                    : new ArrayList<>();
            // 判断没有经过的节点，不能退回
            List<String> nodeCodeList = operatorUtil.getList(taskEntity.getId()).stream()
                    .filter(e -> !e.getStatus().equals(OperatorStateEnum.Futility.getCode()))
                    .map(OperatorEntity::getNodeCode).distinct().collect(Collectors.toList());
            nodeCodeList.add(start.getNodeCode());
            for (String step : stepList) {
                if (!nodeCodeList.contains(step)) {
                    throw new WorkFlowException(MsgCode.WF047.get());
                }
            }
        }

        AfterFo afterFo = new AfterFo();
        afterFo.setDeploymentId(deploymentId);
        afterFo.setTaskKeys(stepList);
        // 获取目标节点之后的所有节点，将这些节点的经办全部保存、更新状态
        List<String> afterList = flowAbleUrl.getAfter(afterFo);
        afterList.addAll(stepList);
        afterList = afterList.stream().distinct().collect(Collectors.toList());
        QueryWrapper<OperatorEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId())
                .in(OperatorEntity::getNodeCode, afterList);
        List<OperatorEntity> list = this.list(wrapper);

        // 当前审批时 保存 任务、经办 转json
        RejectDataEntity rejectDataEntity = null;
        if (FlowNature.PresentType.equals(backType)) {
            rejectDataEntity = rejectDataService.create(taskEntity, list, stepList.get(0));
        } else {
            // 子流程处理，重新审批：子流程需删除，当前审批：无需终止
            taskUtil.deleteSubflow(taskEntity.getId(), afterList);
        }

        // 更改状态 state 转 -1
        for (OperatorEntity operatorEntity : list) {
            operatorEntity.setStatus(OperatorStateEnum.Futility.getCode());
            // 删除超时相关
            FlowJobUtil.deleteByOperatorId(operatorEntity.getId(), redisUtil);
        }
        this.updateBatchById(list);

        // 记录
        FlowMethod flowMethod = new FlowMethod();
        flowMethod.setType(RecordEnum.back.getCode());
        flowMethod.setFlowModel(flowModel);
        flowMethod.setOperatorEntity(operator);
        recordUtil.createRecord(flowMethod);

        // 记录作废
        if (ObjectUtil.equals(backType, FlowNature.RestartType)) {
            recordService.updateStatusToInvalid(taskEntity.getId(), afterList);
        }

        // 节点记录
        NodeRecordModel nodeRecordModel = new NodeRecordModel();
        nodeRecordModel.setTaskId(operator.getTaskId());
        nodeRecordModel.setNodeId(operator.getNodeId());
        nodeRecordModel.setNodeCode(operator.getNodeCode());
        nodeRecordModel.setNodeName(operator.getNodeName());
        nodeRecordModel.setNodeStatus(5);
        nodeRecordService.create(nodeRecordModel);

        UpdateWrapper<TaskEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(TaskEntity::getId, operator.getTaskId());
        if (null != rejectDataEntity) {
            updateWrapper.lambda().set(TaskEntity::getRejectDataId, rejectDataEntity.getId());
        }
        FlowMsgModel flowMsgModel = new FlowMsgModel();

        flowModel.setAction(3);
        flowModel.setOperatorEntity(operator);
        if (null != nodeEntity) {
            Map<String, Object> map = serviceUtil.infoData(nodeEntity.getFormId(), operator.getTaskId());
            flowModel.setFormData(map);
        }
        if (!FlowNature.PresentType.equals(backType)) {
            operatorUtil.handleTrigger(operator, flowModel);
        }

        // 开始节点
        if (stepList.size() == 1 && stepList.get(0).equals(start.getNodeCode())) {
            // 更新任务
            updateWrapper.lambda()
                    .set(TaskEntity::getCurrentNodeName, FlowNature.START_NAME)
                    .set(TaskEntity::getCurrentNodeCode, FlowNature.START_CODE)
                    .set(TaskEntity::getStatus, TaskStatusEnum.BACKED.getCode());
            if (rejectDataEntity == null) {
                updateWrapper.lambda().set(TaskEntity::getInstanceId, null);
            }
            taskService.update(updateWrapper);

            List<OperatorEntity> entityList = new ArrayList<>();
            OperatorEntity operatorEntity = new OperatorEntity();
            operatorEntity.setNodeCode(start.getNodeCode());
            operatorEntity.setHandleId(taskEntity.getCreatorUserId());
            entityList.add(operatorEntity);
            flowMsgModel.setOperatorList(entityList);
            flowMsgModel.setWait(false);

            if (!FlowNature.PresentType.equals(backType)) {
                // 删除发起用户
                launchUserService.delete(taskEntity.getId());
            }
            // 删除引擎实例
            if (rejectDataEntity == null) {
                String instanceId = taskEntity.getInstanceId();
                flowAbleUrl.deleteInstance(instanceId, "back");
            }
        } else {
            String sourceId = StringUtil.isNotEmpty(flowModel.getBackId()) ? flowModel.getBackId()
                    : operator.getNodeId();
            BackFo fo = new BackFo();
            fo.setTaskId(sourceId);
            fo.setTargetKey(backStep);
            flowAbleUrl.back(fo);
            List<OperatorEntity> entityList = this.handleOperator(flowModel);

            // 更新状态为退回状态
            for (OperatorEntity entity : entityList) {
                entity.setStatus(OperatorStateEnum.Back.getCode());
            }
            this.updateBatchById(entityList);

            flowMsgModel.setOperatorList(entityList);

            TimeUtil.timeModel(entityList, flowModel, redisUtil);

            if (null != rejectDataEntity) {
                taskService.update(updateWrapper);
            }
        }
        if (!FlowNature.PresentType.equals(backType)) {
            // 重新审批，删除候选人
            if (CollectionUtil.isNotEmpty(afterList)) {
                candidatesService.deleteByCodes(taskEntity.getId(), afterList);
            }
        }

        // 消息
        flowMsgModel.setNodeList(nodeEntityList);
        flowMsgModel.setFlowModel(flowModel);
        flowMsgModel.setTaskEntity(taskEntity);
        flowMsgModel.setNodeCode(nodeModel.getNodeId());
        flowMsgModel.setBack(true);
        msgUtil.message(flowMsgModel);

    }

    // 撤回
    @DSTransactional
    @Override
    public void recall(String id, FlowModel flowModel) throws WorkFlowException {
        RecordEntity record = flowModel.getRecordEntity();
        OperatorEntity operator = flowModel.getOperatorEntity();

        taskUtil.setFlowModel(operator.getTaskId(), flowModel);
        TaskEntity taskEntity = flowModel.getTaskEntity();
        taskUtil.checkTemplateHide(taskEntity.getTemplateId());
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);
        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
        if (CollectionUtil.isEmpty(nodeEntityList)) {
            throw new WorkFlowException(MsgCode.WF076.get());
        }
        TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                .filter(e -> e.getNodeCode().equals(operator.getNodeCode())).findFirst().orElse(null);
        if (null == nodeEntity) {
            throw new WorkFlowException(MsgCode.WF076.get());
        }

        flowModel.setNodeEntity(nodeEntity);
        flowModel.setRecordEntity(record);
        flowModel.setFlag(2);
        flowModel.setIsException(true);
        if (!buttonUtil.checkRecall(flowModel)) {
            throw new WorkFlowException(MsgCode.WF077.get());
        }
        List<String> nextCodes = flowModel.getNextCodes();
        // 删除子流程
        taskUtil.deleteSubflow(taskEntity.getId(), nextCodes);

        // 更新记录状态
        record.setStatus(FlowNature.Invalid);
        recordService.updateById(record);

        // 记录
        FlowMethod flowMethod = new FlowMethod();
        flowMethod.setType(RecordEnum.recall.getCode());
        flowMethod.setFlowModel(flowModel);
        operator.setHandleTime(null);
        flowMethod.setOperatorEntity(operator);
        recordUtil.createRecord(flowMethod);

        List<String> currentNodes = new ArrayList<>();
        String currentNodeCode = taskEntity.getCurrentNodeCode();
        if (StringUtil.isNotBlank(currentNodeCode)) {
            currentNodes = Arrays.stream(currentNodeCode.split(",")).collect(Collectors.toList());
        }
        if (currentNodes.contains(operator.getNodeCode())) {
            // 加签 撤回的处理
            if (!ObjectUtil.equals(operator.getParentId(), "0")) {
                OperatorEntity parentEntity = this.getById(operator.getParentId());
                if (null != parentEntity) {
                    if (ObjectUtil.equals(parentEntity.getCompletion(), 0)) {
                        parentEntity.setCompletion(1);
                        this.updateById(parentEntity);
                    }
                }
            }
            // 当前节点已审批的人 撤回无需跳转
            UpdateWrapper<OperatorEntity> wrapper = new UpdateWrapper<>();
            wrapper.lambda().eq(OperatorEntity::getId, operator.getId())
                    .set(OperatorEntity::getCompletion, 0)
                    .set(OperatorEntity::getStatus, OperatorStateEnum.Recall.getCode())
                    .set(OperatorEntity::getHandleStatus, null)
                    .set(OperatorEntity::getCreatorTime, new Date())
                    .set(OperatorEntity::getHandleTime, null);
            // 依次审批，删除其他的经办
            if (StringUtil.isNotBlank(operator.getHandleAll()) && ObjectUtil.equals(operator.getParentId(), "0")) {
                operatorUtil.deleteInTurnOperator(operator, operator.getHandleId());
            }
            this.update(wrapper);
            return;
        }
        // 节点记录
        NodeRecordModel nodeRecordModel = new NodeRecordModel();
        nodeRecordModel.setTaskId(operator.getTaskId());
        nodeRecordModel.setNodeId(operator.getNodeId());
        nodeRecordModel.setNodeCode(operator.getNodeCode());
        nodeRecordModel.setNodeName(operator.getNodeName());
        nodeRecordModel.setNodeStatus(6);
        nodeRecordService.update(nodeRecordModel);

        // 删除该节点下一级的经办
        if (CollectionUtil.isNotEmpty(nextCodes)) {
            QueryWrapper<OperatorEntity> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(OperatorEntity::getTaskId, taskEntity.getId())
                    .in(OperatorEntity::getNodeCode, nextCodes);
            List<OperatorEntity> list = this.list(wrapper);
            if (CollectionUtil.isNotEmpty(list)) {
                this.remove(wrapper);
                // 删除超时相关
                FlowJobUtil.deleteByOperatorId(operator.getId(), redisUtil);
                for (OperatorEntity operatorEntity : list) {
                    FlowJobUtil.deleteByOperatorId(operatorEntity.getId(), redisUtil);
                }
            }
        }

        // 撤回跳转
        JumpFo fo = new JumpFo();
        fo.setInstanceId(taskEntity.getInstanceId());
        List<String> executeNodes = this.getNodeCodeByGroupId(nextCodes, flowModel.getNodes());
        if (CollectionUtil.isNotEmpty(executeNodes)) {
            nextCodes.addAll(executeNodes);
        }
        fo.setSource(nextCodes);
        List<String> targetList = new ArrayList<>();
        targetList.add(nodeEntity.getNodeCode());
        fo.setTarget(targetList);
        flowAbleUrl.jump(fo);

        List<FlowableTaskModel> taskModelList = flowAbleUrl.getCurrentTask(taskEntity.getInstanceId());
        FlowableTaskModel model = taskModelList.stream().filter(e -> e.getTaskKey().equals(operator.getNodeCode()))
                .findFirst().orElse(null);
        String nodeId = null;
        if (null != model) {
            nodeId = model.getTaskId();
        }

        // 还原经办（其它已审批、作废的经办无需还原）
        UpdateWrapper<OperatorEntity> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(OperatorEntity::getId, operator.getId())
                .set(OperatorEntity::getCompletion, 0)
                .set(OperatorEntity::getNodeId, nodeId)
                .set(OperatorEntity::getStatus, OperatorStateEnum.Recall.getCode())
                .set(OperatorEntity::getHandleStatus, null)
                .set(OperatorEntity::getCreatorTime, new Date())
                .set(OperatorEntity::getHandleTime, null);
        this.update(wrapper);
        // 更新节点经办的nodeId
        wrapper.clear();
        wrapper.lambda().eq(OperatorEntity::getTaskId, operator.getTaskId())
                .eq(OperatorEntity::getNodeCode, operator.getNodeCode())
                .eq(OperatorEntity::getParentId, operator.getParentId())
                .set(OperatorEntity::getNodeId, nodeId);
        this.update(wrapper);

        List<String> userIds = new ArrayList<>();
        userIds.add(operator.getHandleId());
        // 获取未审批过的复原
        operatorUtil.recallRestore(operator, nodeId, userIds);

        // 删除该节点下一级的候选人，有修改操作的
        // candidatesService.deleteByCodes(taskEntity.getId(), nextCodes);
        candidatesService.delete(taskEntity.getId(), nextCodes, userIds);

        // 超时
        List<OperatorEntity> entityList = new ArrayList<>();
        OperatorEntity entity = this.getById(operator.getId());
        entityList.add(entity);
        TimeUtil.timeModel(entityList, flowModel, redisUtil);

        // 获取当前节点信息
        taskUtil.updateCurrentNode(taskModelList, flowModel.getNodes(), taskEntity);
    }

    // 根据组ID获取同组的执行节点
    public List<String> getNodeCodeByGroupId(List<String> nextCodes, Map<String, NodeModel> nodes) {
        List<String> list = new ArrayList<>();
        if (CollectionUtil.isEmpty(nextCodes) || CollectionUtil.isEmpty(nodes)) {
            return list;
        }
        for (String nextCode : nextCodes) {
            NodeModel nodeModel = nodes.get(nextCode);
            if (null != nodeModel && ObjectUtil.equals(nodeModel.getType(), NodeEnum.trigger.getType())) {
                String groupId = nodeModel.getGroupId();
                for (String key : nodes.keySet()) {
                    NodeModel model = nodes.get(key);
                    if (null != model && ObjectUtil.equals(model.getGroupId(), groupId)) {
                        list.add(key);
                    }
                }
            }
        }
        return list;
    }

    // 转审
    @Override
    public void transfer(String id, FlowModel flowModel) throws Exception {
        String transferUserId = flowModel.getHandleIds();
        OperatorEntity operator = operatorUtil.checkOperator(id);
        boolean isProcessing = ObjectUtil.equals(operator.getIsProcessing(), 1);
        if (StringUtil.isBlank(transferUserId) || operator.getStatus().equals(OperatorStateEnum.Transfer.getCode())
                || operator.getStatus().equals(OperatorStateEnum.AddSign.getCode())) {
            throw new WorkFlowException(isProcessing ? MsgCode.WF151.get() : MsgCode.WF084.get());
        }
        String userId = flowModel.getUserInfo() == null ? UserProvider.getLoginUserId()
                : flowModel.getUserInfo().getUserId();
        if (StringUtil.equals(transferUserId, userId)) {
            throw new WorkFlowException(isProcessing ? MsgCode.WF149.get() : MsgCode.WF107.get());
        }
        if (!ObjectUtil.equals(operator.getHandleId(), userId)) {
            List<DelegateEntity> delegateList = delegateService.getByToUserId(userId);
            List<String> userIds = delegateList.stream().map(DelegateEntity::getUserId).distinct()
                    .collect(Collectors.toList());
            if (userIds.contains(transferUserId)) {
                throw new WorkFlowException(isProcessing ? MsgCode.WF150.get() : MsgCode.WF117.get());
            }
        }

        taskUtil.setFlowModel(operator.getTaskId(), flowModel);
        TaskEntity taskEntity = flowModel.getTaskEntity();
        taskUtil.checkTemplateHide(taskEntity.getTemplateId());
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);

        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();

        TemplateNodeEntity globalEntity = nodeEntityList.stream()
                .filter(e -> StringUtil.equals(NodeEnum.global.getType(), e.getNodeType())).findFirst()
                .orElse(new TemplateNodeEntity());
        NodeModel global = JsonUtil.getJsonToBean(globalEntity.getNodeJson(), NodeModel.class);

        // 记录
        FlowMethod flowMethod = new FlowMethod();
        flowMethod.setType(ObjectUtil.equals(operator.getIsProcessing(), 0) ? RecordEnum.transfer.getCode()
                : RecordEnum.transferProcessing.getCode());
        flowMethod.setFlowModel(flowModel);
        flowMethod.setOperatorEntity(operator);
        List<String> userIds = new ArrayList<>();
        userIds.add(transferUserId);
        flowMethod.setUserId(String.join(",", userIds));
        recordUtil.createRecord(flowMethod);

        // 更新经办
        UpdateWrapper<OperatorEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(OperatorEntity::getId, operator.getId())
                .set(OperatorEntity::getHandleId, transferUserId)
                .set(OperatorEntity::getCreatorTime, new Date())
                .set(OperatorEntity::getDraftData, null)
                .set(OperatorEntity::getStatus, OperatorStateEnum.Transfer.getCode());
        Boolean flowTodo = serviceUtil.getFlowTodo();
        if (!flowTodo) {
            updateWrapper.lambda().set(OperatorEntity::getStartHandleTime, null);
            Boolean flowSign = serviceUtil.getFlowSign();
            if (!flowSign) {
                if (global != null && global.getHasSignFor()) {
                    updateWrapper.lambda().set(OperatorEntity::getSignTime, null);
                }
            }
        }
        this.update(updateWrapper);

        // 消息
        FlowMsgModel flowMsgModel = new FlowMsgModel();
        List<OperatorEntity> list = new ArrayList<>();
        operator = this.getById(operator.getId());
        list.add(operator);
        flowMsgModel.setOperatorList(list);
        flowMsgModel.setNodeList(nodeEntityList);
        flowMsgModel.setFlowModel(flowModel);
        flowMsgModel.setTaskEntity(taskEntity);
        flowMsgModel.setNodeCode(operator.getNodeCode());
        flowMsgModel.setFormData(FlowContextHolder.getAllData());
        flowMsgModel.setTransfer(true);
        msgUtil.message(flowMsgModel);

        // 删除超时相关
        FlowJobUtil.deleteByOperatorId(operator.getId(), redisUtil);
        // 超时
        TimeUtil.timeModel(list, flowModel, redisUtil);
    }

    // 协办， 新增经办，节点通过后，删除协办
    @Override
    public void assist(String id, FlowModel flowModel) throws WorkFlowException {
        String handleIds = flowModel.getHandleIds();
        List<String> ids = Arrays.stream(handleIds.split(",")).collect(Collectors.toList());
        String userId = UserProvider.getLoginUserId();
        if (ids.contains(userId)) {
            throw new WorkFlowException(MsgCode.WF108.get());
        }

        OperatorEntity operator = operatorUtil.checkOperator(id);

        if (!ObjectUtil.equals(operator.getHandleId(), userId)) {
            List<DelegateEntity> delegateList = delegateService.getByToUserId(userId);
            List<String> userIds = delegateList.stream().map(DelegateEntity::getUserId).distinct()
                    .collect(Collectors.toList());
            List<String> filterList = userIds.stream().filter(ids::contains).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(filterList)) {
                throw new WorkFlowException(MsgCode.WF118.get());
            }
        }

        // QueryWrapper<OperatorEntity> wrapper = new QueryWrapper<>();
        // wrapper.lambda().eq(OperatorEntity::getParentId,
        // id).eq(OperatorEntity::getStatus, OperatorStateEnum.Assist.getCode());
        // long count = this.count(wrapper);
        // if (count > 0) {
        // throw new WorkFlowException(MsgCode.WF085.get());
        // }

        taskUtil.setFlowModel(operator.getTaskId(), flowModel);
        TaskEntity taskEntity = flowModel.getTaskEntity();
        taskUtil.checkTemplateHide(taskEntity.getTemplateId());
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);

        Map<String, NodeModel> nodes = flowModel.getNodes();
        NodeModel global = nodes.get(NodeEnum.global.getType());
        boolean signFor = false;
        if (null != global) {
            signFor = global.getHasSignFor();
        }
        List<UserEntity> userList = serviceUtil.getUserName(ids);
        if (CollectionUtil.isNotEmpty(userList)) {
            Boolean flowTodo = serviceUtil.getFlowTodo();
            Boolean flowSign = serviceUtil.getFlowSign();
            List<OperatorEntity> list = new ArrayList<>();
            for (UserEntity user : userList) {
                OperatorEntity operatorEntity = new OperatorEntity();
                operatorEntity.setParentId(operator.getId());
                operatorEntity.setNodeName(operator.getNodeName());
                operatorEntity.setNodeCode(operator.getNodeCode());
                operatorEntity.setTaskId(operator.getTaskId());
                operatorEntity.setNodeId(operator.getNodeId());
                operatorEntity.setEngineType(operator.getEngineType());
                operatorEntity.setHandleId(user.getId());
                operatorEntity.setStatus(OperatorStateEnum.Assist.getCode());
                operatorEntity.setCompletion(0);
                if (flowTodo) {
                    operatorEntity.setSignTime(new Date());
                    operatorEntity.setStartHandleTime(new Date());
                } else {
                    if (flowSign) {
                        operatorEntity.setSignTime(new Date());
                    } else {
                        if (!signFor) {
                            operatorEntity.setSignTime(new Date());
                        }
                    }
                }
                list.add(operatorEntity);
            }
            this.saveBatch(list);

            // 记录
            FlowMethod flowMethod = new FlowMethod();
            flowMethod.setType(RecordEnum.assist.getCode());
            flowMethod.setFlowModel(flowModel);
            flowMethod.setOperatorEntity(operator);
            List<String> userIds = userList.stream().map(UserEntity::getId).collect(Collectors.toList());
            flowMethod.setUserId(String.join(",", userIds));
            recordUtil.createRecord(flowMethod);

            // 消息
            FlowMsgModel flowMsgModel = new FlowMsgModel();
            flowMsgModel.setOperatorList(list);
            flowMsgModel.setNodeList(flowModel.getNodeEntityList());
            flowMsgModel.setFlowModel(flowModel);
            flowMsgModel.setTaskEntity(taskEntity);
            flowMsgModel.setNodeCode(operator.getNodeCode());
            msgUtil.message(flowMsgModel);
        }
    }

    // 协办保存，仅保存表单数据
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public void assistSave(String id, FlowModel flowModel) throws WorkFlowException {
        OperatorEntity operator = operatorUtil.checkOperator(id);
        taskUtil.setFlowModel(operator.getTaskId(), flowModel);
        TaskEntity taskEntity = flowModel.getTaskEntity();
        taskUtil.checkTemplateHide(taskEntity.getTemplateId());
        taskUtil.isSuspend(taskEntity);
        taskUtil.isCancel(taskEntity);
        Map<String, Object> formData = flowModel.getFormData();
        List<TemplateNodeEntity> nodeEntityList = flowModel.getNodeEntityList();
        TemplateNodeEntity nodeEntity = nodeEntityList.stream()
                .filter(e -> e.getNodeCode().equals(operator.getNodeCode())).findFirst().orElse(null);
        if (null == nodeEntity) {
            throw new WorkFlowException(MsgCode.WF076.get());
        }
        NodeModel nodeModel = JsonUtil.getJsonToBean(nodeEntity.getNodeJson(), NodeModel.class);

        FlowContextHolder.addChildData(operator.getTaskId(), nodeEntity.getFormId(), formData,
                nodeModel.getFormOperates(), true);
        serviceUtil.handleFormData(taskEntity.getFlowId(), false);
    }

    @Override
    public List<FlowBatchModel> batchFlowSelector() {
        List<OperatorEntity> batchList = this.getBatchList();
        List<String> taskIdList = batchList.stream().map(OperatorEntity::getTaskId).collect(Collectors.toList());

        List<TaskEntity> taskList = taskUtil.getOrderStaList(taskIdList);

        Map<String, List<TaskEntity>> flowList = taskList.stream()
                .collect(Collectors.groupingBy(TaskEntity::getTemplateId));

        List<FlowBatchModel> batchFlowList = new ArrayList<>();
        for (String key : flowList.keySet()) {
            List<TaskEntity> flowTaskList = flowList.get(key);
            if (CollectionUtil.isNotEmpty(flowTaskList)) {
                List<String> taskIds = flowTaskList.stream().map(TaskEntity::getId).collect(Collectors.toList());
                List<String> flowIds = flowTaskList.stream().map(TaskEntity::getFlowId).collect(Collectors.toList());
                List<TemplateJsonEntity> jsonList = templateJsonService.listByIds(flowIds);

                String fullName = flowTaskList.stream().map(TaskEntity::getFlowName).distinct()
                        .collect(Collectors.joining(","));
                String flowId = jsonList.stream().map(TemplateJsonEntity::getTemplateId).distinct()
                        .collect(Collectors.joining(","));
                long count = batchList.stream().filter(e -> taskIds.contains(e.getTaskId())).count();

                FlowBatchModel model = new FlowBatchModel();
                model.setNum(count);
                model.setId(flowId);
                model.setFullName(fullName + "(" + count + ")");
                batchFlowList.add(model);
            }
        }
        batchFlowList = batchFlowList.stream().sorted(Comparator.comparing(FlowBatchModel::getNum).reversed())
                .collect(Collectors.toList());
        return batchFlowList;
    }

    public List<OperatorEntity> getBatchList() {
        String userId = UserProvider.getLoginUserId();
        List<String> userList = delegateService.getByToUserId(userId).stream()
                .map(DelegateEntity::getCreatorUserId).collect(Collectors.toList());
        userList.add(userId);
        QueryWrapper<OperatorEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(OperatorEntity::getHandleId, userList)
                .eq(OperatorEntity::getCompletion, 0)
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Futility.getCode())
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Assist.getCode())
                .isNotNull(OperatorEntity::getSignTime).isNotNull(OperatorEntity::getStartHandleTime)
                .isNull(OperatorEntity::getHandleStatus)
                .select(OperatorEntity::getTaskId);
        return this.list(queryWrapper);
    }

    @Override
    public List<FlowBatchModel> batchVersionSelector(String templateId) {
        List<String> taskIdList = this.getBatchList().stream().map(OperatorEntity::getTaskId)
                .collect(Collectors.toList());
        List<TaskEntity> taskList = taskUtil.getOrderStaList(taskIdList);
        List<String> flowIdList = taskList.stream().filter(e -> e.getTemplateId().equals(templateId))
                .map(TaskEntity::getFlowId).collect(Collectors.toList());
        List<FlowBatchModel> batchFlowList = new ArrayList<>();
        if (CollectionUtil.isEmpty(flowIdList)) {
            return batchFlowList;
        }

        List<TemplateJsonEntity> jsonList = templateJsonService.listByIds(flowIdList);
        List<TemplateEntity> templateList = templateService.listByIds(
                jsonList.stream().map(TemplateJsonEntity::getTemplateId).distinct().collect(Collectors.toList()));

        for (TemplateJsonEntity jsonEntity : jsonList) {
            FlowBatchModel model = JsonUtil.getJsonToBean(jsonEntity, FlowBatchModel.class);
            TemplateEntity template = templateList.stream().filter(e -> e.getId().equals(jsonEntity.getTemplateId()))
                    .findFirst().orElse(null);
            if (null != template) {
                model.setFullName(template.getFullName() + "(v" + jsonEntity.getVersion() + ")");
                batchFlowList.add(model);
            }
        }
        return batchFlowList;
    }

    @Override
    public List<FlowBatchModel> batchNodeSelector(String flowId) {
        List<TemplateNodeEntity> nodeList = templateNodeService.getList(flowId);
        List<FlowBatchModel> list = new ArrayList<>();
        for (TemplateNodeEntity nodeEntity : nodeList) {
            if (NodeEnum.approver.getType().equals(nodeEntity.getNodeType())) {
                NodeModel nodeModel = JsonUtil.getJsonToBean(nodeEntity.getNodeJson(), NodeModel.class);
                FlowBatchModel model = new FlowBatchModel();
                model.setId(nodeModel.getNodeId());
                model.setFullName(nodeModel.getNodeName());
                list.add(model);
            }
        }
        return list;
    }

    @Override
    public Map<String, Object> batchNode(FlowModel flowModel) throws WorkFlowException {
        String flowId = flowModel.getFlowId();
        String nodeCode = flowModel.getNodeCode();

        TemplateJsonInfoVO jsonInfoVO = templateJsonService.getInfoVo(flowId);
        Map<String, Map<String, Object>> flowNodes = jsonInfoVO.getFlowNodes();

        return flowNodes.get(nodeCode);
    }

    // 批量获取候选人，不允许条件 1.线上存在条件 2.下一级节点存在候选人（20240711 第二项去除）
    @Override
    public CandidateCheckVo batchCandidates(String flowId, String operatorId, Integer batchType)
            throws WorkFlowException {
        TemplateJsonEntity jsonEntity = templateJsonService.getInfo(flowId);
        OperatorEntity operator = this.getById(operatorId);
        if (null == operator) {
            throw new WorkFlowException(MsgCode.FA001.get());
        }

        List<TemplateNodeEntity> nodeEntityList = templateNodeService.getList(flowId);
        Map<String, NodeModel> nodes = new HashMap<>();
        for (TemplateNodeEntity nodeEntity : nodeEntityList) {
            nodes.put(nodeEntity.getNodeCode(), JsonUtil.getJsonToBean(nodeEntity.getNodeJson(), NodeModel.class));
        }

        NodeModel nodeModel = nodes.get(operator.getNodeCode());
        if (taskUtil.checkBranch(nodeModel)) {
            throw new WorkFlowException("下一节点为选择分支无法批量审批");
        }

        NodeModel global = nodes.get(NodeEnum.global.getType());
        if (ObjectUtil.equals(batchType, 1) && !global.getHasContinueAfterReject()) {
            return new CandidateCheckVo();
        }
        // 获取节点的出线
        OutgoingFlowsFo flowsFo = new OutgoingFlowsFo();
        flowsFo.setDeploymentId(jsonEntity.getFlowableId());
        flowsFo.setTaskKey(operator.getNodeCode());
        List<String> outgoingFlows = flowAbleUrl.getOutgoingFlows(flowsFo);
        // 线上存在条件
        for (String outgoingFlow : outgoingFlows) {
            NodeModel flowNode = nodes.get(outgoingFlow);
            if (flowNode != null && CollectionUtil.isNotEmpty(flowNode.getConditions())) {
                throw new WorkFlowException(MsgCode.WF119.get());
            }
        }

        CandidateCheckFo fo = new CandidateCheckFo();
        fo.setFlowId(flowId);
        fo.setHandleStatus(ObjectUtil.equals(batchType, 1) ? FlowNature.RejectCompletion : FlowNature.AuditCompletion);
        return taskService.checkCandidates(operatorId, fo);
    }

    @DSTransactional
    @Override
    public void batch(FlowModel flowModel) throws Exception {
        Integer batchType = flowModel.getBatchType();
        List<String> ids = new ArrayList<>();
        List<String> idList = new ArrayList<>();
        operatorUtil.checkBatch(flowModel.getIds(), idList, false);
        operatorUtil.checkBatchRevoke(idList, ids, batchType);
        int count = 0;
        List<TaskEntity> taskList = new ArrayList<>();
        for (String id : ids) {
            OperatorEntity operator = operatorUtil.checkOperator(id);
            TaskEntity taskEntity = taskService.getInfo(operator.getTaskId());
            taskList.add(taskEntity);
            FlowModel model = JsonUtil.getJsonToBean(flowModel, FlowModel.class);
            model.setId(id);
            switch (batchType) {
                case 0:
                    model.setVoluntarily(true);
                    model.setHandleStatus(FlowNature.AuditCompletion);
                    try {
                        this.audit(id, model);
                    } catch (Exception e) {
                        if (e instanceof WorkFlowException) {
                            // 当选择多条数据且下个审批节点出现异常时，跳过异常节点能通过的即审批通过，异常的不处理
                            WorkFlowException workFlowException = (WorkFlowException) e;
                            if (ObjectUtil.equals(workFlowException.getCode(), 200)) {
                                count++;
                                break;
                            }
                        }
                        operatorUtil.compensate(taskEntity);
                        throw e;
                    }
                    break;
                case 1:
                    model.setHandleStatus(FlowNature.RejectCompletion);
                    try {
                        this.audit(id, model);
                    } catch (Exception e) {
                        if (e instanceof WorkFlowException) {
                            // 当选择多条数据且下个审批节点出现异常时，跳过异常节点能通过的即审批通过，异常的不处理
                            WorkFlowException workFlowException = (WorkFlowException) e;
                            if (ObjectUtil.equals(workFlowException.getCode(), 200)) {
                                count++;
                                break;
                            }
                        }
                        operatorUtil.compensate(taskEntity);
                        throw e;
                    }
                    break;
                case 2:
                    this.transfer(id, model);
                    break;
                case 3:
                    try {
                        this.back(id, model);
                    } catch (Exception e) {
                        operatorUtil.compensate(taskEntity);
                        throw e;
                    }
            }
        }
        // 当选择的数据都是异常时，提示：“下一节点审批异常，无法批量审批”
        if (ids.size() == count) {
            flowModel.setTaskList(taskList);
            throw new WorkFlowException(MsgCode.WF120.get());
        }
    }

    @Override
    public FlowWorkListVO flowWork(String fromId) {
        FlowWorkListVO vo = new FlowWorkListVO();
        List<FlowWorkModel> waitList = new ArrayList<>();
        // 经办
        QueryWrapper<OperatorEntity> operatorWrapper = new QueryWrapper<>();
        operatorWrapper.lambda().eq(OperatorEntity::getHandleId, fromId).eq(OperatorEntity::getCompletion, 0)
                .ne(OperatorEntity::getStatus, OperatorStateEnum.Futility.getCode());
        List<OperatorEntity> operatorList = this.list(operatorWrapper);

        if (CollectionUtil.isNotEmpty(operatorList)) {
            List<String> taskIds = operatorList.stream().map(OperatorEntity::getTaskId).collect(Collectors.toList());
            List<TaskEntity> taskList = taskUtil.getOrderStaList(taskIds);

            List<TemplateEntity> templateList = templateService
                    .getListOfHidden(taskList.stream().map(TaskEntity::getTemplateId).collect(Collectors.toList()));

            for (OperatorEntity operator : operatorList) {
                FlowWorkModel workModel = JsonUtil.getJsonToBean(operator, FlowWorkModel.class);
                TaskEntity taskEntity = taskList.stream().filter(e -> e.getId().equals(operator.getTaskId()))
                        .findFirst().orElse(null);
                if (null != taskEntity) {
                    workModel.setFullName(taskEntity.getFullName());
                    TemplateEntity template = templateList.stream()
                            .filter(e -> e.getId().equals(taskEntity.getTemplateId())).findFirst().orElse(null);
                    if (null != template) {
                        workModel.setIcon(template.getIcon());
                        waitList.add(workModel);
                    }
                }
            }
        }
        vo.setFlowTask(waitList);

        // 流程
        List<FlowWorkModel> flowList = new ArrayList<>();
        List<TemplateNodeEntity> nodeList = templateNodeService.getListLikeUserId(fromId);
        if (CollectionUtil.isNotEmpty(nodeList)) {
            List<String> flowIds = nodeList.stream().map(TemplateNodeEntity::getFlowId).collect(Collectors.toList());
            List<TemplateJsonEntity> versionList = templateJsonService.listByIds(flowIds);
            List<TemplateEntity> templateList = templateService.getListByFlowIds(flowIds);
            for (TemplateJsonEntity jsonEntity : versionList) {
                if (!ObjectUtil.equals(jsonEntity.getState(), 1)) {
                    continue;
                }
                FlowWorkModel workModel = JsonUtil.getJsonToBean(jsonEntity, FlowWorkModel.class);
                for (TemplateNodeEntity nodeEntity : nodeList) {
                    if (nodeEntity.getNodeJson().contains(fromId)) {
                        TemplateEntity template = templateList.stream()
                                .filter(e -> e.getId().equals(jsonEntity.getTemplateId())).findFirst().orElse(null);
                        if (null != template) {
                            workModel.setIcon(template.getIcon());
                            workModel.setFullName(template.getFullName() + "(V" + jsonEntity.getVersion() + ")");
                            flowList.add(workModel);
                            break;
                        }
                    }
                }
            }
        }
        vo.setFlow(flowList);
        return vo;
    }

    @Override
    public boolean flowWork(WorkHandoverModel workHandoverModel) {
        String fromId = workHandoverModel.getFromId();
        String toId = workHandoverModel.getToId();
        List<String> waitList = workHandoverModel.getFlowTaskList();
        if (!waitList.isEmpty()) {
            // 更新经办
            QueryWrapper<OperatorEntity> operator = new QueryWrapper<>();
            operator.lambda().in(OperatorEntity::getId, waitList)
                    .eq(OperatorEntity::getHandleId, fromId);
            List<OperatorEntity> operatorList = this.list(operator);
            if (CollectionUtil.isNotEmpty(operatorList)) {
                for (OperatorEntity entity : operatorList) {
                    entity.setHandleId(toId);
                    String handleAll = entity.getHandleAll();
                    if (StringUtil.isNotBlank(handleAll)) {
                        String str = handleAll.replaceAll(fromId, toId);
                        entity.setHandleAll(str);
                    }
                }
                this.updateBatchById(operatorList);
            }
            // 更新候选人
            UpdateWrapper<CandidatesEntity> candidate = new UpdateWrapper<>();
            candidate.lambda().in(CandidatesEntity::getOperatorId, waitList)
                    .eq(CandidatesEntity::getHandleId, fromId)
                    .set(CandidatesEntity::getHandleId, toId);
            candidatesService.update(candidate);
        }
        // 流程
        List<String> flowList = workHandoverModel.getFlowList();
        if (!flowList.isEmpty()) {
            UserEntity toUser = serviceUtil.getUserInfo(toId);
            String toUserName = toUser != null ? toUser.getRealName() + "/" + toUser.getAccount() : "";
            UserEntity fromUser = serviceUtil.getUserInfo(fromId);
            String fromUserName = fromUser != null ? fromUser.getRealName() + "/" + fromUser.getAccount() : "";

            List<TemplateJsonEntity> versionList = templateJsonService.listByIds(flowList);
            if (CollectionUtil.isNotEmpty(versionList)) {
                List<TemplateNodeEntity> updateList = new ArrayList<>();
                for (TemplateJsonEntity jsonEntity : versionList) {
                    List<TemplateNodeEntity> nodeList = templateNodeService.getList(jsonEntity.getId());
                    for (TemplateNodeEntity nodeEntity : nodeList) {
                        if (nodeEntity.getNodeJson().contains(fromId)) {
                            String str = nodeEntity.getNodeJson().replaceAll(fromId, toId).replaceAll(fromUserName,
                                    toUserName);
                            nodeEntity.setNodeJson(str);
                            updateList.add(nodeEntity);
                        }
                    }
                }
                if (CollectionUtil.isNotEmpty(updateList)) {
                    templateNodeService.updateBatchById(updateList);
                }
            }
        }
        return true;
    }
}
