ludc
2024-02-29 8ef9e366be48dc5e8e52617ea8ed48b37a0e1f74
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmIOServiceImpl.java
@@ -3,7 +3,6 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.protobuf.ServiceException;
import com.vci.ubcs.code.applyjtcodeservice.feign.IMdmInterJtClient;
@@ -13,9 +12,8 @@
import com.vci.ubcs.code.bo.CodeTemplateAttrSqlBO;
import com.vci.ubcs.code.dto.*;
import com.vci.ubcs.code.entity.CodeAllCode;
import com.vci.ubcs.code.enumpack.CodeDefaultLC;
import com.vci.ubcs.code.enumpack.CodeLevelTypeEnum;
import com.vci.ubcs.code.enumpack.sysIntegrationPushTypeEnum;
import com.vci.ubcs.code.entity.CodeSynonym;
import com.vci.ubcs.code.enumpack.*;
import com.vci.ubcs.code.lifecycle.CodeAllCodeLC;
import com.vci.ubcs.code.mapper.CommonsMapper;
import com.vci.ubcs.code.service.*;
@@ -58,6 +56,7 @@
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Workbook;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
@@ -69,7 +68,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.ValidationEvent;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
@@ -86,7 +85,9 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static com.alibaba.druid.util.FnvHash.Constants.LIMIT;
@@ -97,7 +98,6 @@
@Service
@Slf4j
public class MdmIOServiceImpl implements MdmIOService {
   /**
    * 字段
@@ -143,7 +143,7 @@
    * 模板的服务
    */
   @Resource
   private CodeClstemplateServiceImpl templateService;
   private ICodeClstemplateService templateService;
   /**
    * 主数据引擎的服务
@@ -166,40 +166,57 @@
   private ICodeKeyAttrRepeatService keyRuleService;
   /**
    * 近义词规则查询服务
    */
   @Autowired ICodeSynonymService codeSynonymService;
   /**
    * 公式的服务
    */
   @Autowired
   private FormulaServiceImpl formulaService;
   /**
    * 规则的服务
    */
   @Autowired
   private ICodeRuleService ruleService;
   /**
    * 业务类型的服务
    */
   @Autowired
   private IBtmTypeClient btmTypeClient;
   /***
    * 申请集团编码服务
    */
   @Resource
   private IMdmInterJtClient mdmInterJtClient;
   /***
    * 密级服务
    */
   @Resource
   private IWebSecretClient secretService;
   /**
    * 日志保存工具类
    */
   @Autowired
   private SaveLogUtil saveLogUtil;
   /**
    * 客户现场excel为老版本,导出的总数限制为65535
    */
   public static final int EXPORT_LIMIT = 65535;
   /**
    * 自定义并发ForkJoinPool
    */
   private static final ForkJoinPool customForkJoinPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors()-1);
   /**
    * 批量申请:选取选中分类下的所有模板关键属性,相似属性,必填属性,写入execl中
@@ -380,7 +397,7 @@
      CodeClassifyVO codeClassifyVO = classifyService.getObjectByOid(codeClassifyOid);
      //获取码段宽度
      //String secWidth = getCodeSegmentWidth(codeClassifyVO.getOid());
      String secWidth = getCodeSegmentWidth(codeClassifyVO.getOid());
      if(isHistory){
         templateVOList= templateService.childTemplates(codeClassifyOid);
@@ -431,6 +448,8 @@
            excelDataList.add(new WriteExcelData(0,0,"分类路径",""));
            excelDataList.add(new WriteExcelData(0,1,"码段宽度",""));
            excelDataList.add(new WriteExcelData(0,2,!CollectionUtils.isEmpty(idAttrVOList)?idAttrVOList.get(0).getName():"企业编码",idAttrVOList.get(0).getId()));
            // 填充码段
            excelDataList.add(new WriteExcelData(1,1,secWidth));
         }
         for (int i = 0; i < templateAttrVOS.size(); i++) {
            CodeClassifyTemplateAttrVO attrVO = templateAttrVOS.get(i);
@@ -617,22 +636,121 @@
    * @return
    */
   private String getCodeSegmentWidth(String codeClassifyOid){
      CodeClassifyVO codeClassifyVO = classifyService.getObjectByOid(codeClassifyOid);
      CodeClassifyFullInfoBO classifyFullInfoBO = classifyService.getClassifyFullInfo(codeClassifyOid);
      // 要获取码段宽度,先要获取规则,当前没有往上找
      CodeRuleVO codeRuleByClassifyFullInfo = mdmEngineService.getCodeRuleByClassifyFullInfo(classifyService.getClassifyFullInfo(codeClassifyOid));
      List<CodeBasicSecVO> secVOList = codeRuleByClassifyFullInfo.getSecVOList();
      if(secVOList.isEmpty()){
         return "";
      }
      StringBuffer secWidth = new StringBuffer("");
      for (int j = 0; j < secVOList.size(); j++) {
         CodeBasicSecVO secVO = secVOList.get(j);
         int width = VciBaseUtil.getInt(secVO.getCodeSecLength()) + ((secVO.getPrefixCode() + secVO.getSuffixCode()).length());
         secWidth.append(width).append("#");
      }
      secVOList.stream().forEach(item->{
         switch (item.getSecType().toLowerCase(Locale.ROOT)){
            case "codeclassifysec":
            case "codevariablesec":
            case "coderefersec":
            case "codefixedsec":
            case "codeattrsec":
            case "codeserialsec":
               countSecWith(item,secWidth);
               break;
            case "codelevelsec":
               //层级码段,需要从分类上获取相应的信息
               String secValue = "";
               if (CodeLevelTypeEnum.MIN.getValue().equalsIgnoreCase(item.getCodeLevelType())) {
                  //最小层,因为我们只能在叶子节点上申请编码,所以这个就是当前分类的
                  if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(item.getCodeGetValueType()) || CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                     //就是当前分类的
                     secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                  } else {
                     //我们需要从顶层开始找到当前分类为止
                     secValue = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
                  }
               } else {
                  //指定层,我们需要通过上级的来获取
                  if (CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                     //说明当前已经是最高的了
                     secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                  } else {
                     //这个我们需要看看,层级是不是大于了最大层级的数
                     List<CodeClassifyVO> parentClassifyVOList = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).collect(Collectors.toList());
                     if (item.getCodeLevelValue() > (parentClassifyVOList.size() + 1)) {
                        //指定的层级比当前的层级还大了,所以只能获取当前层级了
                        if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(item.getCodeGetValueType())) {
                           secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                        } else {
                           secValue = parentClassifyVOList.stream().map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
                        }
                     } else {
                        //我们获取其中指定层的内容
                        if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(item.getCodeGetValueType())) {
                           CodeClassifyVO classifyVO = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() == item.getCodeLevelValue().intValue()).findFirst().orElseGet(() -> null);
                           if (classifyVO != null) {
                              secValue = classifyVO.getId();
                           }
                        } else {
                           //小于等于的全部拿出来
                           secValue = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() <= item.getCodeLevelValue().intValue()).sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining());
                        }
                     }
                  }
               }
               //看看长度是否需要截断
               if (!CodeCutTypeEnum.NONE.getValue().equalsIgnoreCase(item.getValueCutType()) &&
                  item.getValueCutLength() != null && item.getValueCutLength() > 0 && secValue.length() > item.getValueCutLength()) {
                  if (CodeCutTypeEnum.RIGHT.getValue().equalsIgnoreCase(item.getValueCutType())) {
                     //左截取是从左边剪掉,右截取是从右边剪掉--保留左边
                     secValue = secValue.substring(0, item.getValueCutLength());
                  } else {
                     secValue = secValue.substring(secValue.length() - item.getValueCutLength());
                  }
               }
               secValue = productCodeService.joinPreffixAndSuffix(item,secValue);
               secWidth.append(secValue.length()).append("#");
               break;
            case "codedatesec":
               String dateFormatStr = item.getCodeDateFormatStr();
               if(Func.isNotEmpty(dateFormatStr)) {
                  // 获取当前时间
                  Date currentDate = new Date();
                  // 指定日期格式
                  SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatStr);
                  // 将当前时间转换为指定日期格式
                  // 使用正则表达式去掉除数字以外的所有字符串
                  String cleanedDate = dateFormat.format(currentDate).replaceAll("[^0-9]", "");
                  int width = cleanedDate.length();
                  if (Func.isNotEmpty(item.getPrefixCode())) {
                     width += item.getPrefixCode().length();
                  }
                  if (Func.isNotEmpty(item.getSuffixCode())) {
                     width += item.getSuffixCode().length();
                  }
                  secWidth.append(width).append("#");
               }
               break;
         }
      });
      return secWidth.toString().substring(0, secWidth.length() - 1);
   }
   /**
    * 计算码段长度加前后缀的长度
    * @param codeBasicSecVO
    * @param secWidth
    */
   private void countSecWith(CodeBasicSecVO codeBasicSecVO,StringBuffer secWidth){
      if(Func.isNotEmpty(codeBasicSecVO.getCodeSecLength())){
         int width = VciBaseUtil.getInt(codeBasicSecVO.getCodeSecLength());
         if(Func.isNotEmpty(codeBasicSecVO.getPrefixCode())){
            width += codeBasicSecVO.getPrefixCode().length();
         }
         if(Func.isNotEmpty(codeBasicSecVO.getSuffixCode())){
            width += codeBasicSecVO.getSuffixCode().length();
         }
         secWidth.append(width).append("#");
      }else {
         secWidth.append(0).append("#");
      }
   }
   /**
@@ -771,7 +889,8 @@
         //除去默认的属性.还有只有表单显示的字段才导入
         List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
            !DEFAULT_ATTR_LIST.contains(s.getId()) &&
               ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
         ).collect(Collectors.toList());
         Map<String/**模板属性字段oid**/, String /**模板属性外部名称**/> fieldNameMap =attrVOS.stream().collect(Collectors.toMap(CodeClassifyTemplateAttrVO::getId,s->s.getName()));
