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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.aspose.words.SaveFormat;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
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.controller.BaseController;
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.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.jg.api.dto.*;
import com.yeejoin.amos.boot.module.jg.api.entity.JgRegistrationHistory;
import com.yeejoin.amos.boot.module.jg.api.enums.*;
import com.yeejoin.amos.boot.module.jg.api.mapper.CommonMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgChangeRegistrationTransferService;
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.service.IJgTransferNoticeService;
import com.yeejoin.amos.boot.module.jg.api.vo.SortVo;
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.ICommonService;
import com.yeejoin.amos.boot.module.jg.biz.utils.FileExporter;
import com.yeejoin.amos.boot.module.jg.biz.utils.ImageUtils;
import com.yeejoin.amos.boot.module.jg.biz.utils.JsonUtils;
import com.yeejoin.amos.boot.module.jg.biz.utils.WordTemplateUtils;
import com.yeejoin.amos.boot.module.jg.flc.api.fegin.PrivilegeFeginService;
import com.yeejoin.amos.boot.module.ymt.api.entity.EquipmentCategory;
import com.yeejoin.amos.boot.module.ymt.api.entity.RegistrationInfo;
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.EquipmentCategoryMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgSupervisionInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.RegistrationInfoMapper;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.component.feign.utils.FeignUtil;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.PermissionModel;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.DictionarieValueModel;
import com.yeejoin.amos.feign.systemctl.model.TaskV2Model;
import com.yeejoin.amos.feign.workflow.model.ActTaskDTO;
import com.yeejoin.amos.feign.workflow.model.FlowTaskVo;
import com.yeejoin.amos.feign.workflow.model.ProcessTaskDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 装备分类服务实现类
 *
 * @author system_generator
 * @date 2021-10-20
 */
@Service
@Slf4j
public class CommonServiceImpl implements ICommonService {

    public static final String SPECIAL_REGION_CODE = "SpecialRegionCode";
    public static final String YWCJ = "YWCJ";
    public static final String DICT_DATA_KEY = "dictDataKey";
    // 行政区划redis缓存key
    private static final String PROVINCE = "PROVINCE";
    private static final String CITY = "CITY";
    private static final String REGION = "REGION";
    private static final String STREET = "STREET";
    // 行政区划level
    private static final String PROVINCE_LEVEL = "1";
    private static final String CITY_LEVEL = "2";
    private static final String REGION_LEVEL = "3";
    private static final String STREET_LEVEL = "4";
    // 判断行政区划查询市还是区
    private static final String END_CODE = "0000";
    // 判断行政区划查询街道
    private static final String STREET_END_CODE = "00";
    // 管辖机构redis缓存key
    private static final String REGULATOR_UNIT_TREE = "REGULATOR_UNIT_TREE";
    /**
     * 接收机构redis缓存key前置
     */
    private static final String PREFIX_NOTICE_RECEIVE_UNIT_TREE = "NOTICE_RECEIVE_UNIT_TREE";
    // 管辖机构redis缓存key
    private static final String REGULATOR_UNIT_TREE_ALL = "REGULATOR_UNIT_TREE_ALL";
    // 行政审批局redis缓存key
    private static final String ADMINISTRATION_UNIT_TREE = "ADMINISTRATION_UNIT_TREE";
    private static final String XZSB = "XZSB";
    private static final String CODE = "code";
    private static final String PL_DR = "PL_DR";
    // 管辖机构
    private static final String REGULATOR_UNIT = "监管机构";
    // 行政审批局
    private static final String ADMINISTRATION_UNIT = "行政审批局";
    // 业务通用发起——基本信息
    private static final String basic = "basic";
    // 业务通用发起——告知单详情
    private static final String notice = "notice";
    // 业务通用发起——技术参数-改造变更登记使用
    private static final String techInfo = "techInfo";
    // 业务通用发起——安装告知表单key
    private static final String AZGZ_FORM_ID = "1734141426742095873";
    // 业务通用发起——移装变更表单key
    private static final String YZBG_PAGE_ID = "changeRegistrationTransfer";
    // 业务通用发起——改造告知表单key
    private static final String GZGZ_PAGE_ID = "reformNoticeAdd";
    // 业务通用发起——维修告知表单key
    private static final String WXGZ_PAGE_ID = "maintainInfo";
    // 业务通用发起——移装告知表单key
    private static final String YZGZ_PAGE_ID = "transferNoticeAdd";
    // 业务通用发起——单位变更表单key
    private static final String DWBG_PAGE_ID = "changeRegisInfo";
    // 业务通用发起——设备注销表单key
    private static final String SBZX_PAGE_ID = "jgScrapCancelAdd";
    // 业务通用发起——更名变更表单key
    private static final String GMBG_PAGE_ID = "jgRegistrationInfo";
    private static final String SELECTED_ROLE_SEQS = "selectRoleSeqs";
    @Autowired
    EquipmentCategoryMapper equipmentCategoryMapper;
    @Autowired
    IDataDictionaryService iDataDictionaryService;
    @Autowired
    JgRegistrationHistoryServiceImpl jgRegistrationHistoryService;
    @Autowired
    PrivilegeFeginService privilegeFeginService;
    @Autowired
    CommonMapper commonMapper;
    @Autowired
    RegistrationInfoMapper tzsJgRegistrationInfoMapper;
    @Autowired
    JgMaintenanceContractServiceImpl jgMaintenanceContractServiceImpl;
    @Autowired
    JgUseRegistrationServiceImpl jgUseRegistrationServiceImpl;
    @Autowired
    @Lazy
    JgEquipTransferServiceImpl jgEquipTransferServiceImpl;
    @Autowired
    JgReformNoticeServiceImpl jgReformNoticeService;
    @Autowired
    JgChangeRegistrationReformServiceImpl jgChangeRegistrationReformServiceImpl;
    @Autowired
    IJgChangeRegistrationTransferService jgChangeRegistrationTransferService;
    @Autowired
    JgChangeRegistrationUnitServiceImpl jgChangeRegistrationUnitServiceImpl;
    @Autowired
    JgChangeRegistrationNameServiceImpl jgChangeRegistrationNameService;
    @Autowired
    JgEnableDisableServiceImpl jgEnableDisableServiceImpl;
    @Autowired
    JgScrapCancelServiceImpl jgScrapCancelService;
    @Autowired
    ICmWorkflowService cmWorkflowService;
    @Autowired
    TzsServiceFeignClient tzsServiceFeignClient;
    @Autowired
    DataDictionaryServiceImpl dataDictionaryService;
    @Autowired
    IdxBizJgSupervisionInfoMapper idxBizJgSupervisionInfoMapper;
    @Autowired
    RedissonClient redissonClient;
    @Value("${redis.cache.failure.time}")
    private Long redisRegionTimeSecond;
    @Autowired
    private RedisUtils redisUtils;
    @Value("classpath:/json/superviseBusinessCategory.json")
    private Resource superviseBusinessCategory;
    @Value("classpath:/json/urlInfo.json")
    private Resource urlInfo;
    @Value("classpath:/json/companyCodeRegName.json")
    private Resource regNameJson;
    @Value("${regulator.unit.code}")
    private String code;
    @Autowired
    private IJgInstallationNoticeService iJgInstallationNoticeService;
    @Autowired
    private IJgMaintainNoticeService iJgMaintainNoticeService;
    @Autowired
    private IJgTransferNoticeService jgTransferNoticeService;
    @Autowired
    private JgVehicleInformationServiceImpl jgVehicleInformationService;
    private Map<String, String> companyCodeRegNameMap;

    public static byte[] file2byte(File file) {
        try {
            FileInputStream in = new FileInputStream(file);
            // 当文件没有结束时，每次读取一个字节显示
            byte[] data = new byte[in.available()];
            in.read(data);
            in.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private static String toQueryParams2(JSONObject jsonObject) {
        StringBuilder sb = new StringBuilder();
        Set<String> keys = jsonObject.keySet();
        keys.forEach(key -> {
            Object value = jsonObject.get(key);
            if (sb.length() > 0) {
                sb.append('&');
            }
            try {
                if (value != null && !"".equals(value)) {
                    sb.append(URLEncoder.encode(key, "UTF-8"))
                            .append('=')
                            .append(URLEncoder.encode(value.toString(), "UTF-8"));
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        });
        return sb.toString();
    }

    public static String buildJgExecuteLockKey(String instanceId) {
        return "JG_INSTANCE_LOCK:" + instanceId;
    }

    public static String buildJgInstanceDataKey(String instanceId) {
        return "JG_INSTANCE_DATA:" + instanceId;
    }

    public static void formatTime2StrDateForEquip(JSONObject jsonObject) {
        String[] timeFields = {"designDate", "produceDate", "inspectDate", "nextInspectDate"};
        for (String field : timeFields) {
            if (jsonObject.get(field) != null && jsonObject.get(field) instanceof Long) {
                jsonObject.put(field, DateUtil.format(new Date(Long.parseLong(jsonObject.get(field).toString())), DatePattern.NORM_DATETIME_PATTERN));
            }
        }
    }

    /**
     * 驼峰转下划线
     *
     * @param str
     * @return
     */
    public static String convertToUnderline(String str) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append("_").append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    private static String getSelectedRoleRedisKey() {
        return RequestContext.getToken() + "_" + SELECTED_ROLE_SEQS;
    }

    private static void convertAndAddToUnitList(DictionarieValueModel x, List<Map<String, Object>> unitList) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("useCode", x.getDictDataKey());
        map.put("useUnit", x.getDictDataValue());
        unitList.add(map);
    }

    @PostConstruct
    public void init() {
        companyCodeRegNameMap = JsonUtils.getResourceJson(regNameJson);
    }

    @Override
    public List<EquipmentCategory> getEquipmentCategoryList(String code, String type) {
        List<EquipmentCategory> result = new ArrayList<>();

        LambdaQueryWrapper<EquipmentCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EquipmentCategory::getCode, code);
        EquipmentCategory equipmentCategory = equipmentCategoryMapper.selectOne(wrapper);
        if (ObjectUtils.isEmpty(type)) {
            if (!ValidationUtil.isEmpty(equipmentCategory)) {
                result.add(equipmentCategory);
            }
        } else {
            LambdaQueryWrapper<EquipmentCategory> wrapper2 = new LambdaQueryWrapper<>();
            wrapper2.eq(EquipmentCategory::getParentId, equipmentCategory.getId());
            List<EquipmentCategory> equipmentCategories = equipmentCategoryMapper.selectList(wrapper2);
            if (!ValidationUtil.isEmpty(equipmentCategories)) {
                result = equipmentCategories;
            }
        }
        return result;
    }

    @Override
    public List<LinkedHashMap> getRegion(String level, String parentId) {
        List<LinkedHashMap> list = new ArrayList<>();
        if (!ObjectUtils.isEmpty(level)) {
            list = (List<LinkedHashMap>) redisUtils.get(PROVINCE);
            return ObjectUtils.isEmpty(list) ? getProvinceList(level) : list;
        } else if (!ObjectUtils.isEmpty(parentId)) {
            String regionCode = parentId.split("_")[0];
            // regionCode不是以00结尾查询街道，以0000结果查询市、否则查询区
            if (!regionCode.endsWith(STREET_END_CODE)) {
                list = ObjectUtils.isEmpty(redisUtils.get(STREET)) ? getProvinceList(STREET_LEVEL) : (List<LinkedHashMap>) redisUtils.get(STREET);
            } else if (regionCode.endsWith(END_CODE)) {
                list = ObjectUtils.isEmpty(redisUtils.get(CITY)) ? getProvinceList(CITY_LEVEL) : (List<LinkedHashMap>) redisUtils.get(CITY);
            } else {
                list = ObjectUtils.isEmpty(redisUtils.get(REGION)) ? getProvinceList(REGION_LEVEL) : (List<LinkedHashMap>) redisUtils.get(REGION);
            }
            return list.stream().filter(r -> regionCode.equals(r.get("parentRegionCode").toString())).collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }
    }

    public List<LinkedHashMap> getProvinceList(String level) {
        FeignClientResult result = privilegeFeginService.getProvince(level);
        List<LinkedHashMap> list = (List<LinkedHashMap>) result.getResult();
        for (LinkedHashMap linkedHashMap : list) {
            linkedHashMap.put("sequenceNbr", linkedHashMap.get("regionCode"));
        }
        switch (level) {
            case PROVINCE_LEVEL:
                redisUtils.set(PROVINCE, list);
                break;
            case CITY_LEVEL:
                redisUtils.set(CITY, list);
                break;
            case REGION_LEVEL:
                redisUtils.set(REGION, list);
                break;
            case STREET_LEVEL:
                redisUtils.set(STREET, list);
                break;
            default:
                log.error("不支持的行政区划：{}", level);
                break;
        }
        return list;
    }

    @Override
    public List<LinkedHashMap> getCreatTree() {
        List<LinkedHashMap> result = (List<LinkedHashMap>) redisUtils.get(REGULATOR_UNIT_TREE);
        // 判断redis是否存在管辖机构树
        return !ObjectUtils.isEmpty(result) ? result : creatTree();
    }

    @Override
    public List<LinkedHashMap> getCreatTreeByInstallation() {
        List<LinkedHashMap> result = (List<LinkedHashMap>) redisUtils.get(REGULATOR_UNIT_TREE_ALL);
        // 判断redis是否存在管辖机构树
        return !ObjectUtils.isEmpty(result) ? result : getCreatTreeByInstallationTree();
    }

    @Override
    public List<LinkedHashMap> getCreatTreeByInstallationTree() {
        FeignClientResult tree = privilegeFeginService.queryAgencyTreeForCache(RequestContext.getToken(), RequestContext.getAppKey(), RequestContext.getProduct());
        List<LinkedHashMap> result = (List<LinkedHashMap>) tree.getResult();
        List<LinkedHashMap> treeData = deleteData(result, REGULATOR_UNIT);
        List<LinkedHashMap> supervisionTree = treeData.stream().filter(e -> code.equals(e.get("orgCode"))).collect(Collectors.toList());
        List<LinkedHashMap> resultTree = updateNullChildren(supervisionTree);
        redisUtils.set(REGULATOR_UNIT_TREE_ALL, resultTree);
        return resultTree;
    }

    @Override
    public List<LinkedHashMap> getReceiveUnitTree(String bizType) {
        List<LinkedHashMap> result = (List<LinkedHashMap>) redisUtils.get(genRedisKey(bizType));
        // 判断redis是否存在接收机构树
        return !ObjectUtils.isEmpty(result) ? result : creatReceiveUnitTree(bizType);
    }

    /**
     * 验EQUCODE的唯一性
     *
     * @param equCode
     * @return
     */
    @Override
    public Boolean checkUniquenessOfEQUCODE(String equCode) {
        LambdaQueryWrapper<RegistrationInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RegistrationInfo::getEquCode, equCode);
        Integer count = tzsJgRegistrationInfoMapper.selectCount(wrapper);
        return count > 0;
    }

    @Override
    public Map<String, Object> getPermissionTreeWithCompany(String menuAgent, String permissionType, String path, CompanyBo company) {
        Map<String, Object> result = new HashMap<>();
        Object roleSeqs = redisUtils.get(getSelectedRoleRedisKey());
        Collection<PermissionModel> permissionModels;
        // 监管单位
        if (!"company".equals(company.getLevel()) || null == roleSeqs) {
            permissionModels = FeignUtil.remoteCall(() -> Privilege.permissionClient.currentPermissionTree(menuAgent, permissionType, null, path));
        } else {
            permissionModels = FeignUtil.remoteCall(() -> Privilege.permissionClient.treeByRoles(roleSeqs.toString(), menuAgent, permissionType, path, RequestContext.getAppKey()));
        }
        result.put("permission", permissionModels);
        result.put("company", company);
        return result;
    }

    @Override
    public void useFlagGenerate(UseFlagParamDto useFlagParamDto, HttpServletResponse response) {
        Objects.requireNonNull(useFlagParamDto, "参数不能为空");

        Map<String, Object> paramMap = Bean.BeantoMap(useFlagParamDto);
        // 二维码设置
        setQrCode(useFlagParamDto, paramMap);
        // 日期设置
        setNextDate(useFlagParamDto, paramMap);
        // 登记机关调整为H列内容（原因目前公司结构无行政审批局）
        setRegName(useFlagParamDto, paramMap);
        String ftlPath = this.getFtlPathByBiz(useFlagParamDto);
        if (StringUtils.isEmpty(ftlPath)) {
            throw new BadRequest("无法找到使用标志模板！");
        }

        File pdfFile = null;
        try {
            pdfFile = this.wordToPdf("特种设备使用标志_", ftlPath, paramMap);
            byte[] bytes = file2byte(pdfFile);
            String docTitle = pdfFile.getName();
            FileExporter.exportFile(FileExporter.FileType.valueOf("pdf"), docTitle, bytes, response);
        } catch (Exception e) {
            log.error("特种设备使用标志生成失败", e);
            throw new RuntimeException("特种设备使用标志生成失败", e);
        } finally {
            if (pdfFile != null) {
                pdfFile.delete();
            }
        }
    }

    private void setRegName(UseFlagParamDto useFlagParamDto, Map<String, Object> paramMap) {
        String receiveOrgName = companyCodeRegNameMap.getOrDefault(useFlagParamDto.getReceiveCompanyCode(), useFlagParamDto.getReceiveOrgName());
        paramMap.put("receiveOrgName", receiveOrgName);
    }

    public String getRegName(String receiveCompanyCode, String defaultName) {
        return companyCodeRegNameMap.getOrDefault(receiveCompanyCode, defaultName);
    }

    private void setNextDate(UseFlagParamDto useFlagParamDto, Map<String, Object> paramMap) {
        if (useFlagParamDto.getNextInspectionDate() != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(useFlagParamDto.getNextInspectionDate());
            paramMap.put("year", DateUtil.year(useFlagParamDto.getNextInspectionDate()) + "");
            paramMap.put("month", DateUtil.month(useFlagParamDto.getNextInspectionDate()) + 1);
            paramMap.put("day", calendar.get(Calendar.DAY_OF_MONTH));
            paramMap.put("nextInspectionTime", paramMap.get("year") + "年" + paramMap.get("month") + "月" + paramMap.get("day") + "日");
        }
    }

    private void setQrCode(UseFlagParamDto useFlagParamDto, Map<String, Object> paramMap) {
        String qrCode = ImageUtils.generateQRCode(Optional.ofNullable(useFlagParamDto.getApplyNo()).orElse(""), 180, 180);
        paramMap.put("qrCode", qrCode);
    }

    private String getFtlPathByBiz(UseFlagParamDto useFlagParamDto) {
        String ftlPath = "";
        // 锅炉、压力容器(气瓶除外)、起重机械、客运索道、大型游乐设施、场(厂)内专用机动车辆 使用式样一
        String[] flag1EquipList = {"1000", "2000", "4000", "5000", "9000", "6000"};
        if (Arrays.asList(flag1EquipList).contains(useFlagParamDto.getEquListCode())) {
            ftlPath = "flag1-use-equip.ftl";
        }
        // 电梯使用式样二
        String[] flag2EquipList = {"3000"};
        if (Arrays.asList(flag2EquipList).contains(useFlagParamDto.getEquListCode())) {
            ftlPath = "flag2-use-equip.ftl";
        }
        // 车用气瓶使用式样三, 约定 车用气瓶为 0000
        String[] flag3EquipList = {"0000"};
        if (Arrays.asList(flag3EquipList).contains(useFlagParamDto.getEquListCode())) {
            ftlPath = "flag3-use-equip.ftl";
        }
        return ftlPath;
    }

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

    /**
     * 查询当前登录用户公司下的管理员对应联系方式
     *
     * @param name
     * @return
     */
    @Override
    public Map<String, Object> getUserPhone(String name) {
        ReginParams reginParams = getSelectedOrgInfo();
        String companyCode = reginParams.getCompany().getCompanyCode();
        return commonMapper.getUserPhone(name, companyCode);
    }

    @Override
    public List<LinkedHashMap> getTree(ReginParams reginParams) {
        // 企业逻辑
        if (reginParams.getCompany().getLevel().equals(BaseController.COMPANY_TYPE_COMPANY)) {
            List<LinkedHashMap> result = (List<LinkedHashMap>) redisUtils.get(REGULATOR_UNIT_TREE);
            // 判断redis是否存在管辖机构树
            return !ObjectUtils.isEmpty(result) ? result : creatTree();
        } else {
            return Collections.singletonList((LinkedHashMap) BeanUtil.beanToMap(reginParams.getCompany()));
        }

    }

    @Override
    public List<LinkedHashMap> creatTree() {
        FeignClientResult tree = privilegeFeginService.queryAgencyTreeForCache(RequestContext.getToken(), RequestContext.getAppKey(), RequestContext.getProduct());
        List<LinkedHashMap> result = (List<LinkedHashMap>) tree.getResult();
        List<LinkedHashMap> treeData = deleteTreeData(result, REGULATOR_UNIT);
        List<LinkedHashMap> supervisionTree = treeData.stream().filter(e -> code.equals(e.get("orgCode"))).collect(Collectors.toList());
        List<LinkedHashMap> resultTree = updateNullChildren(supervisionTree);
        redisUtils.set(REGULATOR_UNIT_TREE, resultTree);
        return resultTree;
    }

    private List<LinkedHashMap> creatReceiveUnitTree(String bizType) {
        FeignClientResult tree = privilegeFeginService.tree(RequestContext.getToken(), RequestContext.getAppKey(), RequestContext.getProduct());
        List<LinkedHashMap> result = (List<LinkedHashMap>) tree.getResult();
        // 删除非监管机构的单位
        deleteData(result, REGULATOR_UNIT);
        // 过滤符合指定业务的监管单位
        filterTreeDataByType(result, bizType);
        List<LinkedHashMap> supervisionTree = result.stream().filter(e -> code.equals(e.get("orgCode"))).collect(Collectors.toList());
        List<LinkedHashMap> resultTree = updateNullChildren(supervisionTree);
        redisUtils.set(genRedisKey(bizType), resultTree, 60 * 60 * 2);
        return resultTree;
    }

    private String genRedisKey(String bizType) {
        return PREFIX_NOTICE_RECEIVE_UNIT_TREE + "_" + bizType;
    }

    @Override
    public List<LinkedHashMap> getApproveTree(ReginParams reginParams) {
        // 企业逻辑
        if (reginParams.getCompany().getLevel().equals(BaseController.COMPANY_TYPE_COMPANY)) {
            List<LinkedHashMap> result = (List<LinkedHashMap>) redisUtils.get(ADMINISTRATION_UNIT_TREE);
            // 判断redis是否存在行政审批局树
            return !ObjectUtils.isEmpty(result) ? result : creatApproveTree();
        } else {
            // 监管单位逻辑
            return Collections.singletonList((LinkedHashMap) BeanUtil.beanToMap(reginParams.getCompany()));
        }

    }

    @Override
    public List<LinkedHashMap> creatApproveTree() {
        FeignClientResult tree = privilegeFeginService.queryAgencyTreeForCache(RequestContext.getToken(), RequestContext.getAppKey(), RequestContext.getProduct());
        List<LinkedHashMap> result = (List<LinkedHashMap>) tree.getResult();
        List<LinkedHashMap> children = (List<LinkedHashMap>) result.get(0).get("children");
        List<LinkedHashMap> treeData = deleteTreeData(children, REGULATOR_UNIT);
        List<LinkedHashMap> resultTree = updateNullChildren(treeData);
        redisUtils.set(ADMINISTRATION_UNIT_TREE, resultTree);
        return resultTree;
    }

    @Override
    public List<Map<String, Object>> superviseBusinessCategory(String businessType) {
        ReginParams reginParams = getSelectedOrgInfo();
        Map<String, List<Map<String, Object>>> resourceJson = JsonUtils.getResourceJson(superviseBusinessCategory);
        if (XZSB.equals(businessType) && CompanyTypeEnum.CONSTRUCTION.getName().equals(reginParams.getCompany().getCompanyType())) {
            Iterator<Map<String, Object>> iterator = resourceJson.get(businessType).iterator();
            while (iterator.hasNext()) {
                Map<String, Object> item = iterator.next();
                if (item.get(CODE).equals(PL_DR)) {
                    iterator.remove();
                }
            }
            return resourceJson.get(businessType);
        }
        return resourceJson.get(businessType);
    }

    @Override
    public List<Map<String, Object>> businessScenarios(String type) {
        ReginParams reginParams = getSelectedOrgInfo();
        Map<String, List<Map<String, Object>>> resourceJson = JsonUtils.getResourceJson(superviseBusinessCategory);
        // 新增设备 或者 安改维单位 只有按照设备种类选择的业务
        if (PL_DR.equals(type) || CompanyTypeEnum.CONSTRUCTION.getName().equals(reginParams.getCompany().getCompanyType())) {
            Iterator<Map<String, Object>> iterator = resourceJson.get(YWCJ).iterator();
            while (iterator.hasNext()) {
                Map<String, Object> item = iterator.next();
                if (item.get(DICT_DATA_KEY).equals("1")) {
                    iterator.remove();
                }
            }
            return resourceJson.get(YWCJ);
        }
        return resourceJson.get(YWCJ);

    }

    private List<LinkedHashMap> deleteTreeData(List<LinkedHashMap> result, String companyType) {
        Iterator it = result.iterator();
        while (it.hasNext()) {
            LinkedHashMap e = (LinkedHashMap) it.next();
            // 删除非行政审批局
            if (!e.get("companyType").toString().contains(companyType)) {
                it.remove();
            }
            if (!ObjectUtils.isEmpty(e.get("children"))) {
                deleteTreeData((List<LinkedHashMap>) e.get("children"), companyType);
            }
        }
        return result;
    }

    private List<LinkedHashMap> filterTreeDataByType(List<LinkedHashMap> result, String type) {
        Iterator<LinkedHashMap> it = result.iterator();
        while (it.hasNext()) {
            LinkedHashMap e = it.next();
            if (!(e.get("description") != null && (e.get("description").toString().contains(type) || e.get("description").toString().contains("all")))) {
                // 过滤非全部（all）公共及指定类型外的
                it.remove();
            }
            // disabled的节点设置下不可编辑属性
            if (e.get("description") != null && e.get("description").toString().contains(type + "-disabled")) {
                // 过滤非全部（all）公共及指定类型外的
                e.put("disabled", true);
            }
            if (!ObjectUtils.isEmpty(e.get("children"))) {
                filterTreeDataByType((List<LinkedHashMap>) e.get("children"), type);

            }
        }
        return result;
    }

    private List<LinkedHashMap> deleteData(List<LinkedHashMap> result, String companyType) {
        Iterator it = result.iterator();
        while (it.hasNext()) {
            LinkedHashMap e = (LinkedHashMap) it.next();
            // 删除非指定的单位类型
            if (!e.get("companyType").toString().contains(companyType)) {
                it.remove();
            }
            if (!ObjectUtils.isEmpty(e.get("children"))) {
                deleteData((List<LinkedHashMap>) e.get("children"), companyType);
            }
        }
        return result;
    }

    @Override
    public List<Map<String, Object>> getUnitListByType(String type, String business) {

        switch (type) {
            case "use":
                type = "使用单位";
                break;
            case "maintenance":
                type = "安装改造维修单位";
                break;
            case "inspection":
                type = "检验检测机构";
                break;
            case "manufacture":
                type = "制造单位";
                break;
            case "all":
                type = "all";
                break;
        }
        List<Map<String, Object>> unitList = new ArrayList<>(Collections.emptyList());
        // 检验检测机构 追加车用气瓶
        if ("检验检测机构".equals(type) && "gasCylindersForCars".equals(business)) {
            List<DictionarieValueModel> result = Systemctl.dictionarieClient.dictValues("OLD_INSPECTION_TESTING_UNIT").getResult();
            result.forEach(x -> convertAndAddToUnitList(x, unitList));
        }
        if ("安装改造维修单位".equals(type) && "gasCylindersForCars".equals(business)) {
            List<DictionarieValueModel> result = Systemctl.dictionarieClient.dictValues("OLD_INSTALLATION_UNIT").getResult();
            result.forEach(x -> convertAndAddToUnitList(x, unitList));
        }
        List<Map<String, Object>> unitListByType = commonMapper.getUnitListByType(type);
        unitList.addAll(unitListByType);
        return unitList;
    }

    @Override
    public List<Map<String, Object>> getSecurityAdmin(String type, String companyCode) {
        if (ObjectUtils.isEmpty(companyCode)) {
            ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
            CompanyBo company = reginParams.getCompany();
            companyCode = company.getCompanyCode();
        }
        String postName = null;
        if (type.equals("use")) {
            postName = "安全管理员";
        }
        if (type.equals("jyjc")) {
            postName = "检验检测人员";
        }
        if (type.equals("agw")) {
            postName = "安改维负责人";
        }
        if (type.equals("wbry")) {
            postName = "维保人员";
        }
        return ObjectUtils.isEmpty(postName) ? new ArrayList<>() : commonMapper.getSecurityAdmin(companyCode, postName);
    }

    @Override
    public Map<String, Object> getUserInfo(String sequenceNbr) {
        return commonMapper.getUserInfo(sequenceNbr.split("_")[0]);
    }

    @Override
    public Map<String, Object> getEnterpriseInfo(String useCode) {
        return commonMapper.getEnterpriseInfo(useCode);
    }

    @Override
    public List<Map<String, Object>> getEnterpriseEmployee(String unitCode) {
        return commonMapper.getEnterpriseEmployee(unitCode);
    }

    /**
     * 将管辖机构树中children为[]的修改为null
     *
     * @param result
     * @return
     */
    private List<LinkedHashMap> updateNullChildren(List<LinkedHashMap> result) {
        Iterator it = result.iterator();
        while (it.hasNext()) {
            LinkedHashMap e = (LinkedHashMap) it.next();
            // 将管辖机构树中children为[]的修改为null
            if (e.get("children") != null) {
                if (((List<LinkedHashMap>) e.get("children")).size() == 0) {
                    e.put("children", null);
                }
            }
            if (!ObjectUtils.isEmpty(e.get("children"))) {
                updateNullChildren((List<LinkedHashMap>) e.get("children"));
            }
        }
        return result;
    }

    /**
     * 删除管辖机构树中level为使用单位的数据
     *
     * @param result 管辖机构树
     * @return 筛选过滤后不包含使用单位的管辖机构树
     */
    private List<LinkedHashMap> deleteRegulatorTreeData(List<LinkedHashMap> result) {
        Iterator it = result.iterator();
        while (it.hasNext()) {
            LinkedHashMap e = (LinkedHashMap) it.next();
            // 删除使用单位
            if ("company".equals(e.get("level"))) {
                it.remove();
            }
            if (e.get("companyName").toString().contains("行政审批局")) {
                it.remove();
            }
            // 删除检验检测机构
            if (!"company".equals(e.get("level")) && e.get("companyType").toString().contains("检验检测机构")) {
                it.remove();
            }
            if (!ObjectUtils.isEmpty(e.get("children"))) {
                deleteRegulatorTreeData((List<LinkedHashMap>) e.get("children"));
            }
        }
        return result;
    }

    @Override
    public void generateCertificateReport(Map<String, Object> map, HttpServletResponse response) {
        if (CollectionUtils.isEmpty(map)) {
            throw new IllegalArgumentException("参数不能为空");
        }
        String wordPath = "equipment-registration-certificate-report.ftl";
        wordPath = "unit".equals(map.get("manageType")) ? "unit-registration-certificate-report.ftl" : wordPath;
        // 组装模板变量
        map.put("useRegistrationCode", Optional.ofNullable(map.get("useRegistrationCode")).orElse("").toString()); // 编号
        map.put("useUnitName", Optional.ofNullable(map.get("useUnitName")).orElse("").toString());  // 使用单位名称
        map.put("fullAddress", Optional.ofNullable(map.get("fullAddress")).orElse("").toString());  // 设备使用地点
        map.put("equList", Optional.ofNullable(map.get("equList")).orElse("").toString());  // 设备种类
        map.put("equipDefine", Optional.ofNullable(map.get("equipDefine")).orElse("").toString());  // 设备品种
        map.put("equipCode", Optional.ofNullable(map.get("equipCode")).orElse("").toString());  // 设备代码
        map.put("equipCategory", Optional.ofNullable(map.get("equipCategory")).orElse("").toString());  // 设备类别
        map.put("useInnerCode", Optional.ofNullable(map.get("useInnerCode")).orElse("").toString());  // 单位内编号
        map.put("factoryNum", Optional.ofNullable(map.get("factoryNum")).orElse("").toString());  // 产品编号
        map.put("receiveOrgName", Optional.ofNullable(map.get("receiveOrgName")).orElse("").toString());  // 登记机关
        map.put("giveOutYear", Optional.ofNullable(map.get("giveOutYear")).orElse("").toString());  // 发证日期-年
        map.put("giveOutMonth", Optional.ofNullable(map.get("giveOutMonth")).orElse("").toString());  // 发证日期-月
        map.put("giveOutDay", Optional.ofNullable(map.get("giveOutDay")).orElse("").toString());  // 发证日期-日
        map.put("excelType", Optional.ofNullable(map.get("excelType")).orElse("使用登记").toString());  // 发证日期-日
        map.put("tableName", Optional.ofNullable(map.get("tableName")).orElse("特种设备使用登记证").toString());  // 发证日期-日
        // 生成二维码,之前为设备监管码，调整为申请单号
        String qrCode = ImageUtils.generateQRCode(Optional.ofNullable(map.get("applyNo")).orElse("").toString(), 100, 100);
        map.put("supervisoryCode", qrCode);  // 监管二维码
        // 默认普打
        map.put("printingType", PrintingTypeEnum.REGULAR.getCode());
        // word转pdf
        File pdfFile;
        try {
            pdfFile = this.wordToPdf("特种设备使用登记证_", wordPath, map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        try {
            byte[] bytes = file2byte(pdfFile);
            String docTitle = pdfFile.getName();
            FileExporter.exportFile(FileExporter.FileType.valueOf("pdf"), docTitle, bytes, response);
        } catch (Exception e) {
            log.error("pdf文件转换失败：{}", e);
        } finally {
            try {
                Files.deleteIfExists(pdfFile.toPath());
            } catch (Exception e) {
                log.error("文件找不到，删除失败：{}", e);
            }
        }
    }

    /**
     * 返回附件
     *
     * @param map      参数
     * @param response 响应
     */
    @Override
    public void generatePdfPrint(Map<String, Object> map, HttpServletResponse response) {
        String[] DEFAULT_KEYS = {
                "useRegistrationCode", "useUnitName", "fullAddress", "equList", "equipDefine",
                "equipCode", "equipCategory", "useInnerCode", "factoryNum", "giveOutYear",
                "giveOutMonth", "giveOutDay"
        };

        if (CollectionUtils.isEmpty(map)) {
            throw new IllegalArgumentException("参数不能为空");
        }

        // 设置默认值
        Arrays.stream(DEFAULT_KEYS)
                .forEach(key -> map.computeIfAbsent(key, k -> ""));

        // 生成二维码,之前为设备监管码，调整为申请单号
        String qrCode = ImageUtils.generateQRCode((String) map.getOrDefault("applyNo", ""), 100, 100);
        map.put("supervisoryCode", qrCode);  // 监管二维码 代码优化
        this.fillParamValueToPdf(map, response, "templates/use-registration-model.pdf", "套打使用登记证.pdf", 12.0f);
    }

    @Override
    public byte[] generateSummaryOfCylinderInfo(Map<String, Object> map, String wordPath, String filePrefix) {
        if (CollectionUtils.isEmpty(map)) {
            throw new IllegalArgumentException("参数不能为空");
        }
        // word转pdf
        File pdfFile;
        try {
            pdfFile = this.wordToPdf("", wordPath, map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // file转字节流
        try {
            return file2byte(pdfFile);
        } catch (Exception e) {
            log.error("pdf文件转换失败：{}", e);
        } finally {
            try {
                Files.deleteIfExists(pdfFile.toPath());
            } catch (Exception e) {
                log.error("文件找不到，删除失败：{}", e);
            }
        }
        return new byte[0];
    }

    /**
     * 根据参数填充PDF文本域
     *
     * @param map           参数
     * @param response      response
     * @param pathResource  PDF模版路径
     * @param printFileName 生成文件名称
     * @param textSize      字体大小
     */
    void fillParamValueToPdf(Map<String, Object> map, HttpServletResponse response, String pathResource, String printFileName, float textSize) {
        // 读取资源文件夹下的模板
        ClassPathResource resource = new ClassPathResource(pathResource);

        PdfReader reader = null;
        ByteArrayOutputStream bos = null;
        try {
            InputStream inputStream = resource.getInputStream();
            reader = new PdfReader(inputStream);
            bos = new ByteArrayOutputStream();
            PdfStamper pdfStamper = new PdfStamper(reader, bos);
            AcroFields acroFields = pdfStamper.getAcroFields();
            // 中文字体
            BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

            for (Map.Entry<String, Object> param : map.entrySet()) {
                // 设置文本域的字体为中文字体
                acroFields.setFieldProperty(param.getKey(), "textfont", font, null);
                // 设置字体大小
                acroFields.setFieldProperty(param.getKey(), "textsize", textSize, null);
                // 将 map 中的值写到 pdf 模板对应的文本域中
                acroFields.setField(param.getKey(), param.getValue() + "");
            }

            // 如果为false那么生成的PDF文件还能编辑，所以一定要设为true
            pdfStamper.setFormFlattening(true);
            pdfStamper.close();

            this.writeAttachment(response, bos.toByteArray(), printFileName);
        } catch (IOException | DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                assert bos != null;
                bos.close();
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 返回附件
     *
     * @param response 响应
     * @param content  附件内容
     */
    private void writeAttachment(HttpServletResponse response, byte[] content, String printFileName) throws IOException {
        // 设置 header 和 contentType
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(printFileName, "UTF-8"));
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        // 输出附件
        IoUtil.write(response.getOutputStream(), false, content);
    }

    /**
     * word 转 pdf
     *
     * @param wordPath word文件路径
     */
    private File wordToPdf(String filePrefix, String wordPath, Map<String, Object> placeholders) throws Exception {
        Assert.hasText(wordPath, "word文件路径不能为空");

        String tempFileName = filePrefix + System.currentTimeMillis() + Thread.currentThread().getName() + "_temp.pdf";

        WordTemplateUtils instance = WordTemplateUtils.getInstance();

        return instance.fillAndConvertDocFile(wordPath, tempFileName, placeholders, SaveFormat.PDF);
    }

    /**
     * 上传文件至文件服务器
     *
     * @param file 文件
     */
    private String uploadFile(File file) {
        Assert.notNull(file, "文件不能为空");

        MultipartFile multipartFile = new ByteArrayMultipartFile("file", "file.pdf", "application/pdf", file2byte(file));
        FeignClientResult<Map<String, String>> result = Systemctl.fileStorageClient.updateCommonFile(multipartFile);
        String urlString = "";
        if (result != null) {
            for (String s : result.getResult().keySet()) {
                urlString = s;
            }
        }
        return urlString;
    }

    @Override
    public Object invokeBusinessProcess(String submitType, Map<String, Object> map, ReginParams reginParams) {
        Map<String, Object> basicObj = (Map<String, Object>) map.get(basic);
        Map<String, Object> noticeObj = (Map<String, Object>) map.get(notice);
        Map<String, Object> techInfoObj = (Map<String, Object>) map.get(techInfo);
        Map<String, Object> provideMap = new HashMap<>();

        String type = (String) basicObj.get("type");
        noticeObj.put("businessCode", type);
        if (type.equals(ApplicationFormTypeEnum.AZGZ.getBusinessCode())) {

            JgInstallationNoticeDto jgInstallationNoticeDto = JSON.parseObject(JSON.toJSONString(noticeObj), JgInstallationNoticeDto.class);
            jgInstallationNoticeDto.setReceiveOrgCreditCode(!ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            JSONObject jsonObject1 = (JSONObject) JSONObject.toJSON(jgInstallationNoticeDto);
            provideMap.put(AZGZ_FORM_ID, jsonObject1);
            JSONObject jsonObject = new JSONObject(provideMap);
            return iJgInstallationNoticeService.saveNotice(submitType, jsonObject, reginParams);
        } else if (type.equals(ApplicationFormTypeEnum.GZGZ.getBusinessCode())) {

            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            provideMap.put(GZGZ_PAGE_ID, noticeObj);
            JSONObject jsonObject = new JSONObject(provideMap);
            return jgReformNoticeService.saveNotice(submitType, jsonObject, reginParams);
        } else if (type.equals(ApplicationFormTypeEnum.WXGZ.getBusinessCode())) {

            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            provideMap.put(WXGZ_PAGE_ID, noticeObj);
            JSONObject jsonObject = new JSONObject(provideMap);
            return iJgMaintainNoticeService.saveNotice(submitType, jsonObject, reginParams);
        } else if (type.equals(ApplicationFormTypeEnum.YZGZ.getBusinessCode())) {

            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            provideMap.put(YZGZ_PAGE_ID, noticeObj);
            JSONObject jsonObject = new JSONObject(provideMap);
            return jgTransferNoticeService.saveNotice(submitType, jsonObject, reginParams);
        } else if (type.equals(ApplicationFormTypeEnum.SYDJ.getBusinessCode())) {
            String businessScenarios = (String) basicObj.get("businessScenarios");
            String code = (String) basicObj.get("code");
            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            JSONObject jsonObject = new JSONObject(noticeObj);
            if (submitType.equals("1")) {
                jsonObject.put("submit", Boolean.TRUE);
            }
            // 判断是否为车用气瓶使用登记或者设备使用登记
            return "1".equals(businessScenarios) && CylinderTypeEnum.CYLINDER.getCode().equals(code) ?
                    jgVehicleInformationService.save(submitType, jsonObject) : jgUseRegistrationServiceImpl.save(jsonObject);
        } else if (type.equals(ApplicationFormTypeEnum.GZBG.getBusinessCode())) {
            // 兼容业务逻辑代码
            if (submitType.equals("1")) {
                noticeObj.put("submit", "true");
            }
            noticeObj.put("receiveCompanyCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            noticeObj.put("techInfo", techInfoObj);
            JSONObject jsonObject = new JSONObject(noticeObj);
            return jgChangeRegistrationReformServiceImpl.save(jsonObject);
        } else if (type.equals(ApplicationFormTypeEnum.YZBG.getBusinessCode())) {
            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            provideMap.put(YZBG_PAGE_ID, noticeObj);
            JSONObject jsonObject = new JSONObject(provideMap);
            return jgChangeRegistrationTransferService.createTransfer(submitType, jsonObject, reginParams);
        } else if (type.equals(ApplicationFormTypeEnum.DWBG.getBusinessCode())) {
            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            provideMap.put(DWBG_PAGE_ID, noticeObj);
            JSONObject jsonObject = new JSONObject(provideMap);
            return jgChangeRegistrationUnitServiceImpl.saveNotice(submitType, jsonObject, reginParams);
        } else if (type.equals(ApplicationFormTypeEnum.WBBA.getBusinessCode())) {
            noticeObj.put("equList", basicObj.get("code"));
            noticeObj.put("pageType", "add");
            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            JSONObject jsonObject = new JSONObject(noticeObj);
            return jgMaintenanceContractServiceImpl.saveOrSubmit(submitType, jsonObject, reginParams);
        } else if (type.equals(ApplicationFormTypeEnum.SBYJ.getBusinessCode())) {

            JgEquipTransferDto jgEquipTransferDto = JSON.parseObject(JSON.toJSONString(noticeObj), JgEquipTransferDto.class);
            JSONObject jsonObject = (JSONObject) JSONObject.toJSON(jgEquipTransferDto);
            jsonObject.put("businessCode", type);
            return jgEquipTransferServiceImpl.saveTransfer(submitType, jsonObject, reginParams);
        } else if (type.contains(ApplicationFormTypeEnum.YZBF.getBusinessCode()) || type.contains(ApplicationFormTypeEnum.ZXBF.getBusinessCode())) {
            noticeObj.put("cancelType", type.equals("BF_ZX") ? "1" : "2");
            noticeObj.put("receiveOrgCreditCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            provideMap.put(SBZX_PAGE_ID, noticeObj);
            JSONObject jsonObject = new JSONObject(provideMap);
            return jgScrapCancelService.saveList(submitType, jsonObject);
        } else if (type.equals(ApplicationFormTypeEnum.GMBG.getBusinessCode())) {

            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            provideMap.put(GMBG_PAGE_ID, noticeObj);
            JSONObject jsonObject = new JSONObject(provideMap);
            return jgChangeRegistrationNameService.save2(submitType, jsonObject);
        } else if (type.equals(ApplicationFormTypeEnum.SBQY.getBusinessCode()) || type.equals(ApplicationFormTypeEnum.SBTY.getBusinessCode())) {
            noticeObj.put("submit", submitType);
            noticeObj.put("formType", "add");
            noticeObj.put("receiveOrgCode", !ObjectUtils.isEmpty(basicObj.get("receiveOrgCreditCode")) ? String.valueOf(basicObj.get("receiveOrgCreditCode")) : String.valueOf(basicObj.get("receiveOrgCreditCode1")));
            JSONObject jsonObject = new JSONObject(noticeObj);
            return jgEnableDisableServiceImpl.saveOrUpdate(jsonObject, reginParams);
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object transfer(Map<String, Object> map) {
        if (ObjectUtils.isEmpty(map.get("nextTaskId")) || map.get("nextTaskId") == null) {
            throw new BadRequest("nextTaskId不能为空");
        }
        if (ObjectUtils.isEmpty(map.get("instanceId")) || map.get("instanceId") == null) {
            throw new BadRequest("instanceId不能为空");
        }
        String taskId = map.get("nextTaskId").toString();
        String instanceId = map.get("instanceId").toString();
        String tableName = map.get("tableName").toString();
        String assignee = map.get("assignee").toString();
        String lockKey = buildJgExecuteLockKey(instanceId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            // 解决并发问题：多个人同时操作一个流程（并发执行通过、驳回、撤回）
            if (!isLocked) {
                throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
            }
            // 流程执行前置校验
            this.checkForExecuteFlow(taskId, instanceId);
            FlowTaskVo flowTaskVo = new FlowTaskVo();
            flowTaskVo.setTaskId(taskId);
            flowTaskVo.setAssignee(assignee);
            ProcessTaskDTO processTaskDTO = cmWorkflowService.assign(flowTaskVo);
            // 修改待办
            List<TaskV2Model> result = Systemctl.taskV2Client.selectListByRelationId(instanceId).getResult();
            List<TaskV2Model> collect = result.stream().sorted((r1, r2) -> r2.getSequenceNbr().compareTo(r1.getSequenceNbr())).collect(Collectors.toList());
            if (collect.size() == 0) {
                return null;
            }
            TaskV2Model taskV2Model = collect.get(0);
            taskV2Model.setExecuteUserIds(RequestContext.getExeUserId());
            taskV2Model.setTaskStatus(FlowStatusEnum.TO_BE_TRANSFER.getCode());
            taskV2Model.setTaskStatusLabel(FlowStatusEnum.TO_BE_TRANSFER.getName());
            taskV2Model.setEndUserId(RequestContext.getExeUserId());
            taskV2Model.setEndDate(new Date());
            String routhPath = taskV2Model.getRoutePath().replace("nextExecuteUserIds", "executeUserId") + "&nextExecuteUserIds=" + assignee;
            taskV2Model.setRoutePath(routhPath);
            Systemctl.taskV2Client.update(taskV2Model, taskV2Model.getSequenceNbr());
            // 创建新待办
            taskV2Model.setExecuteUserIds(assignee);
            String nextTaskId = processTaskDTO.getNextTask().get(0).getId();
            taskV2Model.setFlowCode(nextTaskId);
            String routhPath1 = routhPath.replace("nextTaskId", "nextTask") + "&nextTaskId=" + nextTaskId;
            taskV2Model.setCreateDate(new Date());
            taskV2Model.setRoutePath(routhPath1);
            taskV2Model.setTaskStatus(0);
            taskV2Model.setTaskStatusLabel(FlowStatusEnum.TO_BE_PROCESSED.getName());
            taskV2Model.setEndUserId(null);
            taskV2Model.setEndDate(null);
            taskV2Model.setSequenceNbr(null);
            Systemctl.taskV2Client.create(taskV2Model);

            String id = commonMapper.selectBusinessData(tableName, instanceId);
            id = ObjectUtils.isEmpty(id) ? assignee : id + "," + assignee;
            // 修改业务数据
            commonMapper.updateBusinessData(tableName, assignee, id, instanceId, nextTaskId);
            this.saveExecuteFlowData2Redis(instanceId, InstanceRuntimeData.builder()
                    .nextExecuteUserIds(assignee)
                    .nextTaskId(nextTaskId)
                    .promoter(commonMapper.selectPromoterData(tableName, instanceId)).build());
            return Boolean.TRUE;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return Boolean.FALSE;
    }

    public void deleteTaskModel(String id) {
        List<TaskV2Model> result = Systemctl.taskV2Client.selectListByRelationId(id).getResult();
        if (result.size() > 0) {
            List<Long> idList = result.stream().map(TaskV2Model::getSequenceNbr).collect(Collectors.toList());
            String ids = idList.stream().map(Object::toString).collect(Collectors.joining(","));
            Systemctl.taskV2Client.delete(ids);
        }
    }

    /**
     * 待办新增接口
     **/
    public void buildTaskModel(List<TaskModelDto> list) {
        List<TaskV2Model> taskV2Models = new ArrayList<>();
        for (TaskModelDto obj : list) {
            // 判断是否是暂存 新增若无下一节点执行人即为暂存
            boolean flag = StringUtils.isEmpty(obj.getNextExecuteUser()) ? true : false;
            if (flag) {
                List<TaskV2Model> result = Systemctl.taskV2Client.selectListByRelationId(obj.getRelationId()).getResult();
                if (CollectionUtil.isNotEmpty(result) && result.size() > 0) {
                    break;
                }
            }
            ReginParams reginParams = JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
            TaskV2Model model = new TaskV2Model();
            BeanUtil.copyProperties(obj, model);
            String urlParams = "";
            try {
                urlParams = "&" + toQueryParams(obj.getModel());
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            List<Map> urlList = JsonUtils.getResourceList(urlInfo);
            for (Map map : urlList) {
                // 获取暂存的可编辑页面url
                if (flag && map.get("type").equals(obj.getTaskType())
                        && map.get("pageType").equals("draft")) {
                    model.setRoutePath(map.get("url").toString() + urlParams);
                    break;
                }
                // 维保需特殊获取页面  状态不等于监管单位审核的页面均取对应编辑页面
                else if (map.get("type").equals(BusinessTypeEnum.JG_MAINTENANCE_RECORD.getCode())
                        && obj.getTaskType().equals(BusinessTypeEnum.JG_MAINTENANCE_RECORD.getCode())
                        && !obj.getFlowStatus().toString().equals("16723")
                        && map.get("pageType").equals("edit")) {
                    model.setRoutePath(map.get("url").toString().replace("{roleIds}", obj.getNextExecuteUser()) + urlParams + "&nextExecuteUserIds=" + model.getExecuteUserIds());
                    break;
                }
                // 其他逻辑均按详情页面获取
                else if (map.get("type").equals(obj.getTaskType())
                        && map.get("pageType").equals(null == obj.getPageType() ? "look" : obj.getPageType())) {
                    model.setRoutePath(map.get("url").toString().replace("{roleIds}", obj.getNextExecuteUser()) + urlParams + "&nextExecuteUserIds=" + model.getExecuteUserIds());
                    break;
                }
            }
            // 是true则为暂存 除公共部分统一处理
            if (flag) {
                model.setFlowStatus(FlowStatusEnum.TO_BE_SUBMITTED.getCode());
                model.setFlowStatusLabel(FlowStatusEnum.TO_BE_SUBMITTED.getName());
                model.setStartUserId(RequestContext.getExeUserId());
                model.setStartUser(reginParams.getUserModel().getRealName());
                model.setStartUserCompanyName(reginParams.getCompany().getCompanyName());
                model.setStartDate(new Date());
                model.setExecuteUserIds(RequestContext.getExeUserId());
                model.setFlowCreateDate(new Date());
                model.setTaskStatus(FlowStatusEnum.TO_BE_SUBMITTED.getCode());
                model.setTaskTitle("有一条待提交的草稿");
                model.setTaskName(BusinessTypeEnum.getNameByType(obj.getTaskType()));
                model.setTaskTypeLabel(BusinessTypeEnum.getNameByType(obj.getTaskType()));
                //     model.setTaskContent("【申请单号:"+obj.getTaskCode()+"】待提交");
            } else {
                model.setTaskStatus(0);
                model.setTaskTitle(obj.getStartUser() + "发起了" + obj.getTaskName());
            }
            model.setFlowInstanceId(model.getRelationId());
            model.setTaskSource("workFlow");
            model.setExtras(JSON.toJSONString(obj.getModel()));
            // model.setTerminal(params.getOrDefault("terminal","WEB").toString());
            model.setCreateDate(new Date());
            model.setRecUserId(RequestContext.getExeUserId());
            model.setAgencyCode(RequestContext.getAgencyCode());
            taskV2Models.add(model);

        }
        Systemctl.taskV2Client.batchAdd(taskV2Models);
    }

    /**
     * 待办编辑接口
     * 参数
     * taskStatus
     * taskStatusLabel 操作名称  6614驳回 6616已完成 6612待受理
     * flowStatusLabel  任务状态枚举code
     * 流程实例id  instanceId
     * flowCode 任务id
     **/
    public TaskV2Model updateTaskModel(Map<String, Object> params) {
        String exeUserId = RequestContext.getExeUserId();
        List<TaskV2Model> result = Systemctl.taskV2Client.selectListByRelationId(params.get("relationId").toString()).getResult();
        List<TaskV2Model> collect = result.stream().sorted((r1, r2) -> r2.getSequenceNbr().compareTo(r1.getSequenceNbr())).collect(Collectors.toList());

        if (collect == null || collect.size() == 0) {
            return null;
        }
        collect.get(0).setFlowStatus(Integer.valueOf(params.get("flowStatus").toString()));
        collect.get(0).setFlowStatusLabel(params.get("flowStatusLabel").toString());
        collect.get(0).setTaskStatus(Integer.valueOf(params.get("taskStatus").toString()));
        collect.get(0).setTaskStatusLabel(params.get("taskStatusLabel").toString());
        collect.get(0).setEndUserId(exeUserId);
        collect.get(0).setEndDate(new Date());

//        String[] roleIds = model.getRoutePath().split("roleIds=");
//        String[] userIds = roleIds[1].split("&userId");
//        String url = roleIds[0]+"roleIds="+"55555"+"&userId"+ userIds[1];
//        String tarUrl = url.replaceFirst("&executeUserIds=", "");
//        tarUrl+"&executeUserIds="
        // model.setRoutePath( roleIds[0]+"roleIds="+"55555"+"&userId"+userIds[1]);
        // 当流程完成时将所有待办状态统一修改为已完成
        if (collect.get(0).getFlowStatusLabel().equals(FlowStatusEnum.TO_BE_FINISHED.getName())) {
            String urlParams = "";
            try {
                urlParams = "&" + toQueryParams(params.get("model"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            List<Map> urlList = JsonUtils.getResourceList(urlInfo);
            for (Map map : urlList) {
                if (map.get("type").equals(collect.get(0).getTaskType()) && map.get("pageType").equals("look")) {
                    urlParams = map.get("url").toString().replace("{roleIds}", "") + urlParams + "&taskStatus" + collect.get(0).getTaskStatus() + "&nextExecuteUserIds=";
                    break;
                }
            }
            collect.get(0).setRoutePath(urlParams);
            for (TaskV2Model taskV2Model : collect) {
                taskV2Model.setTaskStatusLabel((FlowStatusEnum.TO_BE_FINISHED.getName()));
                taskV2Model.setTaskStatus(FlowStatusEnum.TO_BE_FINISHED.getCode());
                taskV2Model.setFlowStatusLabel((FlowStatusEnum.TO_BE_FINISHED.getName()));
                taskV2Model.setFlowStatus(FlowStatusEnum.TO_BE_FINISHED.getCode());
            }
            Systemctl.taskV2Client.batchUpdate(collect);
        } else {
            collect.get(0).setRoutePath(collect.get(0).getRoutePath().replace("roleIds=", "roleIds=55555&fq="));
            Systemctl.taskV2Client.update(collect.get(0), collect.get(0).getSequenceNbr());
        }
        // 修改model并返回 用于组装新待办
        collect.get(0).setEndUserId(null);
        collect.get(0).setTaskStatus(null);
        collect.get(0).setEndDate(null);
        collect.get(0).setSequenceNbr(null);
        collect.get(0).setCreateDate(new Date());
        collect.get(0).setStartDate(new Date());
        return collect.get(0);
    }

    /**
     * 待办编辑接口       【如果没有代办直接返回空，业务判断】   ---- 在用，误删
     * 参数
     * taskStatus
     * taskStatusLabel 操作名称  1驳回 2通过 3重新提交
     * flowStatusLabel  任务状态枚举code
     * 流程实例id  instanceId
     * flowCode 任务id
     **/
    public TaskV2Model updateTaskModelNew(Map<String, Object> params) {
        String exeUserId = RequestContext.getExeUserId();
        List<TaskV2Model> result = Systemctl.taskV2Client.selectListByRelationId(params.get("relationId").toString()).getResult();

        // TaskV2Model model = result.stream().filter(e->e.getFlowCode().equals(params.get("flowCode").toString())).sorted((r1, r2) -> r2.getSequenceNbr().compareTo(r2.getSequenceNbr())) // 按时间降序排序
        //         .findFirst()
        //         .orElse(null);
        List<TaskV2Model> collect = result.stream().sorted((r1, r2) -> r2.getSequenceNbr().compareTo(r1.getSequenceNbr())).collect(Collectors.toList());
        if (null == collect || collect.size() == 0) {
            TaskV2Model model = new TaskV2Model();
            model.setFlowStatus(Integer.valueOf(params.get("flowStatus").toString()));
            model.setFlowStatusLabel(params.get("flowStatusLabel").toString());
            model.setTaskStatus(Integer.valueOf(params.get("taskStatus").toString()));
            model.setTaskStatusLabel(params.get("taskStatusLabel").toString());
            return model;
        }
        collect.get(0).setFlowStatus(Integer.valueOf(params.get("flowStatus").toString()));
        collect.get(0).setFlowStatusLabel(params.get("flowStatusLabel").toString());
        collect.get(0).setTaskStatus(Integer.valueOf(params.get("taskStatus").toString()));
        collect.get(0).setTaskStatusLabel(params.get("taskStatusLabel").toString());
        collect.get(0).setEndUserId(exeUserId);
        collect.get(0).setEndDate(new Date());
        // 当流程完成时将所有待办状态统一修改为已完成
        if (collect.get(0).getFlowStatusLabel().equals(FlowStatusEnum.TO_BE_FINISHED.getName())) {
            String urlParams = "";
            try {
                urlParams = "&" + toQueryParams(params.get("model"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            List<Map> urlList = JsonUtils.getResourceList(urlInfo);
            for (Map map : urlList) {
                if (map.get("type").equals(collect.get(0).getTaskType()) && map.get("pageType").equals("look")) {
                    urlParams = map.get("url").toString().replace("{roleIds}", "") + urlParams + "&nextExecuteUserIds=";
                    break;
                }
            }
            collect.get(0).setRoutePath(urlParams);
            for (TaskV2Model taskV2Model : collect) {
                taskV2Model.setTaskStatusLabel((FlowStatusEnum.TO_BE_FINISHED.getName()));
                taskV2Model.setTaskStatus(FlowStatusEnum.TO_BE_FINISHED.getCode());
                taskV2Model.setFlowStatusLabel((FlowStatusEnum.TO_BE_FINISHED.getName()));
                taskV2Model.setFlowStatus(FlowStatusEnum.TO_BE_FINISHED.getCode());
            }
            Systemctl.taskV2Client.batchUpdate(collect);
        } else {
            collect.get(0).setRoutePath(collect.get(0).getRoutePath().replace("roleIds=", "roleIds=55555&fq="));
            Systemctl.taskV2Client.update(collect.get(0), collect.get(0).getSequenceNbr());
        }
        collect.get(0).setEndUserId(null);
        collect.get(0).setTaskStatus(null);
        collect.get(0).setEndDate(null);
        collect.get(0).setSequenceNbr(null);
        collect.get(0).setCreateDate(new Date());
        collect.get(0).setStartDate(new Date());
        return collect.get(0);
    }

    /**
     * 待办 撤回
     *
     * @param id  工作流实例id
     * @param obj 自己的实体：taskType为BusinessTypeEnum code；nextExecuteUser
     */
    public void rollbackTask(String id, JSONObject obj) {

        List<TaskV2Model> result = Systemctl.taskV2Client.selectListByRelationId(id).getResult();
        List<TaskV2Model> list = result.stream().sorted((r1, r2) -> r2.getSequenceNbr().compareTo(r1.getSequenceNbr())).collect(Collectors.toList());
        TaskV2Model model = list.get(0);
        Systemctl.taskV2Client.delete(String.valueOf(model.getSequenceNbr()));

        String urlParams = "";
        urlParams = "&" + toQueryParams2(obj);
        List<Map> urlList = JsonUtils.getResourceList(urlInfo);

        if (list.size() > 1) {
            TaskV2Model lastTaskModel = list.get(1);
            lastTaskModel.setEndUserId(null);
            lastTaskModel.setEndDate(null);
            lastTaskModel.setTaskStatus(FlowStatusEnum.TO_SUBMITTED.getCode());
            lastTaskModel.setTaskStatusLabel("重新提交");
            lastTaskModel.setFlowCode(obj.get("nextTaskId").toString());
            if (obj.get("flowStatus") != null) {
                lastTaskModel.setFlowStatus(Integer.valueOf(obj.get("flowStatus").toString()));
            }
            if (obj.get("flowStatusLabel") != null) {
                lastTaskModel.setFlowStatusLabel(obj.get("flowStatusLabel").toString());
            }

            for (Map map : urlList) {
                if (map.get("type").equals(BusinessTypeEnum.JG_MAINTENANCE_RECORD.getCode()) && obj.getString("taskType").equals(BusinessTypeEnum.JG_MAINTENANCE_RECORD.getCode()) && map.get("pageType").equals("edit")) {
                    lastTaskModel.setRoutePath(map.get("url").toString().replace("{roleIds}", obj.getString("nextExecuteUser")) + urlParams);
                    break;
                } else if (map.get("type").equals(obj.get("taskType")) && map.get("pageType").equals(obj.getOrDefault("pageType", "edit"))) {
                    lastTaskModel.setRoutePath(map.get("url").toString().replace("{roleIds}", obj.get("nextExecuteUser").toString()) + urlParams);
                    break;
                }
            }
            Systemctl.taskV2Client.update(lastTaskModel, lastTaskModel.getSequenceNbr());
        } else if (list.size() == 1) {
            model.setExecuteUserIds(model.getStartUserId());
            model.setTaskStatusLabel("重新提交");
            model.setTaskStatus(FlowStatusEnum.TO_SUBMITTED.getCode());
            model.setSequenceNbr(null);
            if (obj.get("flowStatus") != null) {
                model.setFlowStatus(Integer.valueOf(obj.get("flowStatus").toString()));
            }
            if (obj.get("flowStatusLabel") != null) {
                model.setFlowStatusLabel(obj.get("flowStatusLabel").toString());
            }
            for (Map map : urlList) {
                if (map.get("type").equals(BusinessTypeEnum.JG_MAINTENANCE_RECORD.getCode()) && obj.getString("taskType").equals(BusinessTypeEnum.JG_MAINTENANCE_RECORD.getCode()) && map.get("pageType").equals("edit")) {
                    model.setRoutePath(map.get("url").toString().replace("{roleIds}", obj.getString("nextExecuteUser")) + urlParams);
                    break;
                } else if (map.get("type").equals(obj.get("taskType")) && map.get("pageType").equals("edit")) {
                    model.setRoutePath(map.get("url").toString().replace("{roleIds}", obj.get("nextExecuteUser").toString()) + urlParams);
                    break;
                }
            }
            Systemctl.taskV2Client.create(model);
        }
    }

    public <T> String toQueryParams(T obj) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();

        for (Class<?> clazz = obj.getClass(); !clazz.equals(Object.class); clazz = clazz.getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                if (!Modifier.isStatic(field.getModifiers())) {
                    field.setAccessible(true);

                    try {
                        Object value = field.get(obj);

                        if (value != null && !"".equals(value)) {
                            String encodedValue = URLEncoder.encode(value.toString(), "UTF-8");
                            sb.append(field.getName()).append('=').append(encodedValue).append('&');
                        }
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "";
    }

    /**
     * 根据流程状态name 获取流程状态code
     *
     * @param name 流程状态name
     * @return 流程状态code
     */
    public Integer getDictionaryCodeByName(String name) {
        List<DataDictionary> jggzzz = iDataDictionaryService.getByType("JGGZZZ");
        for (DataDictionary item : jggzzz) {
            if (item.getName().equals(name)) {
                return Integer.parseInt(item.getCode());
            }
        }
        return null;
    }

    /**
     * 根据工作流返回信息，组装业务需要的数据
     *
     * @param processTaskDTOS 工作流返回信息
     * @return 组装后的信息
     */
    public List<WorkflowResultDto> buildWorkFlowInfo(List<ProcessTaskDTO> processTaskDTOS) {
        List<WorkflowResultDto> workflowResultDtoList = new ArrayList<>();
        processTaskDTOS.forEach(item -> {
            WorkflowResultDto workflowResultDto = new WorkflowResultDto();
            if (!ObjectUtils.isEmpty(item.getProcessInstance())) {
                workflowResultDto.setInstanceId(item.getProcessInstance().getId());
            }
            if (!ObjectUtils.isEmpty(item.getTask())) {
                workflowResultDto.setTaskName(item.getTask().getName());
            }
            if (!ObjectUtils.isEmpty(item.getCandidateGroups())) {
                workflowResultDto.setExecutorRoleIds(String.join(",", item.getCandidateGroups()));
            }
            if (!ObjectUtils.isEmpty(item.getStartUser())) {
                workflowResultDto.setStartUserId(item.getStartUser().getUserId());
                workflowResultDto.setStartUserName(item.getStartUser().getRealName());
            }
            if (!ObjectUtils.isEmpty(item.getExecutor())) {
                workflowResultDto.setExecutorId(item.getExecutor().getUserId());
                workflowResultDto.setExecutorName(item.getExecutor().getRealName());
            }
            if (!CollectionUtils.isEmpty(item.getNextTask())) {
                ActTaskDTO actTaskDTO = item.getNextTask().get(0);
                workflowResultDto.setNextTaskId(actTaskDTO.getId());
                workflowResultDto.setNextTaskCode(actTaskDTO.getKey());
                workflowResultDto.setNextTaskName(actTaskDTO.getName());
                List<String> nextGroups = item.getNextCandidateGroups().get(actTaskDTO.getId());
                String join = String.join(",", nextGroups);
                workflowResultDto.setNextExecutorRoleIds(join);
                List<String> nextUserIds = item.getNextTaskExecutor().get(actTaskDTO.getId()).stream().map(AgencyUserModel::getUserId).collect(Collectors.toList());
                String nextUserIdsString = String.join(",", nextUserIds);
                workflowResultDto.setNextExecutorUserIds(nextUserIdsString);
            }
            workflowResultDtoList.add(workflowResultDto);
        });
        return workflowResultDtoList;
    }

    @Override
    public List<LinkedHashMap> getCompanyUser(Long companyId) {
        FeignClientResult result = privilegeFeginService.getCompanyUser(companyId);
        List<LinkedHashMap> list = (List<LinkedHashMap>) result.getResult();
        return list;
    }

    /**
     * 生成使用登记编号
     *
     * @param equipId                设备id
     * @param supervisoryCompanyCode 接收机构单位代码
     * @return 使用登记编号
     */
    public String generateRegistrationCode(String equipId, String supervisoryCode, String supervisoryCompanyCode) {
        // 根据设备id查询设备类别、品种
        LambdaQueryWrapper<RegistrationInfo> equipWrapper = new LambdaQueryWrapper<>();
        equipWrapper.eq(RegistrationInfo::getRecord, equipId);
        RegistrationInfo equipRegistrationInfo = tzsJgRegistrationInfoMapper.selectOne(equipWrapper);
        if (!ValidationUtil.isEmpty(equipRegistrationInfo)) {
            String equCategory = equipRegistrationInfo.getEquCategory(); // 设备类别 "3100"
            String equDefine = equipRegistrationInfo.getEquDefine(); // 设备品种 "3110"
            if (!ObjectUtils.isEmpty(equCategory)) {
                // 设备种类简称，如果是气瓶返回瓶
                String equCategoryAbbrName = CylinderTypeEnum.CYLINDER.getCode().equals(equCategory) ?
                        CylinderTypeEnum.CYLINDER.getName() :
                        EquipTypeEnum.getMessage(equCategory.substring(0, 1));

                // 设备代码中间两位
                String equipType2MidDigits;
                if (ValidationUtil.isEmpty(equDefine)) {
                    // 没有设备品种的设备取设备类别代码中间两位
                    equipType2MidDigits = equCategory.substring(1, 3);
                } else {
                    // 设备品种代码中间两位
                    equipType2MidDigits = equDefine.substring(1, 3);
                }
                // 登记机关代号
                String city = supervisoryCode.substring(0, 1);
                // 西咸新区监管码对应的设备使用登记证还按咸阳(D)生成
                if ("X".equals(city)) {
                    city = "D";
                }
                if (!ValidationUtil.isEmpty(supervisoryCompanyCode)) {
                    DataDictionary specialRegionCode = dataDictionaryService.getByCode(supervisoryCompanyCode, SPECIAL_REGION_CODE);
                    if (!ValidationUtil.isEmpty(specialRegionCode)) {
                        city = specialRegionCode.getName();
                    }
                }
                ResponseModel<String> stringResponseModel = tzsServiceFeignClient.useRegistrationCode(equCategoryAbbrName + equipType2MidDigits + "陕" + city);
                return stringResponseModel.getResult();
            }
        }
        return null;
    }

    /**
     * 检查实际状态是否不等于期望状态
     *
     * @param latestStatus 业务最新状态
     */
    public void checkExpectedStatus(String latestStatus) {
        String expectedStatus = String.valueOf(FlowStatusEnum.TO_BE_PROCESSED.getCode());
        // 检查实际状态是否不等于期望状态
        if (!expectedStatus.equals(latestStatus)) {
            throw new BadRequest("当前业务状态已更新，请返回工作台后重新打开！");
        }
    }

    @Override
    public void checkForExecuteFlow(String taskId, String instanceId) {
        InstanceRuntimeData instanceRuntimeData = getInstanceRuntimeData(instanceId);
        if (instanceRuntimeData == null) {
            throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
        }
        // 当前任务id与当前任务id不一致时，不让操作，解决老页面没关闭，但是流程已经被被人执行（通过、驳回、撤回），工作流未限制错误
        String currentTaskId = instanceRuntimeData.getNextTaskId();
        if (!taskId.equals(currentTaskId)) {
            throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
        }
        // 当前流程已经被转办给其他人或者页面按钮问题导致的权限未控制
        String nextExecuteUserIds = instanceRuntimeData.getNextExecuteUserIds();
        if (!nextExecuteUserIds.contains(RequestContext.getExeUserId())) {
            throw new BadRequest("当前登录人无执行权限！");
        }

    }

    private InstanceRuntimeData getInstanceRuntimeData(String instanceId) {
        RBucket<InstanceRuntimeData> rBucket = redissonClient.getBucket(CommonServiceImpl.buildJgInstanceDataKey(instanceId));
        return rBucket.get();
    }

    @Override
    public void saveExecuteFlowData2Redis(String instanceId, InstanceRuntimeData instanceData) {
        redissonClient.getBucket(CommonServiceImpl.buildJgInstanceDataKey(instanceId)).set(instanceData);
    }

    @Override
    public void checkForRevocationFlow(String taskId, String instanceId) {
        InstanceRuntimeData instanceRuntimeData = getInstanceRuntimeData(instanceId);
        if (instanceRuntimeData == null) {
            throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
        }
        // 前端页面上送任务id与当前任务id不一致时，不让操作，解决老页面没关闭，但是流程已经被被人执行（通过、驳回、撤回），工作流未限制错误
        String currentTaskId = instanceRuntimeData.getNextTaskId();
        if (!taskId.equals(currentTaskId)) {
            throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
        }
        if (!instanceRuntimeData.getPromoter().equals(RequestContext.getExeUserId())) {
            throw new BadRequest("无权限执行该任务");
        }
    }

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

    @Override
    public JSONObject queryHistoryData(Long currentDocumentId) {
        LambdaQueryWrapper<JgRegistrationHistory> lambda = new QueryWrapper<JgRegistrationHistory>().lambda();
        lambda.eq(JgRegistrationHistory::getCurrentDocumentId, currentDocumentId);
        JgRegistrationHistory jgRegistrationHistory = jgRegistrationHistoryService.getBaseMapper().selectOne(lambda);
        return jgRegistrationHistory != null ? JSONObject.parseObject(jgRegistrationHistory.getChangeData()) : null;
    }

    @Override
    public JSONArray queryHistoryDataObj(Long currentDocumentId) {
        LambdaQueryWrapper<JgRegistrationHistory> lambda = new QueryWrapper<JgRegistrationHistory>().lambda();
        lambda.eq(JgRegistrationHistory::getCurrentDocumentId, currentDocumentId);
        JgRegistrationHistory jgRegistrationHistory = jgRegistrationHistoryService.getBaseMapper().selectOne(lambda);
        if (jgRegistrationHistory != null) {
            String changeData = jgRegistrationHistory.getChangeData();
            try {
                // 尝试解析为JSONArray
                return JSON.parseArray(changeData);
            } catch (JSONException e) {
                // 解析失败，尝试将对象转换为JSONArray
                JSONObject jsonObject = JSON.parseObject(changeData);
                JSONArray jsonArray = new JSONArray();
                jsonArray.add(jsonObject);
                return jsonArray;
            }
        }
        return new JSONArray();
    }

    @Override
    public Integer countEquipInUseTimesForEdit(String record) {
        return commonMapper.countEquipInUseTimesForEdit(record);
    }

    @Override
    public Integer countEquipInUseTimesForDel(String record) {
        return commonMapper.countEquipInUseTimesForDel(record);
    }

    /**
     * string转化为jsonObject
     *
     * @param obj        jsonobject/map对象
     * @param jsonFields 要转化的字段数据
     */
    public void convertStringToJsonobject(Object obj, String[] jsonFields) {
        if (obj instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) obj;
            for (String field : jsonFields) {
                if (jsonObject.get(field) != null && jsonObject.get(field) instanceof String) {
                    jsonObject.put(field, JSON.parse(jsonObject.get(field).toString()));
                }
            }
        } else if (obj instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) obj;
            for (String field : jsonFields) {
                if (map.containsKey(field) && map.get(field) instanceof String) {
                    map.put(field, JSON.parse(map.get(field).toString()));
                }
            }
        } else {
            // 处理其他类型
            System.out.println("Unsupported Object Type");
        }
    }

    /**
     * 设备分类
     *
     * @param type 1，设备种类  2，设备类别  3，设备品种
     * @return
     */
    @Override
    public List<EquipmentCategory> equipmentClassification(String type) {
        List<EquipmentCategory> categoryList = equipmentCategoryMapper.selectList(new QueryWrapper<>());
        List<EquipmentCategory> result = Collections.emptyList();
        switch (type) {
            case "1":
                result = categoryList.stream().filter(category -> Pattern.compile("^[^\\D0]*000$").matcher(category.getCode()).matches()).collect(Collectors.toList());
                break;
            case "2":
                result = categoryList.stream().filter(category -> Pattern.compile("^[^\\D0]*00$").matcher(category.getCode()).matches()).collect(Collectors.toList());
                break;
            case "3":
                result = categoryList.stream().filter(category -> Pattern.compile("^[^\\D0]*0$").matcher(category.getCode()).matches()).collect(Collectors.toList());
                break;
        }
        return result;
    }


    /**
     * 排序  ：页面列表排序功能支持，将 "字段,ascend" 或 "字段,descend" 转化为对应JSONObject
     *
     * @param sort "字段,ascend" 或 "字段,descend"
     * @return JSONObject
     */
    public SortVo sortFieldConversion(String sort) {
        Optional<String> optionalSort = Optional.ofNullable(sort);
        Optional<SortVo> optionalSortMap = optionalSort.filter(s -> !s.isEmpty())
                .map(s -> {
                    String[] sortParts = s.split(",");
                    if (sortParts.length == 2) {
                        String field = sortParts[0];
                        String sortSituation = sortParts[1].contains("asc") ? "ASC" : "DESC";
                        return SortVo.builder()
                                .field(convertToUnderline(field))
                                .sortType(sortSituation)
                                .build();
                    }
                    return null;
                });
        return optionalSortMap.orElse(null);
    }

    @Override
    public void  fightUseFlagGenerate(UseFlagParamDto useFlagParamDto, HttpServletResponse response) {
        Objects.requireNonNull(useFlagParamDto, "参数不能为空");
        String printFileName = "套打使用登记标志.pdf";

        Map<String, Object> paramMap = Bean.BeantoMap(useFlagParamDto);

        setNextDate(useFlagParamDto, paramMap);
        setRegName(useFlagParamDto, paramMap);
        // 生成二维码,之前为设备监管码，调整为申请单号
        String qrCode = ImageUtils.generateQRCode(Optional.ofNullable(useFlagParamDto.getApplyNo()).orElse(""), 180, 180);
        paramMap.put("supervisoryCode", qrCode);

        this.fillParamValueToPdf(paramMap, response, selectPdfTemplate(useFlagParamDto.getEquListCode()), printFileName, 9.0f);
    }

    @Override
    public List<String> refreshTheDetailsDataOfCompletedUsageRegistration(String since) {
        return commonMapper.refreshTheDetailsDataOfCompletedUsageRegistration(since);
    }

    @Override
    public CompanyBo getOneCompany(String companyCode) {
        CompanyBo companyBo = commonMapper.queryCompanyInfoByCode(companyCode);
        return companyBo == null ? new CompanyBo() : companyBo;
    }

    @Override
    public Integer checkFactoryNumUniquenessForVehicleCylinder(String factoryNum, String sequenceNbr) {
        return commonMapper.checkFactoryNumUniquenessForVehicleCylinder(factoryNum, sequenceNbr);
    }

    /**
     * 根据设备列表代码选择对应的 PDF 模板
     *
     * @param equListCode 设备代码
     * @return model
     */
    private String selectPdfTemplate(String equListCode) {
        switch (equListCode) {
            case "3000":
                return "templates/use-flag-model-elevator.pdf";
            case "0000":
                return "templates/use-flag-model-vehicle.pdf";
            default:
                return "templates/use-flag-model-other.pdf";
        }
    }

    @Override
    public void updateUnitTypeCache(ReginParams reginParams, String unitType, String selectedRoleSeqs) {
        reginParams.getCompany().setCompanyType(unitType);
        redisUtils.set(getSelectedRoleRedisKey(), selectedRoleSeqs, redisRegionTimeSecond);
        redisUtils.set(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken()), JSONObject.toJSONString(reginParams), redisRegionTimeSecond);
    }
}