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

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.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.BaseEntity;
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.biz.common.utils.SnowflakeIdUtil;
import com.yeejoin.amos.boot.module.common.api.enums.CylinderTypeEnum;
import com.yeejoin.amos.boot.module.common.biz.refresh.DataRefreshEvent;
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.*;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgRegistrationHistoryMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgScrapCancelEqMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgScrapCancelMapper;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgUseRegistrationManageMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgScrapCancelService;
import com.yeejoin.amos.boot.module.jg.api.vo.SortVo;
import com.yeejoin.amos.boot.module.jg.api.vo.tableDataExportVo.ScrapCancelVo;
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.edit.permission.FillingEditPermForCurrentUser;
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.ICompensateFlowDataOfRedis;
import com.yeejoin.amos.boot.module.ymt.api.enums.ApplicationFormTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquimentEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgUseInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.SuperviseInfoMapper;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.systemctl.model.TaskV2Model;
import com.yeejoin.amos.feign.workflow.model.ActWorkflowBatchDTO;
import com.yeejoin.amos.feign.workflow.model.ActWorkflowStartDTO;
import com.yeejoin.amos.feign.workflow.model.ProcessTaskDTO;
import com.yeejoin.amos.feign.workflow.model.TaskResultDTO;
import io.seata.spring.annotation.GlobalTransactional;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
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 java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 设备报废注销服务实现类
 *
 * @author system_generator
 * @date 2023-12-20
 */
@Service
public class JgScrapCancelServiceImpl extends BaseService<JgScrapCancelDto, JgScrapCancel, JgScrapCancelMapper> implements IJgScrapCancelService, ICompensateFlowDataOfRedis<JgScrapCancel> {


    private static final String SUBMIT_TYPE_FLOW = "1";
    private static final String PAGE_KEY = "jgScrapCancelAdd";
    private static final String template = "%s发起%s%s业务申请，【申请单号：%s】";
    private final List<String> NOT_FLOWING_STATE = Arrays.asList("使用单位待提交", "一级受理已驳回", "使用单位已撤回", "已作废", "已完成");

    @Autowired
    TzsServiceFeignClient tzsServiceFeignClient;

    @Autowired
    JgResumeInfoServiceImpl jgResumeInfoService;
    @Autowired
    CommonServiceImpl commonService;
    @Autowired
    CmWorkflowServiceImpl cmWorkflowService;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    private JgScrapCancelEqServiceImpl jgScrapCancelEqService;
    @Autowired
    private JgScrapCancelEqMapper jgScrapCancelEqMapper;
    @Autowired
    private IdxBizJgUseInfoMapper idxBizJgUseInfoMapper;
    @Autowired
    private JgRegistrationHistoryMapper jgRegistrationHistoryMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private JgUseRegistrationManageServiceImpl jgUseRegistrationManageService;

    @Autowired
    private JgUseRegistrationManageMapper jgUseRegistrationManageMapper;

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

    @Autowired
    private SnowflakeIdUtil sequence;

    @Autowired
    private EventPublisher eventPublisher;

    /**
     * 移装移装注销/报废注销判断
     *
     * @return BusinessTypeEnum 业务对应枚举
     */
    public static BusinessTypeEnum businessTypeJudgment(String type) {
        return "1".equals(type) ? BusinessTypeEnum.JG_EQUIPMENT_CANCEL : BusinessTypeEnum.JG_EQUIPMENT_MOVE;
    }

    public Page<JgScrapCancelDto> getList(JgScrapCancelDto dto, String sort, Page<JgScrapCancelDto> page, List<String> roleIds,String client) {
        ReginParams reginParams = this.getSelectedOrgInfo();
        CompanyBo company = reginParams.getCompany();
        String companyCode = company.getCompanyCode();
        if (CompanyTypeEnum.INDIVIDUAL.getName().equals(company.getCompanyType())) {
            companyCode = company.getCompanyCode().split("_")[1];
        }
        dto.setCreateUserId(reginParams.getUserModel().getUserId());

        dto.setType("jgLook".equals(client) ? null : dto.getType());
        String orgCode = "jgLook".equals(client) ? company.getOrgCode(): null;
        String currentUserId = reginParams.getUserModel().getUserId();
        SortVo sortMap = commonService.sortFieldConversion(sort);
        Page<JgScrapCancelDto> listPage = this.baseMapper.getListPage(page, sortMap, dto, roleIds, companyCode, currentUserId, orgCode);
        listPage.getRecords().forEach(item -> {
            if (item.getCancelType() != null) {
                item.setCancelTypeDesc(CancelTypeEnum.getNameByType(item.getCancelType()));
            }
            if (item.getEquListCode() != null) {
                item.setEquListName(EquipmentClassifityEnum.getNameByCode(item.getEquListCode()));
            }
        });
        return listPage;
    }

    /**
     * 列表查询-导出用
     */
    public List<ScrapCancelVo> queryScrapCancelInIds(List<String> ids) {
        List<ScrapCancelVo> scrapCancelVos = this.baseMapper.queryScrapCancelInIds(ids);
        return scrapCancelVos.stream().peek(notice -> Optional.ofNullable(notice.getEquListCode())
                .ifPresent(status -> notice.setEquListName(EquipmentClassifityEnum.getNameByCode(notice.getEquListCode()))))
                .collect(Collectors.toList());
    }

    private void convertField(JgScrapCancelDto model) {
        // 处理图片
        if (!ValidationUtil.isEmpty(model.getCancelCertificateList())) {
            model.setCancelCertificate(JSON.toJSONString(model.getCancelCertificateList()));
        }
        String receiveOrgId = model.getReceiveOrgCode();
        if (!ObjectUtils.isEmpty(receiveOrgId)) {
            String[] receiveOrgIdList = receiveOrgId.split("_");
            if (receiveOrgIdList.length > 1) {
                model.setReceiveOrgCode(receiveOrgIdList[0]);
                model.setReceiveCompanyCode(receiveOrgIdList[0]);
                model.setReceiveOrgName(receiveOrgIdList[1]);
            }
        }
    }

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

    @Transactional(rollbackFor = Exception.class)
    public List<JgScrapCancelDto> saveList(String submitType, Map<String, Object> mapParams) {
        return Collections.singletonList(this.save(submitType, mapParams));
    }

    @SuppressWarnings({"Duplicates", "rawtypes"})
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 600000)
    public JgScrapCancelDto save(String submitType, Map<String, Object> mapParams) {
        try {
            ReginParams reginParams = this.getSelectedOrgInfo();
            Map<String, Object> noticeParams = (Map) mapParams.get(PAGE_KEY);
            String[] receiveOrg = String.valueOf(noticeParams.get("receiveOrgCreditCode")).split("_");
            noticeParams.remove("record");
            String[] taskName = new String[]{"流程结束"};
            JgScrapCancelDto model = JSON.parseObject(JSON.toJSONString(noticeParams), JgScrapCancelDto.class);
            model.setReceiveOrgCode(receiveOrg[0]);
            model.setReceiveCompanyCode(receiveOrg[0]);
            model.setReceiveOrgName(receiveOrg[1]);
            // 字段转换
            convertField(model);
            // 获取告知单号 调整之前YZBF为ZX，
            ResponseModel<List<String>> listResponseModel = tzsServiceFeignClient.applicationFormCode(ApplicationFormTypeEnum.getCode.get(String.valueOf(noticeParams.get("businessCode"))), 1);
            if (!ObjectUtils.isEmpty(listResponseModel) && listResponseModel.getStatus() != HttpStatus.OK.value()) {
                log.error(" 获取告知单号失败");
                throw new BadRequest("获取告知单号失败");
            }

            String instanceId = "";
            String nextTaskId = "";
            String nextUserIds = "";
            List<ProcessTaskDTO> processTaskDTOS;
            List<String> roleListNext = new ArrayList<>();
            List<String> roleListAll = new ArrayList<>();
            List<String> applyNoList = listResponseModel.getResult();
            if (CollectionUtils.isEmpty(applyNoList)) {
                return null;
            }
            // 判断当前是否为提交
            List<WorkflowResultDto> workflowResultDtos = null;
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                CompanyBo company = reginParams.getCompany();
                List<JgScrapCancelEq> JgScrapCancelEqList = getCancelEqs(noticeParams);
                this.repeatUsedEquipCheck(JgScrapCancelEqList,
                        CompanyTypeEnum.INDIVIDUAL.getName().equals(company.getCompanyType()) ?
                                company.getCompanyCode().split("_")[1] :
                                company.getCompanyCode());
                // 发起流程
                ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
                List<ActWorkflowStartDTO> list = new ArrayList<>();

                ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                dto.setProcessDefinitionKey("scrapCancelNew");
                dto.setBusinessKey(applyNoList.get(0));
                dto.setCompleteFirstTask(Boolean.TRUE);
                // 下一节点执行人单位（下节点接收机构code）
                dto.setNextExecuteUserCompanyCode(model.getReceiveCompanyCode());
                list.add(dto);

                actWorkflowBatchDTO.setProcess(list);
                processTaskDTOS = cmWorkflowService.startBatch(actWorkflowBatchDTO);
                this.buildRoleList(processTaskDTOS, roleListNext, roleListAll);
                instanceId = processTaskDTOS.get(0).getProcessInstance().getId();
                nextTaskId = processTaskDTOS.get(0).getNextTask().get(0).getId();
                taskName[0] = processTaskDTOS.get(0).getNextTask().get(0).getName();
                workflowResultDtos = commonService.buildWorkFlowInfo(processTaskDTOS);
                nextUserIds = workflowResultDtos.get(0).getNextExecutorUserIds();
                this.buildRoleList(processTaskDTOS, roleListNext, roleListAll);
            }
            JgScrapCancel jgScrapCancel = new JgScrapCancel();
            BeanUtils.copyProperties(model, jgScrapCancel);
            String applyNo = applyNoList.get(0);
            jgScrapCancel.setApplyNo(applyNo);
            jgScrapCancel.setCreateDate(new Date());
            jgScrapCancel.setNextExecuteIds(String.join(",", roleListNext));
            jgScrapCancel.setInstanceStatus(String.join(",", roleListAll));
            jgScrapCancel.setPromoter(reginParams.getUserModel().getUserId());
            jgScrapCancel.setNextTaskId(Objects.isNull(workflowResultDtos) ? null : workflowResultDtos.get(0).getNextTaskId());
            if (!StringUtils.isEmpty(instanceId)) {
                jgScrapCancel.setInstanceId(instanceId);
                jgScrapCancel.setNextTaskId(nextTaskId);
                jgScrapCancel.setNextExecuteUserIds(nextUserIds);
                jgScrapCancel.setAuditStatus(String.valueOf(WorkFlowStatusEnum.CANCEL_RECEIVE.getPass()));
            } else {
                jgScrapCancel.setAuditStatus(String.valueOf(WorkFlowStatusEnum.CANCEL_SUBMIT.getPass()));
            }
            jgScrapCancel.setUseUnitCode(CompanyTypeEnum.INDIVIDUAL.getName().equals(reginParams.getCompany().getCompanyType()) ?
                    reginParams.getCompany().getCompanyCode().split("_")[1] :
                    reginParams.getCompany().getCompanyCode());
            jgScrapCancel.setUseUnitName(reginParams.getCompany().getCompanyName());
            jgScrapCancel.setCreateUserId(RequestContext.getExeUserId());
            jgScrapCancel.setCreateUserName(reginParams.getUserModel().getRealName());
            this.setUseRegisterInfo(jgScrapCancel, noticeParams);
            this.save(jgScrapCancel);
            // 新增代办
            this.createTaskModel(jgScrapCancel, taskName[0], submitType, nextUserIds);
            // 保存设备关系表
            saveEquip(noticeParams, jgScrapCancel);
            jgScrapCancel.setCancelTypeDesc(getRegistrationClass(jgScrapCancel.getCancelType()));
            JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(noticeParams));
            commonService.saveExecuteFlowData2Redis(instanceId, buildInstanceRuntimeData(jgScrapCancel));
            String equListName = EquipmentClassifityEnum.getNameByCode(jsonObject.get("equListCode").toString());
            save2HisData(jsonObject, jgScrapCancel.getSequenceNbr().toString(),jgScrapCancel.getCancelTypeDesc());
            JgScrapCancelDto dto = new JgScrapCancelDto();
            BeanUtil.copyProperties(jgScrapCancel, dto);
            dto.setEquListName(equListName);
            return dto;
        } 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 List<JgScrapCancelEq> getCancelEqs(Map<String, Object> noticeParams) {
        List<JgScrapCancelEq> JgScrapCancelEqList = new ArrayList<>();
        // 判断是否是报废气瓶业务处理
        if (CancelTypeEnum.SCRAPPED.getCode().equals(noticeParams.get("cancelType")) &&
                CylinderTypeEnum.CYLINDER.getCode().equals(noticeParams.get("EQU_CATEGORY_CODE"))) {
            List<Map<String, Object>> list = (List<Map<String, Object>>) noticeParams.get("equipments");
            for (Map<String, Object> equip : list) {
                JgScrapCancelEq jgScrapCancelEq = new JgScrapCancelEq();
                jgScrapCancelEq.setEquId(equip.get("SEQUENCE_NBR").toString());
                JgScrapCancelEqList.add(jgScrapCancelEq);
            }
        } else {
            List<Map<String, Object>> certificates;
            // 证列表
            if (CylinderTypeEnum.SPECIAL_CYLINDER.getCode().equals(noticeParams.get("EQU_CATEGORY_CODE"))) {
                certificates = (List<Map<String, Object>>) noticeParams.get("cylCertificates");
            } else {
                certificates = (List<Map<String, Object>>) noticeParams.get("certificates");
            }
            // 使用登记证表idList
            List<String> registrationIdList = certificates.stream().map(item -> item.get("sequenceNbr").toString()).collect(Collectors.toList());
            List<JSONObject> equipmentList = jgUseRegistrationManageService.queryEquByCertificateSeqList(registrationIdList.stream().map(Long::parseLong).collect(Collectors.toList()));
            for (JSONObject equip : equipmentList) {
                JgScrapCancelEq jgScrapCancelEq = new JgScrapCancelEq();
                jgScrapCancelEq.setEquId(equip.getString("SEQUENCE_NBR"));
                JgScrapCancelEqList.add(jgScrapCancelEq);
            }
        }
        return JgScrapCancelEqList;
    }

    private void repeatUsedEquipCheck(List<JgScrapCancelEq> eqList, String companyCode) {
        eqList.forEach(cancelEq -> EquipUsedCheckStrategyContext.getUsedStrategy(PAGE_KEY)
                .registrationRepeatUsedCheck(cancelEq.getEquId(), companyCode));
    }

    /**
     * 删除 redis校验重复引用设备的数据
     */
    private void delRepeatUseEquipData(JgScrapCancel notice) {
        if (NOT_FLOWING_STATE.contains(notice.getAuditStatus())) {
            LambdaQueryWrapper<JgScrapCancelEq> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(JgScrapCancelEq::getEquipTransferId, notice.getSequenceNbr());
            List<JgScrapCancelEq> noticeEqList = jgScrapCancelEqService.list(queryWrapper);
            noticeEqList.forEach(noticeEq -> EquipUsedCheckStrategyContext.getUsedStrategy(PAGE_KEY)
                    .delDataForCheckEquipRepeatUsed(Collections.singletonList(noticeEq.getEquId()), notice.getUseUnitCode())
            );
        }
    }

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

    /**
     * 设置登记证信息
     *
     * @param jgScrapCancel 对象
     * @param noticeParams  参数
     */
    private void setUseRegisterInfo(JgScrapCancel jgScrapCancel, Map<String, Object> noticeParams) {
        // 判断是否是报废气瓶业务处理
        if (CancelTypeEnum.SCRAPPED.getCode().equals(noticeParams.get("cancelType")) &&
                CylinderTypeEnum.CYLINDER.getCode().equals(noticeParams.get("EQU_CATEGORY_CODE"))) {
            // 证ids
            List<String> certificates = (List<String>) noticeParams.get("sequenceNbrs");
            LambdaQueryWrapper<JgUseRegistrationManage> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.in(JgUseRegistrationManage::getSequenceNbr, certificates.stream().map(Long::parseLong).collect(Collectors.toList()));
            lambdaQueryWrapper.select(JgUseRegistrationManage::getUseRegistrationCode);
            List<JgUseRegistrationManage> jgUseRegistrationManageList = jgUseRegistrationManageMapper.selectList(lambdaQueryWrapper);
            jgScrapCancel.setRegistrationManageId(String.join(",", certificates));
            jgScrapCancel.setUseRegistrationCode(jgUseRegistrationManageList.stream().map(JgUseRegistrationManage::getUseRegistrationCode).collect(Collectors.joining(",")));
        } else {
            List<Map<String, Object>> certificates;
            // 证列表
            if (CylinderTypeEnum.SPECIAL_CYLINDER.getCode().equals(noticeParams.get("EQU_CATEGORY_CODE"))) {
                certificates = (List<Map<String, Object>>) noticeParams.get("cylCertificates");
            } else {
                certificates = (List<Map<String, Object>>) noticeParams.get("certificates");
            }
            if (ObjectUtils.isEmpty(certificates)) {
                throw new BadRequest("请选择使用登记证");
            }
            // 使用登记证表idList
            List<String> registrationIdList = certificates.stream().map(item -> item.get("sequenceNbr").toString()).collect(Collectors.toList());
            List<String> useRegistrationCodeList = certificates.stream().map(item -> item.get("useRegistrationCode").toString()).collect(Collectors.toList());
            jgScrapCancel.setRegistrationManageId(String.join(",", registrationIdList));
            jgScrapCancel.setUseRegistrationCode(String.join(",", useRegistrationCodeList));
        }
    }


    private void saveEquip(Map<String, Object> noticeParams, JgScrapCancel jgScrapCancel) {
        List<JgScrapCancelEq> JgScrapCancelEqList = new ArrayList<>();
        // 判断是否是报废气瓶业务处理
        if (CancelTypeEnum.SCRAPPED.getCode().equals(noticeParams.get("cancelType")) &&
                CylinderTypeEnum.CYLINDER.getCode().equals(noticeParams.get("EQU_CATEGORY_CODE"))) {
            List<Map<String, Object>> list = (List<Map<String, Object>>) noticeParams.get("equipments");
            for (Map<String, Object> equip : list) {
                JgScrapCancelEq jgScrapCancelEq = new JgScrapCancelEq();
                jgScrapCancelEq.setEquId(equip.get("SEQUENCE_NBR").toString());
                jgScrapCancelEq.setUseRegistrationCode(equip.get("USE_ORG_CODE").toString());
                jgScrapCancelEq.setEquipTransferId(String.valueOf(jgScrapCancel.getSequenceNbr()));
                jgScrapCancelEq.setEquCode(equip.get("EQU_CODE") != null ? equip.get("EQU_CODE").toString() : "");
                JgScrapCancelEqList.add(jgScrapCancelEq);
            }
        } else {
            List<Map<String, Object>> certificates;
            // 证列表
            if (CylinderTypeEnum.SPECIAL_CYLINDER.getCode().equals(noticeParams.get("EQU_CATEGORY_CODE"))) {
                certificates = (List<Map<String, Object>>) noticeParams.get("cylCertificates");
            } else {
                certificates = (List<Map<String, Object>>) noticeParams.get("certificates");
            }
            // 使用登记证表idList
            List<String> registrationIdList = certificates.stream().map(item -> item.get("sequenceNbr").toString()).collect(Collectors.toList());
            List<JSONObject> equipmentList = jgUseRegistrationManageService.queryEquByCertificateSeqList(registrationIdList.stream().map(Long::parseLong).collect(Collectors.toList()));
            for (JSONObject equip : equipmentList) {
                JgScrapCancelEq jgScrapCancelEq = new JgScrapCancelEq();
                jgScrapCancelEq.setUseRegistrationCode(equip.getString("USE_ORG_CODE"));
                jgScrapCancelEq.setEquipTransferId(String.valueOf(jgScrapCancel.getSequenceNbr()));
                jgScrapCancelEq.setEquId(equip.getString("SEQUENCE_NBR"));
                jgScrapCancelEq.setEquCode(equip.getString("EQU_CODE"));
                JgScrapCancelEqList.add(jgScrapCancelEq);
            }
        }
        jgScrapCancelEqService.saveBatch(JgScrapCancelEqList);
    }


    private void save2HisData(JSONObject jsonObject, String currentDocumentId,String cancelTypeDesc) {
        commonService.saveOrUpdateHistory(cancelTypeDesc, jsonObject, null, currentDocumentId);
    }

    private void createTaskModel(JgScrapCancel scrapCancel, String taskName, String submitType, String nextUserIds) {
        TaskModelDto taskModelDto = new TaskModelDto();
        if ("1".equals(submitType)) {
            taskModelDto.setFlowCreateDate(scrapCancel.getCreateDate());
            taskModelDto.setTaskName(taskName);
            taskModelDto.setTaskCode(scrapCancel.getApplyNo());
            taskModelDto.setTaskContent(this.buildTaskContent(scrapCancel.getEquListCode(), scrapCancel.getCancelType(), scrapCancel.getApplyNo()));
            taskModelDto.setTaskDesc("");
            taskModelDto.setTaskType(businessTypeJudgment(scrapCancel.getCancelType()).getCode());
            taskModelDto.setTaskTypeLabel(businessTypeJudgment(scrapCancel.getCancelType()).getName());
            taskModelDto.setRelationId(scrapCancel.getInstanceId());
            taskModelDto.setExecuteUserIds(nextUserIds);
            FlowStatusEnum flowStatusEnum = this.getTaskStatus(submitType);
            taskModelDto.setTaskStatus(flowStatusEnum.getCode());
            taskModelDto.setTaskStatusLabel(flowStatusEnum.getName());
            taskModelDto.setFlowStatus(this.getTaskStatusByName(scrapCancel.getAuditStatus()));
            taskModelDto.setFlowStatusLabel(scrapCancel.getAuditStatus());
            taskModelDto.setStartUserId(scrapCancel.getCreateUserId());
            taskModelDto.setFlowCode(scrapCancel.getNextTaskId());
            taskModelDto.setStartUser(scrapCancel.getCreateUserName());
            taskModelDto.setStartUserCompanyName(scrapCancel.getUseUnitName());
            taskModelDto.setNextExecuteUser(scrapCancel.getNextExecuteIds());
            taskModelDto.setStartDate(scrapCancel.getCreateDate() == null ? new Date() : scrapCancel.getCreateDate());
            TaskMessageDto taskMessageDto = new TaskMessageDto();
            BeanUtils.copyProperties(scrapCancel, taskMessageDto);
            taskModelDto.setModel(taskMessageDto);
        } else {
            TaskMessageDto taskMessageDto = new TaskMessageDto();
            BeanUtils.copyProperties(scrapCancel, taskMessageDto);
            taskModelDto.setModel(taskMessageDto);
            taskModelDto.setTaskContent(this.buildTaskContent(scrapCancel.getEquListCode(), scrapCancel.getCancelType(), scrapCancel.getApplyNo()));
            taskModelDto.setTaskCode(scrapCancel.getApplyNo());
            taskModelDto.setTaskType(businessTypeJudgment(scrapCancel.getCancelType()).getCode());
            taskModelDto.setNextExecuteUser(scrapCancel.getNextExecuteIds());
            taskModelDto.setRelationId(taskMessageDto.getSequenceNbr() + "");
        }
        commonService.buildTaskModel(Collections.singletonList(taskModelDto));
    }

    private void buildRoleList(List<ProcessTaskDTO> processTasks, List<String> roleListNext, List<String> roleListAll) {
        processTasks.forEach(p -> {
            p.getNextCandidateGroups().values().forEach(e -> {
                roleListNext.addAll(e);
                roleListAll.addAll(e);
            });
            roleListAll.addAll(p.getCandidateGroups());
        });
    }

    /**
     * 摘要构建
     *
     * @return 摘要
     */
    private String buildTaskContent(String equList, String cancelType, String applyNo) {
        //    XXX发起了电梯注销业务申请，【申请单号：ABCD0000001】
        String type = "1".equals(cancelType) ? "报废" : "注销";
        String equListName = EquipmentClassifityEnum.getNameByCode(equList);
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        String userName = reginParams.getUserModel().getRealName();
        return String.format(template, userName, equListName, type, applyNo);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(List<Long> ids) {
        if (!ids.isEmpty()) {
            for (Long id : ids) {
                LambdaQueryWrapper<JgScrapCancel> lambda = new QueryWrapper<JgScrapCancel>().lambda();
                lambda.eq(JgScrapCancel::getSequenceNbr, id);
                JgScrapCancel jgScrapCancel = this.baseMapper.selectOne(lambda);
                // 删除代办 + 中止流程
                commonService.deleteTaskModel(String.valueOf(jgScrapCancel.getSequenceNbr()), jgScrapCancel.getInstanceId());
                // 删除单子
                this.baseMapper.deleteById(jgScrapCancel.getSequenceNbr());
                // 删除对应eq
                jgScrapCancelEqMapper.delete(new LambdaQueryWrapper<JgScrapCancelEq>()
                        .eq(JgScrapCancelEq::getEquipTransferId, jgScrapCancel.getSequenceNbr()));
                // 删除单子对应历史表数据
                jgRegistrationHistoryMapper.delete(new LambdaQueryWrapper<JgRegistrationHistory>()
                        .eq(JgRegistrationHistory::getCurrentDocumentId, jgScrapCancel.getSequenceNbr()));
            }
        }
    }

    @GlobalTransactional(rollbackFor = Exception.class)
    public JgScrapCancelDto updateInfo(String submitType, JgScrapCancelDto jgScrapCancelDto, String op, JSONObject pageData) {

        try {

            if (Objects.isNull(jgScrapCancelDto) || StringUtils.isEmpty(submitType)) {
                throw new IllegalArgumentException("参数不能为空");
            }
            // 字段转换
            this.convertField(jgScrapCancelDto);
            List<String> roleListNext = new ArrayList<>();
            List<String> roleListAll = new ArrayList<>();
            if (SUBMIT_TYPE_FLOW.equals(submitType)) {
                ReginParams reginParams = JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
                CompanyBo company = reginParams.getCompany();
                List<JgScrapCancelEq> JgScrapCancelEqList = getCancelEqs(pageData);
                this.repeatUsedEquipCheck(JgScrapCancelEqList, CompanyTypeEnum.INDIVIDUAL.getName().equals(company.getCompanyType()) ?
                        company.getCompanyCode().split("_")[1] :
                        company.getCompanyCode());
                // 更新并提交
                // 发起流程
                if (!StringUtils.hasText(jgScrapCancelDto.getInstanceId())) {
                    // 未进流程直接发起并执行
                    List<ProcessTaskDTO> processTasks;
                    ActWorkflowBatchDTO actWorkflowBatchDTO = new ActWorkflowBatchDTO();
                    List<ActWorkflowStartDTO> list = new ArrayList<>();
                    ActWorkflowStartDTO dto = new ActWorkflowStartDTO();
                    dto.setProcessDefinitionKey("scrapCancelNew");
                    dto.setBusinessKey(jgScrapCancelDto.getApplyNo());
                    dto.setCompleteFirstTask(true);
                    dto.setNextExecuteUserCompanyCode(jgScrapCancelDto.getReceiveCompanyCode());
                    list.add(dto);
                    actWorkflowBatchDTO.setProcess(list);
                    processTasks = cmWorkflowService.startBatch(actWorkflowBatchDTO);
                    String instanceId = processTasks.get(0).getProcessInstance().getId();
                    String nextTaskId = processTasks.get(0).getNextTask().get(0).getId();
                    String taskName = processTasks.get(0).getNextTask().get(0).getName();
                    this.buildRoleList(processTasks, roleListNext, roleListAll);
                    List<WorkflowResultDto> workflowResultDtos = commonService.buildWorkFlowInfo(processTasks);
                    String nextUserIds = workflowResultDtos.get(0).getNextExecutorUserIds();
                    jgScrapCancelDto.setInstanceStatus(String.join(",", roleListAll));
                    jgScrapCancelDto.setInstanceId(instanceId);
                    jgScrapCancelDto.setNextExecuteIds(String.join(",", roleListNext));
                    jgScrapCancelDto.setNextTaskId(nextTaskId);
                    jgScrapCancelDto.setNextExecuteUserIds(nextUserIds);
                    jgScrapCancelDto.setAuditStatus(WorkFlowStatusEnum.CANCEL_RECEIVE.getPass());
                    // 创建待办
                    JgScrapCancel bean = new JgScrapCancel();
                    BeanUtil.copyProperties(jgScrapCancelDto, bean);
                    commonService.deleteTasksByRelationId(String.valueOf(jgScrapCancelDto.getSequenceNbr()));
                    createTaskModel(bean, taskName, "1", nextUserIds);
                } else {
                    // 已经在流程中，执行一步
                    ProcessTaskDTO processTaskDTO = submit(jgScrapCancelDto);
                    String nextTaskId = processTaskDTO.getNextTask().get(0).getId();
                    String taskName = processTaskDTO.getNextTask().get(0).getName();
                    this.buildRoleList(Collections.singletonList(processTaskDTO), roleListNext, roleListAll);
                    List<WorkflowResultDto> workflowResultDtos = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO));
                    String nextUserIds = workflowResultDtos.get(0).getNextExecutorUserIds();
                    // 查询下节点任务
                    if (!ObjectUtils.isEmpty(jgScrapCancelDto.getInstanceStatus())) {
                        jgScrapCancelDto.setInstanceStatus(jgScrapCancelDto.getInstanceStatus() + "," + String.join("", roleListNext));
                    } else {
                        jgScrapCancelDto.setInstanceStatus(String.join(",", roleListAll));
                    }
                    jgScrapCancelDto.setPromoter(RequestContext.getExeUserId());
                    jgScrapCancelDto.setNextExecuteIds(String.join(",", roleListNext));
                    jgScrapCancelDto.setAuditStatus(String.valueOf(WorkFlowStatusEnum.CANCEL_RECEIVE.getPass()));
                    jgScrapCancelDto.setNextTaskId(nextTaskId);
                    // 更新下一步可执行人
                    jgScrapCancelDto.setNextExecuteUserIds(nextUserIds);
                    JgScrapCancel jgScrapCancel = new JgScrapCancel();
                    BeanUtils.copyProperties(jgScrapCancelDto, jgScrapCancel);
                    updateTaskModel(jgScrapCancelDto, "0");
                    createTaskModel(jgScrapCancel, taskName, "1", nextUserIds);
                }
                JgScrapCancel cancel = new JgScrapCancel();
                BeanUtils.copyProperties(jgScrapCancelDto, cancel);
                this.setUseRegisterInfo(cancel, new HashMap<>(pageData));
                this.updateById(cancel);
                JgScrapCancel jgScrapCancel = new JgScrapCancel();
                BeanUtils.copyProperties(jgScrapCancelDto, jgScrapCancel, "useUnitName", "useUnitName");
                this.insertJgScrapCancelEqAfterDelete(jgScrapCancel, pageData);
                commonService.saveExecuteFlowData2Redis(jgScrapCancel.getInstanceId(), buildInstanceRuntimeData(jgScrapCancel));
            } else {
                // 更新操作
                JgScrapCancel bean = new JgScrapCancel();
                BeanUtils.copyProperties(jgScrapCancelDto, bean);
                bean.setCancelCertificate(JSON.toJSONString(jgScrapCancelDto.getCancelCertificateList()));
                this.setUseRegisterInfo(bean, new HashMap<>(pageData));
                this.updateById(bean);
                this.insertJgScrapCancelEqAfterDelete(bean, pageData);
            }
            commonService.saveOrUpdateHistory(getRegistrationClass(jgScrapCancelDto.getCancelType()), pageData, "", jgScrapCancelDto.getSequenceNbr().toString());
            return jgScrapCancelDto;
        } 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 insertJgScrapCancelEqAfterDelete(JgScrapCancel jgScrapCancel, JSONObject pageData) {
        this.deleteJgScrapCancelEq(jgScrapCancel);
        List<JgScrapCancelEq> JgScrapCancelEqList = new ArrayList<>();
        // 判断是否是报废气瓶业务处理
        if (CancelTypeEnum.SCRAPPED.getCode().equals(pageData.get("cancelType")) &&
                CylinderTypeEnum.CYLINDER.getCode().equals(pageData.get("EQU_CATEGORY_CODE"))) {
            List<Map<String, Object>> list = (List<Map<String, Object>>) pageData.get("equipments");
            for (Map<String, Object> equip : list) {
                JgScrapCancelEq jgScrapCancelEq = new JgScrapCancelEq();
                jgScrapCancelEq.setEquId(equip.get("SEQUENCE_NBR").toString());
                jgScrapCancelEq.setUseRegistrationCode(equip.get("USE_ORG_CODE").toString());
                jgScrapCancelEq.setEquipTransferId(String.valueOf(jgScrapCancel.getSequenceNbr()));
                jgScrapCancelEq.setEquCode(equip.get("EQU_CODE") != null ? equip.get("EQU_CODE").toString() : "");
                JgScrapCancelEqList.add(jgScrapCancelEq);
            }
        } else {
            List<Map<String, Object>> certificates;
            // 证列表
            if (CylinderTypeEnum.SPECIAL_CYLINDER.getCode().equals(pageData.get("EQU_CATEGORY_CODE"))) {
                certificates = (List<Map<String, Object>>) pageData.get("cylCertificates");
            } else {
                certificates = (List<Map<String, Object>>) pageData.get("certificates");
            }
            // 使用登记证表idList
            List<String> registrationIdList = certificates.stream().map(item -> item.get("sequenceNbr").toString()).collect(Collectors.toList());
            List<JSONObject> equipmentList = jgUseRegistrationManageService.queryEquByCertificateSeqList(registrationIdList.stream().map(Long::parseLong).collect(Collectors.toList()));
            for (JSONObject equip : equipmentList) {
                JgScrapCancelEq jgScrapCancelEq = new JgScrapCancelEq();
                jgScrapCancelEq.setUseRegistrationCode(equip.getString("USE_ORG_CODE"));
                jgScrapCancelEq.setEquipTransferId(String.valueOf(jgScrapCancel.getSequenceNbr()));
                jgScrapCancelEq.setEquId(equip.getString("SEQUENCE_NBR"));
                jgScrapCancelEq.setEquCode(equip.getString("EQU_CODE"));
                JgScrapCancelEqList.add(jgScrapCancelEq);
            }
        }
        jgScrapCancelEqService.saveBatch(JgScrapCancelEqList);
    }

    private void deleteJgScrapCancelEq(JgScrapCancel jgScrapCancel) {
        jgScrapCancelEqMapper.delete(new LambdaQueryWrapper<JgScrapCancelEq>().eq(JgScrapCancelEq::getEquipTransferId, jgScrapCancel.getSequenceNbr()));
    }

    private String getRegistrationClass(String cancelType) {
        return CancelTypeEnum.SCRAPPED.getCode().equals(cancelType) ? CancelTypeEnum.SCRAPPED.getName() : CancelTypeEnum.TRANSFER.getName();
    }

    private void executeOneStep(JgScrapCancelDto jgScrapCancelDto, String taskName, String nextUserIds, String operate) {
        // 先更新之前的待办
        TaskV2Model taskV2Model = updateTaskModel(jgScrapCancelDto, operate);
        taskV2Model.setTaskDesc("");
//        taskV2Model.setTaskContent(this.buildTaskContent(jgScrapCancelDto.getEquList(), jgScrapCancelDto.getCancelType(), jgScrapCancelDto.getApplyNo()));
        taskV2Model.setTaskName(taskName);
        taskV2Model.setTaskCode(jgScrapCancelDto.getApplyNo());
        taskV2Model.setRelationId(jgScrapCancelDto.getInstanceId());
        FlowStatusEnum flowStatusEnum = this.getTaskStatus(operate);
        taskV2Model.setTaskStatus(flowStatusEnum.getCode());
        taskV2Model.setTaskStatusLabel(flowStatusEnum.getName());
        taskV2Model.setFlowStatus(this.getTaskStatusByName(jgScrapCancelDto.getAuditStatus()));
        taskV2Model.setFlowStatusLabel(jgScrapCancelDto.getAuditStatus());
        taskV2Model.setTaskType(businessTypeJudgment(jgScrapCancelDto.getCancelType()).getCode());
        taskV2Model.setTaskTypeLabel(businessTypeJudgment(jgScrapCancelDto.getCancelType()).getName());
        taskV2Model.setStartUserCompanyName(jgScrapCancelDto.getUseUnitName());
        taskV2Model.setExecuteUserIds(nextUserIds);
        taskV2Model.setFlowCode(jgScrapCancelDto.getNextTaskId());
        TaskModelDto modelDto = new TaskModelDto();
        BeanUtil.copyProperties(taskV2Model, modelDto);
        modelDto.setNextExecuteUser(jgScrapCancelDto.getNextExecuteIds());
        TaskMessageDto taskMessageDto = new TaskMessageDto();
        BeanUtils.copyProperties(jgScrapCancelDto, taskMessageDto);
        modelDto.setModel(taskMessageDto);
        modelDto.setPageType(this.getPageTypeForReject(operate, jgScrapCancelDto.getAuditStatus()));
        commonService.buildTaskModel(Collections.singletonList(modelDto));
    }

    private Integer getTaskStatusByName(String auditStatus) {
        return commonService.getDictionaryCodeByName(auditStatus);
    }

    private String getPageTypeForReject(String operate, String auditStatus) {
        // 驳回
        if ("1".equals(operate)) {
            // 且驳回到的节点为使用单位提交 则可编辑
            if (WorkFlowStatusEnum.CANCEL_SUBMIT.getPass().equals(auditStatus) || WorkFlowStatusEnum.CANCEL_SUBMIT.getReject().equals(auditStatus) || WorkFlowStatusEnum.CANCEL_SUBMIT.getRollBack().equals(auditStatus)) {
                return "edit";
            }
            return "look";
        }
        return "look";
    }

    private TaskV2Model updateTaskModel(JgScrapCancelDto jgScrapCancelDto, String operate) {
        Map<String, Object> params = new HashMap<>();
        FlowStatusEnum flowStatusEnum = this.getTaskStatus(operate);
        params.put("relationId", jgScrapCancelDto.getInstanceId());
        params.put("taskStatus", this.getTaskStatusByName(jgScrapCancelDto.getAuditStatus()));
        params.put("taskStatusLabel", jgScrapCancelDto.getAuditStatus());
        params.put("flowStatus", flowStatusEnum.getCode());
        params.put("flowStatusLabel", flowStatusEnum.getName());
        params.put("model", jgScrapCancelDto);
        return commonService.updateTaskModel(params);
    }

    private FlowStatusEnum getTaskStatus(String operate) {
        if ("0".equals(operate)) {
            return FlowStatusEnum.TO_BE_FINISHED;
        } else {
            return FlowStatusEnum.REJECTED;
        }
    }

    public ProcessTaskDTO submit(JgScrapCancelDto jgScrapCancelDto) {
        JgScrapCancel model = this.getById(jgScrapCancelDto.getSequenceNbr());
        // 组装信息
        String op = "提交";
        TaskResultDTO dto = new TaskResultDTO();
        dto.setResultCode("approvalStatus");
        dto.setTaskId(jgScrapCancelDto.getNextTaskId());
        HashMap<String, Object> map = new HashMap<>();
        map.put("approvalStatus", op);
        dto.setNextExecuteUserCompanyCode(model.getReceiveCompanyCode());
        dto.setVariable(map);
        return cmWorkflowService.completeOrReject(jgScrapCancelDto.getNextTaskId(), dto, op);
    }


    public Map<String, Object> queryBySequenceNbr(Long sequenceNbr, CompanyBo company) {
        Map<String, Object> resultMap = new HashMap<>();
        JgScrapCancel scrapCancel = this.baseMapper.selectById(sequenceNbr);
        this.doCompensate(scrapCancel);
        Map<String, Object> beanMap = BeanUtil.beanToMap(scrapCancel, false, true);
        beanMap.put("cancelCertificateList", JSON.parse(scrapCancel.getCancelCertificate()));
        beanMap.put("otherAccessories", JSON.parse(scrapCancel.getOtherAccessories()));
        JgRegistrationHistory jgRegistrationHistory = jgRegistrationHistoryMapper.selectOne(new LambdaQueryWrapper<JgRegistrationHistory>()
                .eq(JgRegistrationHistory::getCurrentDocumentId, sequenceNbr)
                .eq(JgRegistrationHistory::getIsDelete, false));
        // 根据不同类型返回不同的字段、用于台套设备、气瓶、车用气瓶
        if (jgRegistrationHistory != null) {
            JSONObject jsonObject = JSONObject.parseObject(jgRegistrationHistory.getChangeData());
            if (CylinderTypeEnum.SPECIAL_CYLINDER.getCode().equals(jsonObject.get("EQU_CATEGORY_CODE"))) {
                beanMap.put("cylCertificates", JSONArray.parse(jsonObject.get("cylCertificates").toString()));
                beanMap.put("EQU_CATEGORY_CODE", CylinderTypeEnum.SPECIAL_CYLINDER.getCode());
            } else if (CylinderTypeEnum.CYLINDER.getCode().equals(jsonObject.get("EQU_CATEGORY_CODE"))) {
                beanMap.put("equipments", JSONArray.parse(jsonObject.get("equipments").toString()));
                beanMap.put("EQU_CATEGORY_CODE", CylinderTypeEnum.CYLINDER.getCode());
                beanMap.put("sequenceNbrs", jsonObject.get("sequenceNbrs"));
            } else {
                beanMap.put("certificates", JSONArray.parse(jsonObject.get("certificates").toString()));
            }
        }
        resultMap.putAll(beanMap);
        resultMap.put("receiveOrgCode", scrapCancel.getReceiveCompanyCode() + '_' + scrapCancel.getReceiveOrgName());
        // 单位类型及人员权限设置
        new FillingEditPermForCurrentUser(new JSONObject(resultMap), company, BusinessTypeEnum.JG_EQUIPMENT_MOVE_CANCEL).getData();
        return new HashMap<String, Object>() {{
            this.put(PAGE_KEY, resultMap);
        }};
    }


    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void revocation(String instanceId, String nextTaskId) {
        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);

            ReginParams reginParams = this.getSelectedOrgInfo();
            LambdaQueryWrapper<JgScrapCancel> lambda = new QueryWrapper<JgScrapCancel>().lambda();
            lambda.eq(JgScrapCancel::getInstanceId, instanceId);
            JgScrapCancel jgScrapCancel = this.baseMapper.selectOne(lambda);
            ProcessTaskDTO processTaskDTO = cmWorkflowService.rollBack(instanceId);
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            if (!FlowStatusEnum.TO_BE_FINISHED.getName().equals(workflowResultDto.getNextTaskName())) {
                jgScrapCancel.setAuditStatus(Objects.requireNonNull(WorkFlowStatusEnum.getMessage(workflowResultDto.getNextTaskCode())).getRollBack());
            }
            jgScrapCancel.setNextTaskId(workflowResultDto.getNextTaskId());
            List<WorkflowResultDto> workflowResultDtos = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO));
            // 更新下一步可执行人
            String nextUserIds = workflowResultDtos.get(0).getNextExecutorUserIds();
            jgScrapCancel.setNextExecuteUserIds(nextUserIds);
            jgScrapCancel.setPromoter(reginParams.getUserModel().getUserId());
            jgScrapCancel.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
            this.updateById(jgScrapCancel);

            // 删除待办
            JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(jgScrapCancel));
            jsonObject.put("nextTaskId", jgScrapCancel.getNextTaskId());
            jsonObject.put("nextExecuteUser", jgScrapCancel.getNextExecuteIds());
            jsonObject.put("taskType", businessTypeJudgment(jgScrapCancel.getCancelType()).getCode());
            jsonObject.put("flowStatus", this.getTaskCodeByName(jgScrapCancel.getAuditStatus()));
            jsonObject.put("flowStatusLabel", jgScrapCancel.getAuditStatus());
            // 判断撤回后当前的节点，如果当前节点为提交节点则页面可编辑
            jsonObject.put("pageType", this.getPageTypeByCurrentNode(jgScrapCancel.getAuditStatus()));
            commonService.rollbackTask(instanceId, jsonObject);

            // redis流程实时数据更新
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgScrapCancel));
            this.delRepeatUseEquipData(jgScrapCancel);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private Integer getTaskCodeByName(String auditStatus) {
        return commonService.getDictionaryCodeByName(auditStatus);
    }

    private String getPageTypeByCurrentNode(String auditStatus) {
        if (WorkFlowStatusEnum.CANCEL_SUBMIT.getPass().equals(auditStatus) || WorkFlowStatusEnum.CANCEL_SUBMIT.getReject().equals(auditStatus) || WorkFlowStatusEnum.CANCEL_SUBMIT.getRollBack().equals(auditStatus)) {
            return "edit";
        } else {
            return "look";
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 600000)
    public void flowExecute(String equList, Long id, String instanceId, String operate, String comment, String nextTaskId) {
        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);

            JgScrapCancel jgScrapCancel = this.getBaseMapper().selectById(id);
            String taskId = jgScrapCancel.getNextTaskId();
            // 组装信息
            TaskResultDTO dto = new TaskResultDTO();
            dto.setResultCode("approvalStatus");
            dto.setTaskId(taskId);
            dto.setComment(comment);
            HashMap<String, Object> map = new HashMap<>();
            map.put("approvalStatus", operate);
            if (!ObjectUtils.isEmpty(jgScrapCancel.getInstanceStatus()) && (jgScrapCancel.getInstanceStatus().equals(WorkFlowStatusEnum.CANCEL_SUBMIT.getReject()) || jgScrapCancel.getInstanceStatus().equals(WorkFlowStatusEnum.CANCEL_SUBMIT.getRollBack()))) {
                map.put("approvalStatus", "提交");
            }
            dto.setVariable(map);
            // 下一节点执行人单位（下节点接收机构code）
            dto.setNextExecuteUserCompanyCode(this.getNextUserOrgCode(operate, jgScrapCancel));
            // 执行流程
            ProcessTaskDTO processTaskDTO = cmWorkflowService.completeOrReject(taskId, dto, operate);
            // 更新下一步执行人、创建待办
            updateExecuteIds(equList, instanceId, id, operate, processTaskDTO);

            // redis流程实时数据更新
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(jgScrapCancel));
            this.delRepeatUseEquipData(jgScrapCancel);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

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

    public void updateExecuteIds(String equList, String instanceId, Long sequenceNbr, String operate, ProcessTaskDTO processTaskDTO) {
        List<String> roleListNext = new ArrayList<>();
        List<String> roleListAll = new ArrayList<>();
        String taskCode = FlowStatusEnum.TO_BE_FINISHED.getName();
        String taskName = "";
        String nextTaskId = "";
        JgScrapCancel jgScrapCancel = this.getBaseMapper().selectById(sequenceNbr);
        if (processTaskDTO != null && processTaskDTO.getNextTask() != null && !processTaskDTO.getNextTask().isEmpty()) {
            taskCode = processTaskDTO.getNextTask().get(0).getKey();
            taskName = processTaskDTO.getNextTask().get(0).getName();
            nextTaskId = processTaskDTO.getNextTask().get(0).getId();
        }
        if (!FlowStatusEnum.TO_BE_FINISHED.getName().equals(taskCode)) {
            this.buildRoleList(Collections.singletonList(processTaskDTO), roleListNext, roleListAll);
            List<WorkflowResultDto> workflowResultDtos = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO));
            String nextUserIds = workflowResultDtos.get(0).getNextExecutorUserIds();
            jgScrapCancel.setNextExecuteIds(String.join(",", roleListNext));
            jgScrapCancel.setPromoter(RequestContext.getExeUserId());
            jgScrapCancel.setInstanceId(instanceId);
            jgScrapCancel.setNextTaskId(nextTaskId);
            // 更新下一步可执行人
            jgScrapCancel.setNextExecuteUserIds(nextUserIds);
            if (!ObjectUtils.isEmpty(jgScrapCancel.getInstanceStatus())) {
                jgScrapCancel.setInstanceStatus(jgScrapCancel.getInstanceStatus() + "," + String.join(",", roleListNext));
            } else {
                jgScrapCancel.setInstanceStatus(String.join(",", roleListNext));
            }
            if ("0".equals(operate)) {
                // 通过操作
                jgScrapCancel.setAuditStatus(Objects.requireNonNull(WorkFlowStatusEnum.getMessage(taskCode)).getPass());
            } else {
                // 驳回操作
                jgScrapCancel.setAuditStatus(Objects.requireNonNull(WorkFlowStatusEnum.getMessage(taskCode)).getReject());
                jgScrapCancel.setPromoter(null);
            }
            JgScrapCancelDto scrapCancelDto = new JgScrapCancelDto();
            BeanUtils.copyProperties(jgScrapCancel, scrapCancelDto);
            // 更新上一步待办、创建待办
            executeOneStep(scrapCancelDto, taskName, nextUserIds, operate);
        } else {
            // 完成时 下一步骤可执行人清空
            jgScrapCancel.setNextExecuteUserIds("");
            jgScrapCancel.setNextTaskId(nextTaskId);
            JgScrapCancelDto scrapCancelDto = new JgScrapCancelDto();
            BeanUtils.copyProperties(jgScrapCancel, scrapCancelDto);
            scrapCancelDto.setAuditStatus(FlowStatusEnum.TO_BE_FINISHED.getName());
            // 更新代办
            TaskV2Model taskV2Model = updateTaskModel(scrapCancelDto, operate);
            // 修改业务信息
            updateInfoOther(jgScrapCancel, taskV2Model.getRoutePath());
            // 发送数据变更消息
            this.sendDataRefreshMsg(jgScrapCancel);
            //  创建设备履历
            this.createResume(jgScrapCancel, taskV2Model.getRoutePath());
        }
        this.getBaseMapper().updateById(jgScrapCancel);
    }

    private void createResume(JgScrapCancel jgScrapCancel, String routePath) {
        LambdaQueryWrapper<JgScrapCancelEq> lambdaEq = new QueryWrapper<JgScrapCancelEq>().lambda();
        lambdaEq.eq(JgScrapCancelEq::getEquipTransferId, jgScrapCancel.getSequenceNbr());
        lambdaEq.select(JgScrapCancelEq::getEquId, BaseEntity::getSequenceNbr);
        List<JgScrapCancelEq> scrapCancelEqs = jgScrapCancelEqService.list(lambdaEq);
        jgResumeInfoService.saveBatchResume(scrapCancelEqs.stream().map(eq-> JgResumeInfoDto.builder().applyNo(jgScrapCancel.getApplyNo())
                .businessType(getRegistrationClass(jgScrapCancel.getCancelType()))
                .businessId(String.valueOf(jgScrapCancel.getSequenceNbr()))
                .equId(eq.getEquId())
                .approvalUnit(jgScrapCancel.getReceiveOrgName())
                .approvalUnitCode(jgScrapCancel.getReceiveCompanyCode())
                .status("正常")
                .changeContent(getRegistrationClass(jgScrapCancel.getCancelType()) + "业务办理")
                .routePath(routePath)
                .build()).collect(Collectors.toList())
        );
    }

    private void sendDataRefreshMsg(JgScrapCancel jgScrapCancel) {
        LambdaQueryWrapper<JgScrapCancelEq> lambdaEq = new QueryWrapper<JgScrapCancelEq>().lambda();
        lambdaEq.eq(JgScrapCancelEq::getEquipTransferId, jgScrapCancel.getSequenceNbr());
        lambdaEq.select(JgScrapCancelEq::getEquId);
        List<String> records = jgScrapCancelEqService.list(lambdaEq).stream().map(JgScrapCancelEq::getEquId).collect(Collectors.toList());
        eventPublisher.publish(new DataRefreshEvent(this, records, DataRefreshEvent.DataType.equipment.name(), DataRefreshEvent.Operation.UPDATE));
    }

    private void updateInfoOther(JgScrapCancel jgScrapCancel, String routePath) {
        LambdaQueryWrapper<JgScrapCancelEq> lambdaEq = new LambdaQueryWrapper<>();
        lambdaEq.eq(JgScrapCancelEq::getEquipTransferId, jgScrapCancel.getSequenceNbr());
        lambdaEq.select(JgScrapCancelEq::getEquId, JgScrapCancelEq::getUseRegistrationCode);
        List<JgScrapCancelEq> jgScrapCancelEqList = jgScrapCancelEqMapper.selectList(lambdaEq);
        Map<String, Object> map1 = new HashMap<>();
        List<String> equipIds = jgScrapCancelEqList.stream().map(JgScrapCancelEq::getEquId).collect(Collectors.toList());
        List<JgUseRegistrationManage> jgUseRegistrationManageList = getJgUseRegistrationManages(jgScrapCancelEqList);
        Map<String, Map<String, Object>> resultMap = new HashMap<>();
        if (CancelTypeEnum.SCRAPPED.getCode().equals(jgScrapCancel.getCancelType())) {
            idxBizJgUseInfoMapper.batchUpdateUseInfo(equipIds, EquimentEnum.BAOFEI.getCode());
            map1.put("EQU_STATE", String.valueOf(EquimentEnum.BAOFEI.getCode()));
            // 修改证管理表中的证的状态
            // 查出所有需要改的使用登记证
            // 过滤出非气瓶 或是车用气瓶的使用登记证
            jgUseRegistrationManageList = jgUseRegistrationManageList.stream().filter(item -> !CylinderTypeEnum.CYLINDER.getCode().equals(item.getEquCategoryCode()) || item.getRegType().equals(BusinessTypeEnum.JG_VEHICLE_GAS_APPLICATION.getName())).collect(Collectors.toList());
            //组装条件进行修改
            if (!ObjectUtils.isEmpty(jgUseRegistrationManageList)) {
                for(JgUseRegistrationManage useRegistrationManage : jgUseRegistrationManageList){
                    useRegistrationManage.setCertificateStatus(CertificateStatusEnum.YIZHUXIAO.getName());
                    useRegistrationManage.setVersion(useRegistrationManage.getVersion() + 1);
                    useRegistrationManage.setChangeReason(BusinessTypeEnum.JG_EQUIPMENT_CANCEL.getName());
                    useRegistrationManage.setIsScrap("1");
                    useRegistrationManage.setRecDate(new Date());
                    useRegistrationManage.setIsDoBusiness("3");//报废修改为3，不可做业务，可以被证管理查询到
                }
                jgUseRegistrationManageService.updateBatchById(jgUseRegistrationManageList);
            }
        } else {
            map1.put("EQU_STATE", String.valueOf(EquimentEnum.ZHUXIAO.getCode()));
            idxBizJgUseInfoMapper.batchUpdateUseInfo(equipIds, EquimentEnum.ZHUXIAO.getCode());
            // 修改证管理表中的证的状态
            for(JgUseRegistrationManage useRegistrationManage : jgUseRegistrationManageList){
                useRegistrationManage.setCertificateStatus(CertificateStatusEnum.YIZHUXIAO.getName());
                useRegistrationManage.setVersion(useRegistrationManage.getVersion() + 1);
                useRegistrationManage.setChangeReason(BusinessTypeEnum.JG_EQUIPMENT_MOVE.getName());
                useRegistrationManage.setRecDate(new Date());
            }
            jgUseRegistrationManageService.updateBatchById(jgUseRegistrationManageList);
        }
        for (String equipId : equipIds) {
            resultMap.put(equipId, map1);
        }
        // 流水表
        saveRecord(jgScrapCancel, jgScrapCancelEqList, routePath, jgUseRegistrationManageList);
        try {
            tzsServiceFeignClient.commonUpdateEsDataByIds(resultMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        jgScrapCancel.setAuditStatus(FlowStatusEnum.TO_BE_FINISHED.getName());
        jgScrapCancel.setAuditPassDate(new Date());
    }

    private List<JgUseRegistrationManage> getJgUseRegistrationManages(List<JgScrapCancelEq> jgScrapCancelEqList) {
        List<String> useRegistrationCodes = jgScrapCancelEqList.stream().map(JgScrapCancelEq::getUseRegistrationCode).collect(Collectors.toList());
        LambdaQueryWrapper<JgUseRegistrationManage> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(JgUseRegistrationManage::getUseRegistrationCode, useRegistrationCodes);
        return jgUseRegistrationManageMapper.selectList(lambdaQueryWrapper);
    }

    public String getNextUserOrgCode(String operate, JgScrapCancel jgScrapCancel) {
        String code = null;
        if ("0".equals(operate)) {
            code = jgScrapCancel.getReceiveCompanyCode();
        } else {
            // 驳回
            if (WorkFlowStatusEnum.CANCEL_RECEIVE.getPass().equals(jgScrapCancel.getAuditStatus()) ||
                    WorkFlowStatusEnum.CANCEL_RECEIVE.getReject().equals(jgScrapCancel.getAuditStatus()) ||
                    WorkFlowStatusEnum.CANCEL_RECEIVE.getRollBack().equals(jgScrapCancel.getAuditStatus())) {
                code = jgScrapCancel.getUseUnitCode();
            }
        }
        return code == null ? jgScrapCancel.getReceiveCompanyCode() : code;
    }


    private void saveRecord(JgScrapCancel jgScrapCancel, List<JgScrapCancelEq> jgScrapCancelEqList, String routePath, List<JgUseRegistrationManage> jgUseRegistrationManageList) {
        String realName = Privilege.agencyUserClient.queryByUserId(jgScrapCancel.getCreateUserId()).getResult().getRealName();
        String content = jgScrapCancel.getUseUnitName() + "的" + realName + "办理了【" + CancelTypeEnum.getNameByType(jgScrapCancel.getCancelType()) + "】" +
                "单号【" + jgScrapCancel.getApplyNo() + "】，办理日期" + DateUtils.getDateNowShortStr();
        List<JgCertificateChangeRecord> certificateChangeRecords = new ArrayList<>();
        List<JgCertificateChangeRecordEq> changeRecordEqList = new ArrayList<>();
        for (JgUseRegistrationManage jgUseRegistrationManage : jgUseRegistrationManageList) {
            long seq = sequence.nextId();
            JgCertificateChangeRecord changeRecord = new JgCertificateChangeRecord();
            changeRecord.setSequenceNbr(seq);
            changeRecord.setApplyNo(jgScrapCancel.getApplyNo());
            changeRecord.setReceiveOrgName(jgScrapCancel.getReceiveOrgName());
            changeRecord.setAuditPassDate(new Date());
            changeRecord.setRegType(CancelTypeEnum.getNameByType(jgScrapCancel.getCancelType()));
            changeRecord.setRegDate(jgScrapCancel.getCreateDate());
            changeRecord.setChangeContent(content);
            changeRecord.setUseRegistrationCode(jgUseRegistrationManage.getUseRegistrationCode());
            changeRecord.setReceiveCompanyCode(jgScrapCancel.getReceiveOrgCode());
            changeRecord.setUseUnitCreditCode(jgScrapCancel.getUseUnitCode());
            changeRecord.setUseUnitName(jgScrapCancel.getUseUnitName());
            changeRecord.setEquCategory(jgUseRegistrationManage.getEquCategoryCode());
            changeRecord.setCreateDate(new Date());
            changeRecord.setRoutePath(routePath);
            changeRecord.setCreateUserId(jgScrapCancel.getCreateUserId());
            changeRecord.setCertificateNo(jgUseRegistrationManage.getCertificateNo());
            certificateChangeRecords.add(changeRecord);
            jgScrapCancelEqList.stream().filter(eq -> eq.getUseRegistrationCode().equals(jgUseRegistrationManage.getUseRegistrationCode())).forEach(e -> {
                JgCertificateChangeRecordEq changeRecordEq = new JgCertificateChangeRecordEq();
                changeRecordEq.setChangeRecordId(changeRecord.getSequenceNbr().toString()); //登记证记录主键
                changeRecordEq.setEquId(e.getEquId()); //设备主键
                changeRecordEq.setProductCode(e.getEquCode()); //设备代码
                changeRecordEqList.add(changeRecordEq);
            });
        }
        if (!certificateChangeRecords.isEmpty()) {
            certificateChangeRecordService.saveBatch(certificateChangeRecords);
        }
        if (!changeRecordEqList.isEmpty()) {
            jgCertificateChangeRecordEqServiceImpl.saveBatch(changeRecordEqList);
        }
    }

    @Override
    public boolean beforeCheck(JgScrapCancel jgScrapCancel) {
        return jgScrapCancel.getInstanceId() != null && !jgScrapCancel.getAuditStatus().equals(FlowStatusEnum.TO_BE_FINISHED.getName()) &&!jgScrapCancel.getAuditStatus().equals(FlowStatusEnum.TO_BE_DISCARD.getName());
    }

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

    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void handleScrapCancelWrongData(String applyNo) {
        JgScrapCancel jgScrapCancel = this.baseMapper.selectOne(new LambdaQueryWrapper<JgScrapCancel>()
                .in(JgScrapCancel::getApplyNo, applyNo)
                .eq(JgScrapCancel::getIsDelete, 0));
        WorkflowResultDto workflowResultDto = new WorkflowResultDto();
        workflowResultDto.setNextExecutorRoleIds(jgScrapCancel.getNextExecuteIds());
        workflowResultDto.setNextTaskCode("已完成");
        workflowResultDto.setNextTaskId(jgScrapCancel.getNextTaskId());
        workflowResultDto.setNextExecutorUserIds(jgScrapCancel.getNextExecuteUserIds());

        jgScrapCancel.setNextExecuteUserIds("");
        jgScrapCancel.setNextTaskId(jgScrapCancel.getNextTaskId());
        JgScrapCancelDto scrapCancelDto = new JgScrapCancelDto();
        BeanUtils.copyProperties(jgScrapCancel, scrapCancelDto);
        scrapCancelDto.setAuditStatus(FlowStatusEnum.TO_BE_FINISHED.getName());
        // 更新代办
        TaskV2Model taskV2Model = updateTaskModel(scrapCancelDto, "0");
        // 修改业务信息
        updateInfoOther(jgScrapCancel, taskV2Model.getRoutePath());
        // 发送数据变更消息
        this.sendDataRefreshMsg(jgScrapCancel);
        //  创建设备履历
        this.createResume(jgScrapCancel, taskV2Model.getRoutePath());
    }
}