@@ -820,7 +939,7 @@
         //2.判断必输项。。需要全部的属性,如果是必输,但是表单里面不显示的,只能是分类注入或者组合规则
         batchCheckRequiredAttrOnOrder(templateVO,allCboList,errorMap);
         //3.判断关键属性
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, allCboList,errorMap);
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, allCboList,false,errorMap);
         Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
         Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
         if(!CollectionUtils.isEmpty(selfRepeatRowIndexList)){
@@ -853,9 +972,7 @@
         //最后弄组合规则
         batchSwitchComponentAttrOnOrder(attrVOS,allCboList);
         Map<String, ClientBusinessObject> rowIndexCboMap = allCboList.stream().filter(cbo -> cbo != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getAttributeValue((IMPORT_ROW_INDEX)), t -> t));
         List<ClientBusinessObject> needSaveCboList = allCboList.stream().filter(cbo -> {
            String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
@@ -865,6 +982,7 @@
         Map<String,String>resembleMap=new HashMap<>();
         List<DataResembleVO> dataResembleVOS=new ArrayList<>();
         String btmtypeid= classifyFullInfo.getTopClassifyVO().getBtmTypeId();
         //相似项查询规则
         bathcResembleQuery(codeClassifyOid,templateVO,needSaveCboList,resembleMap,btmtypeid,dataResembleVOS);
         if(resembleMap.size()>0) {
            if(!CollectionUtils.isEmpty(dataResembleVOS)) {
@@ -1093,7 +1211,7 @@
            batchSwitchComponentAttrOnOrder(attrVOS, cboList);
            //3.判断关键属性
            CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,errorMap);
            CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,false,errorMap);
            Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
            Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
            if (!CollectionUtils.isEmpty(selfRepeatRowIndexList)) {
@@ -1174,6 +1292,7 @@
            Map<String, String> resembleMap = new HashMap<>();
            List<DataResembleVO> dataResembleVOS = new ArrayList<>();
            String btmtypeid = classifyFullInfo.getTopClassifyVO().getBtmTypeId();
            // 相似项查询
            bathcResembleQuery(templateVO.getCodeclassifyoid(), templateVO, needSaveCboList, resembleMap, btmtypeid, dataResembleVOS);
            if (resembleMap.size() > 0) {
               if (!CollectionUtils.isEmpty(dataResembleVOS)) {
@@ -1181,6 +1300,7 @@
                  createRedisDatas(uuid + "-resemble", templateVO, rowIndexCboMap, dataSet, fieldIndexMap, resembleMap, false);
               }
            }
            //生成class缓存
            Map<String, String> rowIndexClsOidMap = cboList.stream().filter(cbo -> cbo != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getAttributeValue((IMPORT_ROW_INDEX)), t -> t.getAttributeValue(CODE_CLASSIFY_OID_FIELD)));
            createRedisByCodeClassify(uuid + "-class",templateVO,dataSet,fieldIndexMap,true);
@@ -1206,6 +1326,7 @@
               //SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
               List<ClientBusinessObject> finalNeedSaveCboList = needSaveCboList;
               CodeClassifyTemplateVO finalTemplateVO = templateVO;
               final BladeUser user = AuthUtil.getUser();
               ruleRowIndexMap.keySet().parallelStream().forEach(ruleOid -> {
                  //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
                  List<String> rowIndexList = ruleRowIndexMap.get(ruleOid);
@@ -1222,7 +1343,7 @@
                  if (!CollectionUtils.isEmpty(thisCbos)) {
                     try {
                        // TODO 多线程流问题
                        productCodeService.productCodeAndSaveData(classifyFullInfo, finalTemplateVO, ruleVOMap.get(ruleOid), null, dataCBOList);
                        productCodeService.productCodeAndSaveData(classifyFullInfo, finalTemplateVO, ruleVOMap.get(ruleOid), null, dataCBOList,user);
                        importCount.add(dataCBOList.size());
                     } catch (Throwable e) {
                        log.error("批量产生编码的时候出错了", e);
@@ -1240,8 +1361,6 @@
               engineService.batchSaveSelectChar(templateVO, dataCBOIdList);
            }
         }
         //long end = System.currentTimeMillis();
         //log.info("=============for执行时间================="+String.valueOf((end-start)/1000));
         String excelFileName="";
         if(isExport&&!CollectionUtils.isEmpty(shetNameMap)) {
            excelFileName = LocalFileUtil.getDefaultTempFolder() + File.separator + "错误信息.xls";
@@ -1255,14 +1374,17 @@
               throw new VciBaseException(LangBaseUtil.getErrorMsg(e));
            }
            ExcelUtil.writeDataToFile(excelFileName, eo);
            saveLogUtil.operateLog("历史数据导入",true, StringUtil.format("错误信息:{}",JSON.toJSONString(shetNameMap)));
         }else{
            // 历史数据导入时出现了相似项返回结果时不算导入成功
            if(shetNameMap.isEmpty() || !isCreateUUid){
               saveLogUtil.operateLog("历史数据导入",false, StringUtil.format("导入到分类{}中,导入成功总数为:{}", JSON.toJSONString(classifyFullInfo), Func.isEmpty(importCount) ? 0:importCount.get(0)));
            }
         }
         CodeImProtRusultVO codeImProtRusultVO=new CodeImProtRusultVO();
         if(StringUtils.isNotBlank(excelFileName)) {
            codeImProtRusultVO.setFilePath(excelFileName);
            codeImProtRusultVO.setFileOid("");
            saveLogUtil.operateLog("历史数据导入",true, StringUtil.format("错误信息:{}",JSON.toJSONString(shetNameMap)));
         }else{
            saveLogUtil.operateLog("历史数据导入",false, StringUtil.format("导入到分类{}中,导入成功总数为:{}", JSON.toJSONString(classifyFullInfo),importCount.get(0)));
         }
         if(isCreateUUid){
            codeImProtRusultVO.setRedisUuid(uuid);
@@ -1582,7 +1704,8 @@
         //除去默认的属性.还有只有表单显示的字段才导入
         List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
            !DEFAULT_ATTR_LIST.contains(s.getId()) &&
               ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
         ).collect(Collectors.toList());
         Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap = new HashMap<>();
         List<String> titleRowData = dataSet.getColName();
@@ -1605,7 +1728,7 @@
         //2.判断必输项。。需要全部的属性,如果是必输,但是表单里面不显示的,只能是分类注入或者组合规则
         batchCheckRequiredAttrOnOrder(templateVO,cboList,errorMap);
         //3.判断关键属性
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,errorMap);
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO,cboList,false,errorMap);
         Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
         Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
         if(!CollectionUtils.isEmpty(selfRepeatRowIndexList)){
@@ -1650,6 +1773,7 @@
         Map<String,String>resembleMap=new HashMap<>();
         List<DataResembleVO> dataResembleVOS=new ArrayList<>();
         String btmtypeid= classifyFullInfo.getTopClassifyVO().getBtmTypeId();
         //相似项查询
         bathcResembleQuery(orderDTO.getCodeClassifyOid(),templateVO,needSaveCboList,resembleMap,btmtypeid,dataResembleVOS);
         if(resembleMap.size()>0) {
            isCreateUUid=true;
@@ -1674,7 +1798,7 @@
            createRedisDatas(uuid + "-ok",templateVO, rowIndexCboMap, dataSet, fieldIndexMap, newErrorMap,true);
         }else {
            uuid="";
            final BladeUser user = AuthUtil.getUser();
            //要把以上的错误的都抛出后,再继续处理时间和组合规则
            needSaveCboList = cboList.stream().filter(cbo -> {
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
@@ -1694,7 +1818,7 @@
                  dataCBOIdList.add(baseModel.getOid());
               });
               try {
                  codeList = productCodeService.productCodeAndSaveData(classifyFullInfo,templateVO,ruleVO, orderDTO.getSecDTOList(),dataCBOList);
                  codeList = productCodeService.productCodeAndSaveData(classifyFullInfo,templateVO,ruleVO, orderDTO.getSecDTOList(),dataCBOList,user);
                  //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
                  engineService.batchSaveSelectChar(templateVO, dataCBOList);
               } catch (Exception e) {
@@ -1827,24 +1951,27 @@
         tableName = VciBaseUtil.getTableName(btmTypeId);
      }
      String countSql = "select count(*) from (select * FROM " + tableName +" where 1=1" +
      String countSql = "select count(*) from " + tableName +" where 1=1" +
         " and lastr = '1'" +
         " and lastv='1'" +
         " and codeclsfpath like '%" + exportAttrDTO.getCodeClassifyOid() + "%' {}";
         " and codeclsfpath like '%" + exportAttrDTO.getCodeClassifyOid() + "%'";
      //先查询总数
      int total = 0;
      if(exportAttrDTO.getEndPage()!=null && exportAttrDTO.getEndPage()>0
         &&exportAttrDTO.getPage() !=null && exportAttrDTO.getPage() >0
         &&exportAttrDTO.getEndPage()>exportAttrDTO.getPage()){
         //从多少页到多少页的查询方式,
         String countPageSql = "select count(*) from (select * FROM " + tableName +" where 1=1" +
            " and lastr = '1'" +
            " and lastv='1'" +
            " and codeclsfpath like '%" + exportAttrDTO.getCodeClassifyOid() + "%' {}";
         for(int i = exportAttrDTO.getPage() ;i <= exportAttrDTO.getEndPage();i++){
            PageHelper thisPage = new PageHelper(exportAttrDTO.getLimit()==null?-1:exportAttrDTO.getLimit());
            thisPage.setPage(exportAttrDTO.getPage()==null?1:exportAttrDTO.getPage());
            thisPage.setSort(exportAttrDTO.getSort());
            thisPage.setOrder(exportAttrDTO.getOrder());
            thisPage.addDefaultDesc("createTime");
            total += commonsMapper.queryCountBySql(StringUtil.format(countSql," limit " + exportAttrDTO.getLimit() +" offset "+ i +")subquery;"));
            total += commonsMapper.queryCountBySql(StringUtil.format(countPageSql," limit " + exportAttrDTO.getLimit() +" offset "+ i +")subquery;"));
         }
      }else{
         total = commonsMapper.queryCountBySql(countSql);
@@ -2005,10 +2132,18 @@
      ExcelUtil.writeDataToFile(excelName, excelOption);
   }
   /**
    * 相似项查询出来之后再点击确认时调用的
    * @param codeImprotSaveDatVOList
    * @param classifyAttr
    * @param isImprot
    * @return
    */
   @Override
   public R batchImportData(List<CodeImprotSaveDatVO> codeImprotSaveDatVOList, String classifyAttr, boolean isImprot) {
      WriteExcelOption eo = new WriteExcelOption();
      AtomicBoolean success= new AtomicBoolean(true);
      AtomicReference<CodeClassifyTemplateVO> codeClassifyTemplateVO = new AtomicReference<>();
      codeImprotSaveDatVOList.stream().forEach(codeImprotSaveDatVO -> {
         List<SheetRowData> rowDataList = new ArrayList<>();
         List<ClientBusinessObject>cboList=new ArrayList<>();
@@ -2037,15 +2172,16 @@
         log.info("分类:"+classifyFullInfo.getCurrentClassifyVO().getName()+"数据:"+codeImprotSaveDatVO.getDataList().size());
         // CodeClassifyTemplateVO codeClassifyTemplateVO=   engineService.getUsedTemplateByClassifyOid(orderDTO.getCodeClassifyOid());
         CodeClassifyTemplateVO codeClassifyTemplateVO=  templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
         codeClassifyTemplateVO.set(templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid()));
         //规则的主键需要去获取
         CodeRuleVO ruleVO = engineService.getCodeRuleByClassifyFullInfo(classifyFullInfo);
         //除去默认的属性.还有只有表单显示的字段才导入
         List<CodeClassifyTemplateAttrVO> attrVOS = codeClassifyTemplateVO.getAttributes().stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
         List<CodeClassifyTemplateAttrVO> attrVOS = codeClassifyTemplateVO.get().getAttributes().stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId()) &&
               ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
         ).collect(Collectors.toList());
         String fullPath = getFullPath(classifyFullInfo);
         excelToCbo(classifyFullInfo,fieldIndexMap,rowDataList, codeClassifyTemplateVO,cboList,fullPath,!isImprot);
         excelToCbo(classifyFullInfo,fieldIndexMap,rowDataList, codeClassifyTemplateVO.get(),cboList,fullPath,!isImprot);
         Map<String,String> errorMap=new ConcurrentHashMap<>();
         Map<String/**路径**/, CodeClassifyVO> pathMap=new HashMap<>() ;
         //校验编码规则和码段是否正确
@@ -2091,7 +2227,7 @@
         //最后弄组合规则
         batchSwitchComponentAttrOnOrder(attrVOS,cboList);
         //3.判断关键属性
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, codeClassifyTemplateVO, cboList,errorMap);
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, codeClassifyTemplateVO.get(), cboList,false,errorMap);
         Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
         Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
         if(!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)){
@@ -2109,7 +2245,8 @@
            }).collect(Collectors.toList());
            List<ClientBusinessObject> finalNeedSaveCboList = needSaveCboList;
            Map<String, CodeRuleVO> finalRuleVOMap = ruleVOMap;
            // TODO: 多线程流套多线程流,有坑,我把这儿改了
            // TODO: 多线程流套多线程流,有坑,我把这儿改成单线程了
            final BladeUser user = AuthUtil.getUser();
            ruleRowIndexMap.keySet().stream().forEach(ruleOid -> {
               List <BaseModel>dataCBOList=new CopyOnWriteArrayList<>();
               List<String> rowIndexList = ruleRowIndexMap.get(ruleOid);
@@ -2121,7 +2258,7 @@
                     dataCBOList.add(baseModel);
                  });
                  try {
                     productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, finalRuleVOMap.get(ruleOid), null, dataCBOList);
                     productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO.get(), finalRuleVOMap.get(ruleOid), null, dataCBOList, user);
                  } catch (Throwable e) {
                     //success=false;
                     log.error("批量产生编码的时候出错了", e);
@@ -2131,9 +2268,10 @@
                     });
                  }
               }
               engineService.batchSaveSelectChar(codeClassifyTemplateVO, dataCBOList);
               engineService.batchSaveSelectChar(codeClassifyTemplateVO.get(), dataCBOList);
            });
         }else {
            final BladeUser user = AuthUtil.getUser();
            List<BaseModel> dataCBOList=new ArrayList<>();
            List<ClientBusinessObject> needSaveCboList = cboList.stream().filter(cbo -> {
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
@@ -2147,7 +2285,7 @@
                  dataCBOList.add(baseModel);
               });
               try {
                  productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList);
                  productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO.get(), ruleVO, orderDTO.getSecDTOList(), dataCBOList,user);
               } catch (Exception e) {
                  log.error("批量产生编码的时候出错了", e);
                  needSaveCboList.stream().forEach(cbo -> {
@@ -2156,7 +2294,7 @@
                  });
               }
               //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
               engineService.batchSaveSelectChar(codeClassifyTemplateVO, dataCBOList);
               engineService.batchSaveSelectChar(codeClassifyTemplateVO.get(), dataCBOList);
            }
         }
         if(errorMap.size()>0) {
@@ -2167,14 +2305,16 @@
            errorMap.forEach((key,v)->{
               excelDataList.add(new WriteExcelData(index[0]++, 0, "第"+(Integer.parseInt(key)+1)+"行数据:"+v));
            });
            eo.addSheetDataList(codeClassifyTemplateVO.getName() + "导入模板", excelDataList);
            eo.addSheetDataList(codeClassifyTemplateVO.get().getName() + "导入模板", excelDataList);
         }
      });
      if(!success.get()){
         String excelName = LocalFileUtil.getDefaultTempFolder() + File.separator + (isImprot?"批量历史错误信息.xls":"批量申请错误信息.xls");
         ExcelUtil.writeDataToFile(excelName,eo);
         return  R.fail(excelName);
         saveLogUtil.operateLog("历史数据导入",true, StringUtil.format("错误信息:{}",JSON.toJSONString(eo.getWriteDataMap())));
         return R.fail(excelName);
      }else {
         saveLogUtil.operateLog("历史数据导入",false, StringUtil.format("导入到分类{}中,导入成功总数为:{}", JSON.toJSONString(codeClassifyTemplateVO), Func.isEmpty(codeImprotSaveDatVOList.get(0).getDataList().size())));
         return R.success(isImprot ? "批量历史导入成功" : "批量申请成功");
      }
   }
@@ -2245,8 +2385,10 @@
      //校验模板是不是最新的
      //checkTemplateSync(sheetDataSetList,templateVO);
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->!DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      //除去默认的属性.还有只有具有分类注入的才过滤出来
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(
         s ->!DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) &&
            ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
      ).collect(Collectors.toList());
      Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap = new HashMap<>();
      List<String> titleRowData = dataObjectVO.getColName();
@@ -2298,7 +2440,7 @@
      //最后弄组合规则
      batchSwitchComponentAttrOnOrder(attrVOS,cboList);
      //3.判断关键属性
      CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,errorKeyMap);
      CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,false,errorKeyMap);
      Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
      Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
@@ -2393,10 +2535,10 @@
                  if (!CollectionUtils.isEmpty(newCboList)) {
                     //处理关键属性查出多条的话,根据集成调用的当前分类代号取当前分类的码值。
                     Map<String/**编码**/, BaseModel/**重复编码数据**/> classOidTOBaseModelMap = new HashMap<>();
                        newCboList.stream().forEach(baseModel->{
                           String codeclsfid=baseModel.getData().get(CODE_CLASSIFY_OID_FIELD.toUpperCase(Locale.ROOT));
                           classOidTOBaseModelMap.put(codeclsfid,baseModel);
                        });
                     newCboList.stream().forEach(baseModel->{
                        String codeclsfid=baseModel.getData().get(CODE_CLASSIFY_OID_FIELD.toLowerCase(Locale.ROOT));
                        classOidTOBaseModelMap.put(codeclsfid,baseModel);
                     });
                     String codeclsfid= classifyFullInfo.getCurrentClassifyVO().getOid();
                     if(classOidTOBaseModelMap.containsKey(codeclsfid)){
                        BaseModel newCbo= classOidTOBaseModelMap.get(codeclsfid);
@@ -2433,7 +2575,7 @@
                  }
               }
            });
            //关键熟悉更改
            //关键属性更改
            if (!CollectionUtils.isEmpty(editBoList)) {
               engineService.updateBatchByBaseModel(classifyFullInfo.getTopClassifyVO().getBtmTypeId(),editBoList);//保存数据
            }
@@ -2455,6 +2597,7 @@
         List<String>allNeedSaveCboList=new ArrayList<>();
         List<BaseModel> dataCBOList=new ArrayList<>();
         final BladeUser user = AuthUtil.getUser();
         needSaveCboList.stream().forEach(clientBusinessObject -> {
            BaseModel baseModel=new BaseModel();
            BeanUtil.convert(clientBusinessObject,baseModel);
@@ -2464,7 +2607,7 @@
         });
         try {
            List<String>applyGroupCodeIdList=new ArrayList<>();
            productCodeService.productCodeAndSaveData(classifyFullInfo, templateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList);
            productCodeService.productCodeAndSaveData(classifyFullInfo, templateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList,user);
            //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
            engineService.batchSaveSelectChar(templateVO, dataCBOList);
            // if(!isProcess){
@@ -2615,7 +2758,8 @@
      //校验模板是不是最新的
      //checkTemplateSync(sheetDataSetList,templateVO);
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s -> !DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s -> !DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) &&
         ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
      ).collect(Collectors.toList());
      Map<Integer/**列号**/, String/**字段的名称**/> fieldIndexMap = new HashMap<>();
      List<String> titleRowData = dataObjectVO.getColName();
@@ -2625,7 +2769,7 @@
      //cboOidMap.put("id", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(codeDataMap.keySet().toArray(new String[0])) + ")");
      String tableName ="";
      try {
         R<BtmTypeVO> r = btmTypeClient.getAllAttributeByBtmId(templateVO.getBtmTypeId());
         R<BtmTypeVO> r = btmTypeClient.getAllAttributeByBtmId(classifyFullInfo.getTopClassifyVO().getBtmTypeId());
         if(!r.isSuccess()) {
            throw new Throwable(r.getMsg());
         }
@@ -2667,6 +2811,7 @@
      }
      List<Map<String,String>> dataMapList=commonsMapper.queryByOnlySqlForMap(sb.toString());
      DefaultAttrAssimtUtil.mapToLowerCase(dataMapList,true);
      List<ClientBusinessObject> cboList=   ChangeMapTOClientBusinessObjects(dataMapList);
      Map<String, ClientBusinessObject> codeSystemObjectMap = cboList.stream().filter(systeDataObject -> systeDataObject != null && StringUtils.isNotBlank(systeDataObject.getId())).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getId(), t -> t));
      Map<String, String> errorMap = new HashMap<>();
@@ -2722,7 +2867,17 @@
            cbo.setDescription(StringUtils.isBlank(orderDTO.getDescription())?"":orderDTO.getDescription());
            cbo.setName(orderDTO.getName());
            try {
               cbo.setAttributeValueWithNoCheck("description", orderDTO.getDescription());
               //主要处理大小写问题,将data里面的数据的key都转为小写
               HashMap<String,String> lowerData = new HashMap<>();
               Iterator<Map.Entry<String, String>> iterator = cbo.getData().entrySet().iterator();
               while (iterator.hasNext()){
                  Map.Entry<String, String> next = iterator.next();
                  lowerData.put(next.getKey().toLowerCase(Locale.ROOT),next.getValue());
               }
               cbo.getData().clear();
               cbo.getData().putAll(lowerData);
               cbo.setAttributeValueWithNoCheck("description", (StringUtil.isNotBlank(orderDTO.getData()
                  .get("description")) ? orderDTO.getData().get("description") : orderDTO.getDescription() ));
            //   cbo.setAttributeValue("name", orderDTO.getName());
               //  if(finalIsProcess){//在流程中不允许更改
               //     errorMap.put(code,errorMap.getOrDefault(code, errorMap.getOrDefault(code,"")+";数据"+code+"在流程中,不允许更改!"));
@@ -2785,7 +2940,7 @@
               List<CodeAllCode>newCodeAllCodeList= codeAllCodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCreateCodeOid, cbo.getOid()));
               if (!CollectionUtils.isEmpty(newCodeAllCodeList)) {
                  CodeAllCode codeCbo = codeAllCodeList.get(0);
                  CodeAllCode codeCbo = newCodeAllCodeList.get(0);
                  log.info("codeCbos code:" + codeCbo.getId());
                  codeCbo.setLcStatus(status);
                  codeAllCodeList.add(codeCbo);
@@ -2823,7 +2978,7 @@
            engineService.updateBatchByBaseModel(classifyFullInfo.getTopClassifyVO().getBtmTypeId(),updateList);
            codeAllCodeService.saveOrUpdateBatch(codeAllCodeList);
            if(deleteList.size()>0) {
               commonsMapper.deleteByTaleAndOid(tableName, VciBaseUtil.array2String(deleteList.toArray(new String[]{})));
               commonsMapper.deleteByTaleAndOid(tableName, VciBaseUtil.toInSql(deleteList.toArray(new String[]{})));
            }
            //是否调用集团接口申请接口
            if(isCodeOrGroupCode){
@@ -2943,18 +3098,27 @@
      //注意的是keyRuleVO可能为空,表示不使用规则控制
      //获取所有的关键属性
      Map<String, CodeClassifyTemplateAttrVO> ketAttrMap = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getKeyAttrFlag())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      // TODO:2024-02-01 先获取配置了近义词查询规则的属性,不同于关键属性,设置了近义词查询规则的属性可能是多条不同的近义词查询规则
      Map<String, CodeClassifyTemplateAttrVO> sysonymAttrMaps = templateVO.getAttributes().stream().filter(item -> Func.isNotBlank(item.getSysonymRuleOids())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      // 获取是否有配置近义词查询规则属性
      Map<String, List<CodeSynonym>> codeSynonymMaps = new HashMap<>();
      if(!sysonymAttrMaps.isEmpty()){
         // 查询近义词规则,存储方式key:属性id,value近义词查询规则列表
         codeSynonymMaps = codeSynonymService.getCodeSynonymByOids(sysonymAttrMaps);
      }
      Map<String, String> conditionMap = new HashMap<>();
      boolean trimAll = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnoreallspaceflag());
      //全部去空的优先级大于去空
      boolean trim = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorespaceflag());
      boolean ignoreCase = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorecaseflag());
      boolean ignoreWidth = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorewidthflag());
      Map<String, List<CodeSynonym>> finalCodeSynonymMaps = codeSynonymMaps;
      ketAttrMap.forEach((attrId, attrVO) -> {
         String value = getValueFromOrderDTO(orderDTO, attrId);
         if (value == null) {
            value = "";
         }
         engineService.wrapperKeyAttrConditionMap(value, keyRuleVO, attrId, trim, ignoreCase, ignoreWidth, trimAll, conditionMap);
         engineService.wrapperKeyAttrConditionMap(value, keyRuleVO, finalCodeSynonymMaps.get(attrId), attrId, trim, ignoreCase, ignoreWidth, trimAll, conditionMap);
      });
      //没有限制分类,但是一个模板只可能在一个业务类型里面,所以直接查询这个业务类型即可
@@ -3337,7 +3501,7 @@
         String oid=rowData.getOid();
         String rowNumber=rowData.getRowIndex();
         ClientBusinessObject cbo = new ClientBusinessObject();
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId(),null);
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId());
         rowData.getData().forEach((index,value)->{
            String field = fieldIndexMap.get(index);
            if(StringUtils.isBlank(field)){
@@ -3443,7 +3607,7 @@
      String fullPath = getFullPath(classifyFullInfo);
      codeImprotDataVO.getDatas().stream().forEach(rowData -> {
         ClientBusinessObject cbo=new ClientBusinessObject();
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId(),null);
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId());
         rowData.forEach((field,value)->{
            try {
               cbo.setAttributeValueWithNoCheck(field,value);
@@ -3497,7 +3661,12 @@
                     String fullPath,boolean newCode){
      rowDataList.stream().forEach(rowData -> {
         ClientBusinessObject cbo=new ClientBusinessObject();
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId(),null);
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId());
         R<List<BtmTypeVO>> listR = btmTypeClient.selectByIdCollection(Collections.singletonList(classifyFullInfo.getTopClassifyVO().getBtmTypeId()));
         if(!listR.isSuccess() || listR.getData().size() == 0){
            throw new VciBaseException("传入业务类型未查询到相应表单,请检查!");
         }
         cbo.setRevisionRule("".equals(listR.getData().get(0).getVersionRule())?"1":listR.getData().get(0).getVersionRule());
         rowData.getData().forEach((index,value)->{
               String field = fieldIndexMap.get(index);
            if (StringUtils.isBlank(field)) {
@@ -3844,7 +4013,8 @@
                  String sql = "select " + valueField + "," + showText.toLowerCase(Locale.ROOT) +" from " + table + "  where " + showText + " in (%s)";
                  valueCollections.stream().forEach(values->{
                     List<Map<String,String>> dataMapList = commonsMapper.queryByOnlySqlForMap(String.format(sql, VciBaseUtil.toInSql(values.toArray(new String[0]))));
                     List<ClientBusinessObject> cbos=   ChangeMapTOClientBusinessObjects(dataMapList);
                     DefaultAttrAssimtUtil.mapToLowerCase(dataMapList,true);
                     List<ClientBusinessObject> cbos=ChangeMapTOClientBusinessObjects(dataMapList);
                     if(!CollectionUtils.isEmpty(cbos)){
                        valueOidTextMap.putAll(cbos.stream().collect(Collectors.toMap(s->s.getAttributeValue(valueField),t->t.getAttributeValue(showText))));
                     }
@@ -4213,7 +4383,7 @@
                  } else {
                     Map<String, String> classifyDataMap = VciBaseUtil.objectToMapString(classifyVO);
                     String value = classifyDataMap.getOrDefault(attrVO.getClassifyInvokeAttr(), "");
                     log.error("================================当前分类注入的value值为:==========================",value);
//                     log.error("================================当前分类注入的value值为:==========================",value);
                     cbo.setAttributeValue(attrId, value);
                  }
               } catch (Throwable e) {
@@ -4224,19 +4394,28 @@
      }
   }
   /**
    * 校验关键属性
    * 校验关键属性,和近义词查询规则
    * @param classifyFullInfo 分类的全部信息
    * @param templateVO 模板的内容,必须包含模板属性
    * @param cboList 批量的数据
    */
   private CodeImportResultVO batchCheckKeyAttrOnOrder(CodeClassifyFullInfoBO classifyFullInfo, CodeClassifyTemplateVO templateVO,
                                          List<ClientBusinessObject> cboList,Map<String,String> errorMap) {
                                          List<ClientBusinessObject> cboList,boolean isEdit,Map<String,String> errorMap) {
      //与MdmEngineServiceImpl里的checkKeyAttrOnOrder相似
      //先获取关键属性的规则,也利用继承的方式
      CodeKeyAttrRepeatVO keyRuleVO = keyRuleService.getRuleByClassifyFullInfo(classifyFullInfo);
      //注意的是keyRuleVO可能为空,表示不使用规则控制
      //获取所有的关键属性
      Map<String/**属性的编号**/, CodeClassifyTemplateAttrVO> ketAttrMap = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getKeyAttrFlag())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      Map<String/**属性的编号**/, CodeClassifyTemplateAttrVO> keyAttrMap = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getKeyAttrFlag())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      // TODO:2024-02-01 先获取配置了近义词查询规则的属性,不同于关键属性,设置了近义词查询规则的属性可能是多条不同的近义词查询规则
      Map<String, CodeClassifyTemplateAttrVO> sysonymAttrMaps = templateVO.getAttributes().stream().filter(item -> Func.isNotBlank(item.getSysonymRuleOids())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      // 获取是否有配置近义词查询规则属性
      Map<String, List<CodeSynonym>> codeSynonymMaps = new HashMap<>();
      if(!sysonymAttrMaps.isEmpty()){
         // 查询近义词规则,存储方式key:属性id,value近义词查询规则列表
         codeSynonymMaps = codeSynonymService.getCodeSynonymByOids(sysonymAttrMaps);
      }
      boolean trimAll =keyRuleVO ==null?false: VciBaseUtil.getBoolean(keyRuleVO.getIgnoreallspaceflag());
      //全部去空的优先级大于去空
@@ -4248,60 +4427,80 @@
      CodeImportResultVO resultVO = new CodeImportResultVO();
      resultVO.setKeyAttrRuleInfo(String.format(keyRuleVO ==null?"":"查询规则:去除空格--{0},忽略大小写--{1},忽略全半角--{2},忽略全部空格--{3}",
         new String[]{trim?"是":"否",ignoreCase?"是":"否",ignoreWidth?"是":"否",trimAll?"是":"否"}));
      //resultVO.setSelfRepeatRowIndexList(getSelfRepeatRowIndex(ketAttrMap,cboList,keyRuleVO));
      getSelfRepeatRowIndex(ketAttrMap,cboList,keyRuleVO,resultVO);
      //resultVO.setSelfRepeatRowIndexList(getSelfRepeatRowIndex(keyAttrMap,cboList,keyRuleVO));
      // 先在表格中查询关键属性和近义词转换后重复的列
      getSelfRepeatRowIndex(keyAttrMap,cboList,keyRuleVO,codeSynonymMaps,resultVO);
      // 再在表格中查询近义词查询规则的列
      //getSelfRepeatSysnomRowIndex(sysonymAttrMaps,cboList,codeSynonymMaps,resultVO);
      if(!CollectionUtils.isEmpty(resultVO.getSelfRepeatRowIndexList())){
         //我们移除本身重复的数据
         cboList = cboList.stream().filter(s->!resultVO.getSelfRepeatRowIndexList().contains(s.getAttributeValue(IMPORT_ROW_INDEX))).collect(Collectors.toList());
      }
      //2.判断关键属性在系统里是否重复
      //因为数据量很大,所以得想办法并行
      //SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
      Map<String,List<BaseModel>> indexTODataMap=new ConcurrentHashMap<>();
      // 查询不需要参与关键属性校验的除自己以外的所有分类oid
      final String isParticipateCheckOids = classifyService.selectLeafByParentClassifyOid(classifyFullInfo.getTopClassifyVO().getOid(), classifyFullInfo.getCurrentClassifyVO().getOid());
      final HttpServletRequest request = org.springblade.core.tool.utils.WebUtil.getRequest();
      List<ClientBusinessObject> repeatDataMap = cboList.parallelStream().filter(cbo -> {
         //每行都得查询.如果其中出现了错误,我们就直接抛出异常,其余的显示
         //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
         Map<String, String> conditionMap = new HashMap<>();
         ketAttrMap.forEach((attrId, attrVO) -> {
            String value =cbo.getAttributeValue(attrId.toLowerCase(Locale.ROOT));
            if (value == null) {
               value = "";
            }
            value= value.replace(REQUIRED_CHAR,SPECIAL_CHAR);
            engineService.wrapperKeyAttrConditionMap(value, keyRuleVO, attrId, trim, ignoreCase, ignoreWidth, trimAll, conditionMap);
         });
         if (!CollectionUtils.isEmpty(ketAttrMap)) {
            // 添加不参与关键属性校验的分类oid判断
            if(Func.isNotBlank(isParticipateCheckOids)){
               conditionMap.put("t.codeclsfid",QueryOptionConstant.NOTIN+isParticipateCheckOids);
            }
            CodeTemplateAttrSqlBO sqlBO = engineService.getSqlByTemplateVO(classifyFullInfo.getTopClassifyVO().getBtmTypeId(), templateVO, conditionMap, null);
            List<String> repeatData = commonsMapper.selectList(sqlBO.getSqlId());
            if(!repeatData.isEmpty()){
               final List<Map<String,String>> newDataList = commonsMapper.queryByOnlySqlForMap(sqlBO.getSqlUnPage());
               //List<ClientBusinessObject> newCboList=ChangeMapTOClientBusinessObjects(newDataList);
               List<BaseModel> newCboList = new ArrayList<>();
               newDataList.stream().forEach(stringStringMap -> {
                  BaseModel baseModel=new BaseModel();
                  DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(stringStringMap,baseModel,request);
                  baseModel.setData(stringStringMap);
                  newCboList.add(baseModel);
               });
               // 添加错误值
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
               errorMap.put(rowIndex, "重复的记录编号为:"+repeatData.stream().collect(Collectors.joining(",")));
               if(!CollectionUtils.isEmpty(newCboList)) {
                  indexTODataMap.put(cbo.getAttributeValue(IMPORT_ROW_INDEX), newCboList);
      final BladeUser user = AuthUtil.getUser();
      // TODO:Thread limit exceeded replacing blocked 异常是这部分代码抛出的
      //  ,所以暂时将parallelStream改成了stream,改成了stream之后发现巨慢
      // customForkJoinPool控制并发度
      List<ClientBusinessObject> finalCboList = cboList;
      Map<String, List<CodeSynonym>> finalCodeSynonymMaps = codeSynonymMaps;
      List<ClientBusinessObject> repeatDataMap = (List<ClientBusinessObject>) customForkJoinPool.submit(()->{
         finalCboList.parallelStream().filter(cbo -> {
            //每行都得查询.如果其中出现了错误,我们就直接抛出异常,其余的显示
            //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
            Map<String, String> conditionMap = new HashMap<>();
            keyAttrMap.forEach((attrId, attrVO) -> {
               String value =cbo.getAttributeValue(attrId.toLowerCase(Locale.ROOT));
               if (value == null) {
                  value = "";
               }
               value= value.replace(REQUIRED_CHAR,SPECIAL_CHAR);
               // 关键属性查询条件map获取
               engineService.wrapperKeyAttrConditionMap(value, keyRuleVO, finalCodeSynonymMaps.get(attrId), attrId, trim, ignoreCase, ignoreWidth, trimAll, conditionMap);
            });
            if (!CollectionUtils.isEmpty(keyAttrMap)) {
               // 添加不参与关键属性校验的分类oid判断
               if(Func.isNotBlank(isParticipateCheckOids)){
                  conditionMap.put("t.codeclsfid",QueryOptionConstant.NOTIN+isParticipateCheckOids);
               }
               //如果是更改则需排除系统本身
               if(isEdit){
                  conditionMap.put("t.id",QueryOptionConstant.NOTEQUAL+cbo.getId());
               }
               conditionMap.put("t.lastr", "1");
               conditionMap.put("t.lastv", "1");
               CodeTemplateAttrSqlBO sqlBO = engineService.getSqlByTemplateVO(classifyFullInfo.getTopClassifyVO().getBtmTypeId(), templateVO, conditionMap, null);
               List<String> repeatData = commonsMapper.selectList(sqlBO.getSqlId());
               if(!repeatData.isEmpty()){
                  final List<Map<String,String>> newDataList = commonsMapper.queryByOnlySqlForMap(sqlBO.getSqlUnPage());
                  DefaultAttrAssimtUtil.mapToLowerCase(newDataList,true);
                  //List<ClientBusinessObject> newCboList=ChangeMapTOClientBusinessObjects(newDataList);
                  List<BaseModel> newCboList = new ArrayList<>();
                  newDataList.stream().forEach(stringStringMap -> {
                     BaseModel baseModel=new BaseModel();
                     DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(stringStringMap,baseModel,false,user);
                     baseModel.setData(stringStringMap);
                     newCboList.add(baseModel);
                  });
                  // 添加错误值
                  String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                  errorMap.put(rowIndex, "重复的记录编号为:"+repeatData.stream().collect(Collectors.joining(",")));
                  if(!CollectionUtils.isEmpty(newCboList)) {
                     indexTODataMap.put(cbo.getAttributeValue(IMPORT_ROW_INDEX), newCboList);
                  }
               }
               return !repeatData.isEmpty();
            }else{
               return false;
            }
            return !repeatData.isEmpty();
         }else{
            return false;
         }
      }).collect(Collectors.toList());
         }).collect(Collectors.toList());
      }).join();
      if(!CollectionUtils.isEmpty(repeatDataMap)){
         resultVO.setKeyAttrRepeatRowIndexList(repeatDataMap.stream().map(s->s.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toSet()));
      }
@@ -4415,14 +4614,14 @@
   }
   /**
    * 获取导入的内容中关键属性重复的行号
    * 获取导入的内容中关键属性近义词转换后重复的行号
    * @param ketAttrMap 关键属性的映射
    * @param dataList 导入的数据
    * @param keyRuleVO 关键属性控制规则
    * @return 重复的行号
    */
   private void getSelfRepeatRowIndex(Map<String/**属性的编号**/, CodeClassifyTemplateAttrVO> ketAttrMap,
                              List<ClientBusinessObject> dataList,CodeKeyAttrRepeatVO keyRuleVO,CodeImportResultVO resultVO){
                              List<ClientBusinessObject> dataList,CodeKeyAttrRepeatVO keyRuleVO,/*近义词查询规则*/Map<String,List<CodeSynonym>> codeSynonymMaps, CodeImportResultVO resultVO){
      Set<String> selfRepeatRowIndexList = new CopyOnWriteArraySet<>();
      Map<String,List<String>> keyAttrOkOidTORepeatOidMap=new HashMap<>();
      boolean trimAll =keyRuleVO ==null?false: VciBaseUtil.getBoolean(keyRuleVO.getIgnoreallspaceflag());
@@ -4438,9 +4637,10 @@
         String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
         String oid=cbo.getOid();
         StringBuilder sb = new StringBuilder();
         for (int i = 0; i < attrVOList.size(); i++) {
            CodeClassifyTemplateAttrVO attrVO = attrVOList.get(i);
            String attrId = attrVO.getId().toLowerCase(Locale.ROOT);
         // TODO: 2024-02-25改造实现近义词查询规则功能;关键属性重复校验值处理
         attrVOList.stream().forEach(item->{
            String attrId = item.getId().toLowerCase(Locale.ROOT);
            String value = cbo.getAttributeValue( attrId);
            if (value == null) {
               value = "";
@@ -4457,8 +4657,9 @@
            if(ignoreWidth){
               value = VciBaseUtil.toDBC(value);
            }
            value = mdmEngineService.getValueToSynony(codeSynonymMaps.get(attrId),value);
            sb.append(value).append("${ks}");
         }
         });
         String keyString = sb.toString();
         if(rowIndexKeyStringMap.containsValue(keyString) && StringUtils.isNotBlank(keyString)){
            selfRepeatRowIndexList.add(rowIndex);
@@ -4469,7 +4670,6 @@
               if(keyAttrOkOidTORepeatOidMap.containsKey(okOid)){
                  List<String> oldOidList = keyAttrOkOidTORepeatOidMap.get(okOid);
                  newOidList.addAll(oldOidList);
               }
               keyAttrOkOidTORepeatOidMap.put(okOid,newOidList);
            }
@@ -4508,11 +4708,14 @@
         }
      }
   }
   private List<ClientBusinessObject> ChangeMapTOClientBusinessObjects(List<Map<String,String>> oldDataMap){
      List<ClientBusinessObject> clientBusinessObjectList=new ArrayList<>();
      DefaultAttrAssimtUtil.mapToLowerCase(oldDataMap,true);
      final BladeUser user = AuthUtil.getUser();
      oldDataMap.stream().forEach(dataMap->{
         ClientBusinessObject clientBusinessObject=new ClientBusinessObject();
         DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(dataMap,clientBusinessObject,null);
         DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(dataMap,clientBusinessObject,false,user);
         for (String key:dataMap.keySet()){
            Object value= dataMap.getOrDefault(key,"");
            clientBusinessObject.setAttributeValue(key.toLowerCase(Locale.ROOT),value==null?"":value.toString());
@@ -4607,7 +4810,8 @@
   private void createExeclClassData(List<String> titleRowData, CodeClassifyTemplateVO newTemplateVO, Map<Integer, String> execlData, CodeImprotDataVO codeImprotDataVO){
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = newTemplateVO.getAttributes().stream().filter(s ->
         !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
         !DEFAULT_ATTR_LIST.contains(s.getId()) &&
            ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
      ).collect(Collectors.toList());
      Map<String/**中文名称**/, String/**英文名称**/> attrNameIdMap = attrVOS.stream().collect(Collectors.toMap(s -> s.getName(), t -> t.getId()));
      List<String> fields=new ArrayList<>();
@@ -4802,6 +5006,7 @@
               pageHelper.addDefaultDesc("id");
               CodeTemplateAttrSqlBO sqlBO = engineService.getSqlByTemplateVO(btmtypeid, templateVO, conditionMap, pageHelper);
               List<Map<String,String>> dataMapList=commonsMapper.queryByOnlySqlForMap(sqlBO.getSqlUnPage());
               DefaultAttrAssimtUtil.mapToLowerCase(dataMapList,true);
               List<ClientBusinessObject> resembleCboList=   ChangeMapTOClientBusinessObjects(dataMapList);
               if(!CollectionUtils.isEmpty(resembleCboList)) {
                  List<Map<String, String>> finalDataMap = dataMap;
@@ -4964,7 +5169,7 @@
    * @return
    */
   @Override
   public String exportGroupCodeExcel(String codeClassifyOid) throws ServiceException {
   public String exportGroupCodeExcel(String codeClassifyOid) throws VciBaseException {
      VciBaseUtil.alertNotNull(codeClassifyOid,"主题库分类的主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      CodeClassifyVO codeClassifyVO= classifyFullInfo.getCurrentClassifyVO();
@@ -4975,8 +5180,8 @@
      ExecGroupCodePortDataDTO execGroupCodePortDataDTO=new ExecGroupCodePortDataDTO();
      createExportGroupCodeMapConfig(templateVO,execGroupCodePortDataDTO);//组织数据
      if(!CollectionUtils.isEmpty(execGroupCodePortDataDTO.getCodeAttrMapGroupAttrDTOS())){
         throw new ServiceException("集团属性映射未配置");
      if(CollectionUtils.isEmpty(execGroupCodePortDataDTO.getCodeAttrMapGroupAttrDTOS())){
         throw new VciBaseException("集团属性映射未配置");
      }
      fieldList=execGroupCodePortDataDTO.getFieldList();
      List<Map<String,String>>dataList=new ArrayList<>();
@@ -4996,9 +5201,7 @@
      List<WriteExcelData> excelDataList = new ArrayList<>();
      Workbook workbook = new HSSFWorkbook();
      List<CodeAndGroupCodeAttrMappingDTO>  codeAndGroupCodeAttrMappingDTOList=   execGroupCodePortDataDTO.getCodeAttrMapGroupAttrDTOS();
      Map<String, CodeAndGroupCodeAttrMappingDTO> jAttrVOMap = codeAndGroupCodeAttrMappingDTOList.stream().filter(s-> finalFieldList.contains(s.getTargetAttrKey().toLowerCase(Locale.ROOT))).collect(Collectors.toMap(s -> s.getTargetAttrKey().toLowerCase(Locale.ROOT), t -> t));
      WriteExcelData codeExcelData = new WriteExcelData(0, 0, "企业编码");
      WriteExcelData groupExcelData = new WriteExcelData(0, 1, "集团码");
      excelDataList.add(codeExcelData);
@@ -5076,7 +5279,9 @@
    * @param file
    * @return
    */
   public String improtGroupCode(String codeClassifyOid, File file) throws ServiceException {
   @Transactional(rollbackFor = VciBaseException.class)
   @Override
   public String importGroupCode(String codeClassifyOid, File file) throws Throwable {
      VciBaseUtil.alertNotNull(codeClassifyOid,"分类的主键");
      ReadExcelOption reo = new ReadExcelOption();
      reo.setReadAllSheet(true);
@@ -5086,14 +5291,15 @@
         throw new ServiceException("为了保证系统的稳定性,请一次不要导入超过1万条的数据");
      }
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      CodeClassifyTemplateVO templateVO = new CodeClassifyTemplateVO();
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->!DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      //获取最新的模板
      CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(codeClassifyOid);      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->!DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) &&
         ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
      ).collect(Collectors.toList());
      ExecGroupCodePortDataDTO execGroupCodePortDataDTO=new ExecGroupCodePortDataDTO();
      createExportGroupCodeMapConfig(templateVO,execGroupCodePortDataDTO);//组织数据
      List<CodeAndGroupCodeAttrMappingDTO> codeAttrMapGroupAttrDTOS=execGroupCodePortDataDTO.getCodeAttrMapGroupAttrDTOS();
      if(!CollectionUtils.isEmpty(codeAttrMapGroupAttrDTOS)){
      if(CollectionUtils.isEmpty(codeAttrMapGroupAttrDTOS)){
         throw new ServiceException("集团属性映射未配置");
      }
      Map<String, CodeAndGroupCodeAttrMappingDTO> codeSystemObjectMap = codeAttrMapGroupAttrDTOS.stream().filter(codeAttrMappingDTO -> codeAttrMappingDTO != null && StringUtils.isNotBlank(codeAttrMappingDTO.getSourceAttrName())).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getSourceAttrName(), t -> t));
@@ -5102,28 +5308,221 @@
      Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap = new HashMap<>();
      getGroupCodeFieldIndexMap(titleRowData,codeAttrMapGroupAttrDTOS,fieldIndexMap);
      //需要判断是否所有的属性都在模板上了
      List<CodeClassifyTemplateAttrVO> unExistAttrVOs = attrVOS.stream().filter(s -> !fieldIndexMap.containsValue(s.getId().toLowerCase(Locale.ROOT))
   /**   List<CodeClassifyTemplateAttrVO> unExistAttrVOs = attrVOS.stream().filter(s -> !fieldIndexMap.containsValue(s.getId().toLowerCase(Locale.ROOT))
         && com.alibaba.cloud.commons.lang.StringUtils.isBlank(s.getComponentRule()) && com.alibaba.cloud.commons.lang.StringUtils.isBlank(s.getClassifyInvokeAttr())//组合规则和分类注入确实没给用户导出去
      ).collect(Collectors.toList());
      if(!CollectionUtils.isEmpty(unExistAttrVOs)){
         String message=unExistAttrVOs.stream().map(CodeClassifyTemplateAttrVO::getName).collect(Collectors.joining(SERIAL_UNIT_SPACE));
         throw new VciBaseException("【" + message + "】这些属性在excel中没有找到");
      }
      }**/
      List<ClientBusinessObject> cboList = new ArrayList<>();
      List<SheetRowData> rowDataList = dataSet.getRowData();
      getExportGroupCodeDatas(fieldIndexMap,rowDataList,cboList);//构建数据对象
      List<String> codeList= cboList.stream().map(ClientBusinessObject::getId).collect(Collectors.toList());
      List<Map<String,String>>dataList=new ArrayList<>();
      getDatas(classifyFullInfo,templateVO,execGroupCodePortDataDTO.getFieldList(),dataList,codeList);
      //查询系统中存在
      if(!CollectionUtils.isEmpty(dataList)){
      Map<String,String> errorMap=new HashMap<>();
      batchSwitchCheckExist(errorMap,cboList,classifyFullInfo,templateVO,execGroupCodePortDataDTO,fieldIndexMap);
      //判断必输项
      batchCheckRequiredAttrOnOrder(templateVO, cboList, errorMap);
   //   //优先校验编码是否存在
   //   batchCheckIdExistOnOrder(templateVO, cboList, errorMap);
      //boolean
      reSwitchBooleanAttrOnOrder(attrVOS, cboList);
      // 枚举的内容需要根据名称转换为枚举的值
      batchSwitchEnumAttrOnOrder(attrVOS, cboList, errorMap);
      batchSwitchReferAttrOnOrder(attrVOS, cboList, errorMap);
      //6.处理分类注入
      batchSwitchClassifyAttrOnOrder(attrVOS, cboList, classifyFullInfo,false);
      //设置默认值
      batchSwitchAttrDefault(attrVOS, cboList);
      //7.处理组合规则
      batchSwitchComponentAttrOnOrder(attrVOS, cboList);
      //4.校验规则
      batchCheckVerifyOnOrder(attrVOS, cboList, errorMap);
      //6.时间的,必须统一为yyyy-MM-dd HH:mm:ss
      batchSwitchDateAttrOnOrder(attrVOS, cboList, errorMap);
      //3.判断关键属性
      CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,true,errorMap);
      Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
      Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
      if (!CollectionUtils.isEmpty(selfRepeatRowIndexList)) {
         selfRepeatRowIndexList.stream().forEach(rowIndex -> {
            errorMap.put(rowIndex, errorMap.getOrDefault(rowIndex, "") + ";在当前excel文件中关键属性重复");
         });
      }
      return "";
      if (!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)) {
         keyAttrRepeatRowIndexList.stream().forEach(rowIndex -> {
            errorMap.put(rowIndex, "关键属性与系统中的重复;" + errorMap.getOrDefault(rowIndex, ""));
         });
      }
      Map<String,List<WriteExcelData>> shetNameMap=new HashMap<>();
      createWriteExcelData(rowDataList, errorMap, new ArrayList<>(), titleRowData, shetNameMap, templateVO);
      String excelFileName="";
      if(errorMap.size()==0) {
         try {
            String btmTypeId = classifyFullInfo.getTopClassifyVO().getBtmTypeId();
            List<BaseModel>oldCbos= execGroupCodePortDataDTO.getOldList();
            List<BaseModel>newCbos=new ArrayList<>();
            // 修改版次号
            engineService.updateBatchByBaseModel(btmTypeId,oldCbos);
            List<CodeAllCode> codeAllCodeList=new ArrayList<>();
            final BladeUser user = AuthUtil.getUser();
            cboList.stream().forEach(clientBusinessObject -> {
               BaseModel newBaseModel=new BaseModel();
               DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(clientBusinessObject.getData(),newBaseModel,false,user);
               newCbos.add(newBaseModel);
            });
            // 插入新的数据
            engineService.insertBatchByType(btmTypeId, newCbos);
            codeAllCodeService.saveOrUpdateBatch(execGroupCodePortDataDTO.getCodeAllCodeList());
            engineService.batchSaveSelectChar(templateVO, newCbos);
            // 记录数据更改日志
            saveLogUtil.operateLog("数据更改", false, StringUtil.format("{}\n修改为:\n{}", JSON.toJSONString(oldCbos), JSON.toJSONString(newCbos)));
         } catch (Exception vciError) {
            // 记录数据更改报错时的日志
            saveLogUtil.operateLog("数据更改", true, vciError.toString());
            throw new VciBaseException("数据更改保存出错了", new String[0], vciError);
         }
      }else{
         excelFileName = LocalFileUtil.getDefaultTempFolder() + File.separator + "错误信息.xls";
         WriteExcelOption eo = new WriteExcelOption();
         shetNameMap.forEach((shetName, errorDataList) -> {
            eo.addSheetDataList(shetName, errorDataList);
         });
         try {
            new File(excelFileName).createNewFile();
         } catch (IOException e) {
            throw new VciBaseException(LangBaseUtil.getErrorMsg(e));
         }
         ExcelUtil.writeDataToFile(excelFileName, eo);
      }
      return excelFileName;
   }
   public void batchSwitchCheckExist(Map<String,String> errorMap,List<ClientBusinessObject> cboList,CodeClassifyFullInfoBO classifyFullInfo,CodeClassifyTemplateVO templateVO,ExecGroupCodePortDataDTO execGroupCodePortDataDTO,Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap){
      List<BaseModel> oldBaseModelList=new ArrayList<>();
      List<CodeAllCode> codeAllCodeList=new ArrayList<>();
      final BladeUser user = AuthUtil.getUser();
      cboList.stream().forEach(clientBusinessObject -> {
         String code=clientBusinessObject.getId();
         String rowIndex=clientBusinessObject.getAttributeValue(IMPORT_ROW_INDEX);
         List<Map<String,String>>dataList=new ArrayList<>();
         List<String> fieldList= execGroupCodePortDataDTO.getFieldList();
         getDatas(classifyFullInfo,templateVO,execGroupCodePortDataDTO.getFieldList(),dataList,Arrays.asList(code));
         DefaultAttrAssimtUtil.mapToLowerCase(dataList,true);
         if(!CollectionUtils.isEmpty(dataList)){
            Map<String,String> newDataMap=new HashMap<>();//将新对象属性暂时存储在Map<>
            newDataMap.putAll(clientBusinessObject.getData());
            Map<String,String> dataMap=dataList.get(0);
            BaseModel oldBaseModel=new BaseModel();
            DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(dataMap,oldBaseModel,false,user);
            String oldOid=oldBaseModel.getOid();
            clientBusinessObject.setCopyFromVersion(oldOid);
            clientBusinessObject.setAttributeValueWithNoCheck("copyfromversion",oldOid);
            String oid=VciBaseUtil.getPk();
            clientBusinessObject.setOid(oid);
            clientBusinessObject.setAttributeValueWithNoCheck("oid",oid);
            clientBusinessObject.setBtmname(oldBaseModel.getBtmname());
            clientBusinessObject.setAttributeValueWithNoCheck("btmname",oldBaseModel.getBtmname());
            clientBusinessObject.setLastR("1");
            clientBusinessObject.setAttributeValueWithNoCheck("lastr","1");
            clientBusinessObject.setFirstR("1");
            clientBusinessObject.setAttributeValueWithNoCheck("firstr","1");
            clientBusinessObject.setFirstV("1");
            clientBusinessObject.setAttributeValueWithNoCheck("firstv","1");
            clientBusinessObject.setLastV("1");
            clientBusinessObject.setAttributeValueWithNoCheck("lastv","1");
            clientBusinessObject.setRevisionSeq(1);
            clientBusinessObject.setAttributeValueWithNoCheck("revisionseq","1");
            clientBusinessObject.setVersionSeq(1);
            clientBusinessObject.setAttributeValueWithNoCheck("versionseq","1");
            clientBusinessObject.setRevisionRule(oldBaseModel.getRevisionRule());
            clientBusinessObject.setAttributeValueWithNoCheck("revisionrule",oldBaseModel.getRevisionRule());
            clientBusinessObject.setVersionRule(oldBaseModel.getRevisionRule());
            clientBusinessObject.setAttributeValueWithNoCheck("versionrule",oldBaseModel.getVersionRule());
            clientBusinessObject.setVersionValue(oldBaseModel.getVersionValue());
            clientBusinessObject.setAttributeValueWithNoCheck("versionvalue",oldBaseModel.getVersionValue());
            clientBusinessObject.setLctid(oldBaseModel.getLctid());
            clientBusinessObject.setAttributeValueWithNoCheck("lctid",oldBaseModel.getLctid());
            clientBusinessObject.setId(oldBaseModel.getId());
            clientBusinessObject.setAttributeValueWithNoCheck("id",oldBaseModel.getId());
            clientBusinessObject.setName(oldBaseModel.getName());
            clientBusinessObject.setAttributeValueWithNoCheck("name",oldBaseModel.getName());
            clientBusinessObject.setLcStatus(CodeDefaultLC.RELEASED.getValue());
            clientBusinessObject.setAttributeValueWithNoCheck("lcstatus",CodeDefaultLC.RELEASED.getValue());
            clientBusinessObject.setDescription("导入集团码");
            clientBusinessObject.setAttributeValueWithNoCheck("description","导入集团码");
            clientBusinessObject.setOwner("1");
            clientBusinessObject.setAttributeValueWithNoCheck("owner","1");
            clientBusinessObject.setTenantId(AuthUtil.getTenantId());
            clientBusinessObject.setAttributeValueWithNoCheck("tenant_id",AuthUtil.getTenantId());
            clientBusinessObject.setCreator(oldBaseModel.getCreator());
            clientBusinessObject.setAttributeValueWithNoCheck("creator",oldBaseModel.getCreator());
            SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            clientBusinessObject.setCreateTime(oldBaseModel.getCreateTime());
            clientBusinessObject.setAttributeValueWithNoCheck("createtime", formatter.format(oldBaseModel.getCreateTime()));
            clientBusinessObject.setLastModifier(AuthUtil.getUserAccount());
            clientBusinessObject.setAttributeValueWithNoCheck("lastmodifier",AuthUtil.getUserAccount());
            clientBusinessObject.setCreateTime(new Date());
            clientBusinessObject.setAttributeValueWithNoCheck("lastmodifytime", formatter.format(new Date()));
            clientBusinessObject.setRevisionValue(String.valueOf(Integer.parseInt(oldBaseModel.getRevisionValue())+1));
            clientBusinessObject.setRevisionOid(oldBaseModel.getRevisionOid());
            clientBusinessObject.setAttributeValueWithNoCheck("revisionoid",oldBaseModel.getRevisionOid());
            clientBusinessObject.setAttributeValueWithNoCheck("revisionvalue",String.valueOf(Integer.parseInt(oldBaseModel.getRevisionValue())+1));
            clientBusinessObject.setNameOid(oldBaseModel.getNameOid());
            clientBusinessObject.setAttributeValueWithNoCheck("nameoid",oldBaseModel.getNameOid());
            clientBusinessObject.setAttributeValueWithNoCheck(CODE_CLASSIFY_OID_FIELD,oldBaseModel.getData().getOrDefault(CODE_CLASSIFY_OID_FIELD,""));
            clientBusinessObject.setAttributeValueWithNoCheck(CODE_FULL_PATH_FILED,oldBaseModel.getData().getOrDefault(CODE_FULL_PATH_FILED,""));
            clientBusinessObject.setAttributeValueWithNoCheck(CODE_TEMPLATE_OID_FIELD,oldBaseModel.getData().getOrDefault(CODE_TEMPLATE_OID_FIELD,""));
            clientBusinessObject.setTs(new Date());
            clientBusinessObject.setAttributeValueWithNoCheck("ts",formatter.format(new Date()));
            oldBaseModel.setLastV("0");
            oldBaseModel.getData().put("lastv","0");
            oldBaseModelList.add(oldBaseModel);
            List<CodeAllCode> oldCodeAllCodeList= codeAllCodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getId,code));
            CodeAllCode codeAllCode=new CodeAllCode();
            if(!CollectionUtils.isEmpty(oldCodeAllCodeList)){
               codeAllCode=oldCodeAllCodeList.get(0);
               codeAllCode.setId(code);
               codeAllCode.setLcStatus(CodeDefaultLC.RELEASED.getValue());
               codeAllCode.setCreateCodeOid(clientBusinessObject.getOid());
               codeAllCode.setCreateCodeBtm(clientBusinessObject.getBtmname());
               codeAllCode.setLastModifyTime(new Date());
               codeAllCode.setLastModifier(AuthUtil.getUserAccount());
               codeAllCodeList.add(codeAllCode);
               if(!oldBaseModel.getLcStatus().equals(CodeDefaultLC.RELEASED.getValue())||!codeAllCode.getLcStatus().equals(CodeDefaultLC.RELEASED.getValue())){
                  errorMap.put(rowIndex,"第"+rowIndex+"行,在系统中数据不是发布状态");
               }
            }else{
               errorMap.put(rowIndex,"第"+rowIndex+"行,在系统中未查询到相应的码值数据");
            }
            //除去默认的属性.还有只有表单显示的字段才导入
            List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->!fieldIndexMap.containsValue(s.getId()) &&
               ((Func.isNotEmpty(s.getClassifyInvokeAttr()) || Func.isNotEmpty(s.getClassifyInvokeAttrName())) || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
            ).collect(Collectors.toList());
            attrVOS.stream().forEach(codeClassifyTemplateAttrVO -> {//将不需要更改的默认字段或者不更改的属性复制到新的版本上
               String arrtibuteKey=codeClassifyTemplateAttrVO.getId();
               Map<String,String>attrDataMap=oldBaseModel.getData();
               if(attrDataMap.containsKey(arrtibuteKey)){
                  String arrtibuteValue=attrDataMap.get(arrtibuteKey);
                  clientBusinessObject.setAttributeValueWithNoCheck(arrtibuteKey,arrtibuteValue);
               }
            });
         }else{
            errorMap.put(rowIndex,"第"+rowIndex+"行,在系统中未查询到相应的最新版数据");
         }
      });
      execGroupCodePortDataDTO.setOldList(oldBaseModelList);
      execGroupCodePortDataDTO.setCodeAllCodeList(codeAllCodeList);
   }
   /**
    *
    * @param fieldIndexMap
@@ -5132,8 +5531,10 @@
    */
   private void getExportGroupCodeDatas(Map<Integer,String> fieldIndexMap,List<SheetRowData> rowDataList,List<ClientBusinessObject>cboList){
      rowDataList.stream().forEach(sheetRowData -> {
         String rowIndex= sheetRowData.getRowIndex();
         ClientBusinessObject cbo=new ClientBusinessObject();
         cbo.setAttributeValue(IMPORT_ROW_INDEX,rowIndex);
         sheetRowData.getData().forEach((index,value)->{
            ClientBusinessObject cbo=new ClientBusinessObject();
            String field = fieldIndexMap.get(index);
            if (StringUtils.isBlank(field)) {
               throw new VciBaseException("第" + (index + 1) + "列的标题在系统中不存在");
@@ -5146,8 +5547,8 @@
            } catch (VciBaseException e) {
               log.error("设置属性的值错误", e);
            }
            cboList.add(cbo);
         });
         cboList.add(cbo);
      });
   }
   /***
@@ -5195,16 +5596,19 @@
      Map<String, CodeAndGroupCodeAttrMappingDTO> codeSystemObjectMap = codeAttrMapGroupAttrDTOS.stream().filter(codeAttrMappingDTO -> codeAttrMappingDTO != null && StringUtils.isNotBlank(codeAttrMappingDTO.getSourceAttrName())).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getSourceAttrName(), t -> t));
      for (int i = 0; i < titleRowData.size(); i++) {
         String title = titleRowData.get(i);
         CodeAndGroupCodeAttrMappingDTO codeAndGroupCodeAttrMappingDTO =codeSystemObjectMap.get(title.replace(KEY_ATTR_CHAR,"").replace(REQUIRED_CHAR,""));
         String id=codeAndGroupCodeAttrMappingDTO.getTargetAttrKey();
         if(com.alibaba.cloud.commons.lang.StringUtils.isBlank(id) && "集团码".equalsIgnoreCase(title)){
         String id = "";
         if ("集团码".equalsIgnoreCase(title)) {
            id = CODE_GROUP_FIELD;
         }
         if(com.alibaba.cloud.commons.lang.StringUtils.isBlank(id) && "企业编码".equalsIgnoreCase(title)){
         if ("企业编码".equalsIgnoreCase(title)) {
            id = CODE_FIELD;
         }
         if(com.alibaba.cloud.commons.lang.StringUtils.isNotBlank(id)){
            fieldIndexMap.put(i,id);
         if(codeSystemObjectMap.containsKey(title)) {
            CodeAndGroupCodeAttrMappingDTO codeAndGroupCodeAttrMappingDTO = codeSystemObjectMap.get(title.replace(KEY_ATTR_CHAR, "").replace(REQUIRED_CHAR, ""));
            id = codeAndGroupCodeAttrMappingDTO.getTargetAttrKey();
         }
         if (com.alibaba.cloud.commons.lang.StringUtils.isNotBlank(id)) {
            fieldIndexMap.put(i, id);
         }
      }
@@ -5217,7 +5621,7 @@
    * @param selectFieldList
    * @param dataList
    */
   private void getDatas(CodeClassifyFullInfoBO classifyFullInfo,CodeClassifyTemplateVO templateVO,LinkedList<String> selectFieldList,List<Map<String,String>>dataList,List<String> codeList ){
   private void getDatas(CodeClassifyFullInfoBO classifyFullInfo,CodeClassifyTemplateVO templateVO,LinkedList<String> selectFieldList,List<Map<String,String>>dataList,List<String> codeList){
      //先查询数据
      String btmTypeId = classifyFullInfo.getTopClassifyVO().getBtmTypeId();
      String codeClassifyOid=classifyFullInfo.getCurrentClassifyVO().getOid();