package com.iformall.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.domain.po.msg.MailMsg;
import com.iformall.domain.po.msg.WxMsgRecord;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.mq.MqBaseProducer;
import com.iformall.service.*;
import com.iformall.utils.Constant;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author luozukai
 * @date 2019/1/10 14:59
 */
@Service
public class WxFlowServiceImpl implements WxFlowService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private WxRentContractService wxRentContractService;
    @Autowired
    private WxFlowRecordService wxFlowRecordService;
    @Autowired
    private MallUserInfoService mallUserInfoService;
    @Autowired
    private WxRentContractMapper wxRentContractMapper;
    @Autowired
    private WxPropertyContractMapper wxPropertyContractMapper;
    @Autowired
    private WxPropertyContractService wxPropertyContractService;
    @Autowired
    private WxFlowRecordMapper wxFlowRecordMapper;
    @Autowired
    private WxBillRentMapper wxBillRentMapper;
    @Autowired
    private WxBillPropertyMapper wxBillPropertyMapper;
    @Autowired
    private WxMerchantService wxMerchantService;
    @Autowired
    private MqBaseProducer mqBaseProducer;
    @Autowired
    private WxBillActionService wxBillActionService;
    @Autowired
    private WxBillPropertyDepositMapper wxBillPropertyDepositMapper;
    @Autowired
    private WxBillDepositMapper wxBillDepositMapper;
    @Autowired
    private WxBillDailyMapper wxBillDailyMapper;
    @Autowired
    private WxBillOtherMapper wxBillOtherMapper;
    @Autowired
    private WxBillOtherDepositMapper wxBillOtherDepositMapper;

    /**
     * 获取流程key,1合同 2账单
     * @param flowType
     * @return
     */
    public static String getFlowKeyByType(int flowType){
        if(1 == flowType){
            return EnumFlowKey.CONTRACT.getCode();
        }else if(2 == flowType){
            return EnumFlowKey.BILL.getCode();
        }else if(3 == flowType){
            return EnumFlowKey.END_CONTRACT.getCode();
        }
        return null;
    }

    /**
     * 更新业务数据状态
     * @param mapInfo
     * @param applyStatus
     */
    @Override
    public void updateBusinessStatus(Map<String, Object> mapInfo,Integer applyStatus){
        Long businessId = Long.parseLong(mapInfo.get("businessId").toString());
        Integer flowType = (Integer)mapInfo.get("flowType");
        List<Map<String,Object>> variables = (List)mapInfo.get("variables");
        Boolean supplement = (Boolean)mapInfo.get("supplement");
        Integer contractType = 0;
        String str = (String)getVariableByKey(variables,"contractType");
        if(StringUtils.isNotBlank(str)){
            contractType = Integer.parseInt(str);
        }

        if(1 == flowType){
            // 1租赁合同 2点位合同 3物业 4点位物业合同
            if(contractType.intValue() == 1 || contractType.intValue() == 2){
                WxRentContract rent = new WxRentContract();
                rent.setId(businessId);
                rent.setApplyStatus(applyStatus);
                rent.setBusinessType(flowType);
                wxRentContractService.updateApplyStatus(rent);

                // 如果审批完成，而且是补录直接改为已签约状态(普通需要绑定商户才是已签约)
                if(supplement!=null && supplement && EnumRentContractAppStatus.FINISH.getCode().intValue() == applyStatus.intValue()) {
                    wxRentContractService.updateRentContractStatus(businessId);
                }
            }else if(contractType.intValue() == 3 || contractType.intValue() == 4){
                WxPropertyContract wxPropertyContract = new WxPropertyContract();
                wxPropertyContract.setId(businessId);
                wxPropertyContract.setApplyStatus(applyStatus);
                wxPropertyContract.setBusinessType(flowType);
                wxPropertyContractMapper.updateApplyStatus(wxPropertyContract);

                // 审批完成，物业合同的合同状态需要和租赁合同同步（一致）
                if(EnumRentContractAppStatus.FINISH.getCode().intValue() == applyStatus.intValue()) {
                    wxPropertyContractService.updatePropertyContractStatus(businessId);
                }
            }
        }else if(3 == flowType){
            if(contractType.intValue() == 1 || contractType.intValue() == 2){
                WxRentContract rent = new WxRentContract();
                rent.setId(businessId);
                rent.setApplyStatus(applyStatus);
                rent.setBusinessType(flowType);
                //合同状态改成提前终止
                if(EnumRentContractAppStatus.FINISH.getCode().intValue() == applyStatus.intValue()) {
                    rent.setStatus(EnumRentContractStatus.CONTRACT_TERMINATE.getCode());

                    //终止租赁合同，同时终止物业合同
                    Integer endProperty = (Integer)getVariableByKey(variables,"endProperty");
                    if(endProperty!=null && EnumEndProperty.END_RENT_AND_PROPERTY.getCode().intValue() == endProperty.intValue()){
                        WxPropertyContract wxPropertyContract = new WxPropertyContract();
                        wxPropertyContract.setRentContractId(businessId);
                        wxPropertyContract.setStatus(EnumRentContractStatus.CONTRACT_TERMINATE.getCode());
                        wxPropertyContractMapper.updateStatusByRentContractId(wxPropertyContract);

                        //物业账单失效
                        wxBillPropertyMapper.updateInvalidStatusByRent(rent);
                    }
                    //租赁账单失效
                    WxBillRent wxBillRent = new WxBillRent();
                    wxBillRent.setRentContractId(businessId);
                    wxBillRentMapper.updateInvalidStatus(wxBillRent);

                    //解绑商户和商铺关系
                    wxMerchantService.disable(wxRentContractMapper.selectByPrimaryKey(businessId).getMerchantId());
                }
                wxRentContractService.updateApplyStatus(rent);
            }else if(contractType.intValue() == 3 || contractType.intValue() == 4){
                WxPropertyContract wxPropertyContract = new WxPropertyContract();
                wxPropertyContract.setId(businessId);
                wxPropertyContract.setApplyStatus(applyStatus);
                wxPropertyContract.setBusinessType(flowType);

                if(EnumRentContractAppStatus.FINISH.getCode().intValue() == applyStatus.intValue()) {
                    wxPropertyContract.setStatus(EnumRentContractStatus.CONTRACT_TERMINATE.getCode());

                    //账单失效
                    WxBillProperty wxBillProperty = new WxBillProperty();
                    wxBillProperty.setPropertyContractId(businessId);
                    wxBillPropertyMapper.updateInvalidStatus(wxBillProperty);
                }
                wxPropertyContractMapper.updateApplyStatus(wxPropertyContract);
            }
        } else if (2 == flowType) {
            if(EnumRentContractAppStatus.FINISH.getCode().intValue() == applyStatus.intValue()) {
                //账单审批
                Integer billType = (Integer) getVariableByKey(variables, "billType");
                Integer oldPrice = (Integer) getVariableByKey(variables, "oldPrice");
                Integer newPrice = (Integer) getVariableByKey(variables, "newPrice");
                Date updateDate = new Date();
                MallUserInfo mallUserInfo = (MallUserInfo) SecurityUtils.getSubject().getSession().getAttribute("userSession");
                if (billType.equals(EnumBillTypeParam.RENT.getCode())) {
                    //租赁账单更新
                    WxBillRent wxBillRent = new WxBillRent();
                    wxBillRent.setId(businessId);
                    wxBillRent.setReceivePay(newPrice);
                    wxBillRent.setUpdatetime(updateDate);
                    wxBillRentMapper.updateByPrimaryKeySelective(wxBillRent);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else if (billType.equals(EnumBillTypeParam.RENT_DEPOSIT.getCode())) {
                    //租赁押金账单更新
                    WxBillDeposit wxBillDeposit = new WxBillDeposit();
                    wxBillDeposit.setId(businessId);
                    wxBillDeposit.setReceivePay(newPrice);
                    wxBillDeposit.setUpdatetime(updateDate);
                    wxBillDepositMapper.updateByPrimaryKeySelective(wxBillDeposit);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else if (billType.equals(EnumBillTypeParam.PROPERTY.getCode())) {
                    //物业账单更新
                    WxBillProperty wxBillProperty = new WxBillProperty();
                    wxBillProperty.setId(businessId);
                    wxBillProperty.setReceivePay(newPrice);
                    wxBillProperty.setUpdatetime(updateDate);
                    wxBillPropertyMapper.updateByPrimaryKeySelective(wxBillProperty);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else if (billType.equals(EnumBillTypeParam.PROPERTY_DEPOSIT.getCode())) {
                    //物业押金账单更新
                    WxBillPropertyDeposit wxBillPropertyDeposit = new WxBillPropertyDeposit();
                    wxBillPropertyDeposit.setId(businessId);
                    wxBillPropertyDeposit.setReceivePay(newPrice);
                    wxBillPropertyDeposit.setUpdatetime(updateDate);
                    wxBillPropertyDepositMapper.updateByPrimaryKeySelective(wxBillPropertyDeposit);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else if (billType.equals(EnumBillTypeParam.WATER.getCode())) {
                    //水费账单更新
                    updateDailyBill(businessId, newPrice, updateDate);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else if (billType.equals(EnumBillTypeParam.POWER.getCode())) {
                    //电费账单更新
                    updateDailyBill(businessId, newPrice, updateDate);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else if (billType.equals(EnumBillTypeParam.ROUTINE.getCode())) {
                    //其他费用账单更新
                    WxBillOther wxBillOther = new WxBillOther();
                    wxBillOther.setId(businessId);
                    wxBillOther.setReceivePay(newPrice);
                    wxBillOther.setUpdatetime(updateDate);
                    wxBillOtherMapper.updateByPrimaryKeySelective(wxBillOther);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else if (billType.equals(EnumBillTypeParam.ATHER_DEPOSIT.getCode())) {
                    //其他押金账单更新
                    WxBillOtherDeposit wxBillOtherDeposit = new WxBillOtherDeposit();
                    wxBillOtherDeposit.setId(businessId);
                    wxBillOtherDeposit.setReceivePay(newPrice);
                    wxBillOtherDeposit.setUpdatetime(updateDate);
                    wxBillOtherDepositMapper.updateByPrimaryKeySelective(wxBillOtherDeposit);
                    //账单日志
                    addBillAction(businessId, oldPrice, newPrice, mallUserInfo);
                } else {
                    logger.info("未找到账单类型");
                }
            }
        }
    }

    public void updateDailyBill(Long businessId, Integer newPrice, Date updateDate) {
        WxBillDaily wxBillDaily = new WxBillDaily();
        wxBillDaily.setId(businessId);
        wxBillDaily.setReceivePay(newPrice);
        wxBillDaily.setUpdatetime(updateDate);
        wxBillDailyMapper.updateByPrimaryKeySelective(wxBillDaily);
    }

    public void addBillAction(Long billId, Integer oldPrice, Integer newPrice, MallUserInfo mallUserInfo) {
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(billId);
        wxBillAction.setOldPrice(oldPrice);
        wxBillAction.setNewPrice(newPrice);
        wxBillActionService.modifyBill(wxBillAction, mallUserInfo);
    }

    public Map<String,Object> mallUserInfoToMap(MallUserInfo userInfo){
        try {
            Map<String, Object> map = new HashMap<>();
            Class<?> clazz = userInfo.getClass();
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object value = field.get(userInfo);
                map.put(fieldName, value);
            }
            return map;
        }catch (IllegalAccessException e){
            logger.error("mallUserInfoToMap error",e);
        }
        return new HashMap<>();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {Exception.class})
    public ResultData start(Map<String, Object> params,Long userId,String userName,String tenantId) {
        String remark = (String)params.get("remark");
        Long businessId = Long.parseLong(params.get("businessId").toString());
        Integer flowType = (Integer)params.get("businessType");
        List<Map<String,String>> taskAssignee = (List)params.get("taskAssignee");
        List<Map<String,Object>> variables = (List)params.get("variables");
        Boolean supplement = (Boolean)params.get("supplement");

        // 设置节点处理人
        HashMap<String, Object> map = new HashMap<>();
        for (Map<String,String> taskAssigneeMap : taskAssignee) {
            map.put(taskAssigneeMap.get("taskKey"), taskAssigneeMap.get("assignee"));
        }
        // map info,设置发起人等信息
        Date startDate = new Date();
        MallUserInfo starterInfo = this.mallUserInfoService.getById(userId);
        map.put("starter", mallUserInfoToMap(starterInfo));
        map.put("startTime", startDate.getTime());
        map.put("startDate", startDate);
        map.put("businessId",businessId+"");
        map.put("flowType",flowType);
        map.put("taskAssignee",taskAssignee);
        map.put("variables",variables);
        map.put("supplement",supplement);

        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(getFlowKeyByType(flowType), map);
        logger.debug("流程启动，流程id:{}",processInstance.getId());

        params.put("flowType",flowType);
        updateBusinessStatus(params,EnumRentContractAppStatus.APPLYING.getCode());

        // 保存wx_flow_record表审批记录
        WxFlowRecord wxFlowRecord = new WxFlowRecord();
        wxFlowRecord.setBusinessId(businessId);
        wxFlowRecord.setBusinessType(flowType);
        wxFlowRecord.setProcessInstanceId(processInstance.getId());
        wxFlowRecord.setRemark(remark);
        wxFlowRecord.setUserId(userId);
        wxFlowRecord.setUserName(userName);
        wxFlowRecord.setStatus(EnumFlowRecordStatus.NEW.getCode());
        wxFlowRecord.setTaskName("发起");
        wxFlowRecord.setCurrStatus(EnumRentContractAppStatus.APPLYING.getCode());
        wxFlowRecord.setVariables(variablesToJson(variables));
        wxFlowRecord.setStartDate(startDate);
        wxFlowRecordService.saveOrUpdate(wxFlowRecord);

        // 给审批人发送代办通知短信
        List<MallUserInfo> mallUserInfoList = getUserByProcessInstanceId(processInstance.getId());
        for (MallUserInfo mallUserInfo:mallUserInfoList) {
            sendAssigneeMsgAndEmail(tenantId,mallUserInfo.getPhone(),mallUserInfo.getEmail(),starterInfo.getName(),businessId);
        }
        return new ResultData();
    }

    public void sendAssigneeMsgAndEmail(String tenantId,String phone,String email,String userName,Long businessId){
        Map<String,String> dynamicContentMap = new HashMap<>();
        dynamicContentMap.put("userName",userName);
        dynamicContentMap.put("page", Constant.adminPage);
        WxMsgRecord wxMsgRecord = new WxMsgRecord();
        wxMsgRecord.setMsgType(EnumMsgRecordType.SMS.getCode());
        wxMsgRecord.setModelType(EnumMsgModel.FLOW_ASSIGNEE_NODIFY.getCode());
        wxMsgRecord.setReceiver(phone);
        wxMsgRecord.setTenantId(tenantId);
        wxMsgRecord.setDynamicContentMap(dynamicContentMap);
        mqBaseProducer.sendMessage(wxMsgRecord, EnumMsgMqTopic.DEFAULT.getCode(),EnumMsgMqTag.DEFAULT.getCode(),EnumMsgMqKey.DEFAULT.getCode());

        //发邮件
        Map msgReplaceMap = new HashedMap();
        msgReplaceMap.put("page", Constant.adminPage);
        msgReplaceMap.put("applyTime", new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
        msgReplaceMap.put("name",userName);
        msgReplaceMap.put("linkName",userName);
        msgReplaceMap.put("linkPhone",phone);
        ResultData resultData = getTaskStatusList(businessId, tenantId);
        List<WxFlowRecord> flowRecordList = (List<WxFlowRecord>) resultData.data;
        String taskListHtml = "";
        for (int i = flowRecordList.size() -1; i>=0; i--) {
            WxFlowRecord record = flowRecordList.get(i);
            String remark = record.getRemark()==null?"":record.getRemark();
            if (record.getStatus().equals(EnumFlowRecordStatus.NEW.getCode())) {
                taskListHtml += "<div style=\"overflow: hidden;\">";
                taskListHtml += "<div style=\"overflow: hidden;\">";
                taskListHtml += "<div style=\"float: left; width: 40px;height: 30px;\"><img src=\"https://s3.cn-northwest-1.amazonaws.com.cn/iformall-net/cimg/emailduihao.png\" style=\"display: block; width: 20px;height: 20px;margin-top: 10px;\"></div>";
                taskListHtml += "<div style=\"float: left; width: auto;margin-right:10px;height: 30px;line-height: 18px;font-size:18px;font-family:MicrosoftYaHei;font-weight:400;color:rgba(51,51,51,1);margin-top: 11px;\">发起申请</div>";
                taskListHtml += "<div style=\"float: left; width: auto;margin-right:10px;height: 30px;margin-top:15px;line-height: 14px;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;color:rgba(51,51,51,1);\">"+record.getUserName()+"</div>";
                taskListHtml += "</div>";
                if(i == 0){
                    taskListHtml += "<div style=\"width: 80%; overflow: hidden;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;padding-left: 30px;margin-left: 10px;padding-bottom: 20px; line-height: 24px; color:rgba(153,153,153,1);\">"+remark+"</div>";
                }else{
                    taskListHtml += "<div style=\"width: 80%; overflow: hidden;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;padding-left: 30px;margin-left: 10px;padding-bottom: 20px; line-height: 24px; border-left: 2px dashed #DEDEDE; color:rgba(153,153,153,1);\">"+remark+"</div>";
                }
                taskListHtml += "</div>";
            } else if (record.getStatus().equals(EnumFlowRecordStatus.ASSIGNEE.getCode())) {
                taskListHtml += "<div style=\"overflow: hidden;\">";
                taskListHtml += "<div style=\"overflow: hidden;\">";
                taskListHtml += "<div style=\"float: left; width: 40px;height: 30px;\"><img src=\"https://s3.cn-northwest-1.amazonaws.com.cn/iformall-net/cimg/emailhong.png\" style=\"display: block; width: 20px;height: 20px;margin-top: 10px;\"></div>";
                taskListHtml += "<div style=\"float: left; width: auto;margin-right:10px;height: 30px;line-height: 18px;font-size:18px;font-family:MicrosoftYaHei;font-weight:400;color:rgba(200,89,98,1);margin-top: 11px;\">待审批</div>";
                taskListHtml += "<div style=\"float: left; width: auto;margin-right:10px;height: 30px;margin-top:15px;line-height: 14px;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;color:rgba(200,89,98,1);\">"+record.getUserName()+"</div>";
                taskListHtml += "</div>";
                if(i == 0){
                    taskListHtml += "<div style=\"width: 80%; overflow: hidden;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;padding-left: 30px;margin-left: 10px;padding-bottom: 20px; line-height: 24px; color:rgba(153,153,153,1);\">"+remark+"</div>";
                }else{
                    taskListHtml += "<div style=\"width: 80%; overflow: hidden;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;padding-left: 30px;margin-left: 10px;padding-bottom: 20px; line-height: 24px; border-left: 2px dashed #DEDEDE; color:rgba(153,153,153,1);\">"+remark+"</div>";
                }
                taskListHtml += "</div>";
            } else {
                taskListHtml += "<div style=\"overflow: hidden;\">";
                taskListHtml += "<div style=\"overflow: hidden;\">";
                taskListHtml += "<div style=\"float: left; width: 40px;height: 30px;\"><img src=\"https://s3.cn-northwest-1.amazonaws.com.cn/iformall-net/cimg/emailhui.png\" style=\"display: block; width: 20px;height: 20px;margin-top: 10px;\"></div>";
                taskListHtml += "<div style=\"float: left; width: auto;margin-right:10px;height: 30px;line-height: 18px;font-size:18px;font-family:MicrosoftYaHei;font-weight:400;color:rgba(153,153,153,1);margin-top: 11px;\">审批通过</div>";
                taskListHtml += "<div style=\"float: left; width: auto;margin-right:10px;height: 30px;margin-top:15px;line-height: 14px;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;color:rgba(153,153,153,1);\">"+record.getUserName()+"</div>";
                taskListHtml += "</div>";
                if(i == 0){
                    taskListHtml += "<div style=\"width: 80%; overflow: hidden;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;padding-left: 30px;margin-left: 10px;padding-bottom: 20px; line-height: 24px; color:rgba(153,153,153,1);\">"+remark+"</div>";
                }else{
                    taskListHtml += "<div style=\"width: 80%; overflow: hidden;font-size:14px;font-family:MicrosoftYaHei;font-weight:400;padding-left: 30px;margin-left: 10px;padding-bottom: 20px; line-height: 24px; border-left: 2px dashed #DEDEDE; color:rgba(153,153,153,1);\">"+remark+"</div>";
                }
                taskListHtml += "</div>";
            }
        }
        msgReplaceMap.put("taskList", taskListHtml);
        MailMsg mailMsg = new MailMsg();
        mailMsg.setSubject("待办通知");
        mailMsg.setHtml(true);
        mailMsg.setMsgType(EnumMsgRecordType.EMAIL.getCode());
        mailMsg.setModelId(EnumMailMsgModel.MAIL_ASSIGNEE_NODIFY.getCode());
        mailMsg.setTo(new String[]{email});
        mailMsg.setTenantId(tenantId);
        mailMsg.setDynamicContentMap(msgReplaceMap);
        mqBaseProducer.sendMessage(mailMsg, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
    }

    public String variablesToJson(List<Map<String,Object>> variables){
        HashMap<String,Object> map = new HashMap<>();
        for (Map<String,Object> mapInfo:variables) {
            map.put((String)mapInfo.get("key"),mapInfo.get("value"));
        }
        return JSONUtils.toJSONString(map);
    }

    @Override
    public ResultData list(String flowType, Integer pageNum, Integer pageSize,Long userId) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        //流程过滤条件
        if(StringUtils.isNotBlank(flowType)) {
            List<String> definitionKeyList = new ArrayList<>();
            for (String ft : flowType.split(",")) {
                definitionKeyList.add(getFlowKeyByType(Integer.parseInt(ft)));
            }
            if(CollectionUtils.isNotEmpty(definitionKeyList)){
                taskQuery.processDefinitionKeyIn(definitionKeyList);
            }
        }

        int total = taskQuery.taskCandidateUser(userId.toString()).list().size();
        int pages;
        if(total % pageSize == 0){
            pages = total / pageSize;
        }else{
            pages = total / pageSize +1;
        }

        List<Task> tasks = taskQuery.orderByTaskCreateTime().desc()
                .listPage((pageNum -1) * pageSize,pageSize);
        List<Map<String,Object>> result = new ArrayList<>();

        for (Task task : tasks) {
            Map<String,Object> taskInfoMap = new HashedMap();
            Map<String,Object> mapInfo = taskService.getVariables(task.getId());
            if(mapInfo!=null){
                Map<String,Object> userMap = (Map<String,Object>)mapInfo.get("starter");
                taskInfoMap.put("starter",userMap!=null?userMap.get("name"):"");
                taskInfoMap.put("startTime",mapInfo.get("startTime"));
                taskInfoMap.put("processInstanceId",task.getProcessInstanceId());
                taskInfoMap.put("taskId",task.getId());
                taskInfoMap.put("businessId",mapInfo.get("businessId"));
                taskInfoMap.put("businessType",mapInfo.get("flowType"));
                List<Map<String,Object>> variables = (List)mapInfo.get("variables"); //定制variables，回传
                if(CollectionUtils.isNotEmpty(variables)){
                    for (Map<String,Object> m:variables) {
                        taskInfoMap.put((String)m.get("key"),m.get("value"));
                    }
                }
                result.add(taskInfoMap);
            }
        }
        PageHelper.startPage(pageNum, pageSize);
        PageInfo<Map<String,Object>> pageInfo = new PageInfo<>(result);
        pageInfo.setPages(pages);
        pageInfo.setTotal(total);
        PageHelper.clearPage();
        return new ResultData(pageInfo);
    }

    @Override
    public ResultData applyHistory(Long businessId,String tenantId) {
        List<WxFlowRecord> result = wxFlowRecordService.findList(new WxFlowRecord(businessId,tenantId));
        if(CollectionUtils.isNotEmpty(result)){
            String processInstanceId = result.get(0).getProcessInstanceId();
            List<MallUserInfo> mallUserInfoList = getUserByProcessInstanceId(processInstanceId);

            // 如果有代办，加一条待审批
            if(CollectionUtils.isNotEmpty(mallUserInfoList)){
                String assignee = "";
                for (MallUserInfo mallUserInfo:mallUserInfoList) {
                    assignee += mallUserInfo.getName()+" ";
                }

                WxFlowRecord wxFlowRecord = new WxFlowRecord();
                wxFlowRecord.setUserName(assignee.trim());
                wxFlowRecord.setStatus(EnumFlowRecordStatus.ASSIGNEE.getCode());
                result.add(0,wxFlowRecord);
            }
        }
        return new ResultData(result);
    }

    @Override
    public ResultData getTaskStatusList(Long businessId, String tenantId) {
        List<WxFlowRecord> resultList = wxFlowRecordService.findList(new WxFlowRecord(businessId,tenantId));
        if(CollectionUtils.isEmpty(resultList)){
            return new ResultData();
        }
        String processInstanceId = resultList.get(0).getProcessInstanceId();
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if(pi == null){
            return new ResultData(ErrorCode.FLOW_INST_NOT_EXIST.getCode(), "任务不存在");
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        Map<String,Object> mapInfo = taskService.getVariables(task.getId());
        List<Map<String,String>> taskAssigneeList = (List)mapInfo.get("taskAssignee");

        for (int i = 0; i < taskAssigneeList.size(); i++) {
            Map<String,String> assignee = taskAssigneeList.get(i);
            if(task.getTaskDefinitionKey().equals(assignee.get("taskKey"))){
                //设置当前节点代办人信息
                String[] assigneeArray = assignee.get("assignee").split(",");
                String userName = "";
                for (String userid:assigneeArray) {
                    MallUserInfo mallUserInfo = this.mallUserInfoService.getById(Long.parseLong(userid));
                    userName += mallUserInfo.getName()+" ";
                }
                WxFlowRecord wxFlowRecord = new WxFlowRecord();
                wxFlowRecord.setUserName(userName.trim());
                wxFlowRecord.setStatus(EnumFlowRecordStatus.ASSIGNEE.getCode());
                resultList.add(0,wxFlowRecord);

                //不是最后一个节点,设置下一个待审批节点代办人
                if(i != taskAssigneeList.size()-1){
                    assignee = taskAssigneeList.get(i+1);
                    // 下一个节点没设置代办人
                    if(StringUtils.isBlank(assignee.get("assignee"))){
                        continue;
                    }
                    assigneeArray = assignee.get("assignee").split(",");
                    userName = "";
                    for (String userid:assigneeArray) {
                        MallUserInfo mallUserInfo = this.mallUserInfoService.getById(Long.parseLong(userid));
                        userName += mallUserInfo.getName()+" ";
                    }

                    wxFlowRecord = new WxFlowRecord();
                    wxFlowRecord.setUserName(userName.trim());
                    wxFlowRecord.setStatus(EnumFlowRecordStatus.ASSIGNEE.getCode());
                    resultList.add(0,wxFlowRecord);
                    break;
                }
            }else{
                continue;
            }
        }
        // 设置最后一个发起节点
        if(CollectionUtils.isNotEmpty(resultList)){
            for (WxFlowRecord wxFlowRecord:resultList) {
                if(wxFlowRecord.getStatus() == 1){
                    wxFlowRecord.setIsLastStart(1);
                    break;
                }
            }
        }
        return new ResultData(resultList);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {Exception.class})
    public ResultData apply(Map<String, String> params,Long userId,String userName,String tenantId) {
        String taskId = params.get("taskId");
        String processInstanceId = params.get("processInstanceId");
        String remark = params.get("remark");
        String taskName;
        String taskKey;

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return new ResultData(ErrorCode.FLOW_INST_NOT_EXIST.getCode(), "任务不存在");
        }
        taskName = task.getName();
        taskKey = task.getTaskDefinitionKey();
        Map<String,Object> mapInfo = taskService.getVariables(task.getId());
        Long businessId = Long.parseLong(mapInfo.get("businessId").toString());
        Integer flowType = (Integer)mapInfo.get("flowType");
        List<Map<String,Object>> variables = (List)mapInfo.get("variables");
        Date startDate = (Date)mapInfo.get("startDate");
        taskService.complete(taskId);

        //保存wx_flow_record表审批记录
        WxFlowRecord wxFlowRecord = new WxFlowRecord();
        wxFlowRecord.setTaskId(taskId);
        wxFlowRecord.setProcessInstanceId(processInstanceId);
        wxFlowRecord.setRemark(remark);
        wxFlowRecord.setUserId(userId);
        wxFlowRecord.setStatus(EnumFlowRecordStatus.APPLY.getCode());
        wxFlowRecord.setBusinessId(businessId);
        wxFlowRecord.setBusinessType(flowType);
        wxFlowRecord.setUserName(userName);
        wxFlowRecord.setTaskName(taskName);
        wxFlowRecord.setTaskKey(taskKey);
        wxFlowRecord.setVariables(variablesToJson(variables));
        wxFlowRecord.setStartDate(startDate);
        wxFlowRecordService.saveOrUpdate(wxFlowRecord);

        // 判断流程是否结束，并发送短信通知
        boolean end = isEndAndSendMsg(mapInfo,taskKey,processInstanceId,tenantId,userName);

        //修改记录表当前状态
        if(end){
            wxFlowRecordMapper.updateCurrStatus(new WxFlowRecord(processInstanceId,EnumRentContractAppStatus.FINISH.getCode()));
        }else{
            wxFlowRecordMapper.updateCurrStatus(new WxFlowRecord(processInstanceId,EnumRentContractAppStatus.APPLYING.getCode()));
        }
        return new ResultData();
    }

    /**
     * 判断流程是否结束，并发送短信通知
     * @param taskKey
     * @param processInstanceId
     * @param tenantId
     */
    public boolean isEndAndSendMsg(Map<String,Object> mapInfo,String taskKey,String processInstanceId,String tenantId,String userName){
        // 发送短信
        Map<String,String> msgReplaceMap;
        WxMsgValidationcode wxMsgValidationcode = new WxMsgValidationcode();
        wxMsgValidationcode.setTenantId(tenantId);
        Map<String,Object> userMap = (Map<String,Object>)mapInfo.get("starter");
        List<Map<String,String>> taskAssigneeList = (List)mapInfo.get("taskAssignee");
        Long businessId = Long.parseLong(mapInfo.get("businessId").toString());
        String email = (String)userMap.get("email");
        List<Map<String,Object>> variables = (List)mapInfo.get("variables");

        // 判断下个节点是否有设置审批人，没有，直接通过,有，发短信通知
        if(!isEnded(processInstanceId)){
            if(hasAssignee(taskAssigneeList,taskKey,processInstanceId)){
                // 给代办人发送通知短信
                String assignee = "";
                List<MallUserInfo> mallUserInfoList = getUserByProcessInstanceId(processInstanceId);
                for (MallUserInfo mallUserInfo:mallUserInfoList) {
                    sendAssigneeMsgAndEmail(tenantId,mallUserInfo.getPhone(),mallUserInfo.getEmail(),userName,businessId);
                }

                // 给发起人发送短信
                msgReplaceMap = new HashedMap();
                msgReplaceMap.put("userName",userName);
                msgReplaceMap.put("page",Constant.adminPage);
                msgReplaceMap.put("contract", (String)getVariableByKey(variables,"contractNumber"));
                msgReplaceMap.put("toUserName",assignee.trim());

                WxMsgRecord wxMsgRecord = new WxMsgRecord();
                wxMsgRecord.setMsgType(EnumMsgRecordType.SMS.getCode());
                wxMsgRecord.setModelType(EnumMsgModel.FLOW_APPLY_NODIFY.getCode());
                wxMsgRecord.setReceiver(userMap!=null?(String)userMap.get("phone"):"");
                wxMsgRecord.setTenantId(tenantId);
                wxMsgRecord.setDynamicContentMap(msgReplaceMap);
                mqBaseProducer.sendMessage(wxMsgRecord, EnumMsgMqTopic.DEFAULT.getCode(),EnumMsgMqTag.DEFAULT.getCode(),EnumMsgMqKey.DEFAULT.getCode());

                //发邮件
                if(StringUtils.isNotBlank(email)){
                    MailMsg mailMsg = new MailMsg();
                    mailMsg.setSubject("审批通知");
                    mailMsg.setHtml(true);
                    mailMsg.setMsgType(EnumMsgRecordType.EMAIL.getCode());
                    mailMsg.setModelId(EnumMailMsgModel.MAIL_APPLY_NODIFY.getCode());
                    mailMsg.setTo(new String[]{email});
                    mailMsg.setTenantId(tenantId);
                    mailMsg.setDynamicContentMap(msgReplaceMap);
                    mqBaseProducer.sendMessage(mailMsg, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
                }
                return false;
            }else{
                //继续递归判断
                return isEndAndSendMsg(mapInfo,taskKey,processInstanceId,tenantId,userName);
            }
        }else{
            updateBusinessStatus(mapInfo,EnumRentContractAppStatus.FINISH.getCode());

            // 给发起人发送审批通过消息
            msgReplaceMap = new HashedMap();
            msgReplaceMap.put("contract",(String)getVariableByKey(variables,"contractNumber"));
            msgReplaceMap.put("page",Constant.adminPage);

            WxMsgRecord wxMsgRecord = new WxMsgRecord();
            wxMsgRecord.setMsgType(EnumMsgRecordType.SMS.getCode());
            wxMsgRecord.setModelType(EnumMsgModel.FLOW_PASS_NODIFY.getCode());
            wxMsgRecord.setReceiver(userMap!=null?(String)userMap.get("phone"):"");
            wxMsgRecord.setTenantId(tenantId);
            wxMsgRecord.setDynamicContentMap(msgReplaceMap);
            mqBaseProducer.sendMessage(wxMsgRecord, EnumMsgMqTopic.DEFAULT.getCode(),EnumMsgMqTag.DEFAULT.getCode(),EnumMsgMqKey.DEFAULT.getCode());

            //发邮件
            if(StringUtils.isNotBlank(email)){
                MailMsg mailMsg = new MailMsg();
                mailMsg.setSubject("审批通过通知");
                mailMsg.setHtml(true);
                mailMsg.setMsgType(EnumMsgRecordType.EMAIL.getCode());
                mailMsg.setModelId(EnumMailMsgModel.MAIL_PASS_NODIFY.getCode());
                mailMsg.setTo(new String[]{email});
                mailMsg.setTenantId(tenantId);
                mailMsg.setDynamicContentMap(msgReplaceMap);
                mqBaseProducer.sendMessage(mailMsg, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
            }
            return true;
        }
    }

    /**
     * 判断下个节点是否有设置审批人，没有，直接通过
     * @param
     * @param taskKey
     * @param processInstanceId
     */
    public boolean hasAssignee(List<Map<String,String>> taskAssigneeList,String taskKey,String processInstanceId){
        boolean has = true;
        for (int i = 0; i < taskAssigneeList.size(); i++) {
            Map<String,String> taskAssignee = taskAssigneeList.get(i);
            if(taskAssignee.get("taskKey").equals(taskKey)){
                if(i != taskAssigneeList.size() -1){
                    Map<String,String> nextTaskAssignee = taskAssigneeList.get(i+1);
                    if(StringUtils.isBlank(nextTaskAssignee.get("assignee"))){
                        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
                        taskService.complete(task.getId());
                        has = false;
                        break;
                    }
                }
            }
        }
        return has;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {Exception.class})
    public ResultData reject(Map<String, Object> params,Long userId,String userName,String userPhone,String tenantId) {
        String processInstanceId = (String)params.get("processInstanceId");
        String remark = (String)params.get("remark");

        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        Map<String,Object> mapInfo = taskService.getVariables(task.getId());
        Long businessId = Long.parseLong(mapInfo.get("businessId").toString());
        Integer flowType = (Integer)mapInfo.get("flowType");
        Map<String,Object> userMap = (Map<String,Object>)mapInfo.get("starter");
        String email = (String) userMap.get("email");
        List<Map<String,Object>> variables = (List)mapInfo.get("variables");
        Date startDate = (Date)mapInfo.get("startDate");

        String taskName;
        String taskKey;
        if (task == null) {
            return new ResultData(ErrorCode.FLOW_INST_NOT_EXIST.getCode(), "任务不存在");
        }
        taskName = task.getName();
        taskKey = task.getTaskDefinitionKey();

        runtimeService.deleteProcessInstance(processInstanceId, "驳回");

        // 修改合同审核状态为驳回
        params.putAll(mapInfo);
        updateBusinessStatus(params,EnumRentContractAppStatus.REJECT.getCode());

        //保存wx_flow_record表审批记录
        WxFlowRecord wxFlowRecord = new WxFlowRecord();
        wxFlowRecord.setBusinessId(businessId);
        wxFlowRecord.setTaskId(task.getId());
        wxFlowRecord.setProcessInstanceId(processInstanceId);
        wxFlowRecord.setRemark(remark);
        wxFlowRecord.setUserId(userId);
        wxFlowRecord.setStatus(EnumFlowRecordStatus.REJECT.getCode());
        wxFlowRecord.setBusinessType(flowType);
        wxFlowRecord.setUserName(userName);
        wxFlowRecord.setTaskKey(taskKey);
        wxFlowRecord.setTaskName(taskName);
        wxFlowRecord.setVariables(variablesToJson(variables));
        wxFlowRecord.setStartDate(startDate);
        wxFlowRecordService.saveOrUpdate(wxFlowRecord);
        //修改记录表当前状态
        wxFlowRecordMapper.updateCurrStatus(new WxFlowRecord(processInstanceId,EnumRentContractAppStatus.REJECT.getCode()));

        //给发起人发送驳回消息
        Map<String,String> msgReplaceMap = new HashedMap();
        WxMsgValidationcode wxMsgValidationcode = new WxMsgValidationcode();
        wxMsgValidationcode.setTenantId(tenantId);
        msgReplaceMap.put("contract",(String)getVariableByKey(variables,"contractNumber"));
        msgReplaceMap.put("page",Constant.adminPage);
        WxMsgRecord wxMsgRecord = new WxMsgRecord();
        wxMsgRecord.setMsgType(EnumMsgRecordType.SMS.getCode());
        wxMsgRecord.setModelType(EnumMsgModel.FLOW_REJECT_NODIFY.getCode());
        wxMsgRecord.setReceiver(userMap!=null?(String)userMap.get("phone"):"");
        wxMsgRecord.setTenantId(tenantId);
        wxMsgRecord.setDynamicContentMap(msgReplaceMap);
        mqBaseProducer.sendMessage(wxMsgRecord, EnumMsgMqTopic.DEFAULT.getCode(),EnumMsgMqTag.DEFAULT.getCode(),EnumMsgMqKey.DEFAULT.getCode());

        //发送邮件
        if(StringUtils.isNotBlank(email)) {
            msgReplaceMap = new HashedMap();
            msgReplaceMap.put("contract",(String)getVariableByKey(variables,"contractNumber"));
            msgReplaceMap.put("page", Constant.adminPage);
            msgReplaceMap.put("name",userName);
            msgReplaceMap.put("remark",remark==null?"":remark);
            msgReplaceMap.put("linkName",userName);
            msgReplaceMap.put("linkPhone",userPhone==null?"":userPhone);
            MailMsg mailMsg = new MailMsg();
            mailMsg.setSubject("驳回通知");
            mailMsg.setHtml(true);
            mailMsg.setMsgType(EnumMsgRecordType.EMAIL.getCode());
            mailMsg.setModelId(EnumMailMsgModel.MAIL_REJECT_NODIFY.getCode());
            mailMsg.setTo(new String[]{email});
            mailMsg.setTenantId(tenantId);
            mailMsg.setDynamicContentMap(msgReplaceMap);
            mqBaseProducer.sendMessage(mailMsg, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
        }
        return new ResultData();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = {Exception.class})
    public ResultData setBack(Map<String, Object> params,Long userId,String userName) {
        String processInstanceId = (String)params.get("processInstanceId");
        String remark = (String)params.get("remark");

        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        Map<String,Object> mapInfo = taskService.getVariables(task.getId());
        Long businessId = Long.parseLong(mapInfo.get("businessId").toString());
        Integer flowType = (Integer)mapInfo.get("flowType");
        List<Map<String,Object>> variables = (List)mapInfo.get("variables");
        Date startDate = (Date)mapInfo.get("startDate");

        String taskName;
        String taskKey;
        if (task == null) {
            return new ResultData(ErrorCode.FLOW_INST_NOT_EXIST.getCode(), "任务不存在");
        }
        taskName = task.getName();
        taskKey = task.getTaskDefinitionKey();

        runtimeService.deleteProcessInstance(processInstanceId, "撤回");

        // 修改合同审核状态为撤回
        params.putAll(mapInfo);
        updateBusinessStatus(params,EnumRentContractAppStatus.SETBACK.getCode());

        //保存wx_flow_record表审批记录
        WxFlowRecord wxFlowRecord = new WxFlowRecord();
        wxFlowRecord.setBusinessId(businessId);
        wxFlowRecord.setTaskId(task.getId());
        wxFlowRecord.setProcessInstanceId(processInstanceId);
        wxFlowRecord.setRemark(remark);
        wxFlowRecord.setUserId(userId);
        wxFlowRecord.setStatus(EnumFlowRecordStatus.SETBACK.getCode());
        wxFlowRecord.setBusinessType(flowType);
        wxFlowRecord.setUserName(userName);
        wxFlowRecord.setTaskKey(taskKey);
        wxFlowRecord.setTaskName(taskName);
        wxFlowRecord.setVariables(variablesToJson(variables));
        wxFlowRecord.setStartDate(startDate);
        wxFlowRecordService.saveOrUpdate(wxFlowRecord);
        //修改记录表当前状态
        wxFlowRecordMapper.updateCurrStatus(new WxFlowRecord(processInstanceId,EnumRentContractAppStatus.SETBACK.getCode()));
        return new ResultData();
    }

    /**
     * 判断流程是否结束
     * @param processInstanceId
     * @return
     */
    public boolean isEnded(String processInstanceId) {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if(processInstance == null){
            return true;
        }
        return processInstance.isEnded();
    }

    /**
     * 根据流程实例id获取当前节点的代办人信息
     * @return
     */
    public List<MallUserInfo> getUserByProcessInstanceId(String processInstanceId){
        List<MallUserInfo> result = new ArrayList<>();
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().desc().list();
        if(CollectionUtils.isNotEmpty(tasks)){
            for (Task task:tasks) {
                List<String> userIdList = getTaskCandidateUserId(task.getId());
                for (String userId:userIdList) {
                    MallUserInfo mallUserInfo = this.mallUserInfoService.getById(Long.parseLong(userId));
                    mallUserInfo.setPassword(null);
                    mallUserInfo.setBopenId(null);
                    if(StringUtils.isNotBlank(mallUserInfo.getWebOpenId())) {
                        mallUserInfo.setWebOpenId("保密");
                    }
                    result.add(mallUserInfo);
                }
            }
        }
        return result;
    }

    /**
     * 获得任务中的候选人
     * @param taskId
     * @return
     */
    private List<String> getTaskCandidateUserId(String taskId) {
        List<String> userIdList = new ArrayList<>();
        List identityLinkList = taskService.getIdentityLinksForTask(taskId);
        if (identityLinkList != null && identityLinkList.size() > 0) {
            for (Iterator iterator = identityLinkList.iterator(); iterator.hasNext();) {
                IdentityLink identityLink = (IdentityLink) iterator.next();
                if (identityLink.getUserId() != null) {
                    userIdList.add(identityLink.getUserId());
                }
//                if (identityLink.getGroupId() != null) {
//                    // 根据组获得对应人员
//                    List userList = identityService.createUserQuery()
//                            .memberOfGroup(identityLink.getGroupId()).list();
//                    if (userList != null && userList.size() > 0)
//                        users.addAll(userList);
//                }
            }
        }
        return userIdList;
    }

    @Override
    public PageInfo<WxFlowRecord> listAsPage(WxFlowRecord record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxFlowRecordMapper.findList(record));
    }

    @Override
    public PageInfo<WxFlowRecord> myHandelList(WxFlowRecord record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxFlowRecordMapper.myHandelList(record));
    }

    @Override
    public void genProcessDiagram(HttpServletResponse httpServletResponse,String businessId) throws Exception {
        List<WxFlowRecord> result = wxFlowRecordService.findList(new WxFlowRecord(Long.parseLong(businessId)));
        if(CollectionUtils.isNotEmpty(result)) {
            String processInstanceId = result.get(0).getProcessInstanceId();
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

            //流程走完的不显示图
            if (pi == null) {
                return;
            }
            Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
            //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
            String InstanceId = task.getProcessInstanceId();
            List<Execution> executions = runtimeService
                    .createExecutionQuery()
                    .processInstanceId(InstanceId)
                    .list();

            //得到正在执行的Activity的Id
            List<String> activityIds = new ArrayList<>();
            List<String> flows = new ArrayList<>();
            for (Execution exe : executions) {
                List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
                activityIds.addAll(ids);
            }

            //获取流程图
            BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
            ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
            ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
            InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0,true);
            OutputStream out = null;
            byte[] buf = new byte[1024];
            int legth = 0;
            try {
                out = httpServletResponse.getOutputStream();
                while ((legth = in.read(buf)) != -1) {
                    out.write(buf, 0, legth);
                }
            } finally {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            }
        }else{
            throw new MallinkException(Result.ERROR, "找不到审批历史");
        }
    }

    public static Object getVariableByKey(List<Map<String,Object>> variables,String key){
        if(variables == null) return null;
        for (Map<String,Object> map:variables) {
            if(map.get("key").equals(key)){
                return map.get("value");
            }
        }
        return null;
    }


}
