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.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
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.jg.api.dto.*;
import com.yeejoin.amos.boot.module.jg.api.entity.JgInstallationNotice;
import com.yeejoin.amos.boot.module.jg.api.entity.JgInstallationNoticeEq;
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.CommonMapper;
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.JgUseRegistrationMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgInstallationNoticeService;
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.feign.utils.FeignUtil;
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 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.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";

    @Autowired
    EquipmentCategoryMapper equipmentCategoryMapper;

    @Autowired
    JgInstallationNoticeEqMapper jgInstallationNoticeEqMapper;

    @Autowired
    JgUseRegistrationMapper jgUseRegistrationMapper;

    @Autowired
    private JgInstallationNoticeMapper jgInstallationNoticeMapper;

    @Autowired
    IdxBizJgRegisterInfoServiceImpl idxBizJgRegisterInfoService;

    @Autowired
    private ProduceInfoMapper produceInfoMapper;

    @Autowired
    IdxBizJgRegisterInfoMapper tzsJgRegistrationInfoMapper;
    @Autowired
    OtherInfoMapper tzsJgOtherInfoMapper;
    @Autowired
    TzsServiceFeignClient tzsServiceFeignClient;
    @Autowired
    SupervisoryCodeInfoMapper supervisoryCodeInfoMapper;

    @Autowired
    SuperviseInfoMapper superviseInfoMapper;

    @Autowired
    IIdxBizJgConstructionInfoService constructionInfoService;

    @Autowired
    IIdxBizJgUseInfoService useInfoService;

    @Autowired
    IdxBizJgUseInfoMapper idxBizJgUseInfoMapper;

    @Autowired
    private DataDictionaryMapper dataDictionaryMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private TzBaseUnitLicenceMapper baseUnitLicenceMapper;

    @Value("classpath:/json/urlInfo.json")
    public Resource bizTypeInfo;

    @Value(value = "${tzs.domain:http://sxtzsb.sxsei.com}")
    String TZSDOMAIN ;

    @Autowired
    AmosRequestContext amosRequestContext;


    @Autowired
    private ICmWorkflowService iCmWorkflowService;

    @Autowired
    private CommonServiceImpl commonService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    CodeUtil codeUtil;

    /**
     * 根据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());
        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());
        }

        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 安装告知
     */
    @SuppressWarnings({"rawtypes", "Duplicates"})
    @Transactional
    public JgInstallationNoticeDto updateInstallationNotice(String submitType, JgInstallationNoticeDto noticeDto, String op) {
        if (Objects.isNull(noticeDto) || StringUtils.isEmpty(submitType)) {
            throw new IllegalArgumentException("参数不能为空");
        }
        // 字段转换
        this.convertField(noticeDto);
        JgInstallationNotice notice = this.getById(noticeDto.getSequenceNbr());

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



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

        String orgCode;
        orgCode = reginParams.getCompany().getCompanyCode();
        model.setTransferToUserIds(reginParams.getUserModel().getUserId());
        Page<JgInstallationNotice> noticePage = jgInstallationNoticeMapper.queryForPage(page, model, type, orgCode);

        // 将Page<JgInstallationNotice>转化为Page<JgInstallationNoticeDto>
        Page<JgInstallationNoticeDto> noticeDtoPage = new Page<>();
        BeanUtils.copyProperties(noticePage, noticeDtoPage, "records");
        List<JgInstallationNoticeDto> records = noticePage.getRecords().stream().map(notice -> {
            JgInstallationNoticeDto noticeDto = new JgInstallationNoticeDto();
            BeanUtils.copyProperties(notice, noticeDto);
            if (Objects.nonNull(notice.getNoticeStatus())) {
                String noticeStatusDesc = FlowStatusEnum.getNameByType(Long.valueOf(notice.getNoticeStatus()));
                noticeDto.setNoticeStatusDesc(noticeStatusDesc);
            }
            return noticeDto;
        }).collect(Collectors.toList());
        noticeDtoPage.setRecords(records);

        return noticeDtoPage;
    }

    /**
     * 批量删除
     *
     * @param sequenceNbrs 主键
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteForBatch(Long[] sequenceNbrs) {
        if (Objects.isNull(sequenceNbrs) || sequenceNbrs.length == 0) {
            return false;
        }
        Collection<JgInstallationNotice> jgInstallationNotices = this.listByIds(Arrays.asList(sequenceNbrs));
        jgInstallationNotices.forEach(notice -> {
            if (StringUtils.hasText(notice.getInspectUnitId())) {
                throw new IllegalStateException("所选数据已存在流程，不能删除！");
            }
            notice.setIsDelete(true);
        });
        // 删除暂存的待办
        jgInstallationNotices.forEach(id -> commonService.deleteTaskModel(String.valueOf(id.getSequenceNbr())));
        return this.updateBatchById(jgInstallationNotices);
    }

    /**
     * 打印安装告知单
     *
     * @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", "".equals(getValue.apply("informNumber")) ?  getValue.apply("applyNo") : 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
    @SuppressWarnings({"Duplicates", "rawtypes"})
    @Transactional(rollbackFor = Exception.class)
    public List<JgInstallationNotice> saveNotice(String submitType, JSONObject jgInstallationNoticeDtoMap, ReginParams reginParams) {

        JgInstallationNoticeDto model = JSON.parseObject(jgInstallationNoticeDtoMap.get(TABLE_PAGE_ID).toString(), JgInstallationNoticeDto.class);
        // 字段转换
        convertField(model);

        // 获取告知设备列表
        List<Map<String, Object>> deviceList = model.getDeviceList();
        if (CollectionUtils.isEmpty(deviceList)) {
            throw new BadRequest("设备列表为空");
        }
        // 获取告知单号
        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;
    }

    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】的业务办理，【申请单号：%s】", obj.getEquList(), StringUtils.isEmpty(obj.getFactoryNum()) ? "" : obj.getFactoryNum(), obj.getApplyNo()));
            //申请单号
            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.deleteTaskModel(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) {
        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());
            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]);
            }
        }
//        StringBuffer buffer = new StringBuffer();
//        buffer.append(model.getProvinceName()).append(model.getCityName()).append(model.getCountyName()).append(model.getStreetName()).append(model.getAddress());
//        model.setEquAddress(buffer.toString());
    }


    @Transactional(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));
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void accept(JgInstallationNoticeDto dto,String op) {
        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 tzsJgRegistrationInfo = tzsJgRegistrationInfoMapper.selectOne(queryWrapper2);
                    String equCode = Optional.ofNullable(tzsJgRegistrationInfo.getEquDefine())
                            .orElse(tzsJgRegistrationInfo.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",tzsJgRegistrationInfo.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());
                    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);
                    jgInstallationNotice.setInformNumber(deviceRegistrationCode);
                    jgInstallationNotice.setSupervisoryCode(mapCode.get("superviseCode").toString());
                    jgInstallationNotice.setPromoter("");
                    // 生成设备代码及更新历史表的的设备代码字段
                    this.justGenerateEquCode(tzsJgRegistrationInfo,jgInstallationNotice.getReceiveOrgCreditCode(), jgInstallationNotice);
                    tzsJgRegistrationInfoMapper.updateById(tzsJgRegistrationInfo);
                    // 更新es
                    updateEquipEs(jgInstallationNotice, tzsJgOtherInfo, tzsJgRegistrationInfo, map1);
                    // 更新施工信息表
                    IdxBizJgConstructionInfo idxBizJgConstructionInfo = constructionInfoService.queryNewestDetailByRecord(jgRelationEquip.getEquId());
                    if (!ObjectUtils.isEmpty(idxBizJgConstructionInfo)) {
                        idxBizJgConstructionInfo.setUscUnitCreditCode(jgInstallationNotice.getInstallUnitCreditCode());
                        idxBizJgConstructionInfo.setUscUnitName(jgInstallationNotice.getInstallUnitName());
                        idxBizJgConstructionInfo.setUscDate(jgInstallationNotice.getInstallStartDate());
                        // 获取施工类型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.saveOrUpdateData(idxBizJgConstructionInfo);
                    }
                    // 更新使用信息
                    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 = commonService.updateTaskModel(taskMap);
                } 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));
            }
            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();
            }
        }
    }

    private void updateEquipEs(JgInstallationNotice jgInstallationNotice, OtherInfo tzsJgOtherInfo, IdxBizJgRegisterInfo tzsJgRegistrationInfo, Map<String, Object> map1) {
        Map<String,Map<String,Object>> objMap = new HashMap<>();
        map1.put("EQU_CODE",tzsJgRegistrationInfo.getEquCode() );
        map1.put("SUPERVISORY_CODE",tzsJgOtherInfo.getSupervisoryCode());
        map1.put("USE_UNIT_CREDIT_CODE",jgInstallationNotice.getUseUnitCreditCode());
        map1.put("USE_UNIT_NAME",jgInstallationNotice.getUseUnitName());
        map1.put("USC_UNIT_CREDIT_CODE",jgInstallationNotice.getInstallUnitCreditCode());
        map1.put("USC_UNIT_NAME",jgInstallationNotice.getInstallUnitName());
        map1.put("USE_PLACE",String.format("%s/%s/%s", jgInstallationNotice.getProvinceName(), jgInstallationNotice.getCityName(), jgInstallationNotice.getCounty()));
        map1.put("ADDRESS",String.format("%s/%s", jgInstallationNotice.getStreetName(), jgInstallationNotice.getAddress()));
        objMap.put(tzsJgOtherInfo.getRecord(), map1);
        tzsServiceFeignClient.commonUpdateEsDataByIds(objMap);
    }


    /**
     * 系统类型的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());
        idxBizJgUseInfoMapper.update(idxBizJgUseInfo, lambda);
    }

    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("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;
    }
}