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.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
import com.yeejoin.amos.boot.biz.common.service.IDataDictionaryService;
import com.yeejoin.amos.boot.biz.common.service.impl.DataDictionaryServiceImpl;
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.mapper.JgMaintainNoticeEqMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgMaintainNoticeMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgRegistrationHistoryMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgInstallationNoticeService;
import com.yeejoin.amos.boot.module.jg.api.service.IJgMaintainNoticeService;
import com.yeejoin.amos.boot.module.jg.api.vo.SortVo;
import com.yeejoin.amos.boot.module.jg.api.vo.tableDataExportVo.MaintainVo;
import com.yeejoin.amos.boot.module.jg.biz.config.LocalBadRequest;
import com.yeejoin.amos.boot.module.jg.biz.context.EquipUsedCheckStrategyContext;
import com.yeejoin.amos.boot.module.jg.biz.context.FlowingEquipRedisContext;
import com.yeejoin.amos.boot.module.jg.biz.event.CancellationEvent;
import com.yeejoin.amos.boot.module.jg.biz.event.publisher.EventPublisher;
import com.yeejoin.amos.boot.module.jg.biz.feign.TzsServiceFeignClient;
import com.yeejoin.amos.boot.module.jg.biz.service.ICmWorkflowService;
import com.yeejoin.amos.boot.module.jg.biz.service.ICompensateFlowDataOfRedis;
import com.yeejoin.amos.boot.module.jg.biz.service.IIdxBizJgRegisterInfoService;
import com.yeejoin.amos.boot.module.jg.biz.utils.WordTemplateUtils;
import com.yeejoin.amos.boot.module.ymt.api.entity.RegistrationInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.TzBaseEnterpriseInfo;
import com.yeejoin.amos.boot.module.ymt.api.enums.ApplicationFormTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.*;
import com.yeejoin.amos.feign.systemctl.model.TaskV2Model;
import com.yeejoin.amos.feign.workflow.Workflow;
import com.yeejoin.amos.feign.workflow.model.*;
import io.seata.spring.annotation.GlobalTransactional;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

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

/**
 * 服务实现类
 *
 * @author system_generator
 * @date 2023-12-12
 */
@Service
public class JgMaintainNoticeServiceImpl extends BaseService<JgMaintainNoticeDto, JgMaintainNotice, JgMaintainNoticeMapper> implements IJgMaintainNoticeService, ICompensateFlowDataOfRedis<JgMaintainNotice> {

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

    @Autowired
    EventPublisher eventPublisher;

    @Autowired
    private ICmWorkflowService iCmWorkflowService;

    @Autowired
    IJgInstallationNoticeService iJgInstallationNoticeService;

    @Autowired
    EquipmentCategoryMapper equipmentCategoryMapper;
    @Autowired
    JgMaintainNoticeEqMapper jgMaintainNoticeEqMapper;

    @Autowired
    JgMaintainNoticeEqServiceImpl jgMaintainNoticeEqService;
    @Autowired
    private JgMaintainNoticeMapper jgMaintainNoticeMapper;

    @Autowired
    TzsServiceFeignClient tzsServiceFeignClient;
    @Autowired
    RegistrationInfoMapper tzsJgRegistrationInfoMapper;

    @Autowired
    OtherInfoMapper tzsJgOtherInfoMapper;

    @Autowired
    ESEquipmentCategory esEquipmentCategory;

    @Autowired
    private Sequence sequence;

    @Autowired
    SupervisoryCodeInfoMapper supervisoryCodeInfoMapper;

    @Autowired
    IDataDictionaryService dataDictionaryService;

    @Autowired
    RedisUtils redisUtils;

    @Autowired
    DataDictionaryServiceImpl iDataDictionaryService;

    @Autowired
    private CommonServiceImpl commonService;

    @Autowired
    private CmWorkflowServiceImpl cmWorkflowService;

    @Autowired
    IIdxBizJgRegisterInfoService idxBizJgRegisterInfoService;

    @Autowired
    JgInstallationNoticeServiceImpl jgInstallationNoticeService;

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private JgRegistrationHistoryMapper jgRegistrationHistoryMapper;
    @Autowired
    private TzBaseEnterpriseInfoMapper tzBaseEnterpriseInfoMapper;

    @Autowired
    private JgCertificateChangeRecordServiceImpl certificateChangeRecordService;
    @Autowired
    private JgCertificateChangeRecordEqServiceImpl jgCertificateChangeRecordEqServiceImpl;

    /**
     * 根据sequenceNbr查询
     *
     * @param sequenceNbr 主键
     * @return 维修告知
     */
    @Override
    public Map<String, Map<String, Object>> queryBySequenceNbr(Long sequenceNbr) {
        // 维修告知信息
        JgMaintainNotice notice = jgMaintainNoticeMapper.selectById(sequenceNbr);
        if (Objects.isNull(notice)) {
            return null;
        }
        this.doCompensate(notice);
        Map<String, Object> maintainInfo = BeanUtil.beanToMap(notice, false, true);
        maintainInfo.put("powerOfAttorneyList", JSON.parse(notice.getPowerOfAttorney()));
        maintainInfo.put("constructionContractList", JSON.parse(notice.getConstructionContract()));
        maintainInfo.put("province", notice.getProvince() + "_" + notice.getProvinceName());
        maintainInfo.put("city", ObjectUtils.isEmpty(notice.getCity()) ? null : notice.getCity() + "_" + notice.getCityName());
        maintainInfo.put("constructionManagerId", ObjectUtils.isEmpty(notice.getConstructionManagerId()) ? null : notice.getConstructionManagerId() + "_" + notice.getConstructionManager());
        maintainInfo.put("county", ObjectUtils.isEmpty(notice.getCounty()) ? null : notice.getCounty() + "_" + notice.getCountyName());
        maintainInfo.put("fullAddress", notice.getProvinceName() + notice.getCityName() + notice.getCounty() + notice.getStreetName() + notice.getAddress());
        maintainInfo.put("projectContraption", notice.getProjectContraption());
        maintainInfo.put("EQU_LIST_CODE", notice.getEquListCode());
        maintainInfo.put("EQU_CATEGORY_CODE", notice.getEquCategory());
        maintainInfo.put("QUERY_TYPE", "GZ_WX");
        maintainInfo.put("IS_INTO_MANAGEMENT", Boolean.TRUE);
        //maintainInfo.put("useUnitCreditCode", ObjectUtils.isEmpty(notice.getUseUnitCreditCode()) ? null : notice.getUseUnitCreditCode() + "_" + notice.getUseUnitName());
        if (!ObjectUtils.isEmpty(notice.getUseUnitCreditCode())) {
            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) : "");
                maintainInfo.put("useUnitCreditCode", result);
            }
        }
        maintainInfo.put("receiveOrgCode", notice.getReceiveCompanyCode() + "_" + notice.getReceiveOrgName());
        if (!ValidationUtil.isEmpty(notice.getInspectionUnitCreditCode()) && !ValidationUtil.isEmpty(notice.getInspectionUnitName())) {
            maintainInfo.put("inspectUnitId", notice.getInspectionUnitCreditCode() + "_" + notice.getInspectionUnitName());
        }
        if (!ValidationUtil.isEmpty(notice.getStreet()) && !ValidationUtil.isEmpty(notice.getStreetName())) {
            maintainInfo.put("street", notice.getStreet() + "_" + notice.getStreetName());
        }
        if ((Integer.parseInt(notice.getNoticeStatus()) == FlowStatusEnum.TO_BE_FINISHED.getCode()) ||
                (Integer.parseInt(notice.getNoticeStatus()) == FlowStatusEnum.TO_BE_DISCARD.getCode())) {
            // 完成 或者 作废时显示历史数据
            JSONObject hisData = commonService.queryHistoryData(notice.getSequenceNbr());
            // 兼容老数据
            if (hisData == null || ObjectUtils.isEmpty(hisData.get("deviceList"))) {
                // 老数据逻辑
                setNewEquipInfo(sequenceNbr, maintainInfo);
                return new HashMap<String, Map<String, Object>>() {{
                    put(TABLE_PAGE_ID, maintainInfo);
                }};
            } else {
                // 新数据逻辑
                hisData.putAll(maintainInfo);
                CommonServiceImpl.formatTime2StrDateForEquip(hisData);
//                setNewEquipInfo(sequenceNbr, maintainInfo);
//                hisData.put("deviceList", maintainInfo.get("deviceList"));
                return new HashMap<String, Map<String, Object>>() {{
                    this.put(TABLE_PAGE_ID, hisData);
                }};
            }
        } else {
            setNewEquipInfo(sequenceNbr, maintainInfo);
            return new HashMap<String, Map<String, Object>>() {{
                put(TABLE_PAGE_ID, maintainInfo);
            }};
        }
    }

    private void checkRepeatUsed(String submitType, JgMaintainNotice notice) {
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            // 流程中校验
            LambdaQueryWrapper<JgMaintainNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(JgMaintainNoticeEq::getEquipTransferId, notice.getSequenceNbr());
            JgMaintainNoticeEq noticeEq = jgMaintainNoticeEqMapper.selectOne(queryWrapper);
            EquipUsedCheckStrategyContext.getUsedStrategy(PROCESS_DEFINITION_KEY)
                    .equipRepeatUsedCheck(noticeEq.getEquId(), notice.getInstallUnitCreditCode());
        }
    }

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

    /**
     * 删除 redis校验重复引用设备的数据
     */
    private void delRepeatUseEquipData(JgMaintainNotice notice) {
        if (NOT_FLOWING_STATE.contains(notice.getNoticeStatus())) {

            LambdaQueryWrapper<JgMaintainNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(JgMaintainNoticeEq::getEquipTransferId, notice.getSequenceNbr());
            List<JgMaintainNoticeEq> noticeEq = jgMaintainNoticeEqMapper.selectList(queryWrapper);
            for (JgMaintainNoticeEq jgMaintainNoticeEq : noticeEq) {
                EquipUsedCheckStrategyContext.getUsedStrategy(PROCESS_DEFINITION_KEY)
                        .delDataForCheckEquipRepeatUsed(Collections.singletonList(jgMaintainNoticeEq.getEquId()), notice.getInstallUnitCreditCode());
            }
        }
    }

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

    private void setNewEquipInfo(Long sequenceNbr, Map<String, Object> maintainInfo) {
        List<JgMaintainNoticeEq> jgMaintainNoticeEq = jgMaintainNoticeEqMapper.selectList(new LambdaQueryWrapper<JgMaintainNoticeEq>().eq(JgMaintainNoticeEq::getEquipTransferId, sequenceNbr));
        List<String> ids = jgMaintainNoticeEq.stream().map(JgMaintainNoticeEq::getEquId).collect(Collectors.toList());

        Iterable<ESEquipmentCategoryDto> esEquipmentCategoryDtos = esEquipmentCategory.findAllById(ids);
        List<Map<String, Object>> deviceList = getEquipListMaps(esEquipmentCategoryDtos);
        maintainInfo.put("deviceList", deviceList);
    }

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

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

    /**
     * 更新维修告知
     *
     * @param noticeDto 维修告知
     */
    @Override
    @SuppressWarnings({"rawtypes", "Duplicates"})
    @Transactional
    public JgMaintainNoticeDto updateMaintainNotice(String submitType, JgMaintainNoticeDto noticeDto, String op, ReginParams reginParams) {

        try {
            if (Objects.isNull(noticeDto) || StringUtils.isEmpty(submitType)) {
                throw new IllegalArgumentException("参数不能为空");
            }
            // 字段转换
            this.convertField(noticeDto);

            // 获取告知设备列表
            List<Map<String, Object>> deviceList = noticeDto.getDeviceList();
            if (CollectionUtils.isEmpty(deviceList)) {
                throw new BadRequest("请选择设备");
            }

            // 提交时对设备状态进行校验（处理并发问题，一个未被使用的设备同时被多个使用这打开，同时提交发起申请）
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                this.repeatUsedEquipCheck(deviceList, reginParams.getCompany().getCompanyCode());
            }

            JgMaintainNotice notice = jgMaintainNoticeMapper.selectById(noticeDto.getSequenceNbr());
            //  submitType=1为流程提交否则仅为保存业务数据
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                ProcessTaskDTO processTaskDTO = new ProcessTaskDTO();
                WorkflowResultDto workflowResultDto = new WorkflowResultDto();
                // 如果没有实例ID，说明是启动并执行一步
                // 直接调用工作流 启动并执行API  -  可以拿到两个节点的信息，用于填充业务字段
                // 如果有实例ID，为撤回或者驳回后重新提交
                if (!StringUtils.hasText(noticeDto.getInstanceId())) {
                    // 发起流程
                    ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
                    List<ActWorkflowStartDTO> list = new ArrayList<>();
                    ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                    dto.setProcessDefinitionKey(PROCESS_DEFINITION_KEY);
                    dto.setBusinessKey(String.valueOf(noticeDto.getSequenceNbr()));
                    dto.setCompleteFirstTask(Boolean.TRUE);
                    //下一节点执行人单位（下节点接收机构code）
                    dto.setNextExecuteUserCompanyCode(notice.getReceiveCompanyCode());
                    list.add(dto);
                    actWorkflowBatchDTO.setProcess(list);
                    processTaskDTO = cmWorkflowService.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.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    notice.setPromoter(RequestContext.getExeUserId());
                    notice.setNextExecuteIds(String.join(",", workflowResultDto.getNextExecutorRoleIds()));
                    notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    notice.setInstanceId(workflowResultDto.getInstanceId());
                    notice.setNextTaskId(workflowResultDto.getNextTaskId());
                    notice.setEquList(String.valueOf(deviceList.get(0).get("EQU_LIST")));
                    jgMaintainNoticeMapper.updateById(notice);
                    // 如果为保存并提交，则创建代办
                    buildTask(notice, Collections.singletonList(workflowResultDto), Boolean.TRUE);
                } else {
                    // 只调用执行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);
                    }
                    //下一节点执行人单位（下节点接收机构code）
                    dto.setNextExecuteUserCompanyCode(notice.getReceiveCompanyCode());
                    dto.setVariable(commMap);
                    processTaskDTO = cmWorkflowService.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.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    notice.setPromoter(RequestContext.getExeUserId());
                    notice.setNextExecuteIds(String.join(",", workflowResultDto.getNextExecutorRoleIds()));
                    notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
                    notice.setNextTaskId(workflowResultDto.getNextTaskId());
                    notice.setEquList(String.valueOf(deviceList.get(0).get("EQU_LIST")));
                    jgMaintainNoticeMapper.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(notice, Collections.singletonList(workflowResultDto), Boolean.FALSE);
                    } else {
                        TaskModelDto taskModelDto = new TaskModelDto();
                        BeanUtils.copyProperties(taskV2Model, taskModelDto);
                        // 创建新的代办
                        TaskMessageDto taskMessageDto = new TaskMessageDto();
                        BeanUtils.copyProperties(notice, taskMessageDto);
                        taskModelDto.setModel(taskMessageDto);
                        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());
                        commonService.buildTaskModel(Collections.singletonList(taskModelDto));
                    }
                }
                commonService.saveExecuteFlowData2Redis(notice.getInstanceId(), this.buildInstanceRuntimeData(notice));
            } else {
                JgMaintainNotice bean = new JgMaintainNotice();
                BeanUtils.copyProperties(noticeDto, bean);
                jgMaintainNoticeMapper.updateById(bean);
            }
            LambdaQueryWrapper<JgMaintainNoticeEq> lambdaQueryWrapper = new LambdaQueryWrapper();
            lambdaQueryWrapper.eq(JgMaintainNoticeEq::getEquipTransferId, noticeDto.getSequenceNbr());
            jgMaintainNoticeEqMapper.delete(lambdaQueryWrapper);
            List<JgMaintainNoticeEq> equipList = new ArrayList<>();
            deviceList.forEach(obj -> {
                JgMaintainNoticeEq jgRelationEquip = new JgMaintainNoticeEq();
                jgRelationEquip.setEquId(String.valueOf(obj.get("SEQUENCE_NBR")));
                jgRelationEquip.setEquipTransferId(noticeDto.getSequenceNbr().toString());
                jgRelationEquip.setEquCode(ObjectUtils.isEmpty(obj.get("EQU_CODE"))?null:String.valueOf(obj.get("EQU_CODE")));
                jgRelationEquip.setEquListCode(String.valueOf(obj.get("EQU_LIST_CODE")));
                jgRelationEquip.setEquCategoryCode(String.valueOf(obj.get("EQU_CATEGORY_CODE")));
                equipList.add(jgRelationEquip);
            });
            jgMaintainNoticeEqMapper.insertBatchSomeColumn(equipList);
            // 更新历史表
            notice.setDeviceList(deviceList);
            commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getName(), JSON.parseObject(JSON.toJSONString(notice)), "", notice.getSequenceNbr().toString());
            return noticeDto;
        } catch (BadRequest | LocalBadRequest e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw e;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw new BadRequest("保存失败！");
        } finally {
            FlowingEquipRedisContext.clean();
        }
    }


    /**
     * 分页查询
     *
     * @param page  分页对象
     * @param model 查询参数
     * @return 维修告知列表
     */
    @Override
    public Page<Map<String, Object>> queryForJgMaintainNoticePage(Page<JgMaintainNotice> page, String sort, JgMaintainNoticeDto model, ReginParams reginParams) {
        String orgCode = reginParams.getCompany().getCompanyCode();
        String type = reginParams.getCompany().getLevel();
        String userId = reginParams.getUserModel().getUserId();
        SortVo sortMap = commonService.sortFieldConversion(sort);
        List<DataDictionary> dictionaries = dataDictionaryService.getByType("WXLX");
        Page<Map<String, Object>> noticePage = jgMaintainNoticeMapper.queryForPage(page, sortMap, model, type, orgCode, userId);

        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);
                String maintainTypeDesc = dictionaries.stream().filter(d -> notice.get("maintainType").equals(d.getCode())).map(DataDictionary::getName).collect(Collectors.joining());
                notice.put("maintainTypeDesc", maintainTypeDesc);
            });
        }).collect(Collectors.toList());
        noticePage.setRecords(mappedRecords);
        return noticePage;
    }

    /**
     * 列表查询-导出用
     */
    public List<MaintainVo> queryMaintainInIds(List<String> ids) {
        List<DataDictionary> dictionaries = dataDictionaryService.getByType("WXLX");
        List<MaintainVo> maintainVos = jgMaintainNoticeMapper.queryMaintainInIds(ids);
        return maintainVos.stream().peek(notice -> {
            Optional.ofNullable(notice.getNoticeStatus()).ifPresent(status -> notice.setNoticeStatus(FlowStatusEnum.getNameByType(Long.valueOf(status))));
            Optional.ofNullable(notice.getMaintainType()).ifPresent(status -> {
                String collect = dictionaries.stream().filter(d -> notice.getMaintainType().equals(d.getCode())).map(DataDictionary::getName).collect(Collectors.joining());
                notice.setMaintainType(collect);
            });
        }).collect(Collectors.toList());
    }


    /**
     * 打印维修告知单
     *
     * @param sequenceNbr 主键
     * @return pdf文件路径
     */
    @Override
    public void generateMaintainNoticeReport(Long sequenceNbr, HttpServletResponse response) {
        if (Objects.isNull(sequenceNbr)) {
            throw new IllegalArgumentException("参数不能为空");
        }
        JgMaintainNotice JgMaintainNotice = this.getById(sequenceNbr);
        List<JgMaintainNoticeEq> list = jgMaintainNoticeEqService.lambdaQuery().eq(JgMaintainNoticeEq::getEquipTransferId, sequenceNbr).list();
        HashMap<String, Object> map = new HashMap<>();
        List<Map<String, Object>> placeholderList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(list)){
            for (JgMaintainNoticeEq jgMaintainNoticeEq : list) {
                List<Map<String, Object>> informationList = jgMaintainNoticeMapper.queryEquipInformation(jgMaintainNoticeEq.getSequenceNbr());
                if (Objects.isNull(JgMaintainNotice) || CollectionUtils.isEmpty(informationList)) {
                    throw new IllegalArgumentException("维修告知单不存在");
                }
                Map<String, Object> placeholders = jgInstallationNoticeService.fullFillTemplateObj(informationList, BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getName().substring(0, 2));
                placeholderList.add(placeholders);
            }
        }
        map.put("equipBasicInfoList", placeholderList);

        String tempFileName = "维修告知单_" + System.currentTimeMillis() + "_temp";
        // String url = WordTemplateUtils.templateToPdf(tempFileName, "installation-notification-report.ftl", placeholders);
        // // 更新到数据库
        // JgMaintainNotice.setNoticeReportUrl(url);
        // this.updateById(JgMaintainNotice);
        WordTemplateUtils.templateToPdfDownload(tempFileName, "installation-notification-report.ftl", map, response);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBySequenceNbr(Long[] sequenceNbrs) {
        for (Long sequenceNbr : sequenceNbrs) {
            JgMaintainNotice jgMaintainNotice = this.baseMapper.selectById(sequenceNbr);
            // 删除待办 + 中止流程
            commonService.deleteTaskModel(sequenceNbr + "", jgMaintainNotice.getInstanceId());
            // 删除业务单
            this.baseMapper.deleteById(sequenceNbr);
            // 删除对应equ
            jgMaintainNoticeEqMapper.delete(new QueryWrapper<JgMaintainNoticeEq>().lambda()
                    .eq(JgMaintainNoticeEq::getEquipTransferId, sequenceNbr));
            // 删除单子对应历史表数据
            jgRegistrationHistoryMapper.delete(new LambdaQueryWrapper<JgRegistrationHistory>()
                    .eq(JgRegistrationHistory::getCurrentDocumentId, jgMaintainNotice.getSequenceNbr()));
        }
        return true;
    }

    @Override
    @SuppressWarnings({"Duplicates", "rawtypes"})
    @Transactional(rollbackFor = Exception.class)
    public List<JgMaintainNotice> saveNotice(String submitType, Map<String, Object> jgMaintainNoticeDtoMap, ReginParams reginParams) {
        try {
            JgMaintainNoticeDto model = JSON.parseObject(JSONObject.toJSONString(jgMaintainNoticeDtoMap.get(TABLE_PAGE_ID)), JgMaintainNoticeDto.class);

            // 字段转换
            convertField(model);
            // 获取告知设备列表
            List<Map<String, Object>> deviceList = model.getDeviceList();
            if (CollectionUtils.isEmpty(deviceList)) {
                throw new BadRequest("请选择设备");
            }

            // 提交时对设备状态进行校验（处理并发问题，一个未被使用的设备同时被多个使用这打开，同时提交发起申请）
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                this.repeatUsedEquipCheck(deviceList, reginParams.getCompany().getCompanyCode());
            }
            // 获取告知单号
            ResponseModel<List<String>> applyNoResult = tzsServiceFeignClient.applicationFormCode(ApplicationFormTypeEnum.WXGZ.getCode(), 1);

            if (CollectionUtils.isEmpty(applyNoResult.getResult())) {
                log.error(" 获取告知单号失败");
                throw new RuntimeException();
            }
            String applyNo = applyNoResult.getResult().get(0);
            List<WorkflowResultDto> workflowResultDtoList = workFlowInfo(submitType, model.getReceiveCompanyCode());
            List<JgMaintainNoticeEq> equipList = new ArrayList<>();
            CompanyBo companyBo = commonService.getOneCompany(model.getReceiveCompanyCode());
            // 维修告知表添加数据
            JgMaintainNotice notice = new JgMaintainNotice();
            BeanUtils.copyProperties(model, notice);
            notice.setApplyNo(applyNo);
            // 统计使用
            notice.setReceiveCompanyOrgCode(companyBo.getOrgCode());
            notice.setNoticeDate(new Date());
            notice.setEquListCode(model.getEquListCode());
            notice.setCreateUserCompanyName(reginParams.getCompany().getCompanyName());

            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                notice.setNextExecuteIds(workflowResultDtoList.get(0).getNextExecutorRoleIds());
                notice.setInstanceStatus(workflowResultDtoList.get(0).getNextExecutorRoleIds() + "," + workflowResultDtoList.get(0).getExecutorRoleIds());
                notice.setPromoter(reginParams.getUserModel().getUserId());
                notice.setNextExecuteUserIds(workflowResultDtoList.get(0).getNextExecutorUserIds());
                notice.setNextTaskId(workflowResultDtoList.get(0).getNextTaskId());
                notice.setInstanceId(workflowResultDtoList.get(0).getInstanceId());
                notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode()));
            } else {
                notice.setNextExecuteUserIds(reginParams.getUserModel().getUserId());
                notice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_SUBMITTED.getCode()));
            }
            notice.setEquListCode(String.valueOf(deviceList.get(0).get("EQU_LIST_CODE")));
            notice.setEquCategory(String.valueOf(deviceList.get(0).get("EQU_CATEGORY_CODE")));

            notice.setInstallUnitName(reginParams.getCompany().getCompanyName());
            notice.setInstallUnitCreditCode(reginParams.getCompany().getCompanyCode());
            notice.setCreateUserName(reginParams.getUserModel().getRealName());
            notice.setCreateUserId(reginParams.getUserModel().getUserId());
            DataDictionary dictionary = iDataDictionaryService.getByCode(notice.getMaintainType(), "WXLX");
            notice.setMaintainTypeDesc(dictionary.getName());
            notice.setFullAddress(notice.getProvinceName() + notice.getCityName() + notice.getCountyName() + notice.getStreetName() + notice.getAddress());
            notice.setEquCategoryDesc(String.valueOf(deviceList.get(0).get("EQU_CATEGORY")));
            notice.setEquList(String.valueOf(deviceList.get(0).get("EQU_LIST")));
            deviceList.forEach(obj -> {
                JgMaintainNoticeEq jgRelationEquip = new JgMaintainNoticeEq();
                jgRelationEquip.setEquId(String.valueOf(obj.get("SEQUENCE_NBR")));
                jgRelationEquip.setEquipTransferId(applyNo);
                jgRelationEquip.setEquCode(ObjectUtils.isEmpty(obj.get("EQU_CODE"))?null:String.valueOf(obj.get("EQU_CODE")));
                jgRelationEquip.setEquListCode(String.valueOf(obj.get("EQU_LIST_CODE")));
                jgRelationEquip.setEquCategoryCode(String.valueOf(obj.get("EQU_CATEGORY_CODE")));
                equipList.add(jgRelationEquip);
            });
            notice.setCreateDate(new Date());
            jgMaintainNoticeMapper.insert(notice);
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                buildTask(notice, workflowResultDtoList, Boolean.TRUE);
            } else {
                // 暂存任务
                buildTaskDraft(notice);
            }
            List<JgMaintainNoticeEq> jgRelationEquipList = equipList.stream().map(jgRelationEquip -> jgRelationEquip.setEquipTransferId(String.valueOf(notice.getSequenceNbr()))).collect(Collectors.toList());
            jgMaintainNoticeEqMapper.insertBatchSomeColumn(jgRelationEquipList);
            this.updateRedisBatch(notice);
            // 写入历史表
            commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getName(), JSON.parseObject(JSON.toJSONString(notice)), "", notice.getSequenceNbr().toString());
            return Collections.singletonList(notice);
        } catch (BadRequest | LocalBadRequest e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw e;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            this.rollBackForDelRedisData();
            throw new BadRequest("保存失败！");
        } finally {
            FlowingEquipRedisContext.clean();
        }
    }

    private void updateRedisBatch(JgMaintainNotice jgMaintainNotice) {
        if (!ObjectUtils.isEmpty(jgMaintainNotice.getInstanceId())){
            commonService.saveExecuteFlowData2Redis(jgMaintainNotice.getInstanceId(), this.buildInstanceRuntimeData(jgMaintainNotice));
        }
    }

    /**
     * 暂存任务生成待办
     *
     * @param maintainNotice 业务信息
     */
    private void buildTaskDraft(JgMaintainNotice maintainNotice) {
        List<TaskModelDto> modelDtos = new ArrayList<>();

        TaskModelDto dto = new TaskModelDto();
        //行数据
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtils.copyProperties(maintainNotice, taskMessageDto);
        taskMessageDto.setNextTaskId(maintainNotice.getNextTaskId());
        dto.setModel(taskMessageDto);
        //摘要 按原有规则组装
        dto.setTaskContent(String.format("来自%s的业务办理，【申请单号%s】",maintainNotice.getEquList(), maintainNotice.getApplyNo()));
        //申请单号
        dto.setTaskCode(maintainNotice.getApplyNo());
        //业务类型枚举code值
        dto.setTaskType(BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getCode());
        ////业务主键
        dto.setRelationId(maintainNotice.getSequenceNbr() + "");
        modelDtos.add(dto);

        commonService.buildTaskModel(modelDtos);
    }

    /**
     * 插入代办
     */
    private void buildTask(JgMaintainNotice dto, List<WorkflowResultDto> workflowResultList, Boolean bool) {
        List<TaskModelDto> taskModelDtoList = new ArrayList<>();
        WorkflowResultDto workflowResultDto = workflowResultList.get(0);

        TaskModelDto taskModelDto = new TaskModelDto();
        taskModelDto.setFlowCreateDate(dto.getCreateDate());
        taskModelDto.setTaskName(workflowResultDto.getNextTaskName()); // 工作流API返回
        taskModelDto.setTaskCode(dto.getApplyNo());
        taskModelDto.setTaskType(BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getCode());
        taskModelDto.setTaskTypeLabel(BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getName());
        String instanceId = workflowResultList.stream().filter(e -> e.getInstanceId().equals(dto.getInstanceId())).findFirst().orElse(null).getInstanceId();
        taskModelDto.setRelationId(instanceId);
        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(dto.getNextTaskId());
        taskModelDto.setStartUserId(dto.getCreateUserId());
        taskModelDto.setStartUser(dto.getCreateUserName());
        taskModelDto.setStartUserCompanyName(dto.getCreateUserCompanyName()); // 任务发起人所在单位
        taskModelDto.setStartDate(dto.getCreateDate());
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtils.copyProperties(dto, taskMessageDto);
        taskMessageDto.setNextTaskId(dto.getNextTaskId());
        taskModelDto.setModel(taskMessageDto);
        taskModelDto.setNextExecuteUser(dto.getNextExecuteIds());
        taskModelDto.setTaskContent(String.format("来自%s的业务办理，【申请单号：%s】",dto.getEquList(), dto.getApplyNo()));
        taskModelDtoList.add(taskModelDto);
        if (bool) {
            // 删除暂存时生成的待办
            commonService.deleteTasksByRelationId(dto.getSequenceNbr() + "");
        }

        commonService.buildTaskModel(taskModelDtoList);
    }


    private List<WorkflowResultDto> workFlowInfo(String submitType,String receiveCompanyCode) {
        if (SUBMIT_TYPE_FLOW.equals(submitType)) {
            // 发起流程
            ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
            List<ActWorkflowStartDTO> list = new ArrayList<>();

                ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                dto.setProcessDefinitionKey(PROCESS_DEFINITION_KEY);
                //下一节点执行人单位（下节点接收机构code）
                dto.setNextExecuteUserCompanyCode(receiveCompanyCode);
                dto.setCompleteFirstTask(Boolean.TRUE);
                list.add(dto);

            actWorkflowBatchDTO.setProcess(list);
            List<ProcessTaskDTO> processTaskDTOS = cmWorkflowService.startBatch(actWorkflowBatchDTO);
            return commonService.buildWorkFlowInfo(processTaskDTOS);
        }
        return new ArrayList<>();
    }


    private void convertField(JgMaintainNoticeDto model) {
        if (null == model) {
            return;
        }
        // 处理附件
        if (!ValidationUtil.isEmpty(model.getPowerOfAttorneyList())) {
            model.setPowerOfAttorney(JSON.toJSONString(model.getPowerOfAttorneyList()));
        }
        if (!ValidationUtil.isEmpty(model.getConstructionContractList())) {
            model.setConstructionContract(JSON.toJSONString(model.getConstructionContractList()));
        }
        // 分割省市区街道字段
        String province = model.getProvince();
        if (!ObjectUtils.isEmpty(province)) {
            String[] provinceList = province.split("_");
            if (provinceList.length > 1) {
                model.setProvince(provinceList[0]);
                model.setProvinceName(provinceList[1]);
            }
        }
        String city = model.getCity();
        if (!ObjectUtils.isEmpty(city)) {
            String[] cityList = city.split("_");
            if (cityList.length > 1) {
                model.setCity(cityList[0]);
                model.setCityName(cityList[1]);
            }
        }

        String county = model.getCounty();
        if (!ObjectUtils.isEmpty(county)) {
            String[] countyList = county.split("_");
            if (countyList.length > 1) {
                model.setCounty(countyList[0]);
                model.setCountyName(countyList[1]);
            }
        }
        String street = model.getStreet();
        if (!ObjectUtils.isEmpty(street)) {
            String[] streetList = street.split("_");
            if (streetList.length > 1) {
                model.setStreet(streetList[0]);
                model.setStreetName(streetList[1]);
            }
        }
        // 分割单位
        String useUnitId = model.getUseUnitCreditCode();
        if (!ObjectUtils.isEmpty(useUnitId)) {
            String[] useUnitList = useUnitId.split("_");
            if (useUnitList.length > 1) {
                model.setUseUnitCreditCode(useUnitList[0]);
                model.setUseUnitName(useUnitList[1]);
            }
        }
        //  分割接收机构
        String receiveOrgId = model.getReceiveOrgCode();
        if (!ObjectUtils.isEmpty(receiveOrgId)) {
            String[] receiveOrgIdList = receiveOrgId.split("_");
            if (receiveOrgIdList.length > 1) {
                model.setReceiveCompanyCode(receiveOrgIdList[0]);
                model.setReceiveOrgName(receiveOrgIdList[1]);
                model.setReceiveOrgCode(null);
            }
        }

        String constructionManager = model.getConstructionManagerId();
        if (!ObjectUtils.isEmpty(constructionManager)) {
            String[] constructionManagerList = constructionManager.split("_");
            if (constructionManagerList.length > 1) {
                model.setConstructionManagerId(constructionManagerList[0]);
                model.setConstructionManager(constructionManagerList[1]);
            }
        }

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

    public boolean submit(JgMaintainNotice notice, String op, String opinion) {
        AjaxResult ajaxResult = Workflow.taskClient.getTask(notice.getInstanceId());
        JSONObject dataObject = JSON.parseObject(JSON.toJSONString(ajaxResult.get("data")));
        String taskId = dataObject.getString("id");
        //组装信息
        TaskResultDTO dto = new TaskResultDTO();
        dto.setResultCode("approvalStatus");
        dto.setTaskId(taskId);
        if (!StringUtils.isEmpty(opinion)) {
            dto.setComment(opinion);
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("approvalStatus", op);
        dto.setVariable(map);
        //执行流程
        AjaxResult ajaxResult1 = null;
        try {
            ajaxResult1 = Workflow.taskClient.completeByTask(taskId, dto);
            if (ajaxResult1.get("code").equals(200)) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("JgMaintainNoticeServiceImpl.submit提交失败：{}", e);
            return false;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void cancel(JgMaintainNoticeDto 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);
            JgMaintainNotice jgMaintainNotice = this.baseMapper.selectById(noticeDto.getSequenceNbr());
            ProcessTaskDTO processTaskDTO = cmWorkflowService.rollBack(jgMaintainNotice.getInstanceId());
            // 提取节点等信息
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            jgMaintainNotice.setPromoter("");
            jgMaintainNotice.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
            jgMaintainNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.ROLLBACK.getCode()));
            jgMaintainNotice.setNextTaskId(workflowResultDto.getNextTaskId());
            jgMaintainNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
            updateById(jgMaintainNotice);
            // 删除待办
            JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(jgMaintainNotice));
            jsonObject.put("nextExecuteUser", jgMaintainNotice.getNextExecuteIds());
            jsonObject.put("taskType", BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getCode());
            jsonObject.put("flowStatusLabel", FlowStatusEnum.ROLLBACK.getName());
            jsonObject.put("flowStatus", FlowStatusEnum.ROLLBACK.getCode());

            commonService.rollbackTask(jgMaintainNotice.getInstanceId(), jsonObject);
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgMaintainNotice));
            this.delRepeatUseEquipData(jgMaintainNotice);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

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

    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void accept(JgMaintainNoticeDto dto, String op, String opinion,Map<String, Object> model) {
        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);
            JgMaintainNotice jgMaintainNotice = this.jgMaintainNoticeMapper.selectById(dto.getSequenceNbr());
            // 组装设备注册代码
            String ym = null;
            try {
                ym = DateUtils.dateFormat(new Date(), DateUtils.DATE_PATTERN_MM);
            } catch (ParseException e) {
                log.error("日期转换失败：{}", e);
            }
            //组装信息
            TaskResultDTO taskResultDTO = assembleData(jgMaintainNotice, op, opinion);
            ProcessTaskDTO processTaskDTO = cmWorkflowService.completeOrReject(jgMaintainNotice.getNextTaskId(), taskResultDTO, op);

            // 提取节点等信息
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            TaskV2Model taskV2Model;
            if ("0".equals(op)) {
                // 判断如果下一步执行角色列表为空则流程完成
                if (StringUtils.isEmpty(workflowResultDto.getNextExecutorRoleIds())) {
                    LambdaQueryWrapper<JgMaintainNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(JgMaintainNoticeEq::getEquipTransferId, dto.getSequenceNbr());
                    List<JgMaintainNoticeEq> jgRelationEquip = jgMaintainNoticeEqMapper.selectList(queryWrapper);
                    for (JgMaintainNoticeEq jgMaintainNoticeEq : jgRelationEquip) {
                        LambdaQueryWrapper<RegistrationInfo> queryWrapper2 = new LambdaQueryWrapper<>();
                        queryWrapper2.eq(RegistrationInfo::getRecord, jgMaintainNoticeEq.getEquId());
                        RegistrationInfo tzsJgRegistrationInfo = tzsJgRegistrationInfoMapper.selectOne(queryWrapper2);
                        String equCode = Optional.ofNullable(tzsJgRegistrationInfo.getEquDefine())
                                .orElse(tzsJgRegistrationInfo.getEquCategory());
                        String registrationCode = equCode + jgMaintainNotice.getReceiveCompanyCode() + ym;
                        ResponseModel<String> responseModel = tzsServiceFeignClient.deviceRegistrationCode(registrationCode);
                        jgMaintainNoticeEq.setInformNumber(responseModel.getResult());
                    }
                    jgMaintainNoticeEqService.saveOrUpdateBatch(jgRelationEquip);

                    jgMaintainNotice.setAcceptDate(new Date());
                    jgMaintainNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode()));
                    jgMaintainNotice.setPromoter("");
                    jgMaintainNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.TO_BE_FINISHED.getCode()));

                    // 上个代办改为已办
                    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", jgMaintainNotice.getInstanceId());
                    taskMap.put("flowStatus", FlowStatusEnum.TO_BE_FINISHED.getCode());
                    taskMap.put("flowStatusLabel", FlowStatusEnum.TO_BE_FINISHED.getName());
                    TaskMessageDto taskMessageDto = new TaskMessageDto();
                    BeanUtils.copyProperties(jgMaintainNotice, taskMessageDto);
                    taskMap.put("model", taskMessageDto);
                    TaskV2Model taskV2Model1 = commonService.updateTaskModel(taskMap);
                    jgMaintainNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    jgMaintainNotice.setNextTaskId(workflowResultDto.getNextTaskId());
                    jgMaintainNoticeMapper.updateById(jgMaintainNotice);

                    // 保存历史表
                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(model));
                    commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_MAINTENANCE_NOTIFICATION.getName(), jsonObject, "", jgMaintainNotice.getSequenceNbr().toString());

                    // 保存流水表
                    saveRecord(jgMaintainNotice, jgRelationEquip, taskV2Model1.getRoutePath());
                } else {
                    jgMaintainNotice.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
                    if (!ObjectUtils.isEmpty(jgMaintainNotice.getInstanceStatus())) {
                        jgMaintainNotice.setInstanceStatus(jgMaintainNotice.getInstanceStatus() + "," + workflowResultDto.getNextExecutorRoleIds());
                    } else {
                        jgMaintainNotice.setInstanceStatus(workflowResultDto.getNextExecutorRoleIds());
                    }
                    jgMaintainNotice.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", jgMaintainNotice.getInstanceId());
                    taskV2Model = commonService.updateTaskModel(taskMap);
                    TaskModelDto taskModelDto = new TaskModelDto();
                    BeanUtils.copyProperties(taskV2Model, taskModelDto);
                    // 创建新的代办
                    TaskMessageDto taskMessageDto = new TaskMessageDto();
                    BeanUtils.copyProperties(jgMaintainNotice, taskMessageDto);
                    taskModelDto.setModel(taskMessageDto);
                    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());
                    commonService.buildTaskModel(Collections.singletonList(taskModelDto));

                    jgMaintainNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                    jgMaintainNotice.setNextTaskId(workflowResultDto.getNextTaskId());
                    jgMaintainNoticeMapper.updateById(jgMaintainNotice);
                }
            } else {
                jgMaintainNotice.setPromoter("");
                jgMaintainNotice.setNoticeStatus(String.valueOf(FlowStatusEnum.REJECTED.getCode()));
                // 上个代办改为已办
                HashMap<String, Object> taskMap = new HashMap<>();
                taskMap.put("taskStatus", jgMaintainNotice.getNoticeStatus());
                taskMap.put("taskStatusLabel", FlowStatusEnum.REJECTED.getName());
                taskMap.put("relationId", jgMaintainNotice.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);
                // 创建新的代办
                TaskMessageDto taskMessageDto = new TaskMessageDto();
                BeanUtils.copyProperties(jgMaintainNotice, taskMessageDto);
                taskModelDto.setModel(taskMessageDto);
                taskModelDto.setTaskName(workflowResultDto.getNextTaskName());
                taskModelDto.setExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                taskModelDto.setFlowStatus(FlowStatusEnum.REJECTED.getCode());
                taskModelDto.setFlowStatusLabel(FlowStatusEnum.REJECTED.getName());
                taskModelDto.setFlowCode(workflowResultDto.getNextTaskId());
                taskModelDto.setNextExecuteUser(workflowResultDto.getNextExecutorRoleIds());
                taskModelDto.setPageType("edit");
                commonService.buildTaskModel(Collections.singletonList(taskModelDto));
                jgMaintainNotice.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
                jgMaintainNotice.setNextTaskId(workflowResultDto.getNextTaskId());
                jgMaintainNoticeMapper.updateById(jgMaintainNotice);
            }
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgMaintainNotice));
            this.delRepeatUseEquipData(jgMaintainNotice);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }

    private void saveRecord(JgMaintainNotice jgMaintainNotice, List<JgMaintainNoticeEq> jgMaintainNoticeEqList, String routePath) {
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);

        String content = jgMaintainNotice.getCreateUserName() + "办理了【维修告知】" +
                "单号【" + jgMaintainNotice.getApplyNo() + "】，办理日期" + DateUtils.getDateNowShortStr();
        List<JgCertificateChangeRecord> certificateChangeRecords = new ArrayList<>();
        List<JgCertificateChangeRecordEq> changeRecordEqList = new ArrayList<>();

        long seq = sequence.nextId();
        JgCertificateChangeRecord changeRecord = new JgCertificateChangeRecord();
        changeRecord.setSequenceNbr(seq);
        changeRecord.setApplyNo(jgMaintainNotice.getApplyNo());
        changeRecord.setReceiveOrgName(jgMaintainNotice.getReceiveOrgName());
        changeRecord.setAuditPassDate(new Date());
        changeRecord.setRegType("维修告知");
        changeRecord.setRegDate(jgMaintainNotice.getCreateDate());
        changeRecord.setChangeContent(content);
        changeRecord.setReceiveCompanyCode(jgMaintainNotice.getReceiveOrgCode());
        changeRecord.setUseUnitCreditCode(jgMaintainNotice.getUseUnitCreditCode());
        changeRecord.setUseUnitName(jgMaintainNotice.getUseUnitName());
        changeRecord.setCreateDate(new Date());
        changeRecord.setCreateUserId(reginParams.getUserModel().getUserId());
        changeRecord.setRoutePath(routePath);
        certificateChangeRecords.add(changeRecord);
        jgMaintainNoticeEqList.stream().forEach(e -> {
            JgCertificateChangeRecordEq changeRecordEq = new JgCertificateChangeRecordEq();
            changeRecordEq.setChangeRecordId(changeRecord.getSequenceNbr().toString()); //登记证记录主键
            changeRecordEq.setEquId(e.getEquId()); //设备主键
            changeRecordEq.setProductCode(e.getEquCode()); //设备代码
            changeRecordEqList.add(changeRecordEq);
        });

        if (certificateChangeRecords.size() > 0) {
            certificateChangeRecordService.saveBatch(certificateChangeRecords);
        }
        if (changeRecordEqList.size() > 0) {
            jgCertificateChangeRecordEqServiceImpl.saveBatch(changeRecordEqList);
        }
    }

    private TaskResultDTO assembleData(JgMaintainNotice jgMaintainNotice, String op, String opinion) {
        TaskResultDTO taskResultDTO = new TaskResultDTO();
        taskResultDTO.setResultCode("approvalStatus");
        taskResultDTO.setTaskId(jgMaintainNotice.getNextTaskId());
        if (!StringUtils.isEmpty(opinion)) {
            taskResultDTO.setComment(opinion);
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("approvalStatus", op);
        taskResultDTO.setNextExecuteUserCompanyCode("1".equals(op) ? jgMaintainNotice.getInstallUnitCreditCode() : jgMaintainNotice.getReceiveCompanyCode());
        taskResultDTO.setVariable(map);
        return taskResultDTO;
    }


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

    private List<String> getEquList(JgMaintainNotice jgMaintainNotice) {
        LambdaQueryWrapper<JgMaintainNoticeEq> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JgMaintainNoticeEq::getEquipTransferId, jgMaintainNotice.getSequenceNbr());
        List<JgMaintainNoticeEq> jgInstallationNoticeEqs = jgMaintainNoticeEqMapper.selectList(queryWrapper);
        return jgInstallationNoticeEqs.stream().map(JgMaintainNoticeEq::getEquId).collect(Collectors.toList());
    }

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

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

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

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

}