package com.xjrsoft.module.workflow.utils;

import camundafeel.de.odysseus.el.ExpressionFactoryImpl;
import camundafeel.de.odysseus.el.util.SimpleContext;
import camundafeel.javax.el.ExpressionFactory;
import camundafeel.javax.el.ValueExpression;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.type.TypeReference;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.*;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.module.magicapi.service.IMagicApiService;
import com.xjrsoft.module.magicapi.vo.MagicApiInfoVo;
import com.xjrsoft.module.oa.utils.SendMessageUtil;
import com.xjrsoft.module.organization.entity.*;
import com.xjrsoft.module.organization.service.IUserService;
import com.xjrsoft.module.system.entity.DictionaryDetail;
import com.xjrsoft.module.workflow.constant.WorkflowConstant;
import com.xjrsoft.module.workflow.dto.LaunchDto;
import com.xjrsoft.module.workflow.entity.WorkflowApproveRecord;
import com.xjrsoft.module.workflow.entity.WorkflowDelegate;
import com.xjrsoft.module.workflow.entity.WorkflowSchema;
import com.xjrsoft.module.workflow.model.*;
import com.xjrsoft.module.workflow.service.IWorkflowApproveRecordService;
import lombok.SneakyThrows;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.ProcessEngines;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.history.HistoricVariableInstance;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.ssssssss.magicapi.core.service.MagicAPIService;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @Author: tzx
 * @Date: 2022/9/26 15:54
 */
public class WorkFlowUtil {

    /**
     * 替换占位符
     *
     * @param str            源字符串
     * @param workflowSchema 工作流模板信息
     * @param serialNumber   流水号  可不填
     * @return 替换后的字符串
     */
    public static String replacePlaceHolder(String str, WorkflowSchema workflowSchema, Long serialNumber, Long workflowSerialNumber) {
        SaSession tokenSession = StpUtil.getTokenSession();
        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
        Department department = tokenSession.get(GlobalConstant.LOGIN_USER_DEPT_INFO_KEY, new Department());
        Post post = tokenSession.get(GlobalConstant.LOGIN_USER_POST_INFO_KEY, new Post());

        //流程流水号
        if (workflowSerialNumber != null && workflowSerialNumber != 0) {
            char zeroChar = '0';
            String serialNumberStr = StrUtil.toString(workflowSerialNumber);
            String fillStr = StringPool.EMPTY;

            if (str.contains(WorkflowConstant.SERIAL_NUBMER_FOUR_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillBefore(serialNumberStr, zeroChar, 4);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_FIVE_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 5);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_SIX_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 6);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_SEVEN_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 7);
            } else if (str.contains(WorkflowConstant.SERIAL_NUBMER_EIGHT_PLACEHOLDER)) {
                //4位数 前面补0
                fillStr = StrUtil.fillAfter(serialNumberStr, zeroChar, 8);
            }

            if (StrUtil.isNotBlank(fillStr)) {
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_FOUR_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_FIVE_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_SIX_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_SEVEN_PLACEHOLDER, fillStr);
                str = str.replace(WorkflowConstant.SERIAL_NUBMER_EIGHT_PLACEHOLDER, fillStr);
            }

        }
        if (str.contains(WorkflowConstant.TEMPLATE_CATEGORY_PLACEHOLDER) && ObjectUtil.isNotNull(workflowSchema.getCategory())) {
            RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
            List<DictionaryDetail> detailList = redisUtil.get(GlobalConstant.DIC_DETAIL_CACHE_KEY, new TypeReference<List<DictionaryDetail>>() {
            });

            Optional<DictionaryDetail> dictionaryDetail = detailList.stream().filter(x -> x.getId().equals(workflowSchema.getCategory())).findFirst();

            if (dictionaryDetail.isPresent()) {
                str = str.replace(WorkflowConstant.TEMPLATE_CATEGORY_PLACEHOLDER, StrUtil.toString(dictionaryDetail.get().getName()));
            } else {
                str = str.replace(WorkflowConstant.TEMPLATE_CATEGORY_PLACEHOLDER, StrUtil.toString(workflowSchema.getCategory()));
            }

        }
        if(str.contains(WorkflowConstant.TEMPLATE_REMARK_PLACEHOLDER) && StrUtil.isNotBlank(workflowSchema.getRemark())){ //workflowSchema.getRemark()可能为空
            str = str.replace(WorkflowConstant.TEMPLATE_REMARK_PLACEHOLDER, workflowSchema.getRemark());
        }
        if(StrUtil.isNotBlank(post.getName())){
            str = str.replace(WorkflowConstant.INITIATOR_POST_NAME_PLACEHOLDER, post.getName());
        }else {
            str = str.replace(WorkflowConstant.INITIATOR_POST_NAME_PLACEHOLDER, StringPool.EMPTY);
        }

        if (str.contains(WorkflowConstant.RANDOM_DASH)){
            str = str.replace(WorkflowConstant.RANDOM_DASH,StringPool.DASH);
        }

        return str.replace(WorkflowConstant.TEMPLATE_CODE_PLACEHOLDER, workflowSchema.getCode())
                .replace(WorkflowConstant.TEMPLATE_NAME_PLACEHOLDER, workflowSchema.getName())
                .replace(WorkflowConstant.TEMPLATE_REMARK_PLACEHOLDER, workflowSchema.getRemark())
                .replace(WorkflowConstant.TASK_ID_PLACEHOLDER, workflowSchema.getDefinitionId())
                .replace(WorkflowConstant.INITIATOR_ID_PLACEHOLDER, StrUtil.toString(user.getId()))
                .replace(WorkflowConstant.INITIATOR_USER_NAME_PLACEHOLDER, user.getName())
                .replace(WorkflowConstant.INITIATOR_CODE_PLACEHOLDER, user.getCode())
                .replace(WorkflowConstant.INITIATOR_MOBILE_PLACEHOLDER, user.getMobile())
                .replace(WorkflowConstant.INITIATOR_DEPT_NAME_PLACEHOLDER, department.getName()==null?"":department.getName())
//                .replace(WorkflowConstant.INITIATOR_POST_NAME_PLACEHOLDER, post.getName())
                .replace(WorkflowConstant.YYYYMMDDHHMMSS_24_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD_HH_MM_SS_24))
                .replace(WorkflowConstant.YYYYMMDDHHMMSS_12_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD_HH_MM_SS_12))
                .replace(WorkflowConstant.YYYYMMDD_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.YYYY_MM_DD))
                .replace(WorkflowConstant.HHMMSS_24_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.HH_MM_SS_24))
                .replace(WorkflowConstant.HHMMSS_12_PLACEHOLDER, DateUtil.format(LocalDateTime.now(), GlobalConstant.HH_MM_SS_12))
                .replace(WorkflowConstant.RANDOM_2_PLACEHOLDER, RandomUtil.randomNumbers(2))
                .replace(WorkflowConstant.RANDOM_2_MIX_PLACEHOLDER, RandomUtil.randomString(2))
                .replace(WorkflowConstant.RANDOM_4_PLACEHOLDER, RandomUtil.randomNumbers(4))
                .replace(WorkflowConstant.RANDOM_4_MIX_PLACEHOLDER, RandomUtil.randomString(4))
                .replace(WorkflowConstant.RANDOM_6_PLACEHOLDER, RandomUtil.randomNumbers(6))
                .replace(WorkflowConstant.RANDOM_6_MIX_PLACEHOLDER, RandomUtil.randomString(6))
                .replace(WorkflowConstant.RANDOM_8_PLACEHOLDER, RandomUtil.randomNumbers(8))
                .replace(WorkflowConstant.RANDOM_8_MIX_PLACEHOLDER, RandomUtil.randomString(8))
                .replace(WorkflowConstant.SERIAL_NUBMER_PLACEHOLDER, StrUtil.toString(serialNumber))
                .replace(StringPool.HASH, StringPool.EMPTY)
                .replace(StringPool.LEFT_BRACE, StringPool.EMPTY)
                .replace(StringPool.RIGHT_BRACE, StringPool.EMPTY);

    }

    /**
     * 生成流程名称
     * @param workflowSchema
     * @param workflowSchemaConfig
     * @param workflowSerialNumber
     * @return
     */
    public static String generatorProcessName(WorkflowSchema workflowSchema, WorkflowSchemaConfig workflowSchemaConfig, Long workflowSerialNumber, LaunchDto dto) {

        if (workflowSchemaConfig.getProcessConfig().getNameRuleConfigs().size() == 0) {
            if(dto.getFormData() != null){
                Map<String, Map<String, Object>> formData = dto.getFormData();
                String title_last = null;
                for (Map<String, Object> value : formData.values()) {
                    if(title_last != null){
                        continue;
                    }
                    //物品申购特殊处理
                    if(value.containsKey("wf_subscription_listList")){
                        ArrayList<Map<String, Object>> list = (ArrayList<Map<String, Object>>) value.get("wf_subscription_listList");
                        if(list.size() > 0){
                            Map<String, Object> objectMap = list.get(0);
//                        Set<String> keys = objectMap.keySet();
                            String firstKey = "name_of_the_purchased_item";
//                        for (String key : keys) {
//                            if(firstKey != null){
//                                continue;
//                            }
//                            firstKey = key;
//                        }
                            title_last = objectMap.get(firstKey).toString();
                        }
                    }
                    for (Object o : value.values()) {
                        if(title_last != null){
                            continue;
                        }
                        title_last = o.toString();
                    }
                }
                return "【" + workflowSchema.getName() + "】" + title_last;
            }
            return workflowSchema.getName();
        }

        String nameTemplate = workflowSchemaConfig.getProcessConfig().getNameRuleConfigs().stream().map(NameRuleConfig::getKey).map(String::valueOf).collect(Collectors.joining(StringPool.SPACE));
        String replacePlaceHolder = WorkFlowUtil.replacePlaceHolder(nameTemplate, workflowSchema, workflowSerialNumber, workflowSerialNumber);
        if(dto.getFormData() != null){
            String nameStr = "";
            Map<String, Map<String, Object>> formData = dto.getFormData();
            String[] names = replacePlaceHolder.split(" ");
            for(int i = 0; i < names.length; i ++){
                String name = names[i];
                if(i == 0){
                    nameStr += "【" + name + "】";
                }else{
                    nameStr += name;
                }
                for (Map<String, Object> value : formData.values()) {
                    if(value.containsKey(name)){
                        nameStr = nameStr.replace(name, value.get(name).toString());
                    }
                }
            }

            return nameStr;
        }
        return replacePlaceHolder;
    }

    /**
     * 根据memberConfig  获取所有userIds
     * 例如查审批人  推送人   权限 等
     *
     * @return
     */
    public static List<Long> getUserIdsByMemberConfig(List<MemberConfig> memberConfigs, List<Map<String, Object>> childNodeConfig, String processId) {
        List<Long> result = new ArrayList<>();

        if (memberConfigs.size() == 0) {
            return result;
        }

        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        //如果有选择角色
        List<UserRoleRelation> userRoleRelations = null;
        //如果有选择用户
        List<User> users = null;
        //如果选择岗位
        List<Post> posts = null;
        List<UserPostRelation> userPostRelations = null;

//        Optional<LeaderConfig> maxLevel = memberConfigs.parallelStream().filter(m -> m.getMemberType() == WorkflowMemberType.LEADER.getCode()).map(MemberConfig::getLeaderConfig).max(Comparator.comparing(LeaderConfig::getLevel));


        for (MemberConfig memberConfig : memberConfigs) {
            //如果是用户  memberlistconfig  存储的就是 用户id   直接  添加到返回值中
            if (memberConfig.getMemberType() == WorkflowMemberType.USER.getCode()) {
                result.add(Convert.toLong(memberConfig.getId()));
            }
            //如果是角色
            // 从 缓存中获取到所有角色数据
            // 根据所有角色id   从 缓存中获取 所有 用户角色关联信息
            // 获取到所有用户id  添加到返回值中
            if (memberConfig.getMemberType() == WorkflowMemberType.ROLE.getCode()) {

                if (ObjectUtil.isNull(userRoleRelations)) {
                    userRoleRelations = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
                    });
                }

                //获取到所有角色的关联用户
                List<Long> userIds = userRoleRelations.stream().filter(x -> x.getRoleId().equals(Convert.toLong(memberConfig.getId()))).map(UserRoleRelation::getUserId).collect(Collectors.toList());
                result.addAll(userIds);
            }
            //根据岗位获取用户
            if (memberConfig.getMemberType() == WorkflowMemberType.POST.getCode()) {

                if (ObjectUtil.isNull(userPostRelations)) {
                    userPostRelations = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
                    });
                }
                List<Long> userIds = userPostRelations.stream().filter(p -> ObjectUtil.equals(Convert.toLong(memberConfig.getId()), p.getPostId())).map(UserPostRelation::getUserId).collect(Collectors.toList());
                result.addAll(userIds);
            }
            //指定节点审批人
            if (memberConfig.getMemberType() == WorkflowMemberType.APPROVE.getCode()) {

                //如果是选择的开始节点
                if (memberConfig.getId().equals(WorkflowConstant.START_NODE_DEFAULT_ID)) {
                    //将map 转为 java类  默认只有用户任务节点才有审批人
                    RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                    Object startUserIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_ID_KEY);
                    Long startUserId = Convert.toLong(startUserIdObj);
                    result.add(startUserId);
                    break;
                }

                //必须是用户任务节点
                Optional<Map<String, Object>> userTaskConfigMapOp = childNodeConfig.stream().filter(x -> x.containsValue(memberConfig.getId())).findFirst();
                if (!userTaskConfigMapOp.isPresent()) {
                    break;
                }
                //    将map 转为 java类
                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMapOp.get());
                List<Long> approverUserIds = getUserIdsByMemberConfig(userTaskConfig.getApproverConfigs(), childNodeConfig, processId);
                result.addAll(approverUserIds);

            }
            //上级领导
            if (memberConfig.getMemberType() == WorkflowMemberType.LEADER.getCode()) {

                if (ObjectUtil.isNull(posts)) {
                    posts = redisUtil.get(GlobalConstant.POST_CACHE_KEY, new TypeReference<List<Post>>() {
                    });
                }
                if (ObjectUtil.isNull(users)) {
                    users = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
                    });
                }

                LeaderConfig leaderConfig = memberConfig.getLeaderConfig();
                //获取到节点配置
                Optional<Map<String, Object>> nodeMap = childNodeConfig.stream().filter(x -> x.get(GlobalConstant.DEFAULT_PK).equals(leaderConfig.getNodeId())).findFirst();

                if (!nodeMap.isPresent()) {
                    return result;
                }

                //如果是开始节点
                if (leaderConfig.getNodeId().equals(WorkflowConstant.START_NODE_DEFAULT_ID)) {
                    //将map 转为 java类  默认只有用户任务节点才有审批人
                    RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                    Object startUserIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_ID_KEY);
                    Long startUserId = Convert.toLong(startUserIdObj);

                    //获取到发起人用户信息
                    Optional<User> startUserOp = users.stream().filter(x -> x.getId().equals(startUserId)).findFirst();
                    if (!startUserOp.isPresent()) {
                        return result;
                    }

                    Long postId;
                    //如果发起人id等于当前登陆人id
                    if (startUserId == StpUtil.getLoginIdAsLong()) {
                        Object postIdObj = runtimeService.getVariable(processId, WorkflowConstant.PROCESS_START_USER_POST_ID_KEY);
                        postId = Convert.toLong(postIdObj);
                    } else {
                        //获取当前发起的身份
                        HistoryService historyService = ProcessEngines.getDefaultProcessEngine().getHistoryService();
                        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(processId).variableName(WorkflowConstant.PROCESS_START_USER_POST_ID_KEY).singleResult();

                        postId = Convert.toLong(historicVariableInstance.getValue());
                    }

                    Optional<Post> thisApproveOp = posts.stream().filter(x -> x.getId().equals(postId)).findFirst();
                    if (!thisApproveOp.isPresent()) {
                        return result;
                    }

                    Post thisUserPost = thisApproveOp.get();

                    for (int i = 1; i <= leaderConfig.getLevel(); i++) {

                        Post finalThisUserPost = thisUserPost;
                        Optional<Post> parentPostOp = posts.stream().filter(x -> finalThisUserPost.getParentId().equals(x.getId())).findFirst();

                        //如果当前循环次数 找不到上级
                        if (!parentPostOp.isPresent()) {
                            return result;
                        } else {
                            thisUserPost = parentPostOp.get();
                        }


                        //当前级别 跟 循环次数一致  就把当前所查出来的岗位 所属人员 加入到 leaderUserIds
                        if (i == leaderConfig.getLevel()) {
                            //找到当前角色下的所有人员 id 存入 result
                            Post post = parentPostOp.get();
                            userPostRelations = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
                            });
                            List<Long> leaderUserIds = userPostRelations.stream().filter(x -> ObjectUtil.equals(post.getId(), x.getPostId())).map(UserPostRelation::getUserId).collect(Collectors.toList());
//                            List<Long> leaderUserIds = users.stream().filter(x -> ObjectUtil.equals(post.getId(),x.getPostId())).map(User::getId).collect(Collectors.toList());
                            result.addAll(leaderUserIds);
                        }


                    }

//                    Long finalCurrentPostParentId = thisApproveOp.get().getParentId();
//                    for (int i = 0; i < leaderConfig.getLevel(); i++) {
//                        for (Post post : posts) {
//                            if (post.getId().equals(finalCurrentPostParentId) && leaderConfig.getLevel() == i) {
//                                final long parentId = finalCurrentPostParentId;
//                                List<Long> leaderUserIds = users.stream().filter(u -> u.getPostId().equals(parentId)).map(User::getId).collect(Collectors.toList());
//                                result.addAll(leaderUserIds);
//                                finalCurrentPostParentId = post.getParentId();
//                            }
//                        }
//                    }
                    return result;

                } else {
                    //将map 转为 java类  默认只有用户任务节点才有审批人
                    UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, nodeMap.get());
//                    List<MemberConfig> approverConfigs = userTaskConfig.getApproverConfigs();

                    IWorkflowApproveRecordService workflowApproveRecordService = SpringUtil.getBean(IWorkflowApproveRecordService.class);

                    //获取到当前流程的当前task 的审批记录  可能涉及到 驳回、流程画图流转回来、多实例 等清空 可能会有多条
                    //大部分是一条 默认根据id 倒叙排序 取最后一条数据  代表最新的审批人
                    List<WorkflowApproveRecord> list = workflowApproveRecordService.list(Wrappers.lambdaQuery(WorkflowApproveRecord.class)
                            .eq(WorkflowApproveRecord::getProcessId, processId)
                            .eq(WorkflowApproveRecord::getTaskDefinitionKey, userTaskConfig.getId())
                            .orderByDesc(WorkflowApproveRecord::getId)
                    );

                    //如果查不到审批记录  默认不走下面逻辑
                    if (ObjectUtil.isNull(list) || list.size() == 0) {
                        break;
                    }
                    //获取到最新的一条审批记录中 所存储的 岗位
                    Long approveUserPostId = list.get(0).getApproveUserPostId();

                    Optional<Post> thisApproveOp = posts.stream().filter(x -> x.getId().equals(approveUserPostId)).findFirst();
                    // 如果postId 找不到信息  停止循环
                    if (!thisApproveOp.isPresent()) {
                        break;
                    }
                    Long finalCurrentPostParentId = thisApproveOp.get().getParentId();

                    if (ObjectUtil.isNull(userPostRelations)) {
                        userPostRelations = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
                        });
                    }

                    for (int i = 1; i <= leaderConfig.getLevel(); i++) {
                        for (Post post : posts) {
                            if (post.getId().equals(finalCurrentPostParentId) && leaderConfig.getLevel() == i) {
                                final long parentId = finalCurrentPostParentId;

                                List<Long> leaderUserIds = userPostRelations.stream().filter(x -> x.getPostId().equals(parentId)).map(UserPostRelation::getUserId).collect(Collectors.toList());
//                                List<Long> leaderUserIds = users.stream().filter(u -> u.getPostId().equals(parentId)).map(User::getId).collect(Collectors.toList());
                                result.addAll(leaderUserIds);
                                finalCurrentPostParentId = post.getParentId();
                            }
                        }
                    }
                }


            }
            //表单字段
            if (memberConfig.getMemberType() == WorkflowMemberType.FORM_FIELD.getCode()) {
                //将map 转为 java类  默认只有用户任务节点才有审批人
                RuntimeService runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService();

                FormFieldConfig formFieldConfigs = memberConfig.getFormFieldConfig();

                Object formDataObj = runtimeService.getVariable(processId, formFieldConfigs.getFormKey());
                Map<String, Object> formData = Convert.toMap(String.class, Object.class, formDataObj);

                Object fieldValue = formData.get(formFieldConfigs.getFormField());

                //可能转换不了 捕获错误。
                try {
                    if (fieldValue instanceof String) {
                        //如果包含逗号 表示 可能多个
                        String approveStr = StrUtil.toString(fieldValue);
                        if (approveStr.contains(StringPool.COMMA)) {
                            String[] approveSplit = approveStr.split(StringPool.COMMA);

                            for (String approve : approveSplit) {
                                Long approveId = Convert.toLong(approve);
                                result.add(approveId);
                            }
                        } else {
                            Long approveId = Convert.toLong(fieldValue);
                            result.add(approveId);
                        }
                    } else {
                        Long approveId = Convert.toLong(fieldValue);
                        result.add(approveId);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
        return result;
    }


    /**
     * approveUserIds  获取所有所有委托userids
     * 只用于查询审批人 包括委托人
     *
     * @return
     */
    public static List<Long> getDelegateUserIdsByApproveUserId(List<Long> approveUserIds, List<WorkflowDelegate> delegateList, Long schemaId) {

        List<Long> result = new ArrayList<>(approveUserIds);
        for (Long approveUserId : approveUserIds) {
            List<WorkflowDelegate> thisUserDelegate = delegateList.stream().filter(d -> d.getUserId().equals(approveUserId) && d.getSchemaIds().contains(schemaId.toString())).collect(Collectors.toList());

            for (WorkflowDelegate workflowDelegate : thisUserDelegate) {
                String[] split = workflowDelegate.getDelegateUserIds().split(StringPool.COMMA);
                List<Long> delegateUserIds = Arrays.stream(split).map(Convert::toLong).collect(Collectors.toList());

                result.addAll(delegateUserIds);
            }

        }


        return result;
    }


    /**
     * 获取流程线的所有值  存入变量
     *
     * @param processDefinitionId  流程定义id
     * @param workflowSchemaConfig schema
     * @param nodeId               nodeId当前节点id（key）
     * @param variableMap          变量Map
     */
    @Deprecated
    public static void getFlowConditionVar(String processDefinitionId, WorkflowSchemaConfig workflowSchemaConfig, String nodeId, VariableMap variableMap, Map<String, Map<String, Object>> formData) {

        RepositoryService repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService();

        //找到当前节点 element 对象
        ModelElementInstance currentElement = repositoryService.getBpmnModelInstance(processDefinitionId).getModelElementById(nodeId);
        //找到当前用户节点的子节点 是网关的
        Collection<Gateway> gateways = currentElement.getChildElementsByType(Gateway.class);

        //如果下级节点有网关
        if (gateways.size() > 0) {
            //存储有哪些变量要 存入到工作流数据表中
            List<String> allFlowVarKeys = new ArrayList<>();
            //存储有哪些变量需要从表单的某个字段获取值
            List<String> allFlowVarBindFormField = new ArrayList<>();
            //所有流程线配置
            List<ConditionConfig> conditionConfigs = new ArrayList<>();
            //流程线的key
            List<String> allFlowKey = new ArrayList<>();

            //遍历所有网关
            for (Gateway gateway : gateways) {
                //找到网关所有的下级连接线 的id
                List<String> gatewayFlowIds = gateway.getOutgoing().stream().map(BaseElement::getId).collect(Collectors.toList());

                //遍历所有连接线的配置
                for (String gatewayFlowId : gatewayFlowIds) {
                    Optional<Map<String, Object>> sequenceflowConfigMapOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(gatewayFlowId)).findFirst();

                    //流程线 流转条件 变量名字 取名规则 form:{nodeId}:{formId}
                    sequenceflowConfigMapOp.ifPresent(flow -> {
                        SequenceFlowConfig sequenceFlowConfig = Convert.convert(SequenceFlowConfig.class, flow);

                        //获取到所有需要的  变量key  和绑定表单字段
                        for (ConditionConfig config : sequenceFlowConfig.getConditionConfigs()) {
                            conditionConfigs.add(config);
                            allFlowKey.add(gatewayFlowId);
                            allFlowVarKeys.add(WorkflowConstant.PROCESS_FORMDATA_PREFIX_KEY + config.getFormId());
                            allFlowVarBindFormField.add(config.getFormField());
                        }

                    });
                }
            }


            //key === flow:{flowId}:{nodeId}:{formId}:{formField}   value == 需要存入的值
            for (int i = 0; i < allFlowKey.size(); i++) {
                Object formDataObject = formData.get(allFlowVarKeys.get(i));
                Map<String, Object> formDataMap = Convert.toMap(String.class, Object.class, formDataObject);
                if (formDataMap != null) {
                    Object fieldValue = MapUtil.get(formDataMap, allFlowVarBindFormField.get(i), Object.class);
                    ConditionConfig config = conditionConfigs.get(i);

                    String key = WorkflowConstant.FLOW_PARAM_PREFIX_KEY +
                            allFlowKey.get(i) + StringPool.COLON +
                            config.getNodeId() + StringPool.COLON + config.getFormId() + StringPool.COLON +
                            config.getFormField();


                    variableMap.putValue(key, fieldValue);

                }

            }


        }
    }


    /**
     * 根据子集查询下一个执行节点id
     *
     * @param variableMap 变量map
     * @param list        当前节点的子节点
     * @return
     */
    @Deprecated
    public static String getNextTaskNode(VariableMap variableMap, List<FlowNode> list) {
        String result = null;
        for (FlowNode flowNode : list) {
            //如果是用户任务
            if (WorkflowConstant.BPMN_USER_TASK_TYPE_NAME.equals(flowNode.getElementType().getTypeName())) {
                result = flowNode.getId();
            }
            //如果是排他网关
            else if (WorkflowConstant.BPMN_EXCLUSIVE_GATEWAY_TYPE_NAME.equals(flowNode.getElementType().getTypeName())) {
                Collection<SequenceFlow> outgoing = flowNode.getOutgoing();


                for (SequenceFlow sequenceFlow : outgoing) {
                    ConditionExpression conditionExpression = sequenceFlow.getConditionExpression();
                    ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
                    SimpleContext simpleContext = new SimpleContext();

                    for (String key : variableMap.keySet()) {
                        ValueExpression valueExpression = expressionFactory.createValueExpression(variableMap.get(key), String.class);
                        simpleContext.setVariable(key, valueExpression);
                    }
                    ValueExpression valueExpression = expressionFactory.createValueExpression(simpleContext, conditionExpression.getTextContent(), boolean.class);
                    //判断是否满足条件
                    if ((Boolean) valueExpression.getValue(simpleContext)) {
                        return sequenceFlow.getTarget().getId();
                    }
                }
            }
        }

        return result;
    }

    @Deprecated
    public static boolean judgmentCondition(SequenceFlow sequenceFlow, Map<String, Object> variableMap, List<Map<String, Object>> childNodeConfig) {

        Optional<Map<String, Object>> flowConfigOp = childNodeConfig.stream().filter(x -> x.containsValue(sequenceFlow.getId())).findFirst();
        if (!flowConfigOp.isPresent()) {
            return false;
        }
        //将map 转为 java类
        SequenceFlowConfig sequenceFlowConfig = Convert.convert(SequenceFlowConfig.class, flowConfigOp.get());


        ConditionExpression conditionExpression = sequenceFlow.getConditionExpression();
        ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
        SimpleContext simpleContext = new SimpleContext();

        for (String key : variableMap.keySet()) {
            ValueExpression valueExpression = expressionFactory.createValueExpression(variableMap.get(key), String.class);
            simpleContext.setVariable(key, valueExpression);
        }
        ValueExpression valueExpression = expressionFactory.createValueExpression(simpleContext, conditionExpression.getTextContent(), boolean.class);
        //判断是否满足条件
        return (Boolean) valueExpression.getValue(simpleContext);

    }

    /**
     * 根据id 从 工作流模板配置 获取 节点的配置信息
     *
     * @param id              节点id
     * @param childNodeConfig 所有节点配置
     * @param clazz           类型
     * @param <T>             配置类型
     * @return
     */
    public static <T> T getNodeConfig(String id, List<Map<String, Object>> childNodeConfig, Class<T> clazz) {
        Optional<Map<String, Object>> configOp = childNodeConfig.stream().filter(c -> c.containsValue(id)).findFirst();
        return configOp.map(stringObjectMap -> Convert.convert(clazz, stringObjectMap)).orElse(null);
    }

    /**
     * 执行参数赋值
     *
     * @param assignmentConfig 赋值配置
     * @param processParam     流程参数
     * @param varMap           流程变量
     */
    public static void invokeParamAssignment(AssignmentConfig assignmentConfig, Map<String, Object> processParam, Map<String, Object> varMap, WorkflowSchema workflowSchema) {
        List<ParamAssignmentConfig> paramAssignmentConfigs = assignmentConfig.getParamAssignmentConfigs();

        for (ParamAssignmentConfig paramAssignmentConfig : paramAssignmentConfigs) {
            //如果是值
            if (paramAssignmentConfig.getType() == ParamAssignmentType.VALUE.getCode()) {
                if (processParam.containsKey(paramAssignmentConfig.getTarget())) {
                    processParam.put(paramAssignmentConfig.getTarget(), paramAssignmentConfig.getValue());
                }
            }
            //如果是变量
            if (paramAssignmentConfig.getType() == ParamAssignmentType.VAR.getCode()) {

                Long serialNumber = MapUtil.get(varMap, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.class);

                String newStr = WorkFlowUtil.replacePlaceHolder(paramAssignmentConfig.getVarValue(), workflowSchema, serialNumber, 0L);

                processParam.put(paramAssignmentConfig.getTarget(), newStr);
            }
            //如果是表单
            if (paramAssignmentConfig.getType() == ParamAssignmentType.FORM.getCode()) {

                //使用3下划线切割
                String[] split = paramAssignmentConfig.getFormConfig().getKey().split(StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE);
                String formKey = split[1];
                Map<String, Object> formData = MapUtil.get(varMap, formKey, new cn.hutool.core.lang.TypeReference<Map<String, Object>>() {});
                Object fieldValue = MapUtil.get(formData, paramAssignmentConfig.getFormConfig().getFormField(), Object.class);

                processParam.put(paramAssignmentConfig.getTarget(), fieldValue);
            }

            //如果是api
            if (paramAssignmentConfig.getType() == ParamAssignmentType.API.getCode()) {

                IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
                MagicAPIService magicAPIService = SpringUtil.getBean(MagicAPIService.class);

                ApiConfig apiConfig = paramAssignmentConfig.getApiConfig();

                MagicApiInfoVo info = magicApiService.info(apiConfig.getId());
//                Long serialNumber = MapUtil.get(varMap, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.class);


                Map<String, Object> params = new HashMap<>();
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestParamsConfigs()) {
                    initApiParams(processParam, varMap, params, requestParamsConfig);
                }
                for (ApiRequestParamsConfig requestHeaderConfig : apiConfig.getRequestHeaderConfigs()) {
                    initApiParams(processParam, varMap, params, requestHeaderConfig);
                }
                for (ApiRequestParamsConfig requestBodyConfig : apiConfig.getRequestBodyConfigs()) {
                    initApiParams(processParam, varMap, params, requestBodyConfig);
                }


                Object result = magicAPIService.execute(info.getMethod(), info.getPath(), params);

                processParam.put(paramAssignmentConfig.getTarget(), result);

            }

        }

    }

    public static void initApiParams(Map<String, Object> processParam, Map<String, Object> varMap, Map<String, Object> params, ApiRequestParamsConfig requestParamsConfig) {
        if (Objects.equals(requestParamsConfig.getAssignmentType(), "value")) { //值
            params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
        } else if (Objects.equals(requestParamsConfig.getAssignmentType(), "processParameter")) { //流程参数
            params.put(requestParamsConfig.getName(), processParam.get(requestParamsConfig.getConfig()));
        } else if (Objects.equals(requestParamsConfig.getAssignmentType(), "originator")) {//发起人信息

            //如果是设置的发起人
            if (requestParamsConfig.getConfig().contains("initiator_id")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);

                params.put(requestParamsConfig.getName(), startUserId);
            }
            //组织架构名称
            if (requestParamsConfig.getConfig().contains("initiator_dept_name")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
                RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
                List<UserDeptRelation> userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                });

                List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                });
                List<UserDeptRelation> startUserDeptRelation = userDeptRelations.stream().filter(x -> x.getUserId().equals(startUserId)).collect(Collectors.toList());

                List<Long> allDeptIds = startUserDeptRelation.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());

                List<Department> allDept = departmentList.stream().filter(x -> allDeptIds.contains(x.getId())).collect(Collectors.toList());

                params.put(requestParamsConfig.getName(), allDept.stream().map(Department::getName).collect(Collectors.joining(",")));
            }
        } else {//表单数据
            //使用3下划线切割
            String[] split = requestParamsConfig.getConfig().split(StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE);
            String formKey = split[1];
            Map<String, Object> formData = MapUtil.get(varMap, formKey, new cn.hutool.core.lang.TypeReference<Map<String, Object>>() {
            });
            Object fieldValue = MapUtil.get(formData, split[2], Object.class);
            params.put(requestParamsConfig.getName(), fieldValue);
        }
    }


    /**
     * 根据配置信息 执行表单赋值
     *
     * @param formData         表单数据
     * @param assignmentConfig 赋值配置
     * @param formConfigs      表单配置
     * @param varMap           变量的Map
     */
    public static void invokeFormAssignment(Map<String, Map<String, Object>> formData, AssignmentConfig assignmentConfig, List<FormConfig> formConfigs, Map<String, Object> varMap) {
        //获取 所有赋值操作数据

        List<FormAssignmentConfig> formAssignmentConfigs = assignmentConfig.getFormAssignmentConfigs();

        for (FormAssignmentConfig formAssignmentConfig : formAssignmentConfigs) {
            Object currentVariable = varMap.get(formAssignmentConfig.getSource());

            FormAssignmentSourceConfig targetSource = formAssignmentConfig.getTarget();

            Optional<FormConfig> formConfig = formConfigs.stream().filter(form -> form.getFormId().equals(targetSource.getFormId())).findFirst();
            formConfig.ifPresent(form -> {
                Map<String, Object> currentFormData = formData.get(form.getKey());

                if (currentFormData.containsKey(targetSource.getFormField())) {
                    currentFormData.put(targetSource.getFormField(), currentVariable);
                }

            });
        }
    }


    /**
     * 判断是否有权限
     *
     * @param authConfig 权限配置
     * @return 是否有权限
     */
    public static Boolean hasPermissions(AuthConfig authConfig) {
        //如果是所有人 默认返回true
        if (authConfig.getAuthType() == WorkflowAuth.ALL.getCode()) {
            return true;
        }
        List<MemberConfig> authMemberConfigs = authConfig.getAuthMemberConfigs();
        SaSession tokenSession = StpUtil.getTokenSession();
        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());

        //这里可以不传 第二个参数 因为 只有角色岗位人员  用不着childNodeConfig
        List<Long> userIdsByMemberConfig = getUserIdsByMemberConfig(authMemberConfigs, null, null);

        return userIdsByMemberConfig.contains(user.getId());
    }


    /**
     * 获取流程参数
     *
     * @param processParamConfigs
     * @param workflowSchema
     * @return
     */
    @SneakyThrows
    public static Map<String, Object> getProcessParam(List<ProcessParamConfig> processParamConfigs, WorkflowSchema workflowSchema, Long serialNumber,Map<String, Object> varMap) {
        Map<String, Object> result = new HashMap<>(processParamConfigs.size());

        for (ProcessParamConfig processParamConfig : processParamConfigs) {

            //如果是值  直接前端配置  直接传入就行
            if (processParamConfig.getType() == WorkflowParamType.VALUE.getCode()) {
                result.put(processParamConfig.getId(), processParamConfig.getValue());
            }
            //如果是变量
            if (processParamConfig.getType() == WorkflowParamType.VAR.getCode()) {

                String newStr = WorkFlowUtil.replacePlaceHolder(processParamConfig.getValue(), workflowSchema, serialNumber, 0L);

                result.put(processParamConfig.getId(), newStr);
            }


            //如果是api
            if (processParamConfig.getType() == WorkflowParamType.API.getCode()) {

                IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
                MagicAPIService magicAPIService = SpringUtil.getBean(MagicAPIService.class);

                ApiConfig apiConfig = processParamConfig.getApiConfig();

                MagicApiInfoVo info = magicApiService.info(processParamConfig.getApiConfig().getId());

                Map<String, Object> params = new HashMap<>();
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestParamsConfigs()) {
                    //值
                    if (Objects.equals(requestParamsConfig.getAssignmentType(), "value")) {
                        params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
                    } else if (Objects.equals(requestParamsConfig.getAssignmentType(),"originator")) {
                        dealApiParam(requestParamsConfig,params,varMap);
                    }
                    //流程数据
                    else {
                        String newStr = WorkFlowUtil.replacePlaceHolder(requestParamsConfig.getConfig(), workflowSchema, serialNumber, 0L);
                        params.put(requestParamsConfig.getName(), newStr);
                    }

                }
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestHeaderConfigs()) {
                    //值
                    if (Objects.equals(requestParamsConfig.getDataType(), "value")) {
                        params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
                    }else if (Objects.equals(requestParamsConfig.getAssignmentType(),"originator")) {
                        dealApiParam(requestParamsConfig,params,varMap);
                    }
                    //流程参数
                    else {
                        String newStr = WorkFlowUtil.replacePlaceHolder(processParamConfig.getValue(), workflowSchema, serialNumber, 0L);
                        params.put(requestParamsConfig.getName(), newStr);
                    }

                }
                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestBodyConfigs()) {
                    //值
                    if (Objects.equals(requestParamsConfig.getDataType(), "value")) {
                        params.put(requestParamsConfig.getName(), requestParamsConfig.getValue());
                    }else if (Objects.equals(requestParamsConfig.getAssignmentType(),"originator")) {
                        dealApiParam(requestParamsConfig,params,varMap);
                    }
                    //流程参数
                    else {
                        String newStr = WorkFlowUtil.replacePlaceHolder(processParamConfig.getValue(), workflowSchema, serialNumber, 0L);
                        params.put(requestParamsConfig.getName(), newStr);
                    }

                }
                Object execute = magicAPIService.execute(info.getMethod(), info.getPath(), params);
                result.put(processParamConfig.getId(), execute);
            }
        }

        return result;
    }

    private static void dealApiParam(ApiRequestParamsConfig requestParamsConfig, Map<String, Object> params, Map<String, Object> varMap){
        if (CollectionUtils.isEmpty(varMap)){//为空就是发起时的数据
            //如果是拿发起人的数据,作为流程参数,发起和重新发起赋值,使用当前登录人的信息,如果是其它节点,使用流程的发起人数据信息
            SaSession tokenSession = StpUtil.getTokenSession();
            User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
            //如果是设置的发起人
            if (requestParamsConfig.getConfig().contains("initiator_id")) {
                params.put(requestParamsConfig.getName(), user.getId().toString());
            }
            //组织架构名称
            if (requestParamsConfig.getConfig().contains("initiator_dept_name")) {
                RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
                List<UserDeptRelation> userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                });

                List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                });
                List<UserDeptRelation> startUserDeptRelation = userDeptRelations.stream().filter(x -> x.getUserId().equals(user.getId())).collect(Collectors.toList());

                List<Long> allDeptIds = startUserDeptRelation.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());

                List<Department> allDept = departmentList.stream().filter(x -> allDeptIds.contains(x.getId())).collect(Collectors.toList());

                params.put(requestParamsConfig.getName(), allDept.stream().map(Department::getName).collect(Collectors.joining(",")));
            }
        }else {
            //如果是设置的发起人
            if (requestParamsConfig.getConfig().contains("initiator_id")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
                params.put(requestParamsConfig.getName(), startUserId);
            }
            //组织架构名称
            if (requestParamsConfig.getConfig().contains("initiator_dept_name")) {
                Long startUserId = MapUtil.get(varMap, WorkflowConstant.PROCESS_START_USER_ID_KEY, Long.class);
                RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
                List<UserDeptRelation> userDeptRelations = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
                });
                List<Department> departmentList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
                });
                List<UserDeptRelation> startUserDeptRelation = userDeptRelations.stream().filter(x -> x.getUserId().equals(startUserId)).collect(Collectors.toList());

                List<Long> allDeptIds = startUserDeptRelation.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());

                List<Department> allDept = departmentList.stream().filter(x -> allDeptIds.contains(x.getId())).collect(Collectors.toList());

                params.put(requestParamsConfig.getName(), allDept.stream().map(Department::getName).collect(Collectors.joining(",")));
            }
        }
    }

    /**
     * 自定义表单默认使用的就是数据库字段名
     * 而系统表单的表单数据 默认会将 数据库字段转为驼峰命名
     * 所以将formData 的所有key 转为数据库字段名
     * 为了系统表单 所填写 表单数据 能够使用自定义表单接口执行
     *
     * @param forData
     * @return
     */
    public Map<String, Object> conventFormDataKeyToDbField(Map<String, Object> forData) {
        return null;
    }


    /**
     * 清理掉此任务得所有超时提醒
     *
     * @param taskId
     */
    public static void removeTaskTimeoutRemid(String taskId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        redisUtil.deleteBatch(WorkflowConstant.TIMEOUT_REMID_KEY + taskId + StringPool.COLON + StringPool.STAR);
    }

    /**
     * 清理掉此流程所有的缓存
     *
     * @param processInstanceId 流程实例id
     */
    public static void removeProcessCache(String processInstanceId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        redisUtil.deleteBatch(processInstanceId + StringPool.COLON + StringPool.STAR);
    }

    /**
     * 缓存所有 任务审批人的 记录
     * 格式：
     * {
     * "taskid1" : [userid]                 //普通用户任务节点
     * "taskid2" : [userid,userid,userid]   //会签任务节点（并行）
     * }
     *
     * @param taskId
     */
    public static void cacheTaskAssigneeRecord(String processInstanceId, String taskId, Long userId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        if (redisUtil.containsKey(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY)) {
            Map<String, List<Long>> taskAssigneeRecordMap = redisUtil.get(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, new TypeReference<Map<String, List<Long>>>() {
            });
            List<Long> assigneeUserIds = new ArrayList<>();
            if (taskAssigneeRecordMap.containsKey(taskId)) {
                assigneeUserIds = taskAssigneeRecordMap.get(taskId);
                assigneeUserIds.add(userId);
            } else {
                assigneeUserIds.add(userId);
            }
            taskAssigneeRecordMap.put(taskId, assigneeUserIds);
            redisUtil.set(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, taskAssigneeRecordMap);
        } else {
            //必须要有序Map
            Map<String, List<Long>> taskAssigneeRecordMap = new LinkedHashMap<>(1);
            List<Long> assigneeUserIds = new ArrayList<>();
            assigneeUserIds.add(StpUtil.getLoginIdAsLong());
            taskAssigneeRecordMap.put(taskId, assigneeUserIds);
            redisUtil.set(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, taskAssigneeRecordMap);
        }
    }


    /**
     * 根据流程id  和 任务id  获取审批人
     *
     * @param processInstanceId
     * @param taskId
     * @return
     */
    public static List<Long> getTaskAssigneeRecordCache(String processInstanceId, String taskId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        Map<String, List<Long>> cache = redisUtil.get(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, new TypeReference<Map<String, List<Long>>>() {
        });

        return cache.get(taskId);

    }


    /**
     * 缓存任务审批类型 记录
     *
     * @param processInstanceId   流程实例id
     * @param taskId              任务id
     * @param workflowApproveType 审批类型枚举
     */
    public static void cacheTaskApproveType(String processInstanceId, String taskId, Integer workflowApproveType) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        Map<String, Integer> approveTypeMap;
        if (redisUtil.containsKey(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY)) {
            approveTypeMap = redisUtil.get(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY, new TypeReference<Map<String, Integer>>() {
            });


        } else {
            approveTypeMap = new HashMap<>(1);
        }
        approveTypeMap.put(taskId, workflowApproveType);
        redisUtil.set(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY, approveTypeMap);
    }

    /**
     * 根据参数获取审批类型
     *
     * @param processInstanceId
     * @param taskId
     * @return
     */
    public static Integer getTaskApproveTypeCache(String processInstanceId, String taskId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        Map<String, Integer> approveTypeMap = redisUtil.get(processInstanceId + WorkflowConstant.TASK_APPROVE_TYPE_RECORD_VAR_KEY, new TypeReference<Map<String, Integer>>() {
        });

        return approveTypeMap.get(taskId);
    }

    /**
     * 发送传阅人消息提醒(多线程 异步)
     *
     * @param param
     */
    public static void sendCirculatedNoticePolicy(NoticePolicyParam param, String name) {
        //如果有设置通知策略
        if (param.getNoticePolicyConfigs().size() > 0) {

            //如果包含系统消息
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SYSTEM.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedMessage(param);
                });
            }

            //如果包含短信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SMS.getCode())) {
                //TODO 发送短信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedSms(param, name);
                });
            }
            //如果包含email
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.EMAIL.getCode())) {
                //TODO 发邮件
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowCirculatedEmail(param);
                });
            }
            //如果包含企业微信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.WECHAT.getCode())) {
                //TODO 发送企业微信
            }
            //如果包含钉钉
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.DING.getCode())) {
                //TODO 发送钉钉
            }

        }
    }

    /**
     * 发送审批人消息提醒(多线程 异步)
     *
     * @param param
     */
    public static void sendApproveNoticePolicy(NoticePolicyParam param, String name) {
        //如果有设置通知策略
        if (param.getNoticePolicyConfigs().size() > 0) {

            //如果包含系统消息
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SYSTEM.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveMessage(param);
                });
            }

            //如果包含短信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SMS.getCode())) {
                //TODO 发送短信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveSms(param, name);
                });
            }
            //如果包含email
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.EMAIL.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveEmail(param);
                });
            }
            //如果包含企业微信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.WECHAT.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveWx(param, name);
                });
            }
            //如果包含钉钉
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.DING.getCode())) {
                //TODO 发送钉钉
            }

        }
    }

    /**
     * 发送超时消息提醒(多线程 异步)
     *
     * @param param
     */
    public static void sendTimeOutNoticePolicy(NoticePolicyParam param, String name) {
        //如果有设置通知策略
        if (param.getNoticePolicyConfigs().size() > 0) {

            //如果包含系统消息
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SYSTEM.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutMessage(param);
                });
            }

            //如果包含短信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.SMS.getCode())) {
                //TODO 发送短信
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutSms(param, name);
                });
            }
            //如果包含email
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.EMAIL.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowTimeoutEmail(param);
                });
            }
            //如果包含企业微信
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.WECHAT.getCode())) {
                CompletableFuture.runAsync(() -> {
                    SendMessageUtil.sendWorkflowApproveWx(param, name);
                });
            }
            //如果包含钉钉
            if (param.getNoticePolicyConfigs().contains(WorkflowNoticePolicyType.DING.getCode())) {
                //TODO 发送钉钉
            }

        }
    }

    /**
     * 根据用户id获取对应的用户名，并进行拼接输出
     *
     * @param allUserIds 用户ids
     * @return 用户名（张三、李四）
     */
    public static String getAllUserNamesByIds(List<Long> allUserIds) {
        String allDelegateUserNames = StringPool.EMPTY;

        //TODO 第一种：redis中获取用户 ->用户数量太多时json反序列化耗时比较长
//        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
//        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {});
//        //如果缓存中不存在用户信息，就直接去数据库查询,并保存到缓存中去
//        if (userList.size() == 0) {
//            IUserService userService = SpringUtil.getBean(IUserService.class);
//            userList = userService.list();
//            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
//        }
//        if (allUserIds.size() > 0) {
//            //获取用户id对应的用户名
//            List<String> allUserName = userList.stream().filter(u -> allUserIds.contains(u.getId())).map(User::getName).collect(Collectors.toList());
//            String chineseDot = "、";
//
//            if (allUserName.size() > 0) {
//                allDelegateUserNames = StrUtil.join(chineseDot, allUserName);
//            }
//        }
//        return allDelegateUserNames;

        //TODO 第二种：mysql中直接获取用户信息，数据量大时建议采用第二种
        if (allUserIds != null && allUserIds.size()>0){
            IUserService userService = SpringUtil.getBean(IUserService.class);
            List<User> userList = userService.listByIds(allUserIds);
            if (allUserIds.size() > 0) {
                //获取用户id对应的用户名
                List<String> allUserName = userList.stream().filter(u -> allUserIds.contains(u.getId())).map(User::getName).collect(Collectors.toList());
                String chineseDot = "、";

                if (allUserName.size() > 0) {
                    allDelegateUserNames = StrUtil.join(chineseDot, allUserName);
                }
            }
        }
        return allDelegateUserNames;

    }

    /**
     * 发起流程时， 遍历所有节点 如果有需要监听器的  默认缓存 key -> deployId:ActivityId
     *
     * @param deployId        部署id
     * @param childNodeConfig 所有节点配置
     */
    public static void cacheNodeListener(String deployId, List<Map<String, Object>> childNodeConfig) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        for (Map<String, Object> map : childNodeConfig) {
            //转换为node 配置类型
            NodeBasicConfig nodeBasicConfig = BeanUtil.toBean(map, NodeBasicConfig.class);

            if (nodeBasicConfig.getStartEventConfigs().size() > 0) {
                String startKey = WorkflowConstant.START_EVENT_CACHE_PRE + deployId + StringPool.COLON + nodeBasicConfig.getId() + StringPool.COLON + WorkflowEventType.START.getValue();
                redisUtil.set(startKey, nodeBasicConfig.getStartEventConfigs());
            }
            if (nodeBasicConfig.getEndEventConfigs().size() > 0) {
                String endKey = WorkflowConstant.END_EVENT_CACHE_PRE + deployId + StringPool.COLON + nodeBasicConfig.getId() + StringPool.COLON + WorkflowEventType.END.getValue();
                redisUtil.set(endKey, nodeBasicConfig.getEndEventConfigs());
            }


        }
    }

    /**
     * 删除监听器
     *
     * @param deployId 部署id
     */
    public static void removeNodeListener(String deployId) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        redisUtil.deleteBatch(deployId + StringPool.COLON + "*");
    }

    /**
     * 获取一天的开始时间 00:00:00
     *
     * @param date 某一天时间
     * @return 某一天的开始时间, 比如2023-01-01 00:00:00
     */
    public static Date getStartOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取一天的结束时间 23:59:59
     *
     * @param date 某一天时间
     * @return 某一天的结束时间, 比如2023-01-01 23:59:59
     */
    public static Date getEndOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }
}

