package com.qmth.sop.business.activiti.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.gson.reflect.TypeToken;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.sop.business.activiti.service.ActivitiService;
import com.qmth.sop.business.bean.params.FlowApproveParam;
import com.qmth.sop.business.bean.result.*;
import com.qmth.sop.business.cache.CommonCacheService;
import com.qmth.sop.business.entity.*;
import com.qmth.sop.business.exec.MySQLExec;
import com.qmth.sop.business.mapper.SysUserMapper;
import com.qmth.sop.business.service.*;
import com.qmth.sop.common.contant.SpringContextHolder;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.*;
import com.qmth.sop.common.lock.MemoryLock;
import com.qmth.sop.common.util.GsonUtil;
import com.qmth.sop.common.util.JacksonUtil;
import com.qmth.sop.common.util.ResultUtil;
import com.qmth.sop.common.util.ServletUtil;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricIdentityLink;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

/**
 * @Description: activiti service impl
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/7/12
 */
@Service
public class ActivitiServiceImpl implements ActivitiService {

    private final static Logger log = LoggerFactory.getLogger(ActivitiServiceImpl.class);

    @Resource
    RepositoryService repositoryService;

    @Resource
    TaskService taskService;

    @Resource
    TFCustomFlowService tfCustomFlowService;

    @Resource
    RuntimeService runtimeService;

    @Resource
    TFCustomFlowEntityService tfCustomFlowEntityService;

    @Resource
    SysUserMapper sysUserMapper;

    @Resource
    MemoryLock memoryLock;

    @Resource
    HistoryService historyService;

    @Resource
    TFFlowApproveService tfFlowApproveService;

    @Resource
    TFFlowLogService tfFlowLogService;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Resource
    SysUserService sysUserService;

    @Resource
    CommonCacheService commonCacheService;

    @Resource
    SequenceService sequenceService;

    @Resource
    TDFormWidgetMetadataService tdFormWidgetMetadataService;

    @Resource
    MySQLExec mySQLExec;

    @Resource
    TBSopInfoService tbSopInfoService;

    @Resource
    TBCrmService tbCrmService;

    @Resource
    SysUserRoleService sysUserRoleService;

    @Resource
    TSJobRemindService tsJobRemindService;

    @Resource
    TBDeviceDeliveryService tbDeviceDeliveryService;

    /**
     * 根据deploymentId查找processDefinitionId
     *
     * @param deploymentId
     * @return
     */
    @Override
    public String findProcessDefinitionIdByDeploymentId(String deploymentId) {
        return sysUserMapper.findProcessDefinitionIdByDeploymentId(deploymentId);
    }

    /**
     * 上传流程
     *
     * @param file
     * @return
     * @throws IOException
     */
    @Override
    public Map<String, Object> upload(MultipartFile file) throws Exception {
        basicAttachmentService.validateAttachment(file);
        Map<String, Object> map = new HashMap<>();
        DeploymentBuilder builder = repositoryService.createDeployment();
        ZipInputStream zip = new ZipInputStream(file.getInputStream());
        builder.addZipInputStream(zip);
        return formPropertiesGet(builder.deploy().getId(), null, null, true, null);
    }

    /**
     * 部署流程
     *
     * @param tfCustomTypeEnumList
     * @return
     * @throws IOException
     */
    @Override
    public Map<String, Object> createDeployment(List<TFCustomTypeEnum> tfCustomTypeEnumList) throws Exception {
        Map<String, Object> map = new HashMap<>();
        for (TFCustomTypeEnum tfCustomTypeEnum : tfCustomTypeEnumList) {
            List<TFCustomFlow> tfCustomFlowList = tfCustomFlowService.list(
                    new QueryWrapper<TFCustomFlow>().lambda().eq(TFCustomFlow::getType, tfCustomTypeEnum));
            if (CollectionUtils.isEmpty(tfCustomFlowList)) {
                DeploymentBuilder builder = repositoryService.createDeployment();
                ClassPathResource resource = new ClassPathResource(tfCustomTypeEnum.getFileName());
                ZipInputStream zip = new ZipInputStream(resource.getInputStream());
                builder.addZipInputStream(zip);
                Map<String, Object> mapData = formPropertiesGet(builder.deploy().getId(), null, null, true, null);
                map.put(tfCustomTypeEnum.name(), mapData);
            } else {
                Map<String, Object> mapData = formPropertiesGet(tfCustomFlowList.get(0).getFlowDeploymentId(), null,
                        null, true, null);
                map.put(tfCustomTypeEnum.name(), mapData);
            }
        }
        return map;
    }

    /**
     * 审批任务
     *
     * @param flowApproveParam
     * @return
     */
    @Override
    public Map<String, Object> taskApprove(FlowApproveParam flowApproveParam) throws InterruptedException {
        ActivitiService activitiService = SpringContextHolder.getBean(ActivitiService.class);
        Map<String, Object> map = activitiService.taskApproveCommon(flowApproveParam);

        TFCustomFlow tfCustomFlow = (TFCustomFlow) map.get(SystemConstant.FLOW_CUSTOM);
        Optional.ofNullable(tfCustomFlow).orElseThrow(() -> ExceptionResultEnum.FLOW_CUSTOM_NO_DATA.exception());

        TFCustomFlowEntity tfCustomFlowEntity = (TFCustomFlowEntity) map.get(SystemConstant.FLOW_ENTITY);
        Optional.ofNullable(tfCustomFlowEntity).orElseThrow(() -> ExceptionResultEnum.FLOW_ENTITY_NO_DATA.exception());

        if (tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW
                || tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW) {
            int count = tfFlowApproveService.findFlowPassageSopByCrmNo(tfCustomFlowEntity.getCrmNo());
            if (count == 0) {
                tbCrmService.updateCrmStatus(tfCustomFlowEntity.getCrmNo(), CrmStatusEnum.FINISH);
            }
        }
        return map;
    }

    /**
     * 审批任务
     *
     * @param flowApproveParam
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> taskApproveCommon(FlowApproveParam flowApproveParam) throws InterruptedException {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        Map<String, Object> map = new HashMap<>();
        List<String> approveUserIds = flowApproveParam.getApproveUserIds();
        if (CollectionUtils.isEmpty(approveUserIds) && (flowApproveParam.getApprove() == FlowApprovePassEnum.START
                || flowApproveParam.getApprove() == FlowApprovePassEnum.DRAFT
                || flowApproveParam.getApprove() == FlowApprovePassEnum.PASS)) {
            approveUserIds = new ArrayList<>();
            approveUserIds.add(String.valueOf(sysUser.getId()));//否则是当前登录用户
        }
        String processFlowId = null;
        TFCustomFlowEntity tfCustomFlowEntity = null;
        TFFlowApprove tfFlowApprove = null;
        Task taskTemp = null;
        FlowResult flowResult = null;
        TFCustomFlow tfCustomFlow = null;
        if (Objects.nonNull(flowApproveParam.getFlowDeploymentId()) && Objects.isNull(flowApproveParam.getTaskId())) {
            Optional.ofNullable(flowApproveParam.getCrmNo())
                    .orElseThrow(() -> ExceptionResultEnum.CRM_NO_NO_DATA.exception());

            tfCustomFlow = tfCustomFlowService.getOne(new QueryWrapper<TFCustomFlow>().lambda()
                    .eq(TFCustomFlow::getFlowDeploymentId, flowApproveParam.getFlowDeploymentId()));
            Optional.ofNullable(tfCustomFlow).orElseThrow(() -> ExceptionResultEnum.FLOW_CUSTOM_NO_DATA.exception());
            Optional.ofNullable(tfCustomFlow.getFlowProcessVar())
                    .orElseThrow(() -> ExceptionResultEnum.FLOW_PROCESS_VAR_NO_DATA.exception());

            TFCustomFlow maxTfCustomFlow = tfCustomFlowService.findMaxVersion(null, null, tfCustomFlow.getType());
            if (maxTfCustomFlow.getVersion().intValue() != tfCustomFlow.getVersion().intValue()) {//说明版本发生变化
                BeanUtils.copyProperties(maxTfCustomFlow, tfCustomFlow);
            }
            Optional.ofNullable(maxTfCustomFlow).orElseThrow(() -> ExceptionResultEnum.FLOW_CUSTOM_NO_DATA.exception());
            Optional.ofNullable(maxTfCustomFlow.getFlowProcessVar())
                    .orElseThrow(() -> ExceptionResultEnum.FLOW_PROCESS_VAR_NO_DATA.exception());

            map.put(SystemConstant.DEFAULT_ASSIGNEE_LIST + 1, approveUserIds);
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(
                    tfCustomFlow.getFlowDefinitionId(), map);
            processFlowId = processInstance.getId();

            String code = sequenceService.createFlowCode(tfCustomFlow.getType());
            tfCustomFlowEntity = new TFCustomFlowEntity(tfCustomFlow.getId(), sysUser.getId(), code,
                    flowApproveParam.getCrmNo());
            tfFlowApprove = new TFFlowApprove(sysUser.getOrgId(),
                    Long.parseLong(approveUserIds.get(approveUserIds.size() - 1)),
                    FlowStatusEnum.valueOf(flowApproveParam.getApprove().name()), sysUser.getId());
            flowResult = JSONObject.parseObject(tfCustomFlow.getFlowProcessVar(), FlowResult.class);
        } else if (Objects.nonNull(flowApproveParam.getTaskId())) {
            taskTemp = taskService.createTaskQuery().taskId(String.valueOf(flowApproveParam.getTaskId()))
                    .singleResult();
            Optional.ofNullable(taskTemp).orElseThrow(() -> ExceptionResultEnum.FLOW_TASK_NO_DATA.exception());
            processFlowId = taskTemp.getProcessInstanceId();
        }

        boolean lock = memoryLock.lock(SystemConstant.LOCK_FLOW_TASK_PREFIX + processFlowId, processFlowId,
                SystemConstant.LOCK_FLOW_TIME_OUT);
        if (!lock) {
            throw ExceptionResultEnum.ERROR.exception("正在审批中，请稍候再试！");
        }
        try {
            List<Task> taskList = new ArrayList<>();
            if (Objects.isNull(taskTemp)) {
                taskList = taskService.createTaskQuery().processInstanceId(processFlowId).list();
            } else {
                tfCustomFlowEntity = tfCustomFlowEntityService.getOne(new QueryWrapper<TFCustomFlowEntity>().lambda()
                        .eq(TFCustomFlowEntity::getFlowId, Long.parseLong(processFlowId)));
                Optional.ofNullable(tfCustomFlowEntity)
                        .orElseThrow(() -> ExceptionResultEnum.FLOW_ENTITY_NO_DATA.exception());
                flowResult = JSONObject.parseObject(tfCustomFlowEntity.getFlowProcessVar(), FlowResult.class);

                tfCustomFlow = tfCustomFlowService.getById(tfCustomFlowEntity.gettFCustomFlowId());

                tfFlowApprove = tfFlowApproveService.getOne(new QueryWrapper<TFFlowApprove>().lambda()
                        .eq(TFFlowApprove::getFlowId, Long.parseLong(processFlowId)));
                Optional.ofNullable(tfFlowApprove)
                        .orElseThrow(() -> ExceptionResultEnum.FLOW_APPROVE_NO_DATA.exception());
                taskList.add(taskTemp);
            }
            List<TFFlowLog> tfFlowLogList = new ArrayList<>();
            LinkedHashMap<String, FlowTaskResult> setupMap = flowResult.getSetupMap();

            tfCustomFlowEntity.setFlowId(Long.parseLong(processFlowId));
            tfFlowApprove.setFlowId(Long.parseLong(processFlowId));
            tfFlowApprove.setApproveMaxSetup(setupMap.size());
            for (Task task : taskList) {
                BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
                FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());
                FlowTaskResult currFlowTaskResult = null, nextFlowTaskResult = null, formDataFlowTaskResult = null;
                Integer nrOfCompletedInstances = null, nrOfInstances = null;
                boolean multiInstance = false;
                if (currFlow instanceof UserTask) {
                    if (currFlow.getBehavior() instanceof MultiInstanceActivityBehavior) {
                        nrOfCompletedInstances = (Integer) taskService.getVariable(task.getId(),
                                SystemConstant.NR_OF_COMPLETED_INSTANCES);
                        nrOfCompletedInstances++;
                        nrOfInstances = (Integer) taskService.getVariable(task.getId(), SystemConstant.NR_OF_INSTANCES);
                        multiInstance = true;
                    }
                    currFlowTaskResult = GsonUtil.fromJson(GsonUtil.toJson(setupMap.get(task.getTaskDefinitionKey())),
                            FlowTaskResult.class);
                    if (Objects.nonNull(flowApproveParam.getFormProperties())) {
                        formDataFlowTaskResult = JSONObject.parseObject(flowApproveParam.getFormProperties(),
                                FlowTaskResult.class);
                    }
                    int currSetup = currFlowTaskResult.getSetup().intValue();
                    if (currSetup != 1 && flowApproveParam.getApprove() == FlowApprovePassEnum.START) {
                        throw ExceptionResultEnum.ERROR.exception("只有流程第一步才需要提交！");
                    }
                    if (currSetup != 2 && flowApproveParam.getApprove() == FlowApprovePassEnum.CANCEL) {
                        throw ExceptionResultEnum.ERROR.exception("只有流程第二步才能撤回！");
                    }
                    //流程流水日志
                    TFFlowLog tfFlowLog = new TFFlowLog(sysUser.getOrgId(), sysUser.getId(), sysUser.getId(),
                            currFlowTaskResult.getSetup(), Long.parseLong(processFlowId), Long.parseLong(task.getId()),
                            tfCustomFlowEntity.getId(),
                            StringUtils.join(approveUserIds, SystemConstant.LIST_JOIN_SPLIT));
                    if (flowApproveParam.getApprove() == FlowApprovePassEnum.PASS
                            || flowApproveParam.getApprove() == FlowApprovePassEnum.DRAFT
                            || flowApproveParam.getApprove() == FlowApprovePassEnum.START) {
                        boolean dingExceptionNoPass = false;
                        if (Objects.nonNull(flowApproveParam.getSetup())) {
                            currSetup = flowApproveParam.getSetup();
                        } else {
                            if (tfCustomFlow.getType() == TFCustomTypeEnum.DING_EXCEPTION_FLOW && currSetup == 2
                                    && Objects.nonNull(flowApproveParam.getApproveRemark()) && Objects.equals(
                                    DingExceptionApproveEnum.NO_PASS.getTitle(), flowApproveParam.getApproveRemark())) {
                                currSetup = 0;
                                nrOfCompletedInstances = nrOfInstances;
                                dingExceptionNoPass = true;
                            } else {
                                currSetup = currSetup == setupMap.size() - 1 ? 0 : currSetup + 1;
                            }
                        }
                        nextFlowTaskResult = this.getNextFlowTaskResult(nrOfCompletedInstances, nrOfInstances,
                                currFlowTaskResult, nextFlowTaskResult, currSetup, setupMap,
                                flowApproveParam.getApprove());

                        this.approvePass(currFlowTaskResult, setupMap, multiInstance, nrOfCompletedInstances,
                                nrOfInstances, tfFlowApprove, tfFlowLog, nextFlowTaskResult, map,
                                flowApproveParam.getApprove(), flowApproveParam.getApproveRemark());
                        if (dingExceptionNoPass) {
                            map.put(FlowApproveOperationEnum.REJECT.getId() + currFlowTaskResult.getSetup(), 1);
                        }
                        map.put(SystemConstant.ASSIGNEE + nextFlowTaskResult.getSetup(), approveUserIds);
                        map.put(SystemConstant.DEFAULT_ASSIGNEE_LIST + nextFlowTaskResult.getSetup(), approveUserIds);
                    } else if (flowApproveParam.getApprove() == FlowApprovePassEnum.REJECT
                            || flowApproveParam.getApprove() == FlowApprovePassEnum.CANCEL) {
                        if (Objects.nonNull(flowApproveParam.getSetup())) {
                            currSetup = flowApproveParam.getSetup();
                        } else {
                            currSetup = currSetup - 1;
                        }

                        nextFlowTaskResult = this.getNextFlowTaskResult(nrOfCompletedInstances, nrOfInstances,
                                currFlowTaskResult, nextFlowTaskResult, currSetup, setupMap,
                                flowApproveParam.getApprove());

                        this.approveReject(multiInstance, map, currFlowTaskResult, nextFlowTaskResult, tfFlowApprove,
                                tfFlowLog, flowApproveParam.getApprove(), flowApproveParam.getApproveRemark());
                    }
                    map.put(SystemConstant.APPROVE, nextFlowTaskResult.getTaskKey());
                    if (Objects.nonNull(formDataFlowTaskResult) && Objects.equals(task.getTaskDefinitionKey(),
                            formDataFlowTaskResult.getTaskKey())) {
                        setupMap.put(task.getTaskDefinitionKey(), formDataFlowTaskResult);
                        if (tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW
                                || tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW) {
                            tbSopInfoService.saveDynamicSop(tfCustomFlow, tfCustomFlowEntity.getCode(),
                                    Long.parseLong(processFlowId), formDataFlowTaskResult);
                        }
                    }
                    flowResult.setSetupMap(setupMap);
                    tfCustomFlowEntity.setFlowProcessVar(JacksonUtil.parseJson(flowResult));
                    if (flowApproveParam.getApprove() == FlowApprovePassEnum.START
                            || flowApproveParam.getApprove() == FlowApprovePassEnum.PASS
                            || flowApproveParam.getApprove() == FlowApprovePassEnum.CANCEL
                            || flowApproveParam.getApprove() == FlowApprovePassEnum.REJECT) {
                        if (flowApproveParam.getApprove() == FlowApprovePassEnum.CANCEL
                                || flowApproveParam.getApprove() == FlowApprovePassEnum.REJECT) {
                            List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                                    .processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceEndTime()
                                    .desc().list();
                            if (!CollectionUtils.isEmpty(historicTaskInstanceList)) {
                                Set<String> approveIdSet = new LinkedHashSet<>();
                                for (int i = historicTaskInstanceList.size() - 1; i >= 0; i--) {
                                    HistoricTaskInstance historicTaskInstance = historicTaskInstanceList.get(i);
                                    if (Objects.equals(historicTaskInstance.getTaskDefinitionKey(),
                                            nextFlowTaskResult.getTaskKey())) {
                                        if (Objects.nonNull(historicTaskInstance.getAssignee())) {
                                            approveIdSet.add(historicTaskInstance.getAssignee());
                                        } else {
                                            List<HistoricIdentityLink> historicIdentityLinkList = historyService.getHistoricIdentityLinksForTask(
                                                    historicTaskInstance.getId());
                                            if (!CollectionUtils.isEmpty(historicIdentityLinkList)) {
                                                for (HistoricIdentityLink h : historicIdentityLinkList) {
                                                    approveIdSet.add(h.getUserId());
                                                }
                                            }
                                        }
                                    }
                                }
                                tfFlowLog.setPendApproveId(
                                        approveIdSet.toString().replaceAll("\\[", "").replaceAll("\\]", "")
                                                .replaceAll(", ", ","));
                                map.put(SystemConstant.ASSIGNEE + nextFlowTaskResult.getSetup(),
                                        new ArrayList<>(approveIdSet));
                                map.put(SystemConstant.DEFAULT_ASSIGNEE_LIST + nextFlowTaskResult.getSetup(),
                                        new ArrayList<>(approveIdSet));
                            }
                        }
                        taskService.setVariable(task.getId(), SystemConstant.FLOW_CUSTOM, tfCustomFlow);
                        taskService.setVariable(task.getId(), SystemConstant.FLOW_APPROVE, tfFlowApprove);
                        taskService.setVariable(task.getId(), SystemConstant.FLOW_ENTITY, tfCustomFlowEntity);
                        taskService.setVariable(task.getId(), SystemConstant.FLOW_APPROVE_LOG, tfFlowLog);
                        taskService.setVariable(task.getId(), SystemConstant.FLOW_SYS_USER, sysUser);
                        //                        taskService.setVariable(task.getId(), SystemConstant.APPROVE_MAP_VAR, flowApproveParam.getVar());
                        taskService.complete(task.getId(), map);
                        if (flowApproveParam.getApprove() == FlowApprovePassEnum.START
                                || flowApproveParam.getApprove() == FlowApprovePassEnum.PASS) {
                            List<Task> tasks = taskService.createTaskQuery().processInstanceId(processFlowId).list();
                            if (!CollectionUtils.isEmpty(tasks)) {
                                Set<String> approveIdSet = new LinkedHashSet<>();
                                for (Task t : tasks) {
                                    if (Objects.isNull(t.getAssignee())) {
                                        List<IdentityLink> identityLinkList = taskService.getIdentityLinksForTask(
                                                t.getId());
                                        if (!CollectionUtils.isEmpty(identityLinkList)) {
                                            for (IdentityLink i : identityLinkList) {
                                                approveIdSet.add(i.getUserId());
                                            }
                                        }
                                    } else {
                                        approveIdSet.add(t.getAssignee());
                                    }
                                }
                                tfFlowLog.setPendApproveId(
                                        approveIdSet.toString().replaceAll("\\[", "").replaceAll("\\]", "")
                                                .replaceAll(", ", ","));
                            } else {
                                tfFlowLog.setPendApproveId(null);
                            }
                        }
                    }
                    map.put(SystemConstant.FLOW_APPROVE_LOG, tfFlowLog);
                    tfFlowLogList.add(tfFlowLog);
                }
            }
            tfCustomFlowEntityService.saveOrUpdate(tfCustomFlowEntity);
            tfFlowApproveService.saveOrUpdate(tfFlowApprove);
            tfFlowLogService.saveBatch(tfFlowLogList);
            map.put(SystemConstant.FLOW_CUSTOM, tfCustomFlow);
            map.put(SystemConstant.FLOW_APPROVE, tfFlowApprove);
            map.put(SystemConstant.FLOW_ENTITY, tfCustomFlowEntity);
            //            map.put(SystemConstant.APPROVE_MAP_VAR, flowApproveParam.getVar());
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        } finally {
            memoryLock.unlock(SystemConstant.LOCK_FLOW_TASK_PREFIX + processFlowId);
        }
        return map;
    }

    /**
     * 获取流程表单属性接口
     *
     * @param flowDeploymentId
     * @param flowId
     * @param taskId
     * @param dynamicTable
     * @param crmNo
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> formPropertiesGet(String flowDeploymentId, Long flowId, Long taskId,
            Boolean dynamicTable, String crmNo) throws Exception {
        Map<String, Object> map = new HashMap<>();
        FlowResult flowResult = null;
        TFCustomFlow tfCustomFlow = null;
        List<Task> taskList = null;
        if (Objects.nonNull(flowDeploymentId)) {
            tfCustomFlow = tfCustomFlowService.getOne(
                    new QueryWrapper<TFCustomFlow>().lambda().eq(TFCustomFlow::getFlowDeploymentId, flowDeploymentId));
            Optional.ofNullable(tfCustomFlow)
                    .orElseThrow(() -> ExceptionResultEnum.FLOW_DEPLOYMENT_NO_DATA.exception());
            if (Objects.isNull(tfCustomFlow.getFlowDefinitionId())) {
                String processDefinitionId = this.findProcessDefinitionIdByDeploymentId(flowDeploymentId);
                tfCustomFlow.setFlowDefinitionId(processDefinitionId);
                tfCustomFlowService.updateById(tfCustomFlow);
            }
            flowResult = JSONObject.parseObject(tfCustomFlow.getFlowProcessVar(), FlowResult.class);
            if (tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW
                    || tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW
                    || tfCustomFlow.getType() == TFCustomTypeEnum.QUALITY_PROBLEM_FLOW) {
                map = this.getFlowFormPropertie(flowResult, map, 1);
                if ((Objects.nonNull(dynamicTable) && dynamicTable) && (
                        tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW
                                || tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW)) {
                    Map<String, FlowTaskResult> setupMap = flowResult.getSetupMap();
                    Set<TDFormWidgetMetadata> tdFormWidgetMetadataSet = new LinkedHashSet<>();
                    for (Map.Entry<String, FlowTaskResult> entry : setupMap.entrySet()) {
                        FlowTaskResult flowTaskResultTemp = GsonUtil.fromJson(GsonUtil.toJson(entry.getValue()),
                                FlowTaskResult.class);
                        List<FlowFormWidgetResult> formWidgetResultList = flowTaskResultTemp.getFormProperty();
                        if (!CollectionUtils.isEmpty(formWidgetResultList)) {
                            for (FlowFormWidgetResult f : formWidgetResultList) {
                                if (f.getCode() != WidgetCodeEnum.FORM_GROUP_TITLE
                                        && f.getCode() != WidgetCodeEnum.ONLY_TITLE
                                        && f.getCode() != WidgetCodeEnum.BUTTON && f.getCode() != WidgetCodeEnum.IMG
                                        && f.getCode() != WidgetCodeEnum.LABEL && f.getCode() != WidgetCodeEnum.SIGN
                                        && f.getCode() != WidgetCodeEnum.OTHER) {
                                    tdFormWidgetMetadataSet.add(new TDFormWidgetMetadata(tfCustomFlow.getType(),
                                            tfCustomFlow.getFlowDeploymentId(), tfCustomFlow.getVersion(),
                                            flowTaskResultTemp.getSetup(), f.getCode(), f.getFormId(), f.getFormName(),
                                            f.getTitle()));
                                }
                            }
                        }
                    }
                    tdFormWidgetMetadataService.selectMetadataExist(tfCustomFlow.getType(), tfCustomFlow.getVersion(),
                            tdFormWidgetMetadataSet);
                    mySQLExec.execCreateSopDynamicTable(SystemConstant.SOP_DYNAMIC_TABLE_FILE_NAME,
                            tfCustomFlow.getType(), tfCustomFlow.getVersion());
                }
            }
        } else if (Objects.nonNull(flowId)) {
            if (tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW
                    || tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW
                    || tfCustomFlow.getType() == TFCustomTypeEnum.QUALITY_PROBLEM_FLOW) {
                taskList = taskService.createTaskQuery().processInstanceId(String.valueOf(flowId)).list();
                map = this.getFlowFormPropertie(map, taskList, flowResult, tfCustomFlow);
            }
        } else {
            if (tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW
                    || tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW
                    || tfCustomFlow.getType() == TFCustomTypeEnum.QUALITY_PROBLEM_FLOW) {
                taskList = taskService.createTaskQuery().taskId(String.valueOf(taskId)).list();
                map = this.getFlowFormPropertie(map, taskList, flowResult, tfCustomFlow);
            }
        }
        map.put(SystemConstant.FLOW_DEPLOYMENT_ID, tfCustomFlow.getFlowDeploymentId());
        map.put(SystemConstant.ID, tfCustomFlow.getId());
        if (Objects.nonNull(crmNo)) {
            CrmProjectResult crmProjectResult = tbCrmService.findCrmProjectBySopNoOrCrmNo(null, crmNo);
            if (Objects.nonNull(crmProjectResult)) {
                map.put(SystemConstant.CRM_INFO, crmProjectResult);
            }
        }
        return map;
    }

    /**
     * 获取用户待办
     *
     * @param iPage
     * @param userId
     * @param type
     * @param serviceId
     * @param customName
     * @param flowTaskTypeEnum
     * @param crmNo
     * @return
     */
    @Override
    public IPage<WorkTaskResult> getFlowTaskList(IPage<Map> iPage, Long userId, TFCustomTypeEnum type, Long serviceId,
            String customName, FlowTaskTypeEnum flowTaskTypeEnum, String crmNo) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        userId = Objects.nonNull(sysUser) ? sysUser.getId() : userId;
        Map<String, Object> map = new HashMap<>();
        IPage<WorkTaskResult> workTaskResultIPage = sysUserService.getFlowTaskList(iPage, userId, type, serviceId,
                customName, flowTaskTypeEnum, crmNo);
        if (Objects.nonNull(workTaskResultIPage) && !CollectionUtils.isEmpty(workTaskResultIPage.getRecords())) {
            Set<String> sopNoSet = new HashSet<>(workTaskResultIPage.getRecords().size());
            Map<String, WorkTaskResult> workTaskMap = new LinkedHashMap<>();
            for (WorkTaskResult w : workTaskResultIPage.getRecords()) {
                sopNoSet.add(w.getCode());
                workTaskMap.put(w.getCode(), w);
                List<Task> taskList = taskService.createTaskQuery().taskId(String.valueOf(w.getTaskId())).list();
                if (!CollectionUtils.isEmpty(taskList)) {
                    for (Task t : taskList) {
                        FlowResult flowResult = JSONObject.parseObject(w.getFlowProcessVar(), FlowResult.class);
                        LinkedHashMap<String, FlowTaskResult> setupMap = flowResult.getSetupMap();
                        FlowTaskResult currFlowTaskResult = GsonUtil.fromJson(
                                GsonUtil.toJson(setupMap.get(t.getTaskDefinitionKey())), FlowTaskResult.class);
                        map = this.getFlowFormPropertie(flowResult, map, currFlowTaskResult.getSetup());
                        w.setFlowProcessVar(null);
                        w.setSetupMap((FlowTaskResult) map.get(SystemConstant.FORM_PROPERTIES));
                    }
                }
            }
            List<WorkTaskResult> workTaskResultList = tsJobRemindService.getJobRemindProcessHour(sysUser.getId(),
                    sopNoSet);
            if (!CollectionUtils.isEmpty(workTaskResultList)) {
                for (WorkTaskResult w : workTaskResultList) {
                    if (Objects.nonNull(workTaskMap.get(w.getCode())) && Objects.nonNull(w.getProcessHour())) {
                        workTaskMap.get(w.getCode()).setProcessHour(w.getProcessHour());
                    }
                }
            }
        }
        return workTaskResultIPage;
    }

    /**
     * 获取用户待办计数
     *
     * @param userId
     * @param type
     * @param serviceId
     * @param customName
     * @param flowTaskTypeEnum
     * @param crmNo
     * @return
     */
    @Override
    public int getFlowTaskListCount(Long userId, TFCustomTypeEnum type, Long serviceId, String customName,
            FlowTaskTypeEnum flowTaskTypeEnum, String crmNo) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        userId = Objects.nonNull(sysUser) ? sysUser.getId() : userId;
        return sysUserService.getFlowTaskListCount(userId, type, serviceId, customName, flowTaskTypeEnum, crmNo);
    }

    /**
     * 流程节点转他人审批
     *
     * @param userId
     * @param taskId
     * @return
     */
    @Override
    @Transactional
    public Boolean taskApproverExchange(Long userId, Long taskId) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        if (Objects.equals(String.valueOf(sysUser.getId()), String.valueOf(userId))) {
            throw ExceptionResultEnum.ERROR.exception("不能转给自己！");
        }

        boolean lock = memoryLock.lock(SystemConstant.LOCK_FLOW_EXCHANGE_PREFIX + taskId, taskId,
                SystemConstant.LOCK_FLOW_TIME_OUT);
        if (!lock) {
            throw ExceptionResultEnum.ERROR.exception("正在转审中，请稍候再试！");
        }
        try {
            Task task = taskService.createTaskQuery().taskId(String.valueOf(taskId)).singleResult();
            Optional.ofNullable(task).orElseThrow(() -> ExceptionResultEnum.FLOW_TASK_NO_DATA.exception());

            BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
            FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());
            boolean multiInstance = false;
            if (currFlow.getBehavior() instanceof MultiInstanceActivityBehavior) {//会签
                multiInstance = true;

                List<Task> taskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId())
                        .list();
                List<String> taskApproveList = new ArrayList<>();
                for (Task t : taskList) {
                    if (Objects.equals(String.valueOf(t.getAssignee()), String.valueOf(userId))) {
                        throw ExceptionResultEnum.ERROR.exception("不能转给自己！");
                    }
                    taskApproveList.add(t.getAssignee());
                }
                if (taskApproveList.contains(userId)) {
                    throw ExceptionResultEnum.ERROR.exception("该审批人已有审批权限，无需流转");
                }
            } else {//或签
                Task taskUser = taskService.createTaskQuery().taskId(String.valueOf(taskId))
                        .taskCandidateOrAssigned(String.valueOf(userId)).singleResult();
                if (Objects.nonNull(taskUser)) {
                    throw ExceptionResultEnum.ERROR.exception("该审批人已有审批权限，无需流转");
                }
            }

            if (!multiInstance) {
                taskService.deleteCandidateUser(String.valueOf(taskId), String.valueOf(sysUser.getId()));
                taskService.addCandidateUser(String.valueOf(taskId), String.valueOf(userId));
            } else {
                taskService.setAssignee(String.valueOf(taskId), String.valueOf(userId));
            }

            TFCustomFlowEntity tfCustomFlowEntity = tfCustomFlowEntityService.getOne(
                    new QueryWrapper<TFCustomFlowEntity>().lambda()
                            .eq(TFCustomFlowEntity::getFlowId, Long.parseLong(task.getProcessInstanceId())));
            Optional.ofNullable(tfCustomFlowEntity)
                    .orElseThrow(() -> ExceptionResultEnum.FLOW_ENTITY_NO_DATA.exception());

            FlowResult flowResult = JSONObject.parseObject(tfCustomFlowEntity.getFlowProcessVar(), FlowResult.class);
            LinkedHashMap<String, FlowTaskResult> setupMap = flowResult.getSetupMap();
            FlowTaskResult currFlowTaskResult = GsonUtil.fromJson(
                    GsonUtil.toJson(setupMap.get(task.getTaskDefinitionKey())), FlowTaskResult.class);
            TFFlowLog tfFlowLog = new TFFlowLog(sysUser.getOrgId(), sysUser.getId(), sysUser.getId(),
                    currFlowTaskResult.getSetup(), Long.parseLong(task.getProcessInstanceId()),
                    Long.parseLong(task.getId()), tfCustomFlowEntity.getId(), String.valueOf(userId));
            tfFlowLog.setApproveOperation(FlowApproveOperationEnum.EXCHANGE);
            SysUser exchangeUser = sysUserService.getById(userId);
            Optional.ofNullable(exchangeUser).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("转审人为空"));

            SysOrg sysOrg = commonCacheService.orgCache(sysUser.getOrgId());
            SysOrg exchangeOrg = commonCacheService.orgCache(exchangeUser.getOrgId());
            String orgName = Objects.nonNull(sysOrg) ? sysOrg.getName() : "无机构";
            String exchangeOrgName = Objects.nonNull(exchangeOrg) ? exchangeOrg.getName() : "无机构";
            tfFlowLog.setApproveRemark(
                    sysUser.getRealName() + "(" + orgName + ")转" + exchangeUser.getRealName() + "(" + exchangeOrgName
                            + ")审批");
            tfFlowLogService.save(tfFlowLog);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        } finally {
            memoryLock.unlock(SystemConstant.LOCK_FLOW_EXCHANGE_PREFIX + taskId);
        }
        return true;
    }

    /**
     * 流程终止
     *
     * @param flowId
     * @return
     */
    @Override
    @Transactional
    public Boolean flowEnd(Long flowId) {
        Optional.ofNullable(flowId).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("流程id不能为空"));
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        boolean lock = memoryLock.lock(SystemConstant.LOCK_FLOW_END_PREFIX + flowId, flowId,
                SystemConstant.LOCK_FLOW_TIME_OUT);
        if (!lock) {
            throw ExceptionResultEnum.ERROR.exception("正在终止中，请稍候再试！");
        }
        try {
            TFFlowApprove tfFlowApprove = tfFlowApproveService.getOne(
                    new QueryWrapper<TFFlowApprove>().lambda().eq(TFFlowApprove::getFlowId, flowId));
            Optional.ofNullable(tfFlowApprove).orElseThrow(() -> ExceptionResultEnum.FLOW_APPROVE_NO_DATA.exception());

            if (tfFlowApprove.getStatus() == FlowStatusEnum.FINISH) {
                throw ExceptionResultEnum.ERROR.exception("已结束的流程不能作废");
            } else if (tfFlowApprove.getStatus() == FlowStatusEnum.END) {
                throw ExceptionResultEnum.ERROR.exception("该流程已作废");
            }

            TFCustomFlowEntity tfCustomFlowEntity = tfCustomFlowEntityService.getOne(
                    new QueryWrapper<TFCustomFlowEntity>().lambda().eq(TFCustomFlowEntity::getFlowId, flowId));
            Optional.ofNullable(tfCustomFlowEntity)
                    .orElseThrow(() -> ExceptionResultEnum.FLOW_ENTITY_NO_DATA.exception());

            TFCustomFlow tfCustomFlow = tfCustomFlowService.getById(tfCustomFlowEntity.gettFCustomFlowId());
            Optional.ofNullable(tfCustomFlow).orElseThrow(() -> ExceptionResultEnum.FLOW_CUSTOM_NO_DATA.exception());

            if (tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW && tfFlowApprove.getSetup().intValue() >= 4
                    && tfFlowApprove.getSetup().intValue() < 8) {
                FlowTaskResult flowTaskResultDeviceOut = tbSopInfoService.getFormProperties(tfCustomFlowEntity, 4);
                tbDeviceDeliveryService.updateDeviceRelated(flowTaskResultDeviceOut, tfCustomFlowEntity.getCode(), null,
                        sysUser.getId(), false);
            } else if (tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW
                    && tfFlowApprove.getSetup().intValue() >= 4) {
                FlowTaskResult flowTaskResultDeviceOut = tbSopInfoService.getFormProperties(tfCustomFlowEntity, 4);
                tbDeviceDeliveryService.updateDeviceRelated(flowTaskResultDeviceOut, tfCustomFlowEntity.getCode(),
                        DeviceDeliveryStatusEnum.RECEIVE, sysUser.getId(), true);
            }

            FlowResult flowResult = JSONObject.parseObject(tfCustomFlowEntity.getFlowProcessVar(), FlowResult.class);
            LinkedHashMap<String, FlowTaskResult> setupMap = flowResult.getSetupMap();
            List<Task> taskList = taskService.createTaskQuery().processInstanceId(String.valueOf(flowId)).list();
            if (CollectionUtils.isEmpty(taskList)) {
                throw ExceptionResultEnum.FLOW_TASK_NO_DATA.exception();
            }
            FlowTaskResult currFlowTaskResult = GsonUtil.fromJson(
                    GsonUtil.toJson(setupMap.get(taskList.get(0).getTaskDefinitionKey())), FlowTaskResult.class);

            TFFlowLog tfFlowLog = new TFFlowLog(sysUser.getOrgId(), sysUser.getId(), sysUser.getId(),
                    currFlowTaskResult.getSetup(), flowId, Long.parseLong(taskList.get(0).getId()),
                    tfCustomFlowEntity.getId(), null);
            tfFlowLog.setApproveOperation(FlowApproveOperationEnum.END);
            tfFlowLog.setApproveRemark(sysUser.getRealName() + "终止流程");
            tfFlowLogService.save(tfFlowLog);

            tfFlowApprove.setStatus(FlowStatusEnum.END);
            tfFlowApprove.setSetup(FlowApproveSetupEnum.END.getSetup());
            tfFlowApproveService.updateById(tfFlowApprove);

            runtimeService.deleteProcessInstance(String.valueOf(flowId), "结束");
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        } finally {
            memoryLock.unlock(SystemConstant.LOCK_FLOW_END_PREFIX + flowId);
        }
        return true;
    }

    /**
     * 流程批量终止
     *
     * @param flowIds
     * @return
     */
    @Override
    @Transactional
    public Boolean flowEnd(List<Long> flowIds) {
        ActivitiService activitiService = SpringContextHolder.getBean(ActivitiService.class);
        for (Long l : flowIds) {
            activitiService.flowEnd(l);
        }
        return true;
    }

    /**
     * 流程终止
     *
     * @param crmNo
     * @return
     */
    @Override
    @Transactional
    public Boolean flowEnd(String crmNo) {
        Optional.ofNullable(crmNo).orElseThrow(() -> ExceptionResultEnum.CRM_NO_NO_DATA.exception());
        List<Long> flowIdList = tfFlowApproveService.findFlowIdByCrmNo(crmNo);
        if (!CollectionUtils.isEmpty(flowIdList)) {
            ActivitiService activitiService = SpringContextHolder.getBean(ActivitiService.class);
            for (Long l : flowIdList) {
                activitiService.flowEnd(l);
            }
        }
        tsJobRemindService.updateJobRemind(crmNo);
        return true;
    }

    /**
     * 获取流程详细信息接口
     *
     * @param flowId
     * @param code
     * @return
     */
    @Override
    public FlowViewResult flowView(Long flowId, String code) {
        if (Objects.isNull(flowId) && Objects.isNull(code)) {
            throw ExceptionResultEnum.ERROR.exception("流程id和流程编码必须有一个不能为空");
        }
        TFCustomFlowEntity tfCustomFlowEntity = null;
        if (Objects.nonNull(flowId)) {
            tfCustomFlowEntity = tfCustomFlowEntityService.getOne(
                    new QueryWrapper<TFCustomFlowEntity>().lambda().eq(TFCustomFlowEntity::getFlowId, flowId));
        } else {
            tfCustomFlowEntity = tfCustomFlowEntityService.getOne(
                    new QueryWrapper<TFCustomFlowEntity>().lambda().eq(TFCustomFlowEntity::getCode, code));
        }
        Optional.ofNullable(tfCustomFlowEntity).orElseThrow(() -> ExceptionResultEnum.FLOW_ENTITY_NO_DATA.exception());
        flowId = Objects.isNull(flowId) ? tfCustomFlowEntity.getFlowId() : flowId;

        TFCustomFlow tfCustomFlow = tfCustomFlowService.getById(tfCustomFlowEntity.gettFCustomFlowId());
        Optional.ofNullable(tfCustomFlow).orElseThrow(() -> ExceptionResultEnum.FLOW_CUSTOM_NO_DATA.exception());

        //获取当前流程节点
        TFFlowApprove tfFlowApprove = tfFlowApproveService.getOne(
                new QueryWrapper<TFFlowApprove>().lambda().eq(TFFlowApprove::getFlowId, flowId));
        Optional.ofNullable(tfFlowApprove).orElseThrow(() -> ExceptionResultEnum.FLOW_APPROVE_NO_DATA.exception());

        FlowResult flowResult = JSONObject.parseObject(tfCustomFlowEntity.getFlowProcessVar(), FlowResult.class);
        LinkedHashMap<String, FlowTaskResult> setupMap = flowResult.getSetupMap();

        FlowTaskResult currFlowTaskResult = null;
        List<FlowTaskResult> flowTaskHistoryList = null;
        List<Long> taskIdList = null;

        List<TFFlowViewLogResult> flowApproveHistoryList = null;
        Map<Integer, Integer> approveSetupMap = new HashMap<>();

        List<FlowFormSuggestionJiaResult> flowFormSuggestionJiaResultList = new ArrayList<>();
        List<FlowFormSuggestionYiResult> flowFormSuggestionYiResultList = new ArrayList<>();
        //获取流程审批历史
        List<TFFlowLogResult> tfFlowLogResultList = tfFlowLogService.findByObjectId(tfCustomFlowEntity.getId());
        if (!CollectionUtils.isEmpty(tfFlowLogResultList)) {
            flowApproveHistoryList = GsonUtil.fromJson(GsonUtil.toJson(tfFlowLogResultList),
                    new TypeToken<List<TFFlowViewLogResult>>() {

                    }.getType());
            for (TFFlowViewLogResult t : flowApproveHistoryList) {
                t.setMessageType(FlowMsgTypeEnum.STANDARD);
                approveSetupMap.put(t.getApproveSetup(), t.getApproveSetup());
                if (Objects.nonNull(t.getApproveRemark()) && t.getApproveRemark().contains(";")
                        && tfCustomFlow.getType() == TFCustomTypeEnum.QUALITY_PROBLEM_FLOW && (
                        t.getApproveSetup().intValue() == 3 || t.getApproveSetup().intValue() == 4)) {
                    String[] strs = t.getApproveRemark().split(";");
                    StringJoiner stringJoiner = new StringJoiner("");
                    for (int i = 1; i < strs.length; i++) {
                        stringJoiner.add(strs[i]);
                    }
                    t.setApproveFormSuggestion(stringJoiner.toString());
                    if (t.getApproveSetup().intValue() == 3) {
                        flowFormSuggestionJiaResultList.add(
                                new FlowFormSuggestionJiaResult(t.getCreateTime(), t.getApproveUserName(),
                                        t.getApproveOperation() == FlowApproveOperationEnum.APPROVE ? "同意" : "不同意",
                                        t.getApproveFormSuggestion(), strs[0]));
                    } else {
                        flowFormSuggestionYiResultList.add(
                                new FlowFormSuggestionYiResult(t.getCreateTime(), t.getApproveUserName(),
                                        t.getApproveOperation() == FlowApproveOperationEnum.APPROVE ? "同意" : "不同意",
                                        t.getApproveFormSuggestion(), strs[0]));
                    }
                }
                if (Objects.nonNull(t.getApproveOperation())) {
                    t.setApproveRemark(t.getApproveOperation().getTitle());
                }
            }
        }
        if (tfCustomFlow.getType() != TFCustomTypeEnum.QUALITY_PROBLEM_FLOW) {
            flowFormSuggestionJiaResultList = null;
            flowFormSuggestionYiResultList = null;
        } else {
            Collections.sort(flowFormSuggestionJiaResultList);
            Collections.sort(flowFormSuggestionYiResultList);
        }
        for (Map.Entry<String, FlowTaskResult> entry : setupMap.entrySet()) {
            FlowTaskResult flowTaskResult = GsonUtil.fromJson(GsonUtil.toJson(entry.getValue()), FlowTaskResult.class);
            if (flowTaskResult.getSetup().intValue() > 0) {
                //正在审批的表单
                if (Objects.nonNull(tfFlowApprove.getSetup())
                        && flowTaskResult.getSetup().intValue() == tfFlowApprove.getSetup().intValue()) {
                    currFlowTaskResult = flowTaskResult;
                    List<Task> taskList = taskService.createTaskQuery().processInstanceId(String.valueOf(flowId))
                            .list();
                    if (!CollectionUtils.isEmpty(taskList)) {
                        taskIdList = taskList.stream().map(s -> Long.parseLong(s.getId())).collect(Collectors.toList());
                    }
                } else if (approveSetupMap.containsKey(flowTaskResult.getSetup())) {//已经审批过的表单
                    flowTaskHistoryList = CollectionUtils.isEmpty(flowTaskHistoryList) ?
                            new ArrayList<>(approveSetupMap.size()) :
                            flowTaskHistoryList;
                    flowTaskHistoryList.add(flowTaskResult);
                }
            }
        }
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        if ((tfCustomFlow.getType() == TFCustomTypeEnum.OFFICE_SOP_FLOW
                || tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW)) {
            if (Objects.nonNull(currFlowTaskResult) && currFlowTaskResult.getSetup().intValue() == 3) {
                List<Task> taskList = taskService.createTaskQuery().processInstanceId(String.valueOf(flowId)).list();
                List<FlowFormWidgetResult> flowFormWidgetResultListNew = new ArrayList<>();
                if (!CollectionUtils.isEmpty(taskList) && taskList.size() > 1) {
                    SysRole sysRole = null;
                    jump:
                    for (Task task : taskList) {
                        if (task.getAssignee().equals(sysUser.getId().toString())) {
                            List<SysRole> sysRoleList = sysUserRoleService.listRoleByUserId(sysUser.getId());
                            if (!CollectionUtils.isEmpty(sysRoleList)) {
                                for (SysRole s : sysRoleList) {
                                    if (s.getType() == RoleTypeEnum.REGION_MANAGER) {
                                        sysRole = s;
                                        break jump;
                                    } else if (s.getType() == RoleTypeEnum.EFFECT_ENGINEER) {
                                        sysRole = s;
                                        break jump;
                                    }
                                }
                            }
                        }
                    }
                    List<FlowFormWidgetResult> flowFormWidgetResultList = currFlowTaskResult.getFormProperty();
                    for (FlowFormWidgetResult f : flowFormWidgetResultList) {
                        if (Objects.nonNull(sysRole)) {
                            if (f.getRoleType() == sysRole.getType() && (
                                    sysRole.getType() == RoleTypeEnum.REGION_MANAGER
                                            || sysRole.getType() == RoleTypeEnum.EFFECT_ENGINEER)) {
                                flowFormWidgetResultListNew.add(f);
                            }
                        } else {
                            if (f.getFormId().contains(SystemConstant.APPROVE_RADIO_REGION) || f.getFormId()
                                    .contains(SystemConstant.APPROVE_REMARK_REGION) || f.getFormId()
                                    .contains(SystemConstant.SIGN_REGION)) {
                                flowFormWidgetResultListNew.add(f);
                            }
                        }
                    }
                    currFlowTaskResult.setFormProperty(flowFormWidgetResultListNew);
                } else if (!CollectionUtils.isEmpty(taskList) && taskList.size() == 1) {
                    SysRole sysRole = null;
                    jump:
                    for (Task task : taskList) {
                        if (task.getAssignee().equals(sysUser.getId().toString())) {
                            List<SysRole> sysRoleList = sysUserRoleService.listRoleByUserId(sysUser.getId());
                            if (!CollectionUtils.isEmpty(sysRoleList)) {
                                for (SysRole s : sysRoleList) {
                                    if (s.getType() == RoleTypeEnum.REGION_MANAGER) {
                                        sysRole = s;
                                        break jump;
                                    } else if (s.getType() == RoleTypeEnum.EFFECT_ENGINEER) {
                                        sysRole = s;
                                        break jump;
                                    }
                                }
                            }
                        }
                    }
                    List<FlowFormWidgetResult> flowFormWidgetResultList = currFlowTaskResult.getFormProperty();
                    for (FlowFormWidgetResult f : flowFormWidgetResultList) {
                        if (Objects.nonNull(sysRole) && f.getRoleType() != sysRole.getType()) {
                            f.setReadable(true);
                            f.setWritable(false);
                        } else {
                            if (f.getFormId().contains(SystemConstant.APPROVE_RADIO_REGION) || f.getFormId()
                                    .contains(SystemConstant.APPROVE_REMARK_REGION) || f.getFormId()
                                    .contains(SystemConstant.SIGN_REGION)) {
                                flowFormWidgetResultListNew.add(f);
                            }
                        }
                    }
                    if (Objects.isNull(sysRole) && Objects.nonNull(currFlowTaskResult)) {
                        currFlowTaskResult.setFormProperty(flowFormWidgetResultListNew);
                    }
                }
            }
        }

        CrmProjectResult crmProjectResult = null;
        if (Objects.nonNull(tfCustomFlowEntity.getCrmNo())) {
            crmProjectResult = tbCrmService.findCrmProjectBySopNoOrCrmNo(tfCustomFlowEntity.getCode(),
                    tfCustomFlowEntity.getCrmNo());
        }
        return new FlowViewResult(flowId, tfFlowApprove.getStatus(), tfCustomFlowEntity.getCode(), taskIdList,
                flowTaskHistoryList, currFlowTaskResult, flowApproveHistoryList, crmProjectResult,
                flowFormSuggestionJiaResultList, flowFormSuggestionYiResultList);
    }

    /**
     * 获取流程节点审批人员
     *
     * @param task
     * @return
     */
    @Override
    public List<String> getTaskApprove(Task task) {
        List<String> taskApproveUserList = new ArrayList<>();
        if (Objects.nonNull(task.getAssignee())) {
            taskApproveUserList.add(task.getAssignee());
        } else {
            List<IdentityLink> identityLinkList = taskService.getIdentityLinksForTask(task.getId());
            if (!CollectionUtils.isEmpty(identityLinkList)) {
                for (IdentityLink i : identityLinkList) {
                    taskApproveUserList.add(i.getUserId());
                }
            }
        }
        return taskApproveUserList;
    }

    /**
     * 获取表单属性
     *
     * @param map
     * @param taskList
     * @param flowResult
     * @param tfCustomFlow
     * @return
     */
    protected Map<String, Object> getFlowFormPropertie(Map<String, Object> map, List<Task> taskList,
            FlowResult flowResult, TFCustomFlow tfCustomFlow) {
        if (CollectionUtils.isEmpty(taskList)) {
            throw ExceptionResultEnum.ERROR.exception("流程任务数据为空！");
        }
        Long flowId = Long.parseLong(taskList.get(0).getProcessInstanceId());
        TFCustomFlowEntity tfCustomFlowEntity = tfCustomFlowEntityService.getOne(
                new QueryWrapper<TFCustomFlowEntity>().lambda().eq(TFCustomFlowEntity::getFlowId, flowId));
        Optional.ofNullable(tfCustomFlowEntity).orElseThrow(() -> ExceptionResultEnum.FLOW_ENTITY_NO_DATA.exception());
        tfCustomFlow = tfCustomFlowService.getById(tfCustomFlowEntity.gettFCustomFlowId());
        Optional.ofNullable(tfCustomFlow).orElseThrow(() -> ExceptionResultEnum.FLOW_DEPLOYMENT_NO_DATA.exception());

        flowResult = JSONObject.parseObject(tfCustomFlowEntity.getFlowProcessVar(), FlowResult.class);
        LinkedHashMap<String, FlowTaskResult> setupMap = flowResult.getSetupMap();
        for (Task task : taskList) {
            FlowTaskResult currFlowTaskResult = GsonUtil.fromJson(
                    GsonUtil.toJson(setupMap.get(task.getTaskDefinitionKey())), FlowTaskResult.class);
            map = this.getFlowFormPropertie(flowResult, map, currFlowTaskResult.getSetup());
        }
        map.put(SystemConstant.FLOW_DEPLOYMENT_ID, tfCustomFlow.getFlowDeploymentId());
        map.put(SystemConstant.ID, tfCustomFlow.getId());
        return map;
    }

    /**
     * 获取表单属性
     *
     * @param flowResult
     * @param map
     * @param setup
     * @return
     */
    protected Map<String, Object> getFlowFormPropertie(FlowResult flowResult, Map<String, Object> map, int setup) {
        Map<String, FlowTaskResult> setupMap = flowResult.getSetupMap();
        for (Map.Entry<String, FlowTaskResult> entry : setupMap.entrySet()) {
            FlowTaskResult flowTaskResultTemp = GsonUtil.fromJson(GsonUtil.toJson(entry.getValue()),
                    FlowTaskResult.class);
            if (flowTaskResultTemp.getSetup().intValue() == setup) {
                map.put(SystemConstant.FORM_PROPERTIES, flowTaskResultTemp);
                break;
            }
        }
        return map;
    }

    /**
     * 获取流程下一节点
     *
     * @param nrOfCompletedInstances
     * @param nrOfInstances
     * @param currFlowTaskResult
     * @param nextFlowTaskResult
     * @param currSetup
     * @param setupMap
     * @param approvePass
     * @return
     */
    protected FlowTaskResult getNextFlowTaskResult(Integer nrOfCompletedInstances, Integer nrOfInstances,
            FlowTaskResult currFlowTaskResult, FlowTaskResult nextFlowTaskResult, int currSetup,
            Map<String, FlowTaskResult> setupMap, FlowApprovePassEnum approvePass) {
        if (approvePass == FlowApprovePassEnum.PASS || approvePass == FlowApprovePassEnum.START
                || approvePass == FlowApprovePassEnum.DRAFT) {
            if (Objects.nonNull(nrOfCompletedInstances) && Objects.nonNull(nrOfInstances)
                    && nrOfCompletedInstances.intValue() != nrOfInstances.intValue()
                    || approvePass == FlowApprovePassEnum.DRAFT) {
                nextFlowTaskResult = currFlowTaskResult;
            } else {
                nextFlowTaskResult = this.getNextFlowTaskResult(setupMap, currSetup, nextFlowTaskResult);
            }
        } else if (approvePass == FlowApprovePassEnum.REJECT || approvePass == FlowApprovePassEnum.CANCEL) {
            nextFlowTaskResult = this.getNextFlowTaskResult(setupMap, currSetup, nextFlowTaskResult);
        }
        Optional.ofNullable(nextFlowTaskResult).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("该节点不能审批通过"));
        return nextFlowTaskResult;
    }

    /**
     * 获取下级审核节点
     *
     * @param setupMap
     * @param currSetup
     * @param nextFlowTaskResult
     * @return
     */
    protected FlowTaskResult getNextFlowTaskResult(Map<String, FlowTaskResult> setupMap, int currSetup,
            FlowTaskResult nextFlowTaskResult) {
        for (Map.Entry<String, FlowTaskResult> entry : setupMap.entrySet()) {
            FlowTaskResult flowTaskResultTemp = GsonUtil.fromJson(GsonUtil.toJson(entry.getValue()),
                    FlowTaskResult.class);
            if (flowTaskResultTemp.getSetup().intValue() == currSetup) {
                nextFlowTaskResult = flowTaskResultTemp;
                break;
            }
        }
        return nextFlowTaskResult;
    }

    /**
     * 审批通过
     *
     * @param currFlowTaskResult
     * @param setupMap
     * @param multiInstance
     * @param nrOfCompletedInstances
     * @param nrOfInstances
     * @param tfFlowApprove
     * @param tfFlowLog
     * @param nextFlowTaskResult
     * @param map
     * @param approvePass
     * @param approveRemark
     */
    public void approvePass(FlowTaskResult currFlowTaskResult, Map<String, FlowTaskResult> setupMap,
            boolean multiInstance, Integer nrOfCompletedInstances, Integer nrOfInstances, TFFlowApprove tfFlowApprove,
            TFFlowLog tfFlowLog, FlowTaskResult nextFlowTaskResult, Map<String, Object> map,
            FlowApprovePassEnum approvePass, String approveRemark) {
        if (multiInstance) {
            map.computeIfAbsent(FlowApproveOperationEnum.REJECT.getId() + currFlowTaskResult.getSetup(), v -> 0);
        }
        if (currFlowTaskResult.getSetup().intValue() == setupMap.size() - 1) {
            if (approvePass == FlowApprovePassEnum.DRAFT) {
                tfFlowApprove.setStatus(FlowStatusEnum.valueOf(approvePass.name()));
            } else {
                if (multiInstance && Objects.nonNull(nrOfCompletedInstances) && Objects.nonNull(nrOfInstances)
                        && nrOfCompletedInstances.intValue() == nrOfInstances.intValue()) {
                    tfFlowApprove.setStatus(FlowStatusEnum.FINISH);
                    tfFlowApprove.setSetup(FlowApproveSetupEnum.FINISH.getSetup());
                } else if (!multiInstance) {
                    tfFlowApprove.setStatus(FlowStatusEnum.FINISH);
                    tfFlowApprove.setSetup(FlowApproveSetupEnum.FINISH.getSetup());
                } else {
                    tfFlowApprove.setStatus(FlowStatusEnum.AUDITING);
                    tfFlowApprove.setSetup(nextFlowTaskResult.getSetup());
                }
            }
        } else {
            if (approvePass == FlowApprovePassEnum.DRAFT || approvePass == FlowApprovePassEnum.START) {
                tfFlowApprove.setStatus(FlowStatusEnum.valueOf(approvePass.name()));
            } else if (nextFlowTaskResult.getSetup().intValue() == 0) {
                tfFlowApprove.setStatus(FlowStatusEnum.FINISH);
            } else {
                tfFlowApprove.setStatus(FlowStatusEnum.AUDITING);
            }
            tfFlowApprove.setSetup(nextFlowTaskResult.getSetup());
        }
        if (tfFlowApprove.getStatus() == FlowStatusEnum.START) {
            tfFlowLog.setApproveOperation(FlowApproveOperationEnum.START);
        } else if (tfFlowApprove.getStatus() == FlowStatusEnum.DRAFT) {
            tfFlowLog.setApproveOperation(FlowApproveOperationEnum.DRAFT);
        } else {
            tfFlowLog.setApproveOperation(FlowApproveOperationEnum.APPROVE);
        }
        if (Objects.nonNull(approveRemark)) {
            tfFlowLog.setApproveRemark(approveRemark);
        } else {
            tfFlowLog.setApproveRemark(DingExceptionApproveEnum.PASS.getTitle());
        }
    }

    /**
     * 审批驳回
     *
     * @param multiInstance
     * @param map
     * @param currFlowTaskResult
     * @param nextFlowTaskResult
     * @param tfFlowApprove
     * @param tfFlowLog
     * @param approvePass
     * @param approveRemark
     */
    protected void approveReject(boolean multiInstance, Map<String, Object> map, FlowTaskResult currFlowTaskResult,
            FlowTaskResult nextFlowTaskResult, TFFlowApprove tfFlowApprove, TFFlowLog tfFlowLog,
            FlowApprovePassEnum approvePass, String approveRemark) {
        if (multiInstance) {
            map.computeIfAbsent(FlowApproveOperationEnum.REJECT.getId() + currFlowTaskResult.getSetup(), v -> 1);
        }
        tfFlowApprove.setSetup(nextFlowTaskResult.getSetup());
        tfFlowApprove.setStatus(FlowStatusEnum.convertToEnum(approvePass.name()));
        tfFlowLog.setApproveOperation(FlowApproveOperationEnum.convertToEnum(approvePass.name()));
        if (Objects.nonNull(approveRemark)) {
            tfFlowLog.setApproveRemark(approveRemark);
        } else {
            tfFlowLog.setApproveRemark(DingExceptionApproveEnum.NO_PASS.getTitle());
        }
    }
}