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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
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.conditions.update.LambdaUpdateWrapper;
import com.yeejoin.amos.boot.biz.common.utils.SnowflakeIdUtil;
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.*;
import com.yeejoin.amos.boot.module.jg.biz.utils.WordTemplateUtils;
import com.yeejoin.amos.boot.module.ymt.api.entity.*;
import com.yeejoin.amos.boot.module.ymt.api.enums.ApplicationFormTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.*;
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.RequiredArgsConstructor;
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;

import static com.alibaba.fastjson.JSON.toJSONString;

/**
 * 改造告知服务实现类
 *
 * @author system_generator
 * @date 2023-12-19
 */
@Service
@Slf4j
@RequiredArgsConstructor
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";
    public static final String DEVICE_LIST = "deviceList";
    public static final String PIPE_LENGTH = "pipeLength";
    public static final String RECORD = "record";
    public static final String SEQUENCE_NBR = "SEQUENCE_NBR";
    public static final String PROJECT_CONTRAPTION = "projectContraption";
    public static final String EQU_LIST_CODE = "EQU_LIST_CODE";
    public static final String EQU_CATEGORY_CODE = "EQU_CATEGORY_CODE";
    public static final String EQUIP_INFO = "equipInfo";
    public static final String PROJECT_CONTRAPTION_ID = "projectContraptionId";
    public static final String PRODUCT_PHOTO = "PRODUCT_PHOTO";
    public static final String PRODUCT_QUALIFICATION_CERTIFICATE = "PRODUCT_QUALIFICATION_CERTIFICATE";
    public static final String OTHER_ACCESSORIES = "OTHER_ACCESSORIES";
    public static final String DEL_DEVICE_LIST = "delDeviceList";
    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";
    private final EquipmentCategoryMapper equipmentCategoryMapper;
    private final JgReformNoticeEqMapper jgReformNoticeEqMapper;
    private final JgReformNoticeEqServiceImpl jgReformNoticeEqService;
    private final RegistrationInfoMapper tzsJgRegistrationInfoMapper;
    private final OtherInfoMapper otherInfoMapper;
    private final TzsServiceFeignClient tzsServiceFeignClient;
    private final IdxBizJgProjectContraptionMapper idxBizJgProjectContraptionMapper;
    private final RedisUtils redisUtils;
    private final SnowflakeIdUtil sequence;
    private final JgRegistrationHistoryServiceImpl jgRegistrationHistoryService;
    private final JgInstallationNoticeServiceImpl jgInstallationNoticeService;
    private final JgReformNoticeMapper jgReformNoticeMapper;
    private final CommonServiceImpl commonService;
    private final CmWorkflowServiceImpl cmWorkflowService;
    private final RedissonClient redissonClient;
    private final JgRegistrationHistoryMapper jgRegistrationHistoryMapper;
    private final SuperviseInfoMapper superviseInfoMapper;
    private final ESEquipmentCategory esEquipmentCategory;
    private final EventPublisher eventPublisher;
    private final ICmWorkflowService iCmWorkflowService;
    private final IIdxBizJgUseInfoService idxBizJgUseInfoService;
    private final IdxBizJgDesignInfoServiceImpl idxBizJgDesignInfoService;
    private final IIdxBizJgConstructionInfoService iIdxBizJgConstructionInfoService;
    private final IdxBizJgFactoryInfoServiceImpl idxBizJgFactoryInfoService;
    private final IdxBizJgRegisterInfoServiceImpl idxBizJgRegisterInfoServiceImpl;
    private final IIdxBizJgOtherInfoService iIdxBizJgOtherInfoService;
    private final IIdxBizJgSupervisionInfoService iIdxBizJgSupervisionInfoService;
    private final IdxBizJgInspectionDetectionInfoServiceImpl idxBizJgInspectionDetectionInfoService;
    private final IIdxBizJgTechParamsPipelineService iIdxBizJgTechParamsPipelineService;
    private final JgUseRegistrationServiceImpl useRegistrationService;

    /**
     * 根据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())
                || EquipmentClassifityEnum.YLGD.getCode().equals(notice.getEquListCode())) {
            // 完成 或 作废时显示历史数据（压力管道也显示历史数据）
            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(DEVICE_LIST, 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);
    }

    /**
     * 更新改造告知
     */
    @SuppressWarnings({"rawtypes", "Duplicates"})
    public JgReformNoticeDto updateNotice(String submitType, Map<String, Object> noticeMap, String op) {
        try {
            String noticeJsonStr = JSON.toJSONString(noticeMap);
            JgReformNoticeDto noticeDto = JSON.parseObject(noticeJsonStr, JgReformNoticeDto.class);
            if (Objects.isNull(noticeDto) || StringUtils.isEmpty(submitType)) {
                throw new IllegalArgumentException("参数不能为空");
            }
            // 压力管道使用
            JSONObject oldPipJsonData = new JSONObject();
            // 字段转换
            this.convertField(noticeDto);
            JgReformNotice notice = this.getById(noticeDto.getSequenceNbr());
            // 业务单据中的设备主键 管道的为record 其他设备为SEQUENCE_NBR
            String equSeq = !EquipmentClassifityEnum.YLGD.getCode().equals(notice.getEquListCode()) ? SEQUENCE_NBR : RECORD;
            List<Map<String, Object>> deviceList = noticeDto.getDeviceList();
            // 管道校验管道编号不重复
            this.verifyThatThePipeNumberIsUnique(notice.getEquListCode(), deviceList);
            List<String> records = deviceList.stream().filter(item -> !Objects.isNull(item.get(RECORD))).map(equ -> String.valueOf(equ.get(RECORD))).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());
                    // 压力管道情况处理
                    if (EquipmentClassifityEnum.YLGD.getCode().equals(notice.getEquListCode())) {
                        oldPipJsonData = this.getNowPipJsonData(noticeDto.getProjectContraptionId());
                        notice.setPipeLengthChanged(this.calculatePipeLengthChange(JSONArray.parseArray(JSON.toJSONString(oldPipJsonData.get(DEVICE_LIST))),
                                                                                   JSONArray.parseArray(JSON.toJSONString(noticeDto.getDeviceList()))));
                    }
                    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());
                    // 上个代办改为已办
                    TaskV2Model taskV2Model = this.updateLastTodo(notice, FlowStatusEnum.TO_BE_PROCESSED);
                    // 创建新的代办
                    this.createNewTodo(notice, workflowResultDto, taskV2Model, FlowStatusEnum.TO_BE_PROCESSED);
                    // 压力管道情况处理
                    if (EquipmentClassifityEnum.YLGD.getCode().equals(notice.getEquListCode())) {
                        oldPipJsonData = this.getNowPipJsonData(noticeDto.getProjectContraptionId());
                        notice.setPipeLengthChanged(this.calculatePipeLengthChange(JSONArray.parseArray(JSON.toJSONString(oldPipJsonData.get(DEVICE_LIST))),
                                                                                   JSONArray.parseArray(JSON.toJSONString(noticeDto.getDeviceList()))));
                    }
                    this.updateById(notice);
                }
                commonService.saveExecuteFlowData2Redis(notice.getInstanceId(), this.buildInstanceRuntimeData(notice));
            } else {
                JgReformNotice bean = new JgReformNotice();
                BeanUtils.copyProperties(noticeDto, bean);
                jgReformNoticeMapper.updateById(bean);
            }
            this.saveOrUpdateHisData(String.valueOf(noticeDto.getSequenceNbr()), JSONObject.parseObject(noticeJsonStr), oldPipJsonData);
            jgReformNoticeEqMapper.delete(new LambdaQueryWrapper<JgReformNoticeEq>()
                                                  .eq(JgReformNoticeEq::getEquipTransferId, notice.getSequenceNbr()));
            // eq关系表
            List<JgReformNoticeEq> noticeEqs = new ArrayList<>();
            // 更新设备关系表
            deviceList.stream().filter(obj -> !Objects.isNull(obj.get(equSeq)))
                    .forEach(obj -> {
                        JgReformNoticeEq jgRelationEquip = new JgReformNoticeEq();
                        jgRelationEquip.setEquId(String.valueOf(obj.get(equSeq)));
                        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);
            });
            // 压力管道添加作废标识：不在流程中即可作废
            if (EquipmentClassifityEnum.YLGD.getCode().equals(notice.get("equListCode")) && !ValidationUtil.isEmpty(notice.get("projectContraptionId"))) {
                notice.put("canVoided", idxBizJgProjectContraptionMapper.countContraptionInUseTimesForDeleteByIntoManagement(Long.parseLong(String.valueOf(notice.get("projectContraptionId")))) == 0);
            }
        }).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<>();
        // 管道按照装置打一份告知书
        if (EquipmentClassifityEnum.YLGD.getCode().equals(notice.getEquListCode()) && !noticeEqs.isEmpty()) {
            Map<String, Object> information = jgReformNoticeMapper.queryEquipInformation(noticeEqs.get(0).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);
        } else {
            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);
            String equListCode = String.valueOf(jsonObject.get(EQU_LIST_CODE));
            String equCategoryCode = String.valueOf(jsonObject.get(EQU_CATEGORY_CODE));
            // 压力管道使用
            JSONObject oldPipJsonData = new JSONObject();
            List<JgReformNoticeEq> noticeEqs = new ArrayList<>();
            // 获取告知设备列表
            List<Map<String, Object>> deviceList = model.getDeviceList();
            // 业务单据中的设备主键 管道的为record 其他设备为SEQUENCE_NBR
            String equSeq = !EquipmentClassifityEnum.YLGD.getCode().equals(equListCode) ? SEQUENCE_NBR : RECORD;
            if (CollectionUtils.isEmpty(deviceList)) {
                throw new BadRequest("请选择设备!");
            }
            // 管道校验管道编号不重复
            this.verifyThatThePipeNumberIsUnique(equListCode, deviceList);
            // 提交时对设备状态进行校验（处理并发问题，一个未被使用的设备同时被多个使用这打开，同时提交发起申请） 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(PROJECT_CONTRAPTION)) ? "" : String.valueOf(jsonObject.get(PROJECT_CONTRAPTION)));
            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()));
            }
            // 压力管道情况处理
            if (EquipmentClassifityEnum.YLGD.getCode().equals(equListCode)) {
                oldPipJsonData = this.getNowPipJsonData(String.valueOf(jsonObject.get(PROJECT_CONTRAPTION_ID)));
                notice.setPipeLengthChanged(this.calculatePipeLengthChange(JSONArray.parseArray(JSON.toJSONString(oldPipJsonData.get(DEVICE_LIST))),
                                                                           JSONArray.parseArray(JSON.toJSONString(jsonObject.get(DEVICE_LIST)))));
            }
            this.saveOrUpdateHisData(String.valueOf(sequenceNbr), jsonObject, oldPipJsonData);
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                this.buildTask(notice, workflowResultList);
            } else {
                this.saveTempReformNotice(notice);
            }
            // 插入业务单
            jgReformNoticeMapper.insert(notice);
            // 更新设备关系表
            deviceList.stream().filter(obj -> !Objects.isNull(obj.get(equSeq)))
                    .map(obj -> new JgReformNoticeEq()
                            .setEquId(obj.get(equSeq).toString())
                            .setEquipTransferId(String.valueOf(sequenceNbr)))
                    .forEach(noticeEqs::add);
            jgReformNoticeEqMapper.insertBatchSomeColumn(noticeEqs);
            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();
        }
    }

    /**
     * 压力管道校验管道编号不能重复
     *
     * @param equListCode 设备种类
     * @param deviceList  设备列表
     */
    public void verifyThatThePipeNumberIsUnique(String equListCode, List<Map<String, Object>> deviceList) {
        if (EquipmentClassifityEnum.YLGD.getCode().equals(equListCode)) {
            if (!CollectionUtils.isEmpty(deviceList) && deviceList.size() != deviceList.stream()
                    .map(v -> (String) v.get("pipelineNumber"))
                    .distinct()
                    .count()) {
                throw new BadRequest("同一工程装置下管道编号不能重复！");
            }
        }
    }

    /**
     * 计算管道长度变化 正值为增长，负值为减少
     *
     * @param oldPipData 旧管道数据
     * @param newPipData 新管道数据
     * @return 管道长度变化，正值为增长，负值为减少
     */
    private String calculatePipeLengthChange(JSONArray oldPipData, JSONArray newPipData) {
        double oldPipLen = oldPipData.stream().mapToDouble(item -> JSONObject.parseObject(item.toString()).getDoubleValue(PIPE_LENGTH)).sum();
        double newPipLen = newPipData.stream().mapToDouble(item -> JSONObject.parseObject(item.toString()).getDoubleValue(PIPE_LENGTH)).sum();
        double change = newPipLen - oldPipLen;
        return change == 0 ? "0" : String.format("%+.2f", change);
    }

    private JSONObject getNowPipJsonData(String projectContraptionId) {
        return new JSONObject(Optional.ofNullable(idxBizJgProjectContraptionMapper.getDetail(projectContraptionId))
                                      .map(map -> {
                                          commonService.convertStringToJsonobject(map, IdxBizJgProjectContraptionServiceImpl.jsonFields);
                                          map.put(DEVICE_LIST, idxBizJgProjectContraptionMapper.selectEquipList((String) map.get(SEQUENCE_NBR)));
                                          return map;
                                      })
                                      .orElse(Collections.emptyMap()));
    }

    private void repeatUsedEquipCheck(List<Map<String, Object>> equipList, String companyCode) {
        equipList.stream().filter(item -> !Objects.isNull(item.get(RECORD))).forEach(equipMap -> EquipUsedCheckStrategyContext.getUsedStrategy(PROCESS_DEFINITION_KEY).equipRepeatUsedCheck(String.valueOf(equipMap.get(RECORD)), companyCode));
    }

    private void checkRepeatUsed(String submitType, List<String> records, JgReformNotice jgReformNotice) {
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            // 流程中校验
            records.stream().filter(item -> !Objects.isNull(item)).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  通过或驳回
     */
    @GlobalTransactional(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);
                    });
                    jgReformNotice.setAcceptDate(new Date());
                    jgReformNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode()));
                    jgReformNotice.setPromoter("");
                    // 压力管道情况处理
                    this.YLGDDataPassHandler(jgReformNotice);
                    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();
            }
        }
    }

    /**
     * redis获取用户信息
     **/
    protected ReginParams getSelectedOrgInfo() {
        return JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
    }

    private void YLGDDataPassHandler(JgReformNotice notice) {
        if (!EquipmentClassifityEnum.YLGD.getCode().equals(notice.getEquListCode())) {
            return;
        }
        // 1.更新工程装置数据
        JgRegistrationHistory registrationHistory = jgRegistrationHistoryMapper.selectOne(new LambdaQueryWrapper<JgRegistrationHistory>().eq(JgRegistrationHistory::getCurrentDocumentId, notice.getSequenceNbr()));
        JSONObject newData = JSONObject.parseObject(registrationHistory.getChangeData());
        JSONArray newPipData = Optional.ofNullable(JSONArray.parseArray(newData.getString(DEVICE_LIST))).orElse(new JSONArray());
        JSONArray delPipData = Optional.ofNullable(JSONArray.parseArray(newData.getString(DEL_DEVICE_LIST))).orElse(new JSONArray());
        // JSONObject oldData = JSONObject.parseObject(registrationHistory.getOldData());
        // JSONArray oldPipData = JSONArray.parseArray(oldData.getString(DEVICE_LIST));
        // 1.1更新工程装置中的【管道信息】增加减少或修改管道信息
        List<JSONObject> toUpdatePipData = newPipData.stream().filter(item -> !StringUtils.isEmpty(JSON.parseObject(item.toString()).getString(RECORD))).map(item -> JSON.parseObject(item.toString())).collect(Collectors.toList());
        List<JSONObject> toAddPipData = newPipData.stream().filter(item -> StringUtils.isEmpty(JSON.parseObject(item.toString()).getString(RECORD))).map(item -> JSON.parseObject(item.toString())).collect(Collectors.toList());
        List<String> toDeletePipRecords = delPipData.stream().map(item -> JSON.parseObject(item.toString()).getString(RECORD)).collect(Collectors.toList());
        this.addPipDataWithFlowPass(toAddPipData, notice);
        this.updatePipDataWithFlowPass(toUpdatePipData);
        this.delPipDataWithFlowPass(toDeletePipRecords);
        // 1.2更新工程装置中的【基本信息】 + 【使用信息】 + 管道长度等
        // List<String> lastAllRecords = new ArrayList<>();
        // lastAllRecords.addAll(toUpdatePipRecords);
        // lastAllRecords.addAll(toAddPipDataRecords);
        // lastAllRecords.forEach(record -> {
        // 产品照片 PRODUCT_PHOTO
        // String productPhoto = JSON.toJSONString(newData.get(PRODUCT_PHOTO));
        // idxBizJgRegisterInfoService.update(new LambdaUpdateWrapper<IdxBizJgRegisterInfo>().set(IdxBizJgRegisterInfo::getProductPhoto, productPhoto).eq(IdxBizJgRegisterInfo::getRecord, record));

        // });
        // 产品质量合格证明 PRODUCT_QUALIFICATION_CERTIFICATE 其他附件 OTHER_ACCESSORIES 管道总长度
        // String productQualificationCertificate = JSON.toJSONString(newData.get(PRODUCT_QUALIFICATION_CERTIFICATE));
        // String otherAccessories = JSON.toJSONString(newData.get(OTHER_ACCESSORIES));
        double pipLengthLastSum = newPipData.stream().mapToDouble(item -> JSONObject.parseObject(item.toString()).getDoubleValue(PIPE_LENGTH)).sum();
        LambdaUpdateWrapper<IdxBizJgProjectContraption> updateWrapper = new LambdaUpdateWrapper<IdxBizJgProjectContraption>()
                .eq(IdxBizJgProjectContraption::getSequenceNbr, notice.getProjectContraptionId())
                // .set(IdxBizJgProjectContraption::getProductQualificationCertificate, productQualificationCertificate)
                // .set(IdxBizJgProjectContraption::getOtherAccessories, otherAccessories)
                .set(IdxBizJgProjectContraption::getPipelineLength, pipLengthLastSum)
                .set(IdxBizJgProjectContraption::getPipeLengthChanged, notice.getPipeLengthChanged());
        idxBizJgProjectContraptionMapper.update(null, updateWrapper);
    }

    private void delPipDataWithFlowPass(List<String> toDeletePipRecords) {
        if (toDeletePipRecords.isEmpty()) {
            return;
        }
        List<ESEquipmentCategoryDto> esEquipmentCategoryDtoList = toDeletePipRecords.stream().map(
                record -> new ESEquipmentCategoryDto().setSEQUENCE_NBR(record)
        ).collect(Collectors.toList());
        // 删除涉及的19张表的数据
        superviseInfoMapper.deleteDataAll(toDeletePipRecords);
        // 删除es中的数据
        esEquipmentCategory.deleteAll(esEquipmentCategoryDtoList);
    }

    private void updatePipDataWithFlowPass(List<JSONObject> toUpdatePipData) {
        toUpdatePipData.forEach(pipData -> {
            String record = pipData.getString(RECORD);
            String pipeName = pipData.getString("pipeName");
            String pipelineNumber = pipData.getString("pipelineNumber");
            String deviceLevel = pipData.getString("deviceLevel");
            String nominalDiameter = pipData.getString("nominalDiameter");
            String wallThickness = pipData.getString("wallThickness");
            String pipeLength = pipData.getString("pipeLength");
            String pressure = pipData.getString("pressure");
            String temperature = pipData.getString("temperature");
            String medium = pipData.getString("medium");
            String workPressure = pipData.getString("workPressure");
            String workTemperature = pipData.getString("workTemperature");
            String workMedium = pipData.getString("workMedium");
            String remarks = pipData.getString("remarks");
            LambdaUpdateWrapper<IdxBizJgTechParamsPipeline> pipelineLambdaUpdateWrapper = new LambdaUpdateWrapper<IdxBizJgTechParamsPipeline>().eq(IdxBizJgTechParamsPipeline::getRecord, record)
                    .set(IdxBizJgTechParamsPipeline::getPipeName, pipeName)
                    .set(IdxBizJgTechParamsPipeline::getPipelineNumber, pipelineNumber)
                    .set(IdxBizJgTechParamsPipeline::getDeviceLevel, deviceLevel)
                    .set(IdxBizJgTechParamsPipeline::getNominalDiameter, nominalDiameter)
                    .set(IdxBizJgTechParamsPipeline::getWallThickness, wallThickness)
                    .set(IdxBizJgTechParamsPipeline::getPipeLength, pipeLength)
                    .set(IdxBizJgTechParamsPipeline::getPressure, pressure)
                    .set(IdxBizJgTechParamsPipeline::getTemperature, temperature)
                    .set(IdxBizJgTechParamsPipeline::getMedium, medium)
                    .set(IdxBizJgTechParamsPipeline::getWorkPressure, workPressure)
                    .set(IdxBizJgTechParamsPipeline::getWorkTemperature, workTemperature)
                    .set(IdxBizJgTechParamsPipeline::getWorkMedium, workMedium)
                    .set(IdxBizJgTechParamsPipeline::getRemarks, remarks);
            iIdxBizJgTechParamsPipelineService.update(pipelineLambdaUpdateWrapper);

        });
    }

    private void addPipDataWithFlowPass(List<JSONObject> toAddPipData, JgReformNotice notice) {

        IdxBizJgProjectContraption projectContraption = idxBizJgProjectContraptionMapper.selectById(notice.getProjectContraptionId());
        List<IdxBizJgUseInfo> useInfoList = new ArrayList<>(15);
        List<IdxBizJgDesignInfo> designInfoList = new ArrayList<>(15);
        List<IdxBizJgFactoryInfo> factoryInfoList = new ArrayList<>(15);
        List<IdxBizJgConstructionInfo> constructionInfoList = new ArrayList<>(15);
        List<IdxBizJgRegisterInfo> registerInfoList = new ArrayList<>(15);
        List<IdxBizJgSupervisionInfo> supervisionInfoList = new ArrayList<>(15);
        List<IdxBizJgOtherInfo> otherInfoList = new ArrayList<>(15);
        List<IdxBizJgInspectionDetectionInfo> inspectionDetectionInfoList = new ArrayList<>(15);
        List<IdxBizJgTechParamsPipeline> paramsPipelineList = new ArrayList<>(15);
        List<ESEquipmentCategoryDto> esEquipmentCategoryList = new ArrayList<>(15);
        // eq关系表
        List<JgReformNoticeEq> noticeEqs = new ArrayList<>(15);
        // 设备信息
        toAddPipData.forEach(pipData -> {
            String record = UUID.randomUUID().toString();
            Date date = new Date();
            // eq表
            JgReformNoticeEq jgRelationEquip = new JgReformNoticeEq();
            jgRelationEquip.setEquId(record);
            jgRelationEquip.setEquipTransferId(String.valueOf(notice.getSequenceNbr()));
            noticeEqs.add(jgRelationEquip);
            // 使用信息
            IdxBizJgUseInfo useInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgUseInfo.class);
            useInfo.setRecord(record);
            useInfo.setSequenceNbr(null);
            useInfo.setRecDate(date);
            useInfo.setDataSource("jg");
            useInfo.setIsIntoManagement(Boolean.TRUE);
            useInfo.setUseUnitCreditCode(notice.getUseUnitCreditCode());
            useInfo.setUseUnitName(notice.getUseUnitName());
            useInfo.setEquState("1");
            useInfo.setProjectContraption(notice.getProjectContraption());
            useInfo.setProjectContraptionId(notice.getProjectContraptionId());
            useInfoList.add(useInfo);

            // 设计信息
            IdxBizJgDesignInfo designInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgDesignInfo.class);
            designInfo.setRecord(record);
            designInfo.setRecDate(date);
            designInfo.setSequenceNbr(null);
            designInfoList.add(designInfo);

            // 制造信息
            IdxBizJgFactoryInfo factoryInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgFactoryInfo.class);
            factoryInfo.setRecord(record);
            factoryInfo.setRecDate(date);
            factoryInfo.setSequenceNbr(null);
            factoryInfoList.add(factoryInfo);

            // 施工信息
            IdxBizJgConstructionInfo constructionInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgConstructionInfo.class);
            constructionInfo.setRecord(record);
            constructionInfo.setRecDate(date);
            constructionInfo.setSequenceNbr(null);
            constructionInfoList.add(constructionInfo);

            // 注册登记信息
            IdxBizJgRegisterInfo registerInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgRegisterInfo.class);
            registerInfo.setRecord(record);
            registerInfo.setRecDate(date);
            registerInfo.setSequenceNbr(null);
            registerInfo.setEquCodeType("2");
            registerInfo.setRegisterState("6045");
            registerInfo.setEquCode(useRegistrationService.generateEquCode(projectContraption.getEquList(), projectContraption.getEquCategory(), projectContraption.getEquDefine(), date, notice.getReceiveCompanyCode()));
            registerInfo.setProductName(pipData.getString("pipeName"));
            registerInfoList.add(registerInfo);

            // 监督管理
            IdxBizJgSupervisionInfo supervisionInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgSupervisionInfo.class);
            supervisionInfo.setRecord(record);
            supervisionInfo.setRecDate(date);
            supervisionInfo.setSequenceNbr(null);
            supervisionInfoList.add(supervisionInfo);

            // 其他信息
            IdxBizJgOtherInfo otherInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgOtherInfo.class);
            otherInfo.setRecord(record);
            otherInfo.setSequenceNbr(null);
            otherInfo.setClaimStatus("已认领");
            otherInfo.setRecDate(date);
            otherInfo.setSupervisoryCode(projectContraption.getSupervisoryCode());
            otherInfo.setCylinderStampAttachment("");
            otherInfo.setInformationSituation("");
            otherInfo.setInformationManageCode("");
            otherInfoList.add(otherInfo);

            // 检验检测
            IdxBizJgInspectionDetectionInfo inspectionDetectionInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgInspectionDetectionInfo.class);
            if (!BeanUtil.isEmpty(inspectionDetectionInfo)) {
                inspectionDetectionInfo.setRecord(record);
                inspectionDetectionInfo.setRecDate(date);
                Optional.ofNullable(inspectionDetectionInfo.getNextInspectDate()).ifPresent(x -> inspectionDetectionInfo.setNextInspectDate(DateUtil.parse(DateUtil.format(inspectionDetectionInfo.getNextInspectDate(), DatePattern.NORM_DATE_PATTERN))));
                inspectionDetectionInfo.setSequenceNbr(null);
                idxBizJgInspectionDetectionInfoService.saveOrUpdateData(inspectionDetectionInfo);
            }

            // 管道技术参数
            IdxBizJgTechParamsPipeline pipelineInfo = JSON.parseObject(toJSONString(pipData), IdxBizJgTechParamsPipeline.class);
            if (!ValidationUtil.isEmpty(pipelineInfo)) {
                pipelineInfo.setRecord(record);
                pipelineInfo.setRecDate(date);
                pipelineInfo.setSequenceNbr(null);
                paramsPipelineList.add(pipelineInfo);
            }


            ESEquipmentCategoryDto esEquipmentDto = JSON.parseObject(toJSONString(pipData), ESEquipmentCategoryDto.class);
            esEquipmentDto.setDATA_SOURCE(useInfo.getDataSource());
            esEquipmentDto.setREC_DATE(System.currentTimeMillis());
            esEquipmentDto.setSEQUENCE_NBR(record);
            esEquipmentDto.setIS_INTO_MANAGEMENT(false);
            esEquipmentDto.setEQU_CATEGORY_CODE(projectContraption.getEquCategory());
            esEquipmentDto.setEQU_CATEGORY(projectContraption.getEquCategoryName());
            esEquipmentDto.setEQU_LIST_CODE(projectContraption.getEquList());
            esEquipmentDto.setEQU_LIST(projectContraption.getEquListName());
            esEquipmentDto.setEQU_DEFINE_CODE(projectContraption.getEquDefine());
            esEquipmentDto.setEQU_DEFINE(projectContraption.getEquDefineName());
            esEquipmentDto.setSTATUS("已认领");
            esEquipmentDto.setUSC_UNIT_CREDIT_CODE(projectContraption.getUscUnitCreditCode());
            esEquipmentDto.setUSC_UNIT_NAME(projectContraption.getUscUnitName());
            esEquipmentDto.setUSE_UNIT_CREDIT_CODE(projectContraption.getUseUnitCreditCode());
            esEquipmentDto.setUSE_UNIT_NAME(projectContraption.getUseUnitName());
            esEquipmentDto.setPROJECT_CONTRAPTION(projectContraption.getProjectContraption());
            esEquipmentDto.setPRODUCT_NAME(pipelineInfo.getPipeName());
            esEquipmentDto.setProjectContraptionId(notice.getProjectContraptionId());
            esEquipmentCategoryList.add(esEquipmentDto);
        });
        idxBizJgUseInfoService.saveBatch(useInfoList);
        idxBizJgDesignInfoService.saveBatch(designInfoList);
        iIdxBizJgConstructionInfoService.saveBatch(constructionInfoList);
        idxBizJgFactoryInfoService.saveBatch(factoryInfoList);
        idxBizJgRegisterInfoServiceImpl.saveBatch(registerInfoList);
        iIdxBizJgOtherInfoService.saveBatch(otherInfoList);
        iIdxBizJgSupervisionInfoService.saveBatch(supervisionInfoList);
        idxBizJgInspectionDetectionInfoService.saveBatch(inspectionDetectionInfoList);
        iIdxBizJgTechParamsPipelineService.saveBatch(paramsPipelineList);
        esEquipmentCategory.saveAll(esEquipmentCategoryList);
        jgReformNoticeEqService.saveBatch(noticeEqs);
    }


    private void saveOrUpdateHisData(String sequenceNbr, JSONObject changeData, JSONObject oldData) {
        this.saveOrUpdateHistory(BusinessTypeEnum.JG_MODIFICATION_NOTIFICATION.getName(), changeData, oldData, sequenceNbr);
    }

    public void saveOrUpdateHistory(String registrationClass, JSON changeData, JSON oldData, String currentDocumentId) {
        JgRegistrationHistory jgRegistrationHistory = new JgRegistrationHistory();
        LambdaQueryWrapper<JgRegistrationHistory> lambda = new QueryWrapper<JgRegistrationHistory>().lambda();
        lambda.eq(JgRegistrationHistory::getCurrentDocumentId, currentDocumentId);
        lambda.eq(JgRegistrationHistory::getIsDelete, false);
        Integer integer = jgRegistrationHistoryService.getBaseMapper().selectCount(lambda);
        if (integer > 0) {
            jgRegistrationHistory.setChangeData(JSON.toJSONString(changeData));
            jgRegistrationHistory.setOldData(JSON.toJSONString(oldData));
            jgRegistrationHistoryService.update(jgRegistrationHistory, lambda);
        } else {
            jgRegistrationHistory.setChangeData(JSON.toJSONString(changeData));
            jgRegistrationHistory.setOldData(JSON.toJSONString(oldData));
            jgRegistrationHistory.setStatus("new");
            jgRegistrationHistory.setRegistrationClass(registrationClass);
            jgRegistrationHistory.setEquId(null);
            jgRegistrationHistory.setCurrentDocumentId(currentDocumentId);
            jgRegistrationHistoryService.save(jgRegistrationHistory);
        }
    }

    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);
                // 2.压力管道回退到改造前的设备数据
                this.fallbackDataWithFlowPass(reformNotice);
                break;
            default:
                // 流程中（驳回、撤回等）
                // 1.待办任务更新为已完成
                this.finishedTask(reformNotice);
                // 2.终止流程-工作流报错暂时注释掉
                iCmWorkflowService.stopProcess(reformNotice.getInstanceId(), reformNotice.getCancelReason());
                // 3.清空redis（缓存的流程中及已完成安装告知的设备）
                this.delRepeatUseEquipData(reformNotice);
                // 4.记录到历史表
                this.recordHistoryWhenVoided(reformNotice);
        }
    }

    /**
     * 压力管道回退到改造前的设备数据
     *
     * @param notice
     */
    private void fallbackDataWithFlowPass(JgReformNotice notice) {
        if (!EquipmentClassifityEnum.YLGD.getCode().equals(notice.getEquListCode())) {
            return;
        }
        JgRegistrationHistory registrationHistory = jgRegistrationHistoryMapper.selectOne(new LambdaQueryWrapper<JgRegistrationHistory>().eq(JgRegistrationHistory::getCurrentDocumentId, notice.getSequenceNbr()));
        JSONObject newData = Optional.ofNullable(JSONObject.parseObject(registrationHistory.getChangeData())).orElse(new JSONObject());
        JSONArray alreadyDelPipData = Optional.ofNullable(JSONArray.parseArray(newData.getString(DEL_DEVICE_LIST))).orElse(new JSONArray());
        JSONObject oldData = Optional.ofNullable(JSONObject.parseObject(registrationHistory.getOldData())).orElse(new JSONObject());
        JSONArray oldPipData = Optional.ofNullable(JSONArray.parseArray(oldData.getString(DEVICE_LIST))).orElse(new JSONArray());
        double oldPipLength = oldPipData.stream().mapToDouble(item -> JSON.parseObject(item.toString()).getDoubleValue(PIPE_LENGTH)).sum();
        List<String> oldPipDataRecords = oldPipData.stream().map(item -> JSON.parseObject(item.toString()).getString(RECORD)).collect(Collectors.toList());
        List<String> nowPipDataRecords = idxBizJgProjectContraptionMapper.selectEquipList(notice.getProjectContraptionId()).stream().map(item -> String.valueOf(item.get("record"))).collect(Collectors.toList());
        List<JSONObject> toAddPipData = alreadyDelPipData.stream().map(item -> JSON.parseObject(item.toString())).collect(Collectors.toList());
        List<String> toDeletePipRecords = nowPipDataRecords.stream().filter(item -> !oldPipDataRecords.contains(item)).collect(Collectors.toList());
        this.addPipDataWithFlowPass(toAddPipData, notice);
        this.delPipDataWithFlowPass(toDeletePipRecords);
        LambdaUpdateWrapper<IdxBizJgProjectContraption> updateWrapper = new LambdaUpdateWrapper<IdxBizJgProjectContraption>()
                .eq(IdxBizJgProjectContraption::getSequenceNbr, notice.getProjectContraptionId())
                .set(IdxBizJgProjectContraption::getPipelineLength, oldPipLength)
                .set(IdxBizJgProjectContraption::getPipeLengthChanged, 0);
        idxBizJgProjectContraptionMapper.update(null, updateWrapper);
    }

    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(this.queryBySequenceNbr(reformNotice.getSequenceNbr())));
        // List<String> equList = getEquList(reformNotice);
        // Iterable<ESEquipmentCategoryDto> esEquipmentCategoryDtos = esEquipmentCategory.findAllById(equList);
        // List<Map<String, Object>> deviceList = getEquipListMaps(esEquipmentCategoryDtos);
        // jsonObject.put("deviceList", deviceList);
        this.saveOrUpdateHisData(String.valueOf(reformNotice.getSequenceNbr()), jsonObject, null);
    }

    @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));
    }

}