package com.yeejoin.amos.boot.module.jg.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.util.StringUtil;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.common.api.dao.ESEquipmentCategory;
import com.yeejoin.amos.boot.module.common.api.dto.ESEquipmentCategoryDto;
import com.yeejoin.amos.boot.module.jg.api.dto.*;
import com.yeejoin.amos.boot.module.jg.api.entity.JgReformNotice;
import com.yeejoin.amos.boot.module.jg.api.entity.JgReformNoticeEq;
import com.yeejoin.amos.boot.module.jg.api.entity.JgRegistrationHistory;
import com.yeejoin.amos.boot.module.jg.api.enums.BusinessTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgReformNoticeEqMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgReformNoticeMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgRegistrationHistoryMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgReformNoticeService;
import com.yeejoin.amos.boot.module.jg.api.vo.SortVo;
import com.yeejoin.amos.boot.module.jg.api.vo.tableDataExportVo.ReformVo;
import com.yeejoin.amos.boot.module.jg.biz.config.LocalBadRequest;
import com.yeejoin.amos.boot.module.jg.biz.context.EquipUsedCheckStrategyContext;
import com.yeejoin.amos.boot.module.jg.biz.context.FlowingEquipRedisContext;
import com.yeejoin.amos.boot.module.jg.biz.event.CancellationEvent;
import com.yeejoin.amos.boot.module.jg.biz.event.publisher.EventPublisher;
import com.yeejoin.amos.boot.module.jg.biz.feign.TzsServiceFeignClient;
import com.yeejoin.amos.boot.module.jg.biz.service.ICmWorkflowService;
import com.yeejoin.amos.boot.module.jg.biz.service.ICompensateFlowDataOfRedis;
import com.yeejoin.amos.boot.module.jg.biz.service.IIdxBizJgRegisterInfoService;
import com.yeejoin.amos.boot.module.jg.biz.utils.WordTemplateUtils;
import com.yeejoin.amos.boot.module.ymt.api.entity.EquipmentCategory;
import com.yeejoin.amos.boot.module.ymt.api.entity.RegistrationInfo;
import com.yeejoin.amos.boot.module.ymt.api.enums.ApplicationFormTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.EquipmentCategoryMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.OtherInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.RegistrationInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.SupervisoryCodeInfoMapper;
import com.yeejoin.amos.feign.systemctl.model.TaskV2Model;
import com.yeejoin.amos.feign.workflow.model.ActWorkflowBatchDTO;
import com.yeejoin.amos.feign.workflow.model.ActWorkflowStartDTO;
import com.yeejoin.amos.feign.workflow.model.ProcessTaskDTO;
import com.yeejoin.amos.feign.workflow.model.TaskResultDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 改造告知服务实现类
 *
 * @author system_generator
 * @date 2023-12-19
 */
@Service
@Slf4j
public class JgReformNoticeServiceImpl extends BaseService<JgReformNoticeDto, JgReformNotice, JgReformNoticeMapper> implements IJgReformNoticeService, ICompensateFlowDataOfRedis<JgReformNotice> {

    private static final String SUBMIT_TYPE_FLOW = "1";
    private static final String PROCESS_DEFINITION_KEY = "renovationNoticeNew";
    private static final String TABLE_PAGE_ID = "reformNoticeAdd";
    private final List<String> NOT_FLOWING_STATE = Arrays.asList("6610", "6614", "6615", "6617", "6616");

    // 西安行政区划code
    private static final String XIAN = "610100";

    // 咸阳行政区划code
    private static final String XIAN_YANG = "610400";

    @Autowired
    EquipmentCategoryMapper equipmentCategoryMapper;

    @Autowired
    JgReformNoticeEqMapper jgReformNoticeEqMapper;
    @Autowired
    RegistrationInfoMapper tzsJgRegistrationInfoMapper;
    @Autowired
    OtherInfoMapper tzsJgOtherInfoMapper;
    @Autowired
    TzsServiceFeignClient tzsServiceFeignClient;
    @Autowired
    SupervisoryCodeInfoMapper supervisoryCodeInfoMapper;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    private Sequence sequence;
    @Autowired
    IIdxBizJgRegisterInfoService idxBizJgRegisterInfoService;
    @Autowired
    JgInstallationNoticeServiceImpl jgInstallationNoticeService;
    @Autowired
    private JgReformNoticeMapper jgReformNoticeMapper;
    @Autowired
    private CommonServiceImpl commonService;
    @Autowired
    private CmWorkflowServiceImpl cmWorkflowService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private JgRegistrationHistoryMapper jgRegistrationHistoryMapper;
    @Autowired
    ESEquipmentCategory esEquipmentCategory;
    @Autowired
    private EventPublisher eventPublisher;
    @Autowired
    private ICmWorkflowService iCmWorkflowService;

    /**
     * 根据sequenceNbr查询
     *
     * @param sequenceNbr 主键
     * @return 改造告知
     */
    @Override
    public Map<String, Object> queryBySequenceNbr(Long sequenceNbr) {
        // 改造告知信息
        JgReformNotice notice = jgReformNoticeMapper.selectById(sequenceNbr);
        this.doCompensate(notice);
        Map<String, Object> reformNoticeMap = BeanUtil.beanToMap(notice, false, true);
        reformNoticeMap.put("province", notice.getProvince() + "_" + notice.getProvinceName());
        reformNoticeMap.put("city", notice.getCity() + "_" + notice.getCityName());
        reformNoticeMap.put("county", notice.getCounty() + "_" + notice.getCountyName());
        reformNoticeMap.put("fullAddress", notice.getProvinceName() + notice.getCityName() + notice.getCountyName() + notice.getStreetName() + notice.getAddress());
        reformNoticeMap.put("useUnitCreditCode", notice.getUseUnitCreditCode() + "_" + notice.getUseUnitName());
        reformNoticeMap.put("receiveOrgCode", notice.getReceiveOrgCode() + "_" + notice.getReceiveOrgName());
        if (!ValidationUtil.isEmpty(notice.getStreet()) && !ValidationUtil.isEmpty(notice.getStreetName())) {
            reformNoticeMap.put("street", notice.getStreet() + "_" + notice.getStreetName());
        }
        reformNoticeMap.put("constructionManagerId", notice.getConstructionManagerId() + "_" + notice.getConstructionManager());
        if ((Integer.parseInt(notice.getNoticeStatus()) == FlowStatusEnum.TO_BE_FINISHED.getCode()) || (Integer.parseInt(notice.getNoticeStatus()) == FlowStatusEnum.TO_BE_DISCARD.getCode())) {
            // 完成 或 作废时显示历史数据
            JSONObject hisData = commonService.queryHistoryData(notice.getSequenceNbr());
            if (!ValidationUtil.isEmpty(hisData)) {
                // 格式化基本通用信息的时间类型字段
                CommonServiceImpl.formatTime2StrDateForEquip(hisData);
                hisData.putAll(reformNoticeMap);
                return hisData;
            }
        } else {
            // 显示最新的设备信息
            List<JgReformNoticeEq> noticeEqs = jgReformNoticeEqMapper.selectList(new LambdaQueryWrapper<JgReformNoticeEq>().eq(JgReformNoticeEq::getEquipTransferId, sequenceNbr));
            List<String> ids = noticeEqs.stream().map(JgReformNoticeEq::getEquId).collect(Collectors.toList());
            Iterable<ESEquipmentCategoryDto> equips = esEquipmentCategory.findAllById(ids);
            List<Map<String, Object>> equipListMaps = getEquipListMaps(equips);
            reformNoticeMap.put("deviceList", equipListMaps);
            reformNoticeMap.put("EQU_LIST_CODE", notice.getEquListCode());
            reformNoticeMap.put("EQU_CATEGORY_CODE", notice.getEquCategoryCode());
            reformNoticeMap.put("QUERY_TYPE", "GZ_GZ");
            reformNoticeMap.put("IS_INTO_MANAGEMENT", Boolean.TRUE);
            return reformNoticeMap;
        }
        return new HashMap<>();
    }

    private List<Map<String, Object>> getEquipListMaps(Iterable<ESEquipmentCategoryDto> equips) {
        List<Map<String, Object>> arrayList = new ArrayList<>();
        equips.forEach(equip -> {
            Map<String, Object> objectHashMap = new HashMap<>();
            BeanUtil.beanToMap(equip, objectHashMap, false, false);
            objectHashMap.put("record", equip.getSEQUENCE_NBR());
            objectHashMap.put("ADDRESS", concatDetailAddress(equip));
            arrayList.add(objectHashMap);
        });
        return arrayList;
    }

    private String concatDetailAddress(ESEquipmentCategoryDto esEquipmentCategoryDto) {
        // 省、市、区
        String usePlace = esEquipmentCategoryDto.getUSE_PLACE();
        // 详细地址
        String address = esEquipmentCategoryDto.getADDRESS();
        return String.format("%s%s", usePlace, address);
    }

    /**
     * 更新改造告知
     *
     * @param noticeDto 改造告知
     */
    @SuppressWarnings({"rawtypes", "Duplicates"})
    public JgReformNoticeDto updateInstallationNotice(String submitType, JgReformNoticeDto noticeDto, String op) {
        try {
            if (Objects.isNull(noticeDto) || StringUtils.isEmpty(submitType)) {
                throw new IllegalArgumentException("参数不能为空");
            }
            // 字段转换
            this.convertField(noticeDto);
            JgReformNotice notice = this.getById(noticeDto.getSequenceNbr());
            List<Map<String, Object>> deviceList = noticeDto.getDeviceList();
            List<String> records = deviceList.stream().map(equ -> String.valueOf(equ.get("SEQUENCE_NBR"))).collect(Collectors.toList());
            this.checkRepeatUsed(submitType, records, notice);
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                // 发起流程
                if (!StringUtils.hasText(noticeDto.getInstanceId())) {
                    ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
                    List<ActWorkflowStartDTO> list = new ArrayList<>();
                    ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                    dto.setBusinessKey(noticeDto.getSequenceNbr().toString());
                    dto.setCompleteFirstTask(Boolean.TRUE);
                    dto.setProcessDefinitionKey(PROCESS_DEFINITION_KEY);
                    dto.setNextExecuteUserCompanyCode(noticeDto.getReceiveCompanyCode());
                    list.add(dto);
                    actWorkflowBatchDTO.setProcess(list);
                    ProcessTaskDTO processTaskDTO = cmWorkflowService.startBatch(actWorkflowBatchDTO).get(0);
                    // 提取节点等信息
                    WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
                    BeanUtils.copyProperties(noticeDto, notice);
                    if (!ObjectUtils.isEmpty(notice.getInstanceStatus())) {
                        notice.setInstanceStatus(notice.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                    } else {
                        notice.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                    }
                    notice.setPromoter(RequestContext.getExeUserId());
                    notice.setNextExecuteIds(String.join(",", workflowResultDto.getNextExecutorRoleIds()));
                    notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    notice.setInstanceId(workflowResultDto.getInstanceId());
                    notice.setNextTaskId(workflowResultDto.getNextTaskId());
                    notice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());

                    jgReformNoticeMapper.updateById(notice);
                    // 删除暂存
                    commonService.deleteTasksByRelationId(notice.getSequenceNbr() + "");
                    // 如果为保存并提交，则创建代办
                    this.buildTask(notice, Collections.singletonList(workflowResultDto));
                } else {
                    TaskResultDTO dto = new TaskResultDTO();
                    dto.setResultCode("approvalStatus");
                    dto.setTaskId(notice.getNextTaskId());
                    HashMap<String, Object> commMap = new HashMap<>();
                    if (notice.getNoticeStatus().equals("6614") || notice.getNoticeStatus().equals("6615")) {
                        commMap.put("approvalStatus", "提交");
                    } else {
                        commMap.put("approvalStatus", op);
                    }
                    dto.setNextExecuteUserCompanyCode(notice.getReceiveCompanyCode());
                    dto.setVariable(commMap);
                    ProcessTaskDTO processTaskDTO = cmWorkflowService.completeOrReject(notice.getNextTaskId(), dto, "2");
                    // 提取节点等信息
                    WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
                    BeanUtils.copyProperties(noticeDto, notice);

                    if (!org.apache.commons.lang3.ObjectUtils.isEmpty(notice.getInstanceStatus())) {
                        notice.setInstanceStatus(notice.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                    } else {
                        notice.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                    }
                    notice.setPromoter(RequestContext.getExeUserId());
                    notice.setNextExecuteIds(String.join(",", workflowResultDto.getNextExecutorRoleIds()));
                    notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    notice.setNextTaskId(workflowResultDto.getNextTaskId());
                    notice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    notice.setCreateDate(new Date());
                    updateById(notice);
                    // 上个代办改为已办
                    TaskV2Model taskV2Model = this.updateLastTodo(notice, FlowStatusEnum.TO_BE_PROCESSED);
                    // 创建新的代办
                    this.createNewTodo(notice, workflowResultDto, taskV2Model, FlowStatusEnum.TO_BE_PROCESSED);
                }
                commonService.saveExecuteFlowData2Redis(notice.getInstanceId(), this.buildInstanceRuntimeData(notice));
            } else {
                JgReformNotice bean = new JgReformNotice();
                BeanUtils.copyProperties(noticeDto, bean);
                jgReformNoticeMapper.updateById(bean);
            }

            jgReformNoticeEqMapper.delete(new QueryWrapper<JgReformNoticeEq>()
                    .eq("equip_transfer_id", notice.getSequenceNbr()));
            // eq关系表
            List<JgReformNoticeEq> noticeEqs = new ArrayList<>();
            // 更新设备关系表
            deviceList.forEach(obj -> {
                JgReformNoticeEq jgRelationEquip = new JgReformNoticeEq();
                jgRelationEquip.setEquId(String.valueOf(obj.get("SEQUENCE_NBR")));
                jgRelationEquip.setEquipTransferId(String.valueOf(notice.getSequenceNbr()));
                noticeEqs.add(jgRelationEquip);
            });
            jgReformNoticeEqMapper.insertBatchSomeColumn(noticeEqs);
            return noticeDto;
        } catch (BadRequest | LocalBadRequest e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw e;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw new BadRequest("改造告知保存失败！");
        } finally {
            FlowingEquipRedisContext.clean();
        }
    }


    /**
     * 分页查询
     *
     * @param page  分页对象
     * @param model 查询参数
     * @param type  类型：enterprise-企业端、supervision-监管端
     * @return 改造告知列表
     */
    @Override
    public Page<Map<String, Object>> queryForJgReformNoticePage(Page<JgReformNotice> page, String sort, JgReformNoticeDto model, String type, ReginParams reginParams) {

        String orgCode = reginParams.getCompany().getCompanyCode();
        SortVo sortMap = commonService.sortFieldConversion(sort);
        Page<Map<String, Object>> noticePage = jgReformNoticeMapper.queryForPage(page, sortMap, model, type, orgCode, reginParams.getUserModel().getUserId());

        List<Map<String, Object>> mappedRecords = noticePage.getRecords().stream().peek(notice -> {
            Optional<Long> noticeStatusOpt = Optional.ofNullable((String) notice.get("noticeStatus")).map(Long::valueOf);
            noticeStatusOpt.ifPresent(status -> {
                String noticeStatusDesc = FlowStatusEnum.getNameByType(Long.valueOf((String) notice.get("noticeStatus")));
                notice.put("noticeStatusDesc", noticeStatusDesc);
            });
        }).collect(Collectors.toList());

        noticePage.setRecords(mappedRecords);
        return noticePage;
    }

    /**
     * 列表查询-导出用
     */
    public List<ReformVo> queryReformInIds(List<String> ids) {
        List<ReformVo> reformVos = jgReformNoticeMapper.queryReformInIds(ids);
        return reformVos.stream().peek(notice -> Optional.ofNullable(notice.getNoticeStatus()).ifPresent(status -> notice.setNoticeStatus(FlowStatusEnum.getNameByType(Long.valueOf(status))))).collect(Collectors.toList());
    }

    /**
     * 批量删除
     *
     * @param sequenceNbrs 主键
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteForBatch(Long[] sequenceNbrs) {
        if (Objects.isNull(sequenceNbrs) || sequenceNbrs.length == 0) {
            return false;
        }
        Collection<JgReformNotice> JgReformNotices = this.listByIds(Arrays.asList(sequenceNbrs));
        JgReformNotices.forEach(notice -> {
            // 删除代办 + 中止流程
            commonService.deleteTaskModel(String.valueOf(notice.getSequenceNbr()), notice.getInstanceId());
            // 删除单子
            this.baseMapper.deleteById(notice.getSequenceNbr());
            // 删除对应eq
            jgReformNoticeEqMapper.delete(new LambdaQueryWrapper<JgReformNoticeEq>().eq(JgReformNoticeEq::getEquipTransferId, notice.getSequenceNbr()));
            // 删除单子对应历史表数据
            jgRegistrationHistoryMapper.delete(new LambdaQueryWrapper<JgRegistrationHistory>().eq(JgRegistrationHistory::getCurrentDocumentId, notice.getSequenceNbr()));
        });
        return Boolean.TRUE;
    }

    /**
     * 打印改造告知单
     *
     * @param sequenceNbr 主键
     * @return pdf文件路径
     */
    @Override
    public void generateInstallationNoticeReport(Long sequenceNbr, HttpServletResponse response) {
        if (Objects.isNull(sequenceNbr)) {
            throw new IllegalArgumentException("参数不能为空");
        }

        JgReformNotice notice = this.getById(sequenceNbr);

        List<JgReformNoticeEq> noticeEqs = jgReformNoticeEqMapper.selectList(new LambdaQueryWrapper<JgReformNoticeEq>().eq(JgReformNoticeEq::getEquipTransferId, notice.getSequenceNbr()));

        if (CollectionUtils.isEmpty(noticeEqs)) {
            throw new IllegalArgumentException("改造告知单不存在");
        }
        String tempFileName = "改造告知单_" + System.currentTimeMillis() + "_temp";
        Map<String, Object> data = new HashMap<>();
        ArrayList<Map<String, Object>> maps = new ArrayList<>();
        for (JgReformNoticeEq noticeEq : noticeEqs) {

            Map<String, Object> information = jgReformNoticeMapper.queryEquipInformation(noticeEq.getSequenceNbr());
            if (CollectionUtils.isEmpty(information)) {
                throw new IllegalArgumentException("改造告知单不存在");
            }
            Map<String, Object> stringObjectMap = jgInstallationNoticeService.fullFillTemplateObj(Collections.singletonList(information), BusinessTypeEnum.JG_MODIFICATION_NOTIFICATION.getName().substring(0, 2));
            maps.add(stringObjectMap);
        }
        data.put("equipBasicInfoList", maps);
        WordTemplateUtils.templateToPdfDownload(tempFileName, "installation-notification-report.ftl", data, response);
    }


    @Override
    @SuppressWarnings({"Duplicates", "rawtypes"})
    @Transactional(rollbackFor = Exception.class)
    public List<JgReformNotice> saveNotice(String submitType, Map<String, Object> JgReformNoticeDtoMap, ReginParams reginParams) {
        try {
            String jsonString = JSONObject.toJSONString(JgReformNoticeDtoMap.get(TABLE_PAGE_ID));
            JSONObject jsonObject = JSONObject.parseObject(jsonString);
            JgReformNoticeDto model = JSON.parseObject(jsonString, JgReformNoticeDto.class);
            convertField(model);
            // 获取告知设备列表
            List<Map<String, Object>> deviceList = model.getDeviceList();
            if (CollectionUtils.isEmpty(deviceList)) {
                throw new BadRequest("请选择设备!");
            }
            // 提交时对设备状态进行校验（处理并发问题，一个未被使用的设备同时被多个使用这打开，同时提交发起申请） todo 回滚异常未写
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                this.repeatUsedEquipCheck(deviceList, reginParams.getCompany().getCompanyCode());
            }
            // 获取申请单号
            ResponseModel<List<String>> codeResult = tzsServiceFeignClient.applicationFormCode(ApplicationFormTypeEnum.GZGZ.getCode(), 1);
            List<String> applyNoList = null;
            if (codeResult != null && !ValidationUtil.isEmpty(codeResult.getResult())) {
                applyNoList = codeResult.getResult();
            }
            if (CollectionUtils.isEmpty(applyNoList)) {
                throw new BadRequest("申请单编号生成失败,请稍后重试!");
            }

            // 申请单业务主键seq
            long sequenceNbr = sequence.nextId();
            // 启动工作流
            List<WorkflowResultDto> workflowResultList = this.startWorkFlow(model.getReceiveCompanyCode(), submitType, applyNoList.get(0));
            CompanyBo companyBo = commonService.getOneCompany(model.getReceiveCompanyCode());
            JgReformNotice notice = new JgReformNotice();
            BeanUtils.copyProperties(model, notice);
            notice.setSequenceNbr(sequenceNbr);
            notice.setApplyNo(applyNoList.get(0));
            notice.setNoticeDate(new Date());
            notice.setCreateDate(new Date());
            notice.setCreateUserName(reginParams.getUserModel().getRealName());
            notice.setCreateUserId(reginParams.getUserModel().getUserId());
            notice.setCreateUserCompanyName(reginParams.getCompany().getCompanyName());
            notice.setProjectContraption(ValidationUtil.isEmpty(jsonObject.get("projectContraption")) ? "" : String.valueOf(jsonObject.get("projectContraption")));
            String equListCode = String.valueOf(jsonObject.get("EQU_LIST_CODE"));
            String equCategoryCode = String.valueOf(jsonObject.get("EQU_CATEGORY_CODE"));
            notice.setEquListCode(equListCode);
            EquipmentCategory equipmentCategory1 = equipmentCategoryMapper.selectOne(new LambdaQueryWrapper<EquipmentCategory>().eq(EquipmentCategory::getCode, equListCode));
            notice.setEquListName(ValidationUtil.isEmpty(equipmentCategory1) ? null : equipmentCategory1.getName());
            notice.setEquCategoryCode(equCategoryCode);
            EquipmentCategory equipmentCategory2 = equipmentCategoryMapper.selectOne(new LambdaQueryWrapper<EquipmentCategory>().eq(EquipmentCategory::getCode, equCategoryCode));
            notice.setEquCategoryName(ValidationUtil.isEmpty(equipmentCategory2) ? null : equipmentCategory2.getName());

            // 统计用
            notice.setReceiveCompanyOrgCode(companyBo.getOrgCode());
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                WorkflowResultDto workflowResult = workflowResultList.get(0);
                notice.setNextExecuteIds(workflowResult.getNextExecutorRoleIds());
                notice.setInstanceStatus(workflowResult.getNextExecutorRoleIds() + "," + workflowResult.getExecutorRoleIds());
                notice.setPromoter(reginParams.getUserModel().getUserId());
                notice.setNextTaskId(workflowResult.getNextTaskId());
                notice.setNextExecuteUserIds(workflowResult.getNextExecutorUserIds());
            } else {
                notice.setNextExecuteUserIds(RequestContext.getExeUserId());
            }
            notice.setInstallUnitName(reginParams.getCompany().getCompanyName());
            notice.setInstallUnitCreditCode(reginParams.getCompany().getCompanyCode());
            notice.setEntrustingUnitName(reginParams.getCompany().getCompanyName());
            notice.setEntrustingUnitCreditCode(reginParams.getCompany().getCompanyCode());

            if (!CollectionUtils.isEmpty(workflowResultList)) {
                notice.setInstanceId(workflowResultList.get(0).getInstanceId());
                notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
            } else {
                notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_SUBMITTED.getCode()));
            }

//            notice.setCreateUserId(reginParams.getUserModel().getUserId());
            // 插入业务单
            jgReformNoticeMapper.insert(notice);

            List<JgReformNoticeEq> noticeEqs = new ArrayList<>();
            // 更新设备关系表
            deviceList.forEach(obj -> {
                JgReformNoticeEq jgRelationEquip = new JgReformNoticeEq();
                jgRelationEquip.setEquId(String.valueOf(obj.get("SEQUENCE_NBR")));
                jgRelationEquip.setEquipTransferId(String.valueOf(sequenceNbr));
                noticeEqs.add(jgRelationEquip);
            });
            jgReformNoticeEqMapper.insertBatchSomeColumn(noticeEqs);

            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                this.buildTask(notice, workflowResultList);
            } else {
                this.saveTempReformNotice(notice);
            }

            this.updateRedisBatch(Collections.singletonList(notice));
            return Collections.singletonList(notice);
        } catch (BadRequest | LocalBadRequest e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw e;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw new BadRequest("告知单保存失败！");
        } finally {
            FlowingEquipRedisContext.clean();
        }
    }

    private void repeatUsedEquipCheck(List<Map<String, Object>> equipList, String companyCode) {
        equipList.forEach(equipMap -> EquipUsedCheckStrategyContext.getUsedStrategy(PROCESS_DEFINITION_KEY).equipRepeatUsedCheck(String.valueOf(equipMap.get("SEQUENCE_NBR")), companyCode));
    }

    private void checkRepeatUsed(String submitType, List<String> records, JgReformNotice jgReformNotice) {
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            // 流程中校验
            records.forEach(record -> EquipUsedCheckStrategyContext.getUsedStrategy(PROCESS_DEFINITION_KEY)
                    .equipRepeatUsedCheck(record, jgReformNotice.getInstallUnitCreditCode()));
        }
    }

    /**
     * 删除 redis校验重复引用设备的数据
     */
    private void delRepeatUseEquipData(JgReformNotice notice) {
        if (NOT_FLOWING_STATE.contains(notice.getNoticeStatus())) {
            LambdaQueryWrapper<JgReformNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(JgReformNoticeEq::getEquipTransferId, notice.getSequenceNbr());
            List<JgReformNoticeEq> noticeEqs = jgReformNoticeEqMapper.selectList(queryWrapper);
            List<String> ids = noticeEqs.stream().map(JgReformNoticeEq::getEquId).collect(Collectors.toList());
            EquipUsedCheckStrategyContext.getUsedStrategy(PROCESS_DEFINITION_KEY).delDataForCheckEquipRepeatUsed(ids, notice.getInstallUnitCreditCode());
        }
    }

    private void rollBackForDelRedisData() {
        FlowingEquipRedisContext.getContext().forEach(e -> {
            EquipUsedCheckStrategyContext.getUsedStrategy(PROCESS_DEFINITION_KEY).delDataForCheckWithKey(e.getData(), e.getRedisKey());
        });
    }

    private void updateRedisBatch(List<JgReformNotice> jgReformNotices) {
        jgReformNotices.stream().filter(n -> StringUtil.isNotEmpty(n.getInstanceId())).forEach(jgReformNotice -> {
            commonService.saveExecuteFlowData2Redis(jgReformNotice.getInstanceId(), this.buildInstanceRuntimeData(jgReformNotice));
        });
    }

    /**
     * 暂存
     *
     * @param notice 移交信息
     */
    private void saveTempReformNotice(JgReformNotice notice) {
        if (ValidationUtil.isEmpty(notice)) {
            return;
        }
        TaskModelDto taskModelDto = this.buildTempTaskModelDto(notice);
        commonService.buildTaskModel(Collections.singletonList(taskModelDto));
    }

    private TaskModelDto buildTempTaskModelDto(JgReformNotice item) {
        return TaskModelDto.builder().model(item)
                .taskContent(String.format("来自%s的业务办理，【申请单号：%s】", item.getEquListName(), item.getApplyNo()))
                .taskCode(item.getApplyNo())
                .taskType(BusinessTypeEnum.JG_MODIFICATION_NOTIFICATION.getCode())
                .relationId(item.getSequenceNbr() + "").build();
    }

    /**
     * 插入代办
     */
    private void buildTask(JgReformNotice notice, List<WorkflowResultDto> workflowResultList) {
        if (ValidationUtil.isEmpty(notice) || CollectionUtils.isEmpty(workflowResultList)) {
            return;
        }
        TaskModelDto taskModelDto = this.buildTaskModelDto(notice, workflowResultList.get(0));
        commonService.buildTaskModel(Collections.singletonList(taskModelDto));
    }

    /**
     * 组装代办消息
     *
     * @param item              改造告知信息
     * @param workflowResultDto 工作流返回信息
     * @return 代办信息
     */
    private TaskModelDto buildTaskModelDto(JgReformNotice item, WorkflowResultDto workflowResultDto) {
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtil.copyProperties(item, taskMessageDto);
        return TaskModelDto.builder()
                .flowCreateDate(item.getCreateDate())
                .taskName(workflowResultDto.getNextTaskName())
                .taskCode(item.getApplyNo())
                .relationId(workflowResultDto.getInstanceId())
                .taskType(BusinessTypeEnum.JG_MODIFICATION_NOTIFICATION.getCode())
                .taskTypeLabel(BusinessTypeEnum.JG_MODIFICATION_NOTIFICATION.getName())
                .relationId(item.getInstanceId())
                .executeUserIds(workflowResultDto.getNextExecutorUserIds())
                .taskStatus(FlowStatusEnum.TO_BE_PROCESSED.getCode())
                .taskStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName())
                .flowStatus(FlowStatusEnum.TO_BE_PROCESSED.getCode())
                .flowCode(workflowResultDto.getNextTaskId())
                .flowStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName())
                .taskContent(String.format("来自%s的业务办理，【申请单号：%s】", item.getEquListName(), item.getApplyNo()))
                .taskDesc(String.format("来自%s的业务办理，【申请单号：%s】", item.getEquListName(), item.getApplyNo()))
                .startUserId(item.getCreateUserId()).startUser(item.getCreateUserName())
                .startUserCompanyName(item.getCreateUserCompanyName())
                .startDate(item.getCreateDate())
                .model(taskMessageDto)
                .nextExecuteUser(item.getNextExecuteIds())
                .startDate(new Date())
                .build();
    }

    /**
     * 启动工作流
     *
     * @param submitType 提交类型
     * @param applyNo    申请单号
     * @return 工作流信息
     */
    private List<WorkflowResultDto> startWorkFlow(String receiveOrgCode, String submitType, String applyNo) {
        if (!SUBMIT_TYPE_FLOW.equals(submitType)) {
            return new ArrayList<>();
        }
        ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
        List<ActWorkflowStartDTO> list = new ArrayList<>();
        ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
        dto.setProcessDefinitionKey(PROCESS_DEFINITION_KEY);
        dto.setBusinessKey(applyNo);
        dto.setCompleteFirstTask(Boolean.TRUE);
        dto.setNextExecuteUserCompanyCode(receiveOrgCode);
        list.add(dto);
        actWorkflowBatchDTO.setProcess(list);
        List<ProcessTaskDTO> processTaskDTOS = cmWorkflowService.startBatch(actWorkflowBatchDTO);
        // 组装工作流返回的数据
        return commonService.buildWorkFlowInfo(processTaskDTOS);
    }

    private void convertField(JgReformNoticeDto model) {
        // 处理图片
        // if (!ValidationUtil.isEmpty(model.getProxyStatementAttachmentList())) {
        //     model.setProxyStatementAttachment(JSON.toJSONString(model.getProxyStatementAttachmentList()));
        // }
        // if (!ValidationUtil.isEmpty(model.getInstallContractAttachmentList())) {
        //     model.setInstallContractAttachment(JSON.toJSONString(model.getInstallContractAttachmentList()));
        // }
        if (model == null) {
            return;
        }
        // 分割省市区字段
        String province = model.getProvince();
        if (!ObjectUtils.isEmpty(province)) {
            String[] provinceList = province.split("_");
            if (provinceList.length > 1) {
                model.setProvince(provinceList[0]);
                model.setProvinceName(provinceList[1]);
            }
        }

        String city = model.getCity();
        if (!ObjectUtils.isEmpty(city)) {
            String[] cityList = city.split("_");
            if (cityList.length > 1) {
                model.setCity(cityList[0]);
                model.setCityName(cityList[1]);
            }
        }

        String county = model.getCounty();
        if (!ObjectUtils.isEmpty(county)) {
            String[] countyList = county.split("_");
            if (countyList.length > 1) {
                model.setCounty(countyList[0]);
                model.setCountyName(countyList[1]);
            }
        }

        String street = model.getStreet();
        if (!ObjectUtils.isEmpty(street)) {
            String[] streetList = street.split("_");
            if (streetList.length > 1) {
                model.setStreet(streetList[0]);
                model.setStreetName(streetList[1]);
            }
        }

        // 分割单位
        String useUnitId = model.getUseUnitCreditCode();
        if (!ObjectUtils.isEmpty(useUnitId)) {
            String[] useUnitList = useUnitId.split("_");
            if (useUnitList.length > 1) {
                model.setUseUnitCreditCode(useUnitList[0]);
                model.setUseUnitName(useUnitList[1]);
            }
        }
        String receiveOrgId = model.getReceiveOrgCode();
        if (!ObjectUtils.isEmpty(receiveOrgId)) {
            String[] receiveOrgIdList = receiveOrgId.split("_");
            if (receiveOrgIdList.length > 1) {
                model.setReceiveOrgCode(receiveOrgIdList[0]);
                model.setReceiveOrgName(receiveOrgIdList[1]);
                model.setReceiveCompanyCode(receiveOrgIdList[0]);
            }
        }
        String constructionManagerId = model.getConstructionManagerId();
        if (!ObjectUtils.isEmpty(constructionManagerId)) {
            String[] constructionManagerIdList = constructionManagerId.split("_");
            if (constructionManagerIdList.length > 1) {
                model.setConstructionManagerId(constructionManagerIdList[0]);
                model.setConstructionManager(constructionManagerIdList[1]);
            }
        }
    }

    /**
     * 撤回操作
     *
     * @param noticeDto 改造信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void cancel(JgReformNoticeDto noticeDto) {
        String instanceId = noticeDto.getInstanceId();
        String nextTaskId = noticeDto.getNextTaskId();
        String lockKey = CommonServiceImpl.buildJgExecuteLockKey(instanceId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            // 解决并发问题：多个人同时操作一个流程（并发执行通过、驳回、撤回）
            if (!isLocked) {
                throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
            }
            // 流程执行时，状态及权限校验
            commonService.checkForRevocationFlow(nextTaskId, instanceId);
            // 查询 改造信息
            JgReformNotice notice = baseMapper.selectById(noticeDto.getSequenceNbr());
            // 回滚工作流
            ProcessTaskDTO processTaskDTO = cmWorkflowService.rollBack(noticeDto.getInstanceId());
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            notice.setPromoter("");
            notice.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
            notice.setNoticeStatus(String.valueOf(FlowStatusEnum.ROLLBACK.getCode()));
            notice.setNextTaskId(workflowResultDto.getNextTaskId());
            notice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
            baseMapper.updateById(notice);
            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(notice));
            jsonObject.put("nextExecuteUser", notice.getNextExecuteIds());
            jsonObject.put("taskType", BusinessTypeEnum.JG_MODIFICATION_NOTIFICATION.getCode());
            jsonObject.put("flowStatus", FlowStatusEnum.ROLLBACK.getCode());
            jsonObject.put("flowStatusLabel", FlowStatusEnum.ROLLBACK.getName());
            commonService.rollbackTask(notice.getInstanceId(), jsonObject);
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(notice));
            this.delRepeatUseEquipData(notice);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 通过和驳回
     *
     * @param dto 改造信息
     * @param op  通过或驳回
     */
    @Transactional(rollbackFor = Exception.class)
    public void accept(Map<String, Object> map, String op) {
        LinkedHashMap model1 = (LinkedHashMap) map.get("model");
        String opinion = (String) map.get("opinion");
        String jsonString = JSON.toJSONString(model1);
        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        JgReformNoticeDto jgReformNoticeDto = JSON.parseObject(jsonString, JgReformNoticeDto.class);
        jgReformNoticeDto.setRemark(opinion);
        String instanceId = jgReformNoticeDto.getInstanceId();
        String nextTaskId = jgReformNoticeDto.getNextTaskId();
        String lockKey = CommonServiceImpl.buildJgExecuteLockKey(instanceId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            // 解决并发问题：多个人同时操作一个流程（并发执行通过、驳回、撤回）
            if (!isLocked) {
                throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
            }
            // 流程执行时，状态及权限校验
            commonService.checkForExecuteFlow(nextTaskId, instanceId);
            ReginParams reginParams = JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
            JgReformNotice jgReformNotice = baseMapper.selectById(jgReformNoticeDto.getSequenceNbr());
            jgReformNotice.setCreateUserCompanyName(reginParams.getCompany().getCompanyName());

            TaskResultDTO workDto = new TaskResultDTO();
            workDto.setResultCode("approvalStatus");
            workDto.setTaskId(jgReformNotice.getNextTaskId());
            HashMap<String, Object> commMap = new HashMap<>();
            if (jgReformNotice.getNoticeStatus().equals("6614") || jgReformNotice.getNoticeStatus().equals("6615")) {
                commMap.put("approvalStatus", "提交");
            } else {
                commMap.put("approvalStatus", op);
            }
            workDto.setNextExecuteUserCompanyCode("1".equals(op) ? jgReformNotice.getInstallUnitCreditCode() : jgReformNotice.getReceiveOrgCode());
            workDto.setVariable(commMap);
            workDto.setComment(jgReformNoticeDto.getRemark());
            ProcessTaskDTO processTaskDTO = cmWorkflowService.completeOrReject(jgReformNotice.getNextTaskId(), workDto, op);
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            jgReformNotice.setPromoter(reginParams.getUserModel().getUserId());
            jgReformNotice.setRemark(jgReformNoticeDto.getRemark());
            TaskV2Model taskV2Model;
            if ("0".equals(op)) {
                if (StringUtils.isEmpty(workflowResultDto.getNextExecutorRoleIds())) {
                    LambdaQueryWrapper<JgReformNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(JgReformNoticeEq::getEquipTransferId, jgReformNoticeDto.getSequenceNbr());
                    List<JgReformNoticeEq> noticeEqs = jgReformNoticeEqMapper.selectList(queryWrapper);
                    noticeEqs.forEach(noticeEq -> {
                        // 安装告知书编号
                        String ym = null;
                        try {
                            ym = DateUtils.dateFormat(new Date(), DateUtils.DATE_PATTERN_MM);
                        } catch (ParseException e) {
                            log.error("日期转换失败：{}", e.getMessage());
                        }
                        LambdaQueryWrapper<RegistrationInfo> queryWrapper2 = new LambdaQueryWrapper<>();
                        queryWrapper2.eq(RegistrationInfo::getRecord, noticeEq.getEquId());
                        RegistrationInfo tzsJgRegistrationInfo = tzsJgRegistrationInfoMapper.selectOne(queryWrapper2);

                        String equCode = Optional.ofNullable(tzsJgRegistrationInfo.getEquDefine()).orElse(tzsJgRegistrationInfo.getEquCategory());
                        String registrationCode = equCode + jgReformNotice.getReceiveCompanyCode() + ym;
                        ResponseModel<String> responseModel = tzsServiceFeignClient.deviceRegistrationCode(registrationCode);
                        String deviceRegistrationCode = responseModel.getResult();
                        noticeEq.setInformNumber(deviceRegistrationCode);
                        jgReformNoticeEqMapper.updateById(noticeEq);
                    });
                    // 通过时记录历史数据
                    this.saveHisDataBeforeUpdate(String.valueOf(jgReformNotice.getSequenceNbr()), jsonObject);
                    jgReformNotice.setAcceptDate(new Date());
                    jgReformNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode()));
                    jgReformNotice.setPromoter("");
                    this.updateLastTodo(jgReformNotice, FlowStatusEnum.TO_BE_FINISHED);
                    this.updateById(jgReformNotice);
                } else {
                    jgReformNotice.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
                    if (!ObjectUtils.isEmpty(jgReformNotice.getInstanceStatus())) {
                        jgReformNotice.setInstanceStatus(jgReformNotice.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                    } else {
                        jgReformNotice.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                    }
                    jgReformNotice.setPromoter(RequestContext.getExeUserId());
                    jgReformNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    jgReformNotice.setNextTaskId(workflowResultDto.getNextTaskId());
                    // 上个代办改为已办
                    taskV2Model = this.updateLastTodo(jgReformNotice, FlowStatusEnum.TO_BE_FINISHED);
                    // 创建新的代办
                    this.createNewTodo(jgReformNotice, workflowResultDto, taskV2Model, FlowStatusEnum.TO_BE_PROCESSED);
                    jgReformNoticeMapper.updateById(jgReformNotice);
                }
            } else {
                jgReformNotice.setPromoter("");
                jgReformNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.REJECTED.getCode()));
                jgReformNotice.setNextTaskId(workflowResultDto.getNextTaskId());
                jgReformNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());

                // 上个代办改为驳回
                taskV2Model = this.updateLastTodo(jgReformNotice, FlowStatusEnum.REJECTED);
                this.createNewTodo(jgReformNotice, workflowResultDto, taskV2Model, FlowStatusEnum.REJECTED);
                jgReformNoticeMapper.updateById(jgReformNotice);
            }
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgReformNotice));
            this.delRepeatUseEquipData(jgReformNotice);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


    private void saveHisDataBeforeUpdate(String sequenceNbr, JSONObject jsonObject) {
        commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_MODIFICATION_NOTIFICATION.getName(), new JSONObject(jsonObject), null, sequenceNbr);
    }

    public InstanceRuntimeData buildInstanceRuntimeData(JgReformNotice jgReformNotice) {
        return InstanceRuntimeData.builder().nextExecuteUserIds(jgReformNotice.getNextExecuteUserIds()).promoter(jgReformNotice.getPromoter()).nextTaskId(jgReformNotice.getNextTaskId()).build();
    }

    /**
     * 上个代办改为已办
     *
     * @param jgReformNotice 设备信息
     * @return 代办信息
     */
    private TaskV2Model updateLastTodo(JgReformNotice jgReformNotice, FlowStatusEnum statusEnum) {
        return commonService.updateTaskModel(MapBuilder.<String, Object>create().put("taskStatus", statusEnum.getCode()).put("taskStatusLabel", statusEnum.getName()).put("flowStatus", statusEnum.getCode()).put("flowStatusLabel", statusEnum.getName()).put("relationId", jgReformNotice.getInstanceId()).put("model", jgReformNotice).build());
    }

    /**
     * 创建新代办
     *
     * @param transfer          设备信息
     * @param workflowResultDto 工作流信息
     * @param taskV2Model       代办信息
     */
    private void createNewTodo(JgReformNotice transfer, WorkflowResultDto workflowResultDto, TaskV2Model taskV2Model, FlowStatusEnum statusEnum) {
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtil.copyProperties(transfer, taskMessageDto);
        TaskModelDto taskModelDto = TaskModelDto.builder().flowCreateDate(taskV2Model.getFlowCreateDate()).taskName(workflowResultDto.getNextTaskName()).taskCode(taskV2Model.getTaskCode()).taskType(taskV2Model.getTaskType()).taskTypeLabel(taskV2Model.getTaskTypeLabel()).relationId(taskV2Model.getRelationId()).executeUserIds(workflowResultDto.getNextExecutorUserIds()).taskStatusLabel(statusEnum.getName()).flowStatus(statusEnum.getCode()).flowCode(workflowResultDto.getNextTaskId()).flowStatusLabel(statusEnum.getName()).taskContent(String.format("来自%s的业务办理，【申请单号：%s】", transfer.getEquListName(), transfer.getApplyNo())).taskDesc(String.format("来自%s的业务办理，【申请单号%s】", transfer.getEquList(), transfer.getApplyNo())).startUserCompanyName(transfer.getCreateUserCompanyName()).startUserId(taskV2Model.getStartUserId()).startUser(taskV2Model.getStartUser()).startDate(taskV2Model.getStartDate()).model(taskMessageDto).pageType(statusEnum.getCode() == 6614 ? "edit" : "look").nextExecuteUser(workflowResultDto.getNextExecutorRoleIds()).build();
        commonService.buildTaskModel(Collections.singletonList(taskModelDto));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public JgReformNotice cancelApplication(Long sequenceNbr, String cancelReason) {
        // 1.更新为已作废
        JgReformNotice reformNotice = this.getById(sequenceNbr);
        String oldNoticeStatus = reformNotice.getNoticeStatus();
        reformNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_DISCARD.getCode()));
        reformNotice.setCancelReason(cancelReason);
        reformNotice.setCancelDate(new Date());
        reformNotice.setCancelUserId(RequestContext.getExeUserId());
        reformNotice.setNextExecuteUserIds(null);
        reformNotice.setPromoter(null);
        this.updateById(reformNotice);
        // 2.更新关联的业务
        this.processElseDataByStatus(Objects.requireNonNull(FlowStatusEnum.getEumByCode(Integer.parseInt(oldNoticeStatus))), reformNotice);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                eventPublisher.publish(new CancellationEvent(this, getEquList(reformNotice)));
            }
        });
        return reformNotice;
    }

    private List<String> getEquList(JgReformNotice reformNotice) {
        LambdaQueryWrapper<JgReformNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JgReformNoticeEq::getEquipTransferId, reformNotice.getSequenceNbr());
        List<JgReformNoticeEq> reformNoticeEqs = jgReformNoticeEqMapper.selectList(queryWrapper);
        return reformNoticeEqs.stream().map(JgReformNoticeEq::getEquId).collect(Collectors.toList());
    }

    private void processElseDataByStatus(FlowStatusEnum oldNoticeStatus, JgReformNotice reformNotice) {
        switch (oldNoticeStatus) {
            case TO_BE_SUBMITTED: // 待提交
                // 1.删除暂存时生成的待办
                commonService.deleteTasksByRelationId(reformNotice.getSequenceNbr() + "");
                // 4.记录到历史表
                this.recordHistoryWhenVoided(reformNotice);
                break;
            case TO_BE_FINISHED: // 已完成
                // 1.清空redis 缓存的流程中及已完成安装告知的设备
                this.delRepeatUseEquipData(reformNotice);
                break;
            default:
                // 流程中（驳回、撤回等）
                // 1.待办任务更新为已完成
                this.finishedTask(reformNotice);
                // 2.终止流程-工作流报错暂时注释掉
                iCmWorkflowService.stopProcess(reformNotice.getInstanceId(), reformNotice.getCancelReason());
                // 3.清空redis（缓存的流程中及已完成安装告知的设备）
                this.delRepeatUseEquipData(reformNotice);
                // 4.记录到历史表
                this.recordHistoryWhenVoided(reformNotice);
        }
    }

    private void finishedTask(JgReformNotice reformNotice) {
        HashMap<String, Object> taskMap = new HashMap<>();
        taskMap.put("taskStatus", FlowStatusEnum.TO_BE_FINISHED.getCode());
        taskMap.put("taskStatusLabel", FlowStatusEnum.TO_BE_FINISHED.getName());
        taskMap.put("flowStatus", FlowStatusEnum.TO_BE_FINISHED.getCode());
        taskMap.put("flowStatusLabel", FlowStatusEnum.TO_BE_FINISHED.getName());
        taskMap.put("relationId", reformNotice.getInstanceId());
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtils.copyProperties(reformNotice, taskMessageDto);
        taskMap.put("model", taskMessageDto);
        commonService.updateTaskModel(taskMap);
    }

    /**
     * 作废时记录数据到历史表
     * @param reformNotice
     */
    private void recordHistoryWhenVoided(JgReformNotice reformNotice) {
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(reformNotice));
        List<String> equList = getEquList(reformNotice);
        Iterable<ESEquipmentCategoryDto> esEquipmentCategoryDtos = esEquipmentCategory.findAllById(equList);
        List<Map<String, Object>> deviceList = getEquipListMaps(esEquipmentCategoryDtos);
        jsonObject.put("deviceList", deviceList);
        this.saveHisDataBeforeUpdate(String.valueOf(reformNotice.getSequenceNbr()), jsonObject);
    }

    @Override
    public boolean beforeCheck(JgReformNotice jgReformNotice) {
        return jgReformNotice.getInstanceId() != null && !jgReformNotice.getNoticeStatus().equals(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode())) &&!jgReformNotice.getNoticeStatus().equals(String.valueOf(FlowStatusEnum.TO_BE_DISCARD.getCode()));
    }

    @Override
    public void compensate(JgReformNotice jgReformNotice) {
        commonService.saveExecuteFlowData2Redis(jgReformNotice.getInstanceId(), this.buildInstanceRuntimeData(jgReformNotice));
    }

}