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

import cn.hutool.core.bean.BeanUtil;
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.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.dao.mapper.DataDictionaryMapper;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
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.*;
import com.yeejoin.amos.boot.module.jg.api.enums.BusinessTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.enums.CompanyTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgInstallationNoticeEqMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgInstallationNoticeMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgRegistrationHistoryMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgUseRegistrationMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgInstallationNoticeService;
import com.yeejoin.amos.boot.module.jg.api.vo.SortVo;
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.feign.TzsServiceFeignClient;
import com.yeejoin.amos.boot.module.jg.biz.service.ICmWorkflowService;
import com.yeejoin.amos.boot.module.jg.biz.service.IIdxBizJgConstructionInfoService;
import com.yeejoin.amos.boot.module.jg.biz.service.IIdxBizJgUseInfoService;
import com.yeejoin.amos.boot.module.jg.biz.utils.CodeUtil;
import com.yeejoin.amos.boot.module.jg.biz.utils.ImageUtils;
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.EquCodeTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.*;
import com.yeejoin.amos.component.robot.AmosRequestContext;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
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.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.GlobalTransactionContext;
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.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
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.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

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

/**
 * 服务实现类
 *
 * @author system_generator
 * @date 2023-12-12
 */
@Service
@Slf4j
public class JgInstallationNoticeServiceImpl extends BaseService<JgInstallationNoticeDto, JgInstallationNotice, JgInstallationNoticeMapper> implements IJgInstallationNoticeService {

    private static final String SUBMIT_TYPE_FLOW = "1";
    private static final String PROCESS_DEFINITION_KEY = "installationNotificationNew";
    private static final String TABLE_PAGE_ID = "1734141426742095873";
    private static final String CONSTRUCTION_TYPE = "SGLX";
    private static final String CONSTRUCTION_TYPE_NAME = "安装";


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

    // 咸阳行政区划code
    private static final String XIAN_YANG = "610400";
    @Value("classpath:/json/urlInfo.json")
    public Resource bizTypeInfo;
    @Autowired
    EquipmentCategoryMapper equipmentCategoryMapper;
    @Autowired
    JgInstallationNoticeEqMapper jgInstallationNoticeEqMapper;
    @Autowired
    JgUseRegistrationMapper jgUseRegistrationMapper;
    @Autowired
    IdxBizJgRegisterInfoServiceImpl idxBizJgRegisterInfoService;
    @Autowired
    IdxBizJgRegisterInfoMapper tzsJgRegistrationInfoMapper;
    @Autowired
    OtherInfoMapper tzsJgOtherInfoMapper;
    @Autowired
    TzsServiceFeignClient tzsServiceFeignClient;
    @Autowired
    IdxBizJgSupervisionInfoMapper idxBizJgSupervisionInfoMapper;
    @Autowired
    SupervisoryCodeInfoMapper supervisoryCodeInfoMapper;
    @Autowired
    SuperviseInfoMapper superviseInfoMapper;
    @Autowired
    IIdxBizJgConstructionInfoService constructionInfoService;
    @Autowired
    IIdxBizJgUseInfoService useInfoService;
    @Autowired
    IdxBizJgUseInfoMapper idxBizJgUseInfoMapper;
    @Value(value = "${tzs.domain:http://sxtzsb.sxsei.com}")
    String TZSDOMAIN;
    @Autowired
    AmosRequestContext amosRequestContext;
    @Autowired
    private Sequence sequence;
    @Autowired
    CodeUtil codeUtil;
    @Autowired
    CommonServiceImpl commonServiceImpl;
    @Autowired
    private JgInstallationNoticeMapper jgInstallationNoticeMapper;
    @Autowired
    private ProduceInfoMapper produceInfoMapper;
    @Autowired
    private DataDictionaryMapper dataDictionaryMapper;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private TzBaseUnitLicenceMapper baseUnitLicenceMapper;
    @Autowired
    private ICmWorkflowService iCmWorkflowService;
    @Autowired
    private CommonServiceImpl commonService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private IdxBizJgConstructionInfoMapper constructionInfoMapper;
    @Autowired
    private ESEquipmentCategory esEquipmentCategory;
    @Autowired
    private JgResumeInfoServiceImpl jgResumeInfoService;
    @Autowired
    private TzBaseEnterpriseInfoMapper tzBaseEnterpriseInfoMapper;
    @Autowired
    private JgRegistrationHistoryMapper jgRegistrationHistoryMapper;
    @Autowired
    JgCertificateChangeRecordServiceImpl certificateChangeRecordService;

    @Autowired
    JgCertificateChangeRecordEqServiceImpl certificateChangeRecordEqService;

    @Autowired
    private IdxBizJgFactoryInfoServiceImpl idxBizJgFactoryInfoService;

    /**
     * 根据sequenceNbr查询
     *
     * @param sequenceNbr 主键
     * @return 安装告知
     */
    @Override
    public Map<String, Map<String, Object>> queryBySequenceNbr(Long sequenceNbr, String companyLevel) {
        // 安装告知信息
        JgInstallationNotice notice = jgInstallationNoticeMapper.selectById(sequenceNbr);
        if (Objects.isNull(notice)) {
            return null;
        }
        Map<String, Object> installationInfo = BeanUtil.beanToMap(notice, false, true);

        installationInfo.put("province", notice.getProvince() + "_" + notice.getProvinceName());
        installationInfo.put("city", notice.getCity() + "_" + notice.getCityName());
        installationInfo.put("county", notice.getCounty() + "_" + notice.getCountyName());

        TzBaseEnterpriseInfo useCodeResult = tzBaseEnterpriseInfoMapper.selectOne(
                new QueryWrapper<TzBaseEnterpriseInfo>()
                        .eq("use_unit_code", notice.getUseUnitCreditCode())
        );

        if (useCodeResult != null) {
            String result = notice.getUseUnitCreditCode() + "_" + notice.getUseUnitName() +
                    ("个人主体".equals(useCodeResult.getUnitType())
                            ? "_" + notice.getUseUnitCreditCode().substring(notice.getUseUnitCreditCode().length() - 4)
                            : "");
            installationInfo.put("useUnitCreditCode", result);
        }
        //installationInfo.put("useUnitCreditCode", notice.getUseUnitCreditCode() + "_" + notice.getUseUnitName());

        installationInfo.put("receiveOrgCreditCode", notice.getReceiveOrgCreditCode() + "_" + notice.getReceiveOrgName());
        installationInfo.put("installLeaderId", notice.getInstallLeaderId() + "_" + notice.getInstallLeaderName());
        if (!ValidationUtil.isEmpty(notice.getInspectUnitId()) && !ValidationUtil.isEmpty(notice.getInspectUnitName())) {
            installationInfo.put("inspectUnitId", notice.getInspectUnitId() + "_" + notice.getInspectUnitName());
        }
        if (!ValidationUtil.isEmpty(notice.getFactoryUseSiteStreet()) && !ValidationUtil.isEmpty(notice.getStreetName())) {
            installationInfo.put("factoryUseSiteStreet", notice.getFactoryUseSiteStreet() + "_" + notice.getStreetName());
        }
        if (!ValidationUtil.isEmpty(notice.getOrgBranchCode()) && !ValidationUtil.isEmpty(notice.getOrgBranchName())) {
            installationInfo.put("orgBranchCode", notice.getOrgBranchCode() + "_" + notice.getOrgBranchName());
        }

        if (!ValidationUtil.isEmpty(notice.getPropertyUnitCreditCode()) && !ValidationUtil.isEmpty(notice.getPropertyUnitName())) {
            //installationInfo.put("propertyUnitName", notice.getPropertyUnitCreditCode() + "_" + notice.getPropertyUnitName());
            TzBaseEnterpriseInfo useCodeResult1 = tzBaseEnterpriseInfoMapper.selectOne(
                    new QueryWrapper<TzBaseEnterpriseInfo>()
                            .eq("use_unit_code", notice.getPropertyUnitCreditCode())
            );
            if (useCodeResult1 != null) {
                installationInfo.put("propertyUnitName", notice.getPropertyUnitCreditCode() + "_" + notice.getPropertyUnitName() +
                        ("个人主体".equals(useCodeResult1.getUnitType())
                                ? "_" + notice.getPropertyUnitCreditCode().substring(notice.getPropertyUnitCreditCode().length() - 4)
                                : ""));
            }
        }

        String[] fields = {"productPhoto", "designDoc", "designStandard", "factoryStandard",
                "productQualityYieldProve", "insUseMaintainExplain", "inspectReport",
                "proxyStatementAttachment", "installContractAttachment", "otherAccessories"};
        // 设备信息
        List<Map<String, Object>> equipmentInfos = jgInstallationNoticeMapper.queryEquipInformation(sequenceNbr);
        for (String s : fields) {
            if (installationInfo.containsKey(s)) {
                installationInfo.put(s, ObjectUtils.isEmpty(installationInfo.get(s)) ? new JSONArray() : parseArray(installationInfo.get(s).toString()));
            }
        }
        if (Integer.parseInt(notice.getNoticeStatus()) >= FlowStatusEnum.TO_BE_FINISHED.getCode()) {
            // 完成及作废时显示历史数据
            JSONObject hisData = commonService.queryHistoryData(notice.getSequenceNbr());
            // 兼容老数据
            if (hisData == null) {
                Map<String, Object> detail = setNewEquipData(companyLevel, installationInfo, equipmentInfos);
                return new HashMap<String, Map<String, Object>>() {{
                    this.put("installationInfo", detail);
                }};
            } else {
                hisData.putAll(installationInfo);
                CommonServiceImpl.formatTime2StrDateForEquip(hisData);
                return new HashMap<String, Map<String, Object>>() {{
                    this.put("installationInfo", hisData);
                }};
            }
        } else {
            // 显示最新的设备信息
            Map<String, Object> detail = setNewEquipData(companyLevel, installationInfo, equipmentInfos);
            return new HashMap<String, Map<String, Object>>() {{
                this.put("installationInfo", detail);
            }};
        }
    }

    private Map<String, Object> setNewEquipData(String companyLevel, Map<String, Object> installationInfo, List<Map<String, Object>> equipmentInfos) {
        Map<String, Object> detail = equipmentInfos.get(0);
        Map<String, Object> equInfo = idxBizJgRegisterInfoService.getDetailFieldCamelCaseByRecord(detail.get("equId").toString());
        equInfo.put("useUnitCreditCodeUse", equInfo.getOrDefault("useUnitCreditCode", ""));
        equInfo.put("useUnitNameUse", equInfo.getOrDefault("useUnitName", ""));
        equInfo.put("productPhoto", JSON.parse(String.valueOf(detail.get("productPhoto"))));
        equInfo.put("factoryStandard", JSON.parse(String.valueOf(detail.get("factoryStandard"))));
        equInfo.put("productQualityYieldProve", JSON.parse(String.valueOf(detail.get("productQualityYieldProve"))));
        equInfo.put("insUseMaintainExplain", JSON.parse(String.valueOf(detail.get("insUseMaintainExplain"))));
        equInfo.put("inspectReport", JSON.parse(String.valueOf(detail.get("inspectReport"))));
        equInfo.put("designStandard", JSON.parse(String.valueOf(detail.get("designStandard"))));
        equInfo.put("designDoc", JSON.parse(String.valueOf(detail.get("designDoc"))));
        equInfo.put("otherAccessoriesList", JSON.parse(String.valueOf(detail.get("otherAccessories"))));
        BeanUtil.copyProperties(equInfo, detail);
        BeanUtil.copyProperties(installationInfo, detail, "equList", "supervisoryCode", "factoryNum", "equRegisterCode");
        detail.put("companyLevel", companyLevel);
        return detail;
    }

    /**
     * 更新安装告知
     *
     * @param noticeDto 安装告知
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public JgInstallationNoticeDto updateInstallationNotice(String submitType, JgInstallationNoticeDto noticeDto, String op) {
        if (Objects.isNull(noticeDto) || StringUtils.isEmpty(submitType)) {
            throw new IllegalArgumentException("参数不能为空");
        }
        try {
            // 字段转换
            this.convertField(noticeDto);
            JgInstallationNotice notice = this.getById(noticeDto.getSequenceNbr());
            this.checkRepeatUsed(submitType, notice);
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                if (!StringUtils.hasText(noticeDto.getInstanceId())) {
                    // 发起流程
                    ProcessTaskDTO processTaskDTO = new ProcessTaskDTO();
                    WorkflowResultDto workflowResultDto = new WorkflowResultDto();
                    // 如果没有实例ID，说明是启动并执行一步
                    // 直接调用工作流 启动并执行API  -  可以拿到两个节点的信息，用于填充业务字段
                    ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
                    List<ActWorkflowStartDTO> list = new ArrayList<>();
                    ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                    dto.setProcessDefinitionKey(PROCESS_DEFINITION_KEY);
                    dto.setBusinessKey(noticeDto.getSequenceNbr().toString());
                    dto.setCompleteFirstTask(Boolean.TRUE);
                    // 下一节点执行人单位（下节点接收机构code）
                    dto.setNextExecuteUserCompanyCode(notice.getReceiveOrgCreditCode());
                    list.add(dto);
                    actWorkflowBatchDTO.setProcess(list);
                    processTaskDTO = iCmWorkflowService.startBatch(actWorkflowBatchDTO).get(0);
                    // 提取节点等信息
                    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.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    notice.setNextTaskId(workflowResultDto.getNextTaskId());
                    notice.setInstanceId(workflowResultDto.getInstanceId());
                    this.updateById(notice);
                    // 如果为保存并提交，则创建代办
                    buildTask(Collections.singletonList(notice), Collections.singletonList(workflowResultDto), Boolean.TRUE);
                } else {
                    ProcessTaskDTO processTaskDTO = new ProcessTaskDTO();
                    WorkflowResultDto workflowResultDto = new WorkflowResultDto();
                    // 只调用执行API，返回下个节点信息，用于填充业务字段
                    // 组装信息
                    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.setVariable(commMap);
                    // 下一节点执行人单位（下节点接收机构code）
                    dto.setNextExecuteUserCompanyCode(notice.getReceiveOrgCreditCode());
                    processTaskDTO = iCmWorkflowService.completeOrReject(notice.getNextTaskId(), dto, op);
                    // 提取节点等信息
                    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.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    notice.setNextTaskId(workflowResultDto.getNextTaskId());
                    this.updateById(notice);
                    // 上个代办改为已办
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("taskStatus", FlowStatusEnum.TO_BE_PROCESSED.getCode());
                    map.put("taskStatusLabel", FlowStatusEnum.TO_BE_PROCESSED.getName());
                    map.put("relationId", notice.getInstanceId());
                    map.put("flowStatus", FlowStatusEnum.TO_BE_PROCESSED.getCode());
                    map.put("flowStatusLabel", FlowStatusEnum.TO_BE_PROCESSED.getName());
                    TaskV2Model taskV2Model = commonService.updateTaskModel(map);
                    if (ObjectUtils.isEmpty(taskV2Model)) {
                        // 如果为保存并提交，则创建代办
                        buildTask(Collections.singletonList(notice), Collections.singletonList(workflowResultDto), Boolean.FALSE);
                    } else {
                        TaskModelDto taskModelDto = new TaskModelDto();
                        BeanUtils.copyProperties(taskV2Model, taskModelDto);
                        // 创建新的代办
                        taskModelDto.setTaskName(workflowResultDto.getNextTaskName());
                        taskModelDto.setExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                        taskModelDto.setFlowStatus(FlowStatusEnum.TO_BE_PROCESSED.getCode());
                        taskModelDto.setFlowStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName());
                        taskModelDto.setFlowCode(notice.getNextTaskId());
                        taskModelDto.setNextExecuteUser(workflowResultDto.getNextExecutorRoleIds());
                        TaskMessageDto taskMessageDto = new TaskMessageDto();
                        BeanUtils.copyProperties(notice, taskMessageDto);
                        taskModelDto.setModel(taskMessageDto);
                        commonService.buildTaskModel(Collections.singletonList(taskModelDto));
                    }
                }
                commonService.saveExecuteFlowData2Redis(notice.getInstanceId(), this.buildInstanceRuntimeData(notice));
            } else {
                JgInstallationNotice bean = new JgInstallationNotice();
                BeanUtils.copyProperties(noticeDto, bean);
                this.updateById(bean);
            }
            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();
        }
    }

    private void checkRepeatUsed(String submitType, JgInstallationNotice jgInstallationNotice) {
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            // 流程中校验
            LambdaQueryWrapper<JgInstallationNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(JgInstallationNoticeEq::getEquipTransferId, jgInstallationNotice.getSequenceNbr());
            JgInstallationNoticeEq jgRelationEquip = jgInstallationNoticeEqMapper.selectOne(queryWrapper);
            EquipUsedCheckStrategyContext.getUsedStrategy("installNotice").equipRepeatUsedCheck(jgRelationEquip.getEquId(), jgInstallationNotice.getInstallUnitCreditCode());
        }
    }


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

        String orgCode = reginParams.getCompany().getCompanyCode();
        SortVo sortMap = commonService.sortFieldConversion(sort);
        model.setTransferToUserIds(reginParams.getUserModel().getUserId());
        Page<Map<String, Object>> noticePage = jgInstallationNoticeMapper.queryForPage(page, model, type, sortMap, orgCode);
        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(status);
                notice.put("noticeStatusDesc", noticeStatusDesc);
            });
        }).collect(Collectors.toList());
        noticePage.setRecords(mappedRecords);
        return noticePage;
    }

    /**
     * 批量删除
     *
     * @param sequenceNbrs 主键
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteForBatch(Long[] sequenceNbrs) {
        if (Objects.isNull(sequenceNbrs) || sequenceNbrs.length == 0) {
            return false;
        }
        for (Long sequenceNbr : sequenceNbrs) {
            // 删除待办 + 中止流程
            JgInstallationNotice jgInstallationNotice = this.baseMapper.selectById(sequenceNbr);
            commonService.deleteTaskModel(String.valueOf(sequenceNbr), jgInstallationNotice.getInstanceId());
            // 删除业务单
            jgInstallationNotice.setIsDelete(true);
            this.getBaseMapper().deleteById(sequenceNbr);
            // 删除对应equ
            jgInstallationNoticeEqMapper.delete(new LambdaUpdateWrapper<JgInstallationNoticeEq>()
                    .eq(JgInstallationNoticeEq::getEquipTransferId, sequenceNbr));
            // 删除单子对应历史表数据
            jgRegistrationHistoryMapper.delete(new LambdaQueryWrapper<JgRegistrationHistory>()
                    .eq(JgRegistrationHistory::getCurrentDocumentId, jgInstallationNotice.getSequenceNbr()));
        }
        return Boolean.TRUE;
    }

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

        JgInstallationNotice jgInstallationNotice = this.getById(sequenceNbr);
        List<Map<String, Object>> informationList = jgInstallationNoticeMapper.queryEquipInformation(sequenceNbr);
        if (Objects.isNull(jgInstallationNotice) || CollectionUtils.isEmpty(informationList)) {
            throw new IllegalArgumentException("安装告知单不存在");
        }
        Map<String, Object> placeholders = fullFillTemplateObj(informationList, BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName().substring(0, 2));

        String tempFileName = "安装告知单_" + System.currentTimeMillis() + "_temp";
//        String url = WordTemplateUtils.templateToPdf(tempFileName, "installation-notification-report.ftl", placeholders);
//
//        // 更新到数据库
//        jgInstallationNotice.setNoticeReportUrl(url);
//        this.updateById(jgInstallationNotice);

        WordTemplateUtils.templateToPdfDownload(tempFileName, "installation-notification-report.ftl", placeholders, response);
    }

    public Map<String, Object> fullFillTemplateObj(List<Map<String, Object>> informationList, String businessType) {
        Map<String, Object> informObj = informationList.get(0);

        String useCode = String.valueOf(informObj.get("installUnitCreditCode"));
        LambdaQueryWrapper<TzBaseUnitLicence> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TzBaseUnitLicence::getUnitCode, useCode);
        wrapper.last(" LIMIT 3");
        List<TzBaseUnitLicence> list = baseUnitLicenceMapper.selectList(wrapper);

        ArrayList<String> installLicenseNoList = new ArrayList<>();
        ArrayList<String> installLicenseExpirationDateList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            list.forEach(tzBaseUnitLicence -> {
                // 因模板许可证编号配置最多支持三个，再多样式混乱，目前返回三个
                if (installLicenseNoList.size() < 3) {
                    installLicenseNoList.add(tzBaseUnitLicence.getCertNo());
                    installLicenseExpirationDateList.add(DateUtils.convertDateToString(tzBaseUnitLicence.getExpiryDate(), DateUtils.DATE_PATTERN));
                }
            });
        }

        Function<String, String> getValue = key -> informObj.getOrDefault(key, "").toString();

        // 组装模板变量
        Map<String, Object> placeholders = new HashMap<>();
        placeholders.put("doMain", TZSDOMAIN);
        placeholders.put("installUnitName", getValue.apply("installUnitName"));
        placeholders.put("informNumber", getValue.apply("informNumber"));
        placeholders.put("productName", getValue.apply("productName"));
        placeholders.put("equipType", getValue.apply("equType"));
        placeholders.put("equipCode", getValue.apply("equRegisterCode"));
        placeholders.put("produceCode", getValue.apply("factoryNum")); // 出厂编号
        placeholders.put("produceUnitName", getValue.apply("produceUnitName"));
        placeholders.put("produceLicenseNum", getValue.apply("produceLicenseNum"));
        placeholders.put("installUnitAddress", getValue.apply("installUnitAddress")); // 施工单位地址
        placeholders.put("installStartDate", getValue.apply("installStartDate"));
        placeholders.put("installType", businessType); // 施工类别
        placeholders.put("installLeaderName", getValue.apply("installLeaderName"));
        placeholders.put("installLeaderPhone", getValue.apply("installLeaderPhone"));
        placeholders.put("fullAddress", getValue.apply("provinceName") + getValue.apply("cityName") + getValue.apply("countyName") + getValue.apply("streetName") + getValue.apply("address"));
        placeholders.put("useUnitName", getValue.apply("useUnitName"));
        placeholders.put("useUnitLeaderName", getValue.apply("safetyManager"));
        placeholders.put("useUnitLeaderPhone", getValue.apply("safetyManagerPhone"));
        placeholders.put("useUnitLeaderAddress", getValue.apply("useUnitLeaderAddress"));

        // 安装单位许可信息
        placeholders.put("installLicenseNoList", installLicenseNoList);
        placeholders.put("installLicenseExpirationDateList", installLicenseExpirationDateList);

        // 生成二维码
        String qrCode = ImageUtils.generateQRCode(getValue.apply("informNumber"), 300, 300);
        placeholders.put("qrCode", qrCode);
        return placeholders;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public List<JgInstallationNotice> saveNotice(String submitType, JSONObject jgInstallationNoticeDtoMap, ReginParams reginParams) {
        try {
            JgInstallationNoticeDto model = JSON.parseObject(jgInstallationNoticeDtoMap.get(TABLE_PAGE_ID).toString(), JgInstallationNoticeDto.class);
            // 字段转换
            this.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>> listResponseModel = tzsServiceFeignClient.applicationFormCode(ApplicationFormTypeEnum.AZGZ.getCode(), deviceList.size());
            if (!ObjectUtils.isEmpty(listResponseModel) && listResponseModel.getStatus() != HttpStatus.OK.value()) {
                log.error("告知单获取失败: {}", listResponseModel.getMessage());
                throw new BadRequest("告知单生成失败！");
            }
            List<String> applyNoList = listResponseModel.getResult();
            if (CollectionUtils.isEmpty(applyNoList)) {
                log.error("告知单返回为空");
                throw new BadRequest("告知单生成失败！");
            }

            // 启动工作流并返回信息
            List<WorkflowResultDto> workflowResultList = workFlowInfo(submitType, deviceList, model.getReceiveOrgCreditCode());

            List<JgInstallationNotice> list = new ArrayList<>();
            List<JgInstallationNoticeEq> equipList = new ArrayList<>();
            // 业务数据组装等
            businessData(submitType, reginParams, model, deviceList, applyNoList, list, equipList, workflowResultList);

            jgInstallationNoticeMapper.insertBatchSomeColumn(list);
            // 如果为保存并提交，则创建代办
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                buildTask(list, workflowResultList, Boolean.TRUE);
            } else {
                // 暂存任务
                buildTaskDraft(list);
            }
            List<JgInstallationNoticeEq> jgRelationEquipList = equipList.stream().map(jgRelationEquip -> {
                List<JgInstallationNotice> collect = list.stream().filter(jgInstallationNotice -> jgRelationEquip.getEquipTransferId().equals(jgInstallationNotice.getApplyNo())).collect(Collectors.toList());
                Long sequenceNbr = collect.get(0).getSequenceNbr();
                return jgRelationEquip.setEquipTransferId(String.valueOf(sequenceNbr));
            }).collect(Collectors.toList());
            jgInstallationNoticeEqMapper.insertBatchSomeColumn(jgRelationEquipList);
            this.updateRedisBatch(list);
            return list;
        } 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 rollBackForDelRedisData() {
        FlowingEquipRedisContext.getContext().forEach(e -> {
            EquipUsedCheckStrategyContext.getUsedStrategy("installNotice").delDataForCheckWithKey(e.getData(), e.getRedisKey());
        });
    }

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

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

    /**
     * 暂存任务生成待办
     *
     * @param list 业务信息
     */
    private void buildTaskDraft(List<JgInstallationNotice> list) {
        List<TaskModelDto> modelDtos = new ArrayList<>();
        list.forEach(obj -> {
            TaskModelDto dto = new TaskModelDto();
            // 行数据
            TaskMessageDto taskMessageDto = new TaskMessageDto();
            BeanUtils.copyProperties(obj, taskMessageDto);
            dto.setModel(taskMessageDto);
            // 摘要 按原有规则组装
            dto.setTaskContent(String.format("来自%s【%s】的业务办理", obj.getEquList(), StringUtils.isEmpty(obj.getFactoryNum()) ? "" : obj.getFactoryNum()));
            // 申请单号
            dto.setTaskCode(obj.getApplyNo());
            // 业务类型枚举code值
            dto.setTaskType(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getCode());
            ////业务主键
            dto.setRelationId(obj.getSequenceNbr() + "");
            modelDtos.add(dto);
        });
        commonService.buildTaskModel(modelDtos);
    }

    private void buildTask(List<JgInstallationNotice> list, List<WorkflowResultDto> workflowResultList, Boolean isDeleteDraft) {
        List<TaskModelDto> taskModelDtoList = new ArrayList<>();
        WorkflowResultDto workflowResultDto = workflowResultList.get(0);
        list.forEach(item -> {
            TaskModelDto taskModelDto = new TaskModelDto();
            taskModelDto.setFlowCreateDate(item.getCreateDate());
            taskModelDto.setTaskName(workflowResultDto.getNextTaskName()); // 工作流API返回
            taskModelDto.setTaskCode(item.getApplyNo());
            taskModelDto.setTaskType(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getCode());
            taskModelDto.setTaskTypeLabel(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName());
            taskModelDto.setRelationId(item.getInstanceId());
            taskModelDto.setExecuteUserIds(workflowResultDto.getNextExecutorUserIds()); // 工作流API返回
            taskModelDto.setTaskStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName());
            taskModelDto.setFlowStatus(commonService.getDictionaryCodeByName(FlowStatusEnum.TO_BE_PROCESSED.getName())); // 流程状态枚举
            taskModelDto.setFlowStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName());
            taskModelDto.setFlowCode(item.getNextTaskId());
            taskModelDto.setStartUserId(item.getCreateUserId());
            taskModelDto.setStartUser(item.getCreateUserName());
            taskModelDto.setStartUserCompanyName(item.getCreateUserCompanyName()); // 任务发起人所在单位
            taskModelDto.setStartDate(item.getCreateDate());
            taskModelDto.setNextExecuteUser(item.getNextExecuteIds());
            taskModelDto.setTaskContent(String.format("来自%s【%s】的业务办理，【申请单号：%s】", item.getEquList(), StringUtils.isEmpty(item.getFactoryNum()) ? "" : item.getFactoryNum(), item.getApplyNo()));
            TaskMessageDto taskMessageDto = new TaskMessageDto();
            BeanUtils.copyProperties(item, taskMessageDto);
            taskModelDto.setModel(taskMessageDto);
            taskModelDtoList.add(taskModelDto);
            if (isDeleteDraft) {
                // 删除暂存时生成的待办
                commonService.deleteTasksByRelationId(item.getSequenceNbr() + "");
            }
        });
        commonService.buildTaskModel(taskModelDtoList);
    }

    private void businessData(String submitType, ReginParams reginParams, JgInstallationNoticeDto model, List<Map<String, Object>> deviceList, List<String> applyNoList, List<JgInstallationNotice> list, List<JgInstallationNoticeEq> equipList, List<WorkflowResultDto> workflowResultList) {
        CompanyBo companyBo = commonService.getOneCompany(model.getReceiveOrgCreditCode());
        deviceList.forEach(obj -> {
            JgInstallationNoticeEq jgRelationEquip = new JgInstallationNoticeEq();
            JgInstallationNotice dto = new JgInstallationNotice();
            BeanUtils.copyProperties(model, dto);
            int i = deviceList.indexOf(obj);
            String applyNo = applyNoList.get(i);
            dto.setApplyNo(applyNo);
            dto.setNoticeDate(new Date());
            // 统计使用
            dto.setReceiveCompanyOrgCode(companyBo.getOrgCode());
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                dto.setNextExecuteIds(workflowResultList.get(i).getNextExecutorRoleIds());
                dto.setNextExecuteUserIds(workflowResultList.get(i).getNextExecutorUserIds());
                dto.setInstanceStatus(workflowResultList.get(i).getNextExecutorRoleIds() + "," + workflowResultList.get(i).getExecutorRoleIds());
                dto.setPromoter(reginParams.getUserModel().getUserId());
                dto.setNextTaskId(workflowResultList.get(i).getNextTaskId());
            } else {
                dto.setNextExecuteUserIds(reginParams.getUserModel().getUserId());
            }
            dto.setInstallUnitName(reginParams.getCompany().getCompanyName());
            dto.setInstallUnitCreditCode(reginParams.getCompany().getCompanyCode());
            dto.setEquList((String.valueOf(obj.get("EQU_LIST"))));
            dto.setEntrustingUnitName(dto.getUseUnitName());
            dto.setCreateUserCompanyName(reginParams.getCompany().getCompanyName());
            dto.setEquRegisterCode(String.valueOf(obj.get("EQU_CODE")));
            dto.setFactoryNum(String.valueOf(obj.get("FACTORY_NUM")));
            jgRelationEquip.setEquId(String.valueOf(obj.get("SEQUENCE_NBR")));
            jgRelationEquip.setEquipTransferId(applyNo);
            if (!CollectionUtils.isEmpty(workflowResultList)) {
                dto.setInstanceId(workflowResultList.get(i).getInstanceId());
                dto.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
            } else {
                dto.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_SUBMITTED.getCode()));
            }
            dto.setCreateUserName(reginParams.getUserModel().getRealName());
            dto.setCreateUserId(reginParams.getUserModel().getUserId());
            dto.setEquAddress(obj.getOrDefault("ADDRESS", "").toString());
            list.add(dto);
            equipList.add(jgRelationEquip);
        });
    }

    /**
     * 工作流启动并执行
     *
     * @param submitType 是否提交
     * @param deviceList 设备信息
     * @return 工作流返回相关数据
     */
    private List<WorkflowResultDto> workFlowInfo(String submitType, List<Map<String, Object>> deviceList, String receiveOrgCreditCode) {
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
            List<ActWorkflowStartDTO> list = new ArrayList<>();
            deviceList.forEach(item -> {
                ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                dto.setProcessDefinitionKey(PROCESS_DEFINITION_KEY);
                dto.setBusinessKey(item.get("SEQUENCE_NBR").toString());
                dto.setCompleteFirstTask(Boolean.TRUE);
                dto.setNextExecuteUserCompanyCode(receiveOrgCreditCode);
                list.add(dto);
            });
            actWorkflowBatchDTO.setProcess(list);
            List<ProcessTaskDTO> processTaskDTOS = iCmWorkflowService.startBatch(actWorkflowBatchDTO);
            // 组装工作流返回的数据
            return commonService.buildWorkFlowInfo(processTaskDTOS);
        }
        return new ArrayList<>();
    }


    private void convertField(JgInstallationNoticeDto model) {
        // 处理图片
        if (!ValidationUtil.isEmpty(model.getProxyStatementAttachmentList())) {
            model.setProxyStatementAttachment(JSON.toJSONString(model.getProxyStatementAttachmentList()));
        }
        if (!ValidationUtil.isEmpty(model.getInstallContractAttachmentList())) {
            model.setInstallContractAttachment(JSON.toJSONString(model.getInstallContractAttachmentList()));
        }
        if (!ValidationUtil.isEmpty(model.getOtherAccessoriesList())) {
            model.setOtherAccessories(JSON.toJSONString(model.getOtherAccessoriesList()));
        }

        // 分割省市区字段
        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 propertyUnitName = model.getPropertyUnitName();
        if (!ObjectUtils.isEmpty(propertyUnitName)) {
            String[] split = propertyUnitName.split("_");
            if (split.length > 1) {
                model.setPropertyUnitCreditCode(split[0]);
                model.setPropertyUnitName(split[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 factoryUseSiteStreet = model.getFactoryUseSiteStreet();
        if (!ObjectUtils.isEmpty(factoryUseSiteStreet)) {
            String[] factoryUseSiteStreetList = factoryUseSiteStreet.split("_");
            if (factoryUseSiteStreetList.length > 1) {
                model.setFactoryUseSiteStreet(factoryUseSiteStreetList[0]);
                model.setStreetName(factoryUseSiteStreetList[1]);
            }
        }

        String branchCodeString = model.getOrgBranchCode();
        if (!ObjectUtils.isEmpty(branchCodeString)) {
            String[] branchCodeStringList = branchCodeString.split("_");
            if (branchCodeStringList.length > 1) {
                model.setOrgBranchCode(branchCodeStringList[0]);
                model.setOrgBranchName(branchCodeStringList[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.getReceiveOrgCreditCode();
        if (!ObjectUtils.isEmpty(receiveOrgId)) {
            String[] receiveOrgIdList = receiveOrgId.split("_");
            if (receiveOrgIdList.length > 1) {
                model.setReceiveOrgCreditCode(receiveOrgIdList[0]);
                model.setReceiveOrgName(receiveOrgIdList[1]);
            }
        }

        String inspectUnitId = model.getInspectUnitId();
        if (!ObjectUtils.isEmpty(inspectUnitId)) {
            String[] inspectUnitIdList = inspectUnitId.split("_");
            if (inspectUnitIdList.length > 1) {
                model.setInspectUnitId(inspectUnitIdList[0]);
                model.setInspectUnitName(inspectUnitIdList[1]);
            }
        }

        String installLeaderId = model.getInstallLeaderId();
        if (!ObjectUtils.isEmpty(installLeaderId)) {
            String[] leaderList = installLeaderId.split("_");
            if (leaderList.length > 1) {
                model.setInstallLeaderId(leaderList[0]);
                model.setInstallLeaderName(leaderList[1]);
            }
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void cancel(JgInstallationNoticeDto 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);
            JgInstallationNotice jgInstallationNotice = this.baseMapper.selectById(noticeDto.getSequenceNbr());
            ProcessTaskDTO processTaskDTO = iCmWorkflowService.rollBack(jgInstallationNotice.getInstanceId());
            // 提取节点等信息
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            jgInstallationNotice.setPromoter("");
            jgInstallationNotice.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
            jgInstallationNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
            jgInstallationNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.ROLLBACK.getCode()));
            jgInstallationNotice.setNextTaskId(workflowResultDto.getNextTaskId());
            this.updateById(jgInstallationNotice);
            TaskMessageDto taskMessageDto = new TaskMessageDto();
            BeanUtils.copyProperties(jgInstallationNotice, taskMessageDto);
            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(taskMessageDto));
            jsonObject.put("taskType", BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getCode());
            jsonObject.put("nextExecuteUser", jgInstallationNotice.getNextExecuteIds());
            jsonObject.put("flowStatusLabel", FlowStatusEnum.ROLLBACK.getName());
            jsonObject.put("flowStatus", FlowStatusEnum.ROLLBACK.getCode());
            jsonObject.put("nextTaskId", jgInstallationNotice.getNextTaskId());
            commonService.rollbackTask(jgInstallationNotice.getInstanceId(), jsonObject);
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgInstallationNotice));
            this.delRepeatUseEquipData(jgInstallationNotice);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 删除 redis校验重复引用设备的数据
     *
     * @param jgInstallationNotice 安装告知entry
     */
    private void delRepeatUseEquipData(JgInstallationNotice jgInstallationNotice) {
        LambdaQueryWrapper<JgInstallationNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JgInstallationNoticeEq::getEquipTransferId, jgInstallationNotice.getSequenceNbr());
        JgInstallationNoticeEq jgRelationEquip = jgInstallationNoticeEqMapper.selectOne(queryWrapper);
        EquipUsedCheckStrategyContext.getUsedStrategy("installNotice").delDataForCheckEquipRepeatUsed(Collections.singletonList(jgRelationEquip.getEquId()), jgInstallationNotice.getInstallUnitCreditCode());
    }

    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    public void accept(JgInstallationNoticeDto dto, String op) {
        String xid = GlobalTransactionContext.getCurrentOrCreate().getXid();
        log.info(xid);
        RootContext.bind(xid);
        String instanceId = dto.getInstanceId();
        String nextTaskId = dto.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);

            JgInstallationNotice jgInstallationNotice = this.getById(dto.getSequenceNbr());
            jgInstallationNotice.setProcessAdvice(dto.getProcessAdvice());
            // 组装设备注册代码
            String ym = null;
            try {
                ym = DateUtils.dateFormat(new Date(), DateUtils.DATE_PATTERN_MM);
            } catch (ParseException e) {
                log.error("日期转换失败：{}", e);
            }
            // 执行工作流并返回组装好的工作流信息
            WorkflowResultDto workflowResultDto = getWorkflowResultDto(op, jgInstallationNotice);
            jgInstallationNotice.setPromoter(RequestContext.getExeUserId());
            jgInstallationNotice.setNextTaskId(workflowResultDto.getNextTaskId());
            TaskV2Model taskV2Model = new TaskV2Model();
            if ("0".equals(op)) {
                if (StringUtils.isEmpty(workflowResultDto.getNextExecutorRoleIds())) {
                    LambdaQueryWrapper<JgInstallationNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(JgInstallationNoticeEq::getEquipTransferId, dto.getSequenceNbr());
                    JgInstallationNoticeEq jgRelationEquip = jgInstallationNoticeEqMapper.selectOne(queryWrapper);
                    this.saveHisDataBeforeUpdate(jgInstallationNotice, jgRelationEquip.getEquId());
                    LambdaQueryWrapper<OtherInfo> queryWrapper1 = new LambdaQueryWrapper<>();
                    queryWrapper1.eq(OtherInfo::getRecord, jgRelationEquip.getEquId());
                    OtherInfo tzsJgOtherInfo = tzsJgOtherInfoMapper.selectOne(queryWrapper1);
                    LambdaQueryWrapper<IdxBizJgRegisterInfo> queryWrapper2 = new LambdaQueryWrapper<>();
                    queryWrapper2.eq(IdxBizJgRegisterInfo::getRecord, jgRelationEquip.getEquId());
                    IdxBizJgRegisterInfo idxBizJgRegisterInfo = tzsJgRegistrationInfoMapper.selectOne(queryWrapper2);
                    String equCode = Optional.ofNullable(idxBizJgRegisterInfo.getEquDefine())
                            .orElse(idxBizJgRegisterInfo.getEquCategory());
                    String registrationCode = equCode + jgInstallationNotice.getReceiveOrgCreditCode() + ym;
                    ResponseModel<String> responseModel = tzsServiceFeignClient.deviceRegistrationCode(registrationCode);
                    String deviceRegistrationCode = responseModel.getResult();
                    Map<String, Object> map = new HashMap<>();
                    map.put("code96333", tzsJgOtherInfo.getCode96333());
                    map.put("superviseCode", tzsJgOtherInfo.getSupervisoryCode());
                    map.put("cityCode", jgInstallationNotice.getCity());
                    map.put("countyCode", jgInstallationNotice.getCounty());
                    map.put("equCategory", idxBizJgRegisterInfo.getEquCategory());
                    map.put("isXiXian", jgInstallationNotice.getIsXixian() == null ? "null" : jgInstallationNotice.getIsXixian().equals("0") ? "null" : "1");
                    Map<String, Object> mapCode;
                    ResponseModel<Map<String, Object>> code = tzsServiceFeignClient.createCode(map);
                    mapCode = code.getResult();
                    supervisoryCodeInfoMapper.updateStatusBySuperviseCode(mapCode.get("superviseCode").toString());
                    jgInstallationNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode()));
                    jgInstallationNotice.setHandleDate(new Date());
                    jgInstallationNotice.setInformNumber(deviceRegistrationCode);
                    jgInstallationNotice.setSupervisoryCode(mapCode.get("superviseCode").toString());
                    jgInstallationNotice.setPromoter("");

                    Map<String, Object> map1 = new HashMap<>();
                    // 更新其他业务表
                    if (!ValidationUtil.isEmpty(mapCode.get("code96333"))) {
                        tzsJgOtherInfo.setCode96333(mapCode.get("code96333").toString());
                        map1.put("CODE96333", tzsJgOtherInfo.getCode96333());
                    }
                    tzsJgOtherInfo.setSupervisoryCode(mapCode.get("superviseCode").toString());
                    tzsJgOtherInfoMapper.updateById(tzsJgOtherInfo);
                    List<LinkedHashMap> tree = commonServiceImpl.getCreatTree();
                    // 更新设备监管部门信息
                    LambdaQueryWrapper<IdxBizJgSupervisionInfo> eq = new QueryWrapper<IdxBizJgSupervisionInfo>().lambda()
                            .eq(IdxBizJgSupervisionInfo::getRecord, jgRelationEquip.getEquId());
                    IdxBizJgSupervisionInfo idxBizJgSupervisionInfo = idxBizJgSupervisionInfoMapper.selectOne(eq);
                    if (!ObjectUtils.isEmpty(jgInstallationNotice.getOrgBranchCode()) && !ObjectUtils.isEmpty(jgInstallationNotice.getOrgBranchName())) {
                        HashMap<String, Object> parentMessage = (HashMap<String, Object>) Privilege.companyClient.queryByOrgcode(jgInstallationNotice.getOrgBranchCode()).getResult();
                        // 目前平台返回key为compnay(存在拼写错误)
                        CompanyModel parentModel = JSON.parseObject(JSON.toJSONString(parentMessage.get("compnay")), CompanyModel.class);
                        idxBizJgSupervisionInfo.setOrgBranchCode(parentModel.getOrgCode());
                        idxBizJgSupervisionInfo.setOrgBranchName(parentModel.getCompanyName());
                        idxBizJgSupervisionInfo.setCompanyOrgBranchCode(parentModel.getCompanyCode());
                        idxBizJgSupervisionInfoMapper.updateById(idxBizJgSupervisionInfo);
                    }

                    // 生成设备代码及更新历史表的的设备代码字段
                    this.justGenerateEquCode(idxBizJgRegisterInfo, jgInstallationNotice.getReceiveOrgCreditCode(), jgInstallationNotice);
                    tzsJgRegistrationInfoMapper.updateById(idxBizJgRegisterInfo);
                    // 更新es
                    updateEquipEs(jgInstallationNotice, tzsJgOtherInfo, idxBizJgRegisterInfo, idxBizJgSupervisionInfo, map1, dto);
                    // 记录施工信息表
                    createConstruction2Db(jgInstallationNotice, jgRelationEquip);

                    // 更新使用信息
                    updateJgUseInfo(jgInstallationNotice, jgRelationEquip);

                    // 上个代办改为已办
                    HashMap<String, Object> taskMap = new HashMap<>();
                    taskMap.put("taskStatus", FlowStatusEnum.TO_BE_FINISHED.getCode());
                    taskMap.put("taskStatusLabel", FlowStatusEnum.TO_BE_FINISHED.getName());
                    taskMap.put("relationId", jgInstallationNotice.getInstanceId());
                    taskMap.put("flowStatus", FlowStatusEnum.TO_BE_FINISHED.getCode());
                    taskMap.put("flowStatusLabel", FlowStatusEnum.TO_BE_FINISHED.getName());

                    TaskMessageDto taskMessageDto = new TaskMessageDto();
                    BeanUtils.copyProperties(jgInstallationNotice, taskMessageDto);
                    taskMap.put("model", taskMessageDto);
                    TaskV2Model taskV2Model1 = commonService.updateTaskModel(taskMap);
                    // 生成证记录表主键
                    long certChangeSeq = sequence.nextId();
                    // 生成jg证书变更记录
                    genJgCertificateChangeRecord(jgInstallationNotice,certChangeSeq, registrationCode, idxBizJgRegisterInfo, taskV2Model1);
                    // 查询设备制造信息
                    LambdaQueryWrapper<IdxBizJgFactoryInfo> factoryInfoWrapper = new LambdaQueryWrapper<>();
                    factoryInfoWrapper.eq(IdxBizJgFactoryInfo::getRecord, jgRelationEquip.getEquId());
                    IdxBizJgFactoryInfo idxBizJgFactoryInfo = idxBizJgFactoryInfoService.getOne(factoryInfoWrapper);

                    // 生成tzs_jg_certificate_change_record_eq记录
                    JgCertificateChangeRecordEq changeRecordEq = new JgCertificateChangeRecordEq();
                    changeRecordEq.setChangeRecordId(String.valueOf(certChangeSeq));//登记证记录主键
                    changeRecordEq.setEquId(jgRelationEquip.getEquId());//设备主键
                    changeRecordEq.setProductCode(idxBizJgFactoryInfo.getFactoryNum());
                    certificateChangeRecordEqService.save(changeRecordEq);

                    jgResumeInfoService.createWithModel(JgResumeInfoDto.builder()
                            .applyNo(jgInstallationNotice.getApplyNo())
                            .businessType(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName())
                            .businessId(jgInstallationNotice.getSequenceNbr() + "")
                            .equId(jgRelationEquip.getEquId())
                            .approvalUnit(jgInstallationNotice.getReceiveOrgName())
                            .approvalUnitCode(jgInstallationNotice.getReceiveOrgCreditCode())
                            .status("正常")
                            .routePath(taskV2Model1.getRoutePath())
                            .build());

                } else {
                    jgInstallationNotice.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
                    jgInstallationNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    if (!ObjectUtils.isEmpty(jgInstallationNotice.getInstanceStatus())) {
                        jgInstallationNotice.setInstanceStatus(jgInstallationNotice.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                    } else {
                        jgInstallationNotice.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                    }
                    jgInstallationNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    // 上个代办改为已办
                    HashMap<String, Object> taskMap = new HashMap<>();
                    taskMap.put("taskStatus", FlowStatusEnum.TO_BE_PROCESSED.getCode());
                    taskMap.put("taskStatusLabel", FlowStatusEnum.TO_BE_PROCESSED.getName());
                    taskMap.put("flowStatus", FlowStatusEnum.TO_BE_PROCESSED.getCode());
                    taskMap.put("flowStatusLabel", FlowStatusEnum.TO_BE_PROCESSED.getName());
                    taskMap.put("relationId", jgInstallationNotice.getInstanceId());
                    taskV2Model = commonService.updateTaskModel(taskMap);
                    TaskModelDto taskModelDto = new TaskModelDto();
                    BeanUtils.copyProperties(taskV2Model, taskModelDto);
                    // 创建新的代办
                    taskModelDto.setTaskName(workflowResultDto.getNextTaskName());
                    taskModelDto.setExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    taskModelDto.setFlowStatus(FlowStatusEnum.TO_BE_PROCESSED.getCode());
                    taskModelDto.setFlowStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName());
                    taskModelDto.setFlowCode(workflowResultDto.getNextTaskId());
                    taskModelDto.setTaskStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName());
                    taskModelDto.setNextExecuteUser(workflowResultDto.getNextExecutorRoleIds());
                    TaskMessageDto taskMessageDto = new TaskMessageDto();
                    BeanUtils.copyProperties(jgInstallationNotice, taskMessageDto);
                    taskModelDto.setModel(taskMessageDto);
                    commonService.buildTaskModel(Collections.singletonList(taskModelDto));
                }
            } else {
                jgInstallationNotice.setPromoter("");
                jgInstallationNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.REJECTED.getCode()));
                // 上个代办改为已办
                HashMap<String, Object> taskMap = new HashMap<>();
                taskMap.put("taskStatus", jgInstallationNotice.getNoticeStatus());
                taskMap.put("taskStatusLabel", FlowStatusEnum.REJECTED.getName());
                taskMap.put("relationId", jgInstallationNotice.getInstanceId());
                taskMap.put("flowStatus", FlowStatusEnum.REJECTED.getCode());
                taskMap.put("flowStatusLabel", FlowStatusEnum.REJECTED.getName());
                taskV2Model = commonService.updateTaskModel(taskMap);
                TaskModelDto taskModelDto = new TaskModelDto();
                BeanUtils.copyProperties(taskV2Model, taskModelDto);
                // 创建新的代办
                taskModelDto.setTaskName(workflowResultDto.getNextTaskName());
                taskModelDto.setFlowStatus(FlowStatusEnum.REJECTED.getCode());
                taskModelDto.setFlowStatusLabel(FlowStatusEnum.REJECTED.getName());
                taskModelDto.setFlowCode(workflowResultDto.getNextTaskId());
                taskModelDto.setNextExecuteUser(workflowResultDto.getNextExecutorRoleIds());
                taskModelDto.setPageType("edit");
                TaskMessageDto taskMessageDto = new TaskMessageDto();
                BeanUtils.copyProperties(jgInstallationNotice, taskMessageDto);
                taskModelDto.setExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                taskModelDto.setModel(taskMessageDto);
                commonService.buildTaskModel(Collections.singletonList(taskModelDto));
                this.delRepeatUseEquipData(jgInstallationNotice);
            }
            jgInstallationNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
            jgInstallationNotice.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
            this.updateById(jgInstallationNotice);
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgInstallationNotice));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public void genJgCertificateChangeRecord(JgInstallationNotice jgInstallationNotice,Long sequenceNbr, String registrationCode, IdxBizJgRegisterInfo idxBizJgRegisterInfo, TaskV2Model taskV2Model1) {
        // 生成一条tzs_jg_certificate_change_record记录
        JgCertificateChangeRecord jgCertificateChangeRecord = new JgCertificateChangeRecord();
        jgCertificateChangeRecord.setApplyNo(jgInstallationNotice.getApplyNo());
        jgCertificateChangeRecord.setReceiveOrgName(jgInstallationNotice.getReceiveOrgName());
        jgCertificateChangeRecord.setAuditPassDate(new Date());
        jgCertificateChangeRecord.setRegType(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName());
        jgCertificateChangeRecord.setRegDate(jgInstallationNotice.getInstallStartDate());
        jgCertificateChangeRecord.setChangeContent(this.buildRecordContent(jgInstallationNotice));//变更内容
        jgCertificateChangeRecord.setUseRegistrationCode(registrationCode);//使用登记编号
        jgCertificateChangeRecord.setReceiveCompanyCode(jgInstallationNotice.getReceiveCompanyOrgCode());//接收机构公司代码
        jgCertificateChangeRecord.setCertificateNo("");//登记证书唯一码
        jgCertificateChangeRecord.setUseUnitCreditCode(jgInstallationNotice.getUseUnitCreditCode());//使用单位统一信用代码
        jgCertificateChangeRecord.setUseUnitName(jgInstallationNotice.getUseUnitName());//使用单位名称
        jgCertificateChangeRecord.setEquCategory(idxBizJgRegisterInfo.getEquCategory());//设备类别编码
        jgCertificateChangeRecord.setCreateDate(new Date());
        jgCertificateChangeRecord.setRoutePath(taskV2Model1.getRoutePath());
        jgCertificateChangeRecord.setCreateUserId(jgInstallationNotice.getCreateUserId());
        jgCertificateChangeRecord.setSequenceNbr(sequenceNbr);
        certificateChangeRecordService.save(jgCertificateChangeRecord);
    }

    private void createConstruction2Db(JgInstallationNotice jgInstallationNotice, JgInstallationNoticeEq jgRelationEquip) {
        IdxBizJgConstructionInfo idxBizJgConstructionInfo = new IdxBizJgConstructionInfo();
        idxBizJgConstructionInfo.setUscUnitCreditCode(jgInstallationNotice.getInstallUnitCreditCode());
        idxBizJgConstructionInfo.setUscUnitName(jgInstallationNotice.getInstallUnitName());
        idxBizJgConstructionInfo.setUscDate(jgInstallationNotice.getInstallStartDate());
        idxBizJgConstructionInfo.setRecord(jgRelationEquip.getEquId());
        idxBizJgConstructionInfo.setRecDate(new Date());
        idxBizJgConstructionInfo.setRecUserId(RequestContext.getExeUserId());
        idxBizJgConstructionInfo.setNoticeId(jgInstallationNotice.getSequenceNbr() + "");
        // 获取施工类型id
        LambdaQueryWrapper<DataDictionary> lambda = new LambdaQueryWrapper<>();
        lambda.eq(DataDictionary::getType, CONSTRUCTION_TYPE);
        lambda.eq(DataDictionary::getName, CONSTRUCTION_TYPE_NAME);
        List<DataDictionary> dataDictionaries = dataDictionaryMapper.selectList(lambda);
        if (!CollectionUtils.isEmpty(dataDictionaries)) {
            idxBizJgConstructionInfo.setConstructionType(String.valueOf(dataDictionaries.get(0).getSequenceNbr()));
        }
        constructionInfoService.save(idxBizJgConstructionInfo);
    }

    private void updateEquipEs(JgInstallationNotice jgInstallationNotice, OtherInfo tzsJgOtherInfo,
                               IdxBizJgRegisterInfo tzsJgRegistrationInfo, IdxBizJgSupervisionInfo idxBizJgSupervisionInfo,
                               Map<String, Object> map1, JgInstallationNoticeDto dto) {
        Map<String, Map<String, Object>> objMap = new HashMap<>();
        map1.put("EQU_CODE", tzsJgRegistrationInfo.getEquCode());
        map1.put("ORG_BRANCH_CODE", idxBizJgSupervisionInfo.getOrgBranchCode());
        map1.put("ORG_BRANCH_NAME", idxBizJgSupervisionInfo.getOrgBranchName());
        map1.put("SUPERVISORY_CODE", tzsJgOtherInfo.getSupervisoryCode());
        map1.put("USE_UNIT_CREDIT_CODE", jgInstallationNotice.getUseUnitCreditCode());
        map1.put("USE_UNIT_NAME", jgInstallationNotice.getUseUnitName());
        map1.put("IS_INTO_MANAGEMENT", true);
        map1.put("USE_SITE_CODE", dto.getProvince().split("_")[0] + "#" + dto.getCity().split("_")[0] + "#" + dto.getCounty().split("_")[0] + "#" + dto.getFactoryUseSiteStreet().split("_")[0]);
        map1.put("USC_UNIT_CREDIT_CODE", jgInstallationNotice.getInstallUnitCreditCode());
        map1.put("USC_UNIT_NAME", jgInstallationNotice.getInstallUnitName());
        map1.put("USE_PLACE", String.format("%s/%s/%s/%s", jgInstallationNotice.getProvinceName(), jgInstallationNotice.getCityName(), jgInstallationNotice.getCountyName(), jgInstallationNotice.getStreetName()));
        map1.put("ADDRESS",jgInstallationNotice.getAddress());
        objMap.put(tzsJgOtherInfo.getRecord(), map1);
        tzsServiceFeignClient.commonUpdateEsDataByIds(objMap);
    }

    private String buildRecordContent(JgInstallationNotice obj) {
        //张三办理了【单位变更】 ，单号【DWBG202407050001】，办理日期2024-07-05
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        return obj.getCreateUserName() + "办理了【"+BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName()+"】，单号【"
                + obj.getApplyNo() + "】，申请日期" + simpleDateFormat.format(obj.getCreateDate());
    }

    /**
     * 系统类型的code 自动生成设备代码
     *
     * @param registerInfo       注册信息
     * @param receiveCompanyCode 接收机构行政区划代码
     */
    private void justGenerateEquCode(IdxBizJgRegisterInfo registerInfo, String receiveCompanyCode, JgInstallationNotice jgInstallationNotice) {
        if (EquCodeTypeEnum.SYSTEM_GENERATED.getCode().equals(registerInfo.getEquCodeType())) {
            // 更新注册信息表的设备代码字段
            String equCode = this.getEquCode(registerInfo, receiveCompanyCode);
            registerInfo.setEquCode(equCode);
            updateHisDataEquCode(registerInfo, jgInstallationNotice, equCode);
        }
    }

    private void updateHisDataEquCode(IdxBizJgRegisterInfo registerInfo, JgInstallationNotice jgInstallationNotice, String equCode) {
        JSONObject his = commonService.queryHistoryData(jgInstallationNotice.getSequenceNbr());
        his.put("equCode", equCode);
        commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName(), new JSONObject(his), registerInfo.getRecord(), jgInstallationNotice.getSequenceNbr().toString());
    }

    private String getEquCode(IdxBizJgRegisterInfo registerInfo, String receiveCompanyCode) {
        ProduceInfo produceInfo = produceInfoMapper.selectOne(new LambdaQueryWrapper<ProduceInfo>().eq(AbstractEquipBaseEntity::getRecord, registerInfo.getRecord()));
        CodeGenerateDto codeGenerateDto = new CodeGenerateDto();
        codeGenerateDto.setEquList(registerInfo.getEquList());
        codeGenerateDto.setEquCategory(registerInfo.getEquCategory());
        codeGenerateDto.setEquDefine(registerInfo.getEquDefine());
        codeGenerateDto.setProduceDate(produceInfo.getProduceDate());
        codeGenerateDto.setReceiveCompanyCode(receiveCompanyCode);
        return codeUtil.generateEquipmentCode(codeGenerateDto);
    }

    private void updateJgUseInfo(JgInstallationNotice jgInstallationNotice, JgInstallationNoticeEq jgRelationEquip) {
        LambdaUpdateWrapper<IdxBizJgUseInfo> lambda = new LambdaUpdateWrapper<>();
        lambda.eq(IdxBizJgUseInfo::getRecord, jgRelationEquip.getEquId());
        IdxBizJgUseInfo idxBizJgUseInfo = new IdxBizJgUseInfo();
        idxBizJgUseInfo.setUseUnitCreditCode(jgInstallationNotice.getUseUnitCreditCode());
        idxBizJgUseInfo.setUseUnitName(jgInstallationNotice.getUseUnitName());
        idxBizJgUseInfo.setProvince(jgInstallationNotice.getProvince());
        idxBizJgUseInfo.setProvinceName(jgInstallationNotice.getProvinceName());
        idxBizJgUseInfo.setCity(jgInstallationNotice.getCity());
        idxBizJgUseInfo.setCityName(jgInstallationNotice.getCityName());
        idxBizJgUseInfo.setCounty(jgInstallationNotice.getCounty());
        idxBizJgUseInfo.setCountyName(jgInstallationNotice.getCountyName());
        idxBizJgUseInfo.setFactoryUseSiteStreet(jgInstallationNotice.getFactoryUseSiteStreet());
        idxBizJgUseInfo.setStreetName(jgInstallationNotice.getStreetName());
        idxBizJgUseInfo.setAddress(jgInstallationNotice.getAddress());
        idxBizJgUseInfo.setIsNotXiXian(jgInstallationNotice.getIsXixian());
        idxBizJgUseInfo.setEstateUnitCreditCode(jgInstallationNotice.getPropertyUnitCreditCode());
        idxBizJgUseInfo.setEstateUnitName(jgInstallationNotice.getPropertyUnitName());
        idxBizJgUseInfo.setIsIntoManagement(Boolean.TRUE);
        idxBizJgUseInfoMapper.update(idxBizJgUseInfo, lambda);
    }

    private void saveHisDataBeforeUpdate(JgInstallationNotice jgInstallationNotice) {
        LambdaQueryWrapper<JgInstallationNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JgInstallationNoticeEq::getEquipTransferId, jgInstallationNotice.getSequenceNbr());
        JgInstallationNoticeEq jgRelationEquip = jgInstallationNoticeEqMapper.selectOne(queryWrapper);
        Map<String, Object> map = idxBizJgRegisterInfoService.getDetailFieldCamelCaseByRecord(jgRelationEquip.getEquId());
        commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName(), new JSONObject(map), jgRelationEquip.getEquId(), jgInstallationNotice.getSequenceNbr().toString());
    }

    private void saveHisDataBeforeUpdate(JgInstallationNotice jgInstallationNotice, String equId) {
        Map<String, Object> map = idxBizJgRegisterInfoService.getDetailFieldCamelCaseByRecord(equId);
        commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.getName(), new JSONObject(map), equId, jgInstallationNotice.getSequenceNbr().toString());
    }

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


    /**
     * 执行工作流并返回组装好的工作流信息
     *
     * @param op               是否通过
     * @param jgTransferNotice 业务信息  opinion 备注信息
     * @return 返回组装好的工作流信息
     */
    private WorkflowResultDto getWorkflowResultDto(String op, JgInstallationNotice jgTransferNotice) {
        ProcessTaskDTO processTaskDTO = new ProcessTaskDTO();
        WorkflowResultDto workflowResultDto = new WorkflowResultDto();
        // 只调用执行API，返回下个节点信息，用于填充业务字段
        // 组装信息
        TaskResultDTO workDto = new TaskResultDTO();
        workDto.setResultCode("approvalStatus");
        workDto.setTaskId(jgTransferNotice.getNextTaskId());
        HashMap<String, Object> commMap = new HashMap<>();
        if (jgTransferNotice.getNoticeStatus().equals("6614") || jgTransferNotice.getNoticeStatus().equals("6615")) {
            commMap.put("approvalStatus", "提交");
        } else {
            commMap.put("approvalStatus", op);
        }
        commMap.put("approvalStatus", op);
        workDto.setVariable(commMap);
        workDto.setComment(jgTransferNotice.getProcessAdvice());
        workDto.setNextExecuteUserCompanyCode("1".equals(op) ? jgTransferNotice.getInstallUnitCreditCode() : jgTransferNotice.getReceiveOrgCreditCode());
        processTaskDTO = iCmWorkflowService.completeOrReject(jgTransferNotice.getNextTaskId(), workDto, op);
        // 提取节点等信息
        workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
        return workflowResultDto;
    }


    @Override
    public Map<String, Object> getCompanyType() {
        Map<String, Object> result = new HashMap<>();
        result.put("companyType", "");
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        if (reginParams == null) {
            return null;
        }
        CompanyBo currentCompany = reginParams.getCompany();
        result.put("companyName", currentCompany.getCompanyName());
        result.put("orgCode", currentCompany.getOrgCode());
        result.put("creditCode", currentCompany.getCompanyCode().contains("_") ? currentCompany.getCompanyCode().split("_")[1] : currentCompany.getCompanyCode());
        // 单位级别
        String companyLevel = CompanyTypeEnum.decideCompanyLevel(currentCompany.getCompanyType());
        // 单位类型
        String companyType = CompanyTypeEnum.decideCompanyCode(currentCompany.getCompanyType());
        String companyTypeName = CompanyTypeEnum.decideCompanyType(currentCompany.getCompanyType());
        if (!ValidationUtil.isEmpty(companyLevel)) {
            result.put("companyLevel", companyLevel);
            if (companyLevel.contains(",")) {
                result.put("companyLevel", "testAdmin");
            }
        }
        if (!ValidationUtil.isEmpty(companyType)) {
            result.put("companyType", companyType);
        }
        if (!ValidationUtil.isEmpty(companyTypeName)) {
            result.put("companyTypeName", companyTypeName);
        }

        return result;
    }

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

    private void processElseDataByStatus(FlowStatusEnum oldNoticeStatus, JgInstallationNotice installationNotice) {
        switch (oldNoticeStatus) {
            case TO_BE_SUBMITTED: // 待提交
                // 1.写入历史表
                this.saveHisDataBeforeUpdate(installationNotice);
                // 2.删除暂存时生成的待办
                commonService.deleteTasksByRelationId(installationNotice.getSequenceNbr() + "");
                break;
            case TO_BE_FINISHED: // 已完成
                // 1.删除之前完成时同步到一码通的施工信息
                this.deleteConstructionInfo(installationNotice);
                // 2.删除与设备的关系，设备可再次发起安装告知
                this.clearUseInfoOfEquip(installationNotice);
                // 3.清空redis 缓存的流程中及已完成安装告知的设备
                this.delRepeatUseEquipData(installationNotice);
                break;
            default:
                // 流程中（驳回、撤回等）
                // 1.待办任务更新为已完成
                this.finishedTask(installationNotice);
                // 2.终止流程-工作流报错暂时注释掉
                iCmWorkflowService.stopProcess(installationNotice.getInstanceId(), installationNotice.getCancelReason());
                // 3.写入历史表
                this.saveHisDataBeforeUpdate(installationNotice);
                // 4.清空redis（缓存的流程中及已完成安装告知的设备）
                this.delRepeatUseEquipData(installationNotice);
        }
    }

    private void finishedTask(JgInstallationNotice jgInstallationNotice) {
        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", jgInstallationNotice.getInstanceId());
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        jgInstallationNotice.setProxyStatementAttachment(null);
        jgInstallationNotice.setInstallContractAttachment(null);
        BeanUtils.copyProperties(jgInstallationNotice, taskMessageDto);
        taskMap.put("model", taskMessageDto);
        commonService.updateTaskModel(taskMap);
    }

    private void deleteConstructionInfo(JgInstallationNotice installationNotice) {
        constructionInfoMapper.delete(new LambdaQueryWrapper<IdxBizJgConstructionInfo>().eq(IdxBizJgConstructionInfo::getNoticeId, installationNotice.getSequenceNbr()));
    }

    private void clearUseInfoOfEquip(JgInstallationNotice installationNotice) {
        // 2.1 数据库的的USE_UNIT_CREDIT_CODE赋空
        LambdaQueryWrapper<JgInstallationNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JgInstallationNoticeEq::getEquipTransferId, installationNotice.getSequenceNbr());
        JgInstallationNoticeEq jgRelationEquip = jgInstallationNoticeEqMapper.selectOne(queryWrapper);
        // 强制更新字段为 NULL
        LambdaUpdateWrapper<IdxBizJgUseInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(IdxBizJgUseInfo::getRecord, jgRelationEquip.getEquId()); // 设置更新条件
        updateWrapper.set(IdxBizJgUseInfo::getUseUnitCreditCode, null);
        updateWrapper.set(IdxBizJgUseInfo::getUseUnitName, null);
        useInfoService.update(updateWrapper);
        // 2.2 es的USE_UNIT_CREDIT_CODE赋空
        Optional<ESEquipmentCategoryDto> optional = esEquipmentCategory.findById(jgRelationEquip.getEquId());
        if (optional.isPresent()) {
            ESEquipmentCategoryDto esEquipmentCategoryDto = optional.get();
            esEquipmentCategoryDto.setUSE_UNIT_CREDIT_CODE(null);
            esEquipmentCategoryDto.setUSE_UNIT_NAME(null);
            esEquipmentCategory.save(esEquipmentCategoryDto);
        }
    }
}