lihang
2023-06-15 b48356e1b39f8e812f85d1627c0fc18e1f4d58ba
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmIOServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1559 @@
package com.vci.ubcs.code.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.vci.ubcs.code.bo.AttributeValue;
import com.vci.ubcs.code.bo.CodeClassifyFullInfoBO;
import com.vci.ubcs.code.bo.CodeTemplateAttrSqlBO;
import com.vci.ubcs.code.dto.CodeOrderDTO;
import com.vci.ubcs.code.enumpack.CodeDefaultLC;
import com.vci.ubcs.code.enumpack.CodeLevelTypeEnum;
import com.vci.ubcs.code.mapper.CommonsMapper;
import com.vci.ubcs.code.service.*;
import com.vci.ubcs.code.util.ClientBusinessObject;
import com.vci.ubcs.code.vo.CodeKeyAttrRepeatVO;
import com.vci.ubcs.code.vo.pagemodel.*;
import com.vci.ubcs.code.vo.webserviceModel.attrmap.DataObjectVO;
import com.vci.ubcs.code.vo.webserviceModel.attrmap.RowDatas;
import com.vci.ubcs.code.vo.webserviceModel.result.xml.XMLResultDataObjectDetailDO;
import com.vci.ubcs.starter.bo.WriteExcelData;
import com.vci.ubcs.starter.exception.VciBaseException;
import com.vci.ubcs.starter.poi.bo.ReadExcelOption;
import com.vci.ubcs.starter.poi.bo.SheetDataSet;
import com.vci.ubcs.starter.poi.bo.SheetRowData;
import com.vci.ubcs.starter.poi.bo.WriteExcelOption;
import com.vci.ubcs.starter.poi.util.ExcelUtil;
import com.vci.ubcs.starter.revision.model.BaseModel;
import com.vci.ubcs.starter.util.DefaultAttrAssimtUtil;
import com.vci.ubcs.starter.util.LocalFileUtil;
import com.vci.ubcs.starter.web.enumpck.BooleanEnum;
import com.vci.ubcs.starter.web.enumpck.VciFieldTypeEnum;
import com.vci.ubcs.starter.web.pagemodel.DataGrid;
import com.vci.ubcs.starter.web.pagemodel.KeyValue;
import com.vci.ubcs.starter.web.pagemodel.PageHelper;
import com.vci.ubcs.starter.web.pagemodel.UIFormReferVO;
import com.vci.ubcs.starter.web.toolmodel.DateConverter;
import com.vci.ubcs.starter.web.util.*;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Workbook;
import org.springblade.core.redis.cache.BladeRedis;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;
import static com.alibaba.druid.util.FnvHash.Constants.LIMIT;
import static com.vci.ubcs.code.constant.MdmEngineConstant.*;
import static com.vci.ubcs.starter.poi.util.ExcelUtil.*;
@RequiredArgsConstructor
@Service
@Slf4j
public class MdmIOServiceImpl implements MdmIOService {
   @Value("${batchadd.redis.time:6000000}")
   public int BATCHADD_REDIS_TIME;
   /**
    * ä¸»é¢˜åº“分类的服务
    */
   @Resource
   private ICodeClassifyService classifyService;
   /**
    * é€šç”¨æŸ¥è¯¢
    */
   @Resource
   CommonsMapper commonsMapper;
   /**
    * æ¨¡æ¿çš„æœåŠ¡
    */
   @Resource
   private CodeClstemplateServiceImpl templateService;
   /**
    * ä¸»æ•°æ®å¼•擎的服务
    */
   @Resource
   private MdmEngineService engineService;
   /***
    * resdis缓存服务
    */
   private final BladeRedis bladeRedis;
   /**
    * ç”Ÿæˆç¼–码的服务
    */
   @Resource
   private MdmProductCodeService productCodeService;
   /**
    * å…³é”®å±žæ€§çš„配置
    */
   @Autowired
   private ICodeKeyAttrRepeatService keyRuleService;
   /**
    * å…¬å¼çš„æœåŠ¡
    */
   @Autowired
   private FormulaServiceImpl formulaService;
   /**
    * ç”Ÿæˆå¯¼å…¥çš„æ–‡ä»¶
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @param isHistory æ˜¯å¦åŽ†å²æ•°æ®å¯¼å…¥
    * @return excel的文件地址
    */
   @Override
   public String createImportExcel(String codeClassifyOid, boolean isHistory) {
      List<CodeClassifyTemplateVO> templateVOList=new ArrayList<>();
      VciBaseUtil.alertNotNull("导出模板","导出的配置",codeClassifyOid,"主题库分类的主键");
      CodeClassifyVO codeClassifyVO = classifyService.getObjectByOid(codeClassifyOid);
      if(isHistory){
         templateVOList= templateService.childTemplates(codeClassifyOid);
      }else{
         //找模板
         CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(codeClassifyOid);
         templateVOList.add(templateVO);
      }
      WriteExcelOption eo = new WriteExcelOption();
      eo.setAppend(true);
      //增加模板的信息导入
      LinkedList<WriteExcelData> tempEDList = new LinkedList<>();
      tempEDList.add(new WriteExcelData(0,0,"模板主键"));
      tempEDList.add(new WriteExcelData(0,1,"模板代号"));
      tempEDList.add(new WriteExcelData(0,2,"模板名称"));
      for(int j=0;j<templateVOList.size();j++){
         CodeClassifyTemplateVO  templateVO=templateVOList.get(j);
         CodeClassifyTemplateVO codeClassifyTemplateVO = new CodeClassifyTemplateVO();
         BeanUtils.copyProperties(templateVO,codeClassifyTemplateVO);
         //组合格式的不导入,
         // æžšä¸¾çš„æä¾›åºåˆ—的选择
         //时间全部统一为yyyy-MM-dd HH:mm:ss
         //参照的自行输入名称
         //分类注入的不用,都是导入后自动处理的
         //编码,状态等字段不导入
         List<CodeClassifyTemplateAttrVO> templateAttrVOS = codeClassifyTemplateVO.getAttributes().stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId())
               && StringUtils.isBlank(s.getComponentRule())
               && StringUtils.isBlank(s.getClassifyInvokeAttr())
               && (isHistory || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
         ).collect(Collectors.toList());
         if(CollectionUtils.isEmpty(templateAttrVOS)){
            throw new VciBaseException("模板没有配置任何【表单显示】为【是】的属性");
         }
         List<CodeClassifyTemplateAttrVO> idAttrVOList = codeClassifyTemplateVO.getAttributes().stream().filter(s -> s.getId().equalsIgnoreCase(CODE_FIELD)).collect(Collectors.toList());
         LinkedList<WriteExcelData> excelDataList = new LinkedList<>();
         Workbook workbook = new HSSFWorkbook();
         if(isHistory){
            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():"企业编码"));
         }
         for (int i = 0; i < templateAttrVOS.size(); i++) {
            CodeClassifyTemplateAttrVO attrVO = templateAttrVOS.get(i);
            Object text = attrVO.getName();
            text = exportKeyAndRequired(workbook,attrVO,text);
            int colIndex = (isHistory?3:0) + i;
            WriteExcelData excelData = new WriteExcelData(0, colIndex, text);
            if(StringUtils.isNotBlank(attrVO.getCodeDateFormat())
               || VciFieldTypeEnum.VTDateTime.name().equalsIgnoreCase(attrVO.getAttributeDataType())
               || VciFieldTypeEnum.VTDate.name().equalsIgnoreCase(attrVO.getAttributeDataType())
               ||VciFieldTypeEnum.VTTime.name().equalsIgnoreCase(attrVO.getAttributeDataType())){
               excelData.setDateFormat(VciDateUtil.DateTimeFormat);
            }
            if(text instanceof RichTextString){
               excelData.setFontColor(String.valueOf(HSSFColor.HSSFColorPredefined.RED.getIndex()));
            }
            excelDataList.add(excelData);
            if(StringUtils.isNotBlank(attrVO.getEnumString()) || StringUtils.isNotBlank(attrVO.getEnumId())){
               //添加数据有效性
               List<String> enumValueList = new ArrayList<>();
               enumValueList.add("");
               List<KeyValue> valueList = engineService.listComboboxItems(attrVO);
               if(!CollectionUtils.isEmpty(valueList)){
                  valueList.stream().forEach(kv->{
                     enumValueList.add(kv.getValue());
                  });
               }
               //默认加1万条
               WriteExcelData ed = new WriteExcelData(1,colIndex,"");
               ed.setRowTo(100);
               ed.setColTo(colIndex);
               ed.setValidation(true);
               ed.setValidationDataList(enumValueList);
               ed.setValidationErrorMsg("请在序列中选择正确的值");
               excelDataList.add(ed);
            }
            if(VciFieldTypeEnum.VTBoolean.name().equalsIgnoreCase(attrVO.getAttributeDataType())){
               List<String> booleanList = new ArrayList<>();
               booleanList.add("是");
               booleanList.add("否");
               //默认加1万条
               WriteExcelData ed = new WriteExcelData(1,colIndex,"");
               ed.setRowTo(100);
               ed.setColTo(colIndex);
               ed.setValidation(true);
               ed.setValidationDataList(booleanList);
               ed.setValidationErrorMsg("请在序列中选择正确的值");
               excelDataList.add(ed);
            }
         }
         eo.addSheetDataList(j+templateVO.getName(),excelDataList);
         tempEDList.add(new WriteExcelData(j+1,0,templateVO.getOid()));
         tempEDList.add(new WriteExcelData(j+1,1,templateVO.getId()));
         tempEDList.add(new WriteExcelData(j+1,2,templateVO.getName()));
      }
      String excelName = LocalFileUtil.getDefaultTempFolder() + File.separator + codeClassifyVO.getName() + (isHistory?"_历史数据导入模板.xls": "_导入模板.xls");
      eo.addSheetDataList(templateVOList.size()+"模板信息【请勿删除或移动】",tempEDList);
      ExcelUtil.writeDataToFile(excelName,eo);
      return excelName;
   }
   /**
    * å¯¼å‡ºçš„æ—¶å€™å°è£…必输和关键属性
    * @param attrVO å±žæ€§çš„æ˜¾ç¤ºå¯¹è±¡
    * @param text å•元格的值
    */
   private Object exportKeyAndRequired(Workbook workbook,CodeClassifyTemplateAttrVO attrVO,Object text){
      //必输加*,关键属性为蓝色
      if (VciBaseUtil.getBoolean(attrVO.getRequireFlag()) || VciBaseUtil.getBoolean(attrVO.getKeyAttrFlag())) {
         String value = text.toString();
         if(VciBaseUtil.getBoolean(attrVO.getRequireFlag())) {
            value += REQUIRED_CHAR;
         }
         if(VciBaseUtil.getBoolean(attrVO.getKeyAttrFlag())){
            value += KEY_ATTR_CHAR;
         }
         RichTextString ts = new HSSFRichTextString(value);
         if(VciBaseUtil.getBoolean(attrVO.getRequireFlag())){
            Font font =  workbook.createFont();
            font.setColor(HSSFColor.HSSFColorPredefined.RED.getIndex());
            ts.applyFont(font);
         }
         if(VciBaseUtil.getBoolean(attrVO.getKeyAttrFlag())){
            Font font =  workbook.createFont();
            font.setColor(HSSFColor.HSSFColorPredefined.BLUE.getIndex());
            ts.applyFont(font);
         }
         return ts;
      }
      return text;
   }
   /**
    * æ‰¹é‡ç”³è¯·ç¼–码数据
    *
    * @param orderDTO ç¼–码申请信息,必须包含分类主键和码段的信息
    * @param file     excel文件的信息
    * @return  æœ‰é”™è¯¯ä¿¡æ¯çš„excel的文件
    */
   @Override
   public CodeImProtRusultVO batchImportCode(CodeOrderDTO orderDTO, File file) {
      VciBaseUtil.alertNotNull(orderDTO,"编码申请相关的数据",orderDTO.getCodeClassifyOid(),"主题库分类主键");
      ReadExcelOption reo = new ReadExcelOption();
      reo.setReadAllSheet(true);
      List<SheetDataSet> sheetDataSetList = ExcelUtil.readDataObjectFromExcel(file,null,reo);
      if(CollectionUtils.isEmpty(sheetDataSetList) || CollectionUtils.isEmpty(sheetDataSetList.get(0).getRowData())
         ||sheetDataSetList.get(0).getRowData().size()<1){
         throw new VciBaseException("没有读取到任何的数据");
      }
      if(sheetDataSetList.size()>LIMIT+1){
         throw new VciBaseException("为了保证系统的稳定性,请一次不要导入超过1万条的数据");
      }
      //先找到每一行的标题,然后根据标题来获取对应的属性
      SheetDataSet dataSet = sheetDataSetList.get(0);
      //找第一行,为了找标题
      CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(orderDTO.getCodeClassifyOid());
      //校验模板是不是最新的
      checkTemplateSync(sheetDataSetList,templateVO,0);
      //先不用管属性是否都存在,先转换一下数据
      Map<String,String> errorMap = new HashMap<>();
      String redisUUid=batchImportCodes(orderDTO,templateVO,dataSet,errorMap,true);
      CodeImProtRusultVO codeImProtRusultVO = new CodeImProtRusultVO();
      List<String> needRowIndexList = new ArrayList<>();
      String filePath = returnErrorToExcel(dataSet.getRowData(), errorMap, needRowIndexList, dataSet.getColName());
      if(StringUtils.isNotBlank(filePath)) {
         codeImProtRusultVO.setFilePath(filePath);
      }
      if(StringUtils.isNotBlank(redisUUid)){
         codeImProtRusultVO.setRedisUuid(redisUUid);
      }
//      return null;
      return codeImProtRusultVO;
   }
   /**
    * é”™è¯¯ä¿¡æ¯è¿”回excel
    * @param rowDataList æ‰€æœ‰çš„导入数据
    * @param errorMap é”™è¯¯çš„信息
    * @param needRowIndexList éœ€è¦å†™å…¥çš„æ•°æ®çš„行号
    * @param titleRowData æ ‡é¢˜è¡Œ
    *
    * @return é”™è¯¯çš„excel文件,没有错误会返回空
    */
   private String returnErrorToExcel(Collection<SheetRowData> rowDataList,
                             Map<String,String> errorMap,
                             List<String> needRowIndexList,List<String> titleRowData){
      if(CollectionUtils.isEmpty(errorMap)){
         return "";
      }
      Map<String, SheetRowData> rowIndexDataMap = rowDataList.stream().filter(s -> !needRowIndexList.contains(s.getRowIndex())).collect(Collectors.toMap(s -> s.getRowIndex(), t -> t));
      List<WriteExcelData> errorDataList = new ArrayList<>();
      errorDataList.add(new WriteExcelData(0,0,"错误信息"));
      for (int i = 0; i < titleRowData.size(); i++) {
         //错误信息在最后
         errorDataList.add(new WriteExcelData(0,i+1,titleRowData.get(i)));
      }
      Integer[] newRowIndex = new Integer[]{1};
      errorMap.forEach((index,error)->{
         //错误信息全部组合到一起
         SheetRowData rowData = rowIndexDataMap.getOrDefault(index, null);
         if(rowData!=null){
            errorDataList.add(new WriteExcelData(newRowIndex[0],0,error));
            rowData.getData().forEach((colIndex,value)->{
               errorDataList.add(new WriteExcelData(newRowIndex[0],colIndex+1,value));
            });
            newRowIndex[0]++;
         }
      });
      String excelFileName = LocalFileUtil.getDefaultTempFolder() + File.separator + "错误信息.xls";
      WriteExcelOption eo = new WriteExcelOption(errorDataList);
      try {
         new File(excelFileName).createNewFile();
      } catch (IOException e) {
         throw new VciBaseException(LangBaseUtil.getErrorMsg(e));
      }
      ExcelUtil.writeDataToFile(excelFileName,eo);
      return excelFileName;
   }
   /**
    * æ ¡éªŒæ¨¡æ¿æ˜¯å¦ä¸ºåŒæ­¥çš„
    * @param sheetDataSetList excel里的内容
    * @param templateVO æ¨¡æ¿çš„信息
    */
   private void checkTemplateSync(List<SheetDataSet> sheetDataSetList,CodeClassifyTemplateVO templateVO,int i){
      String templateOidInExcel = "";
      String templateName="";
      if(!CollectionUtils.isEmpty(sheetDataSetList)
         && sheetDataSetList.size()>1 && !CollectionUtils.isEmpty(sheetDataSetList.get(sheetDataSetList.size()-1).getColName())){
         List<SheetRowData>  rowData=  sheetDataSetList.get(sheetDataSetList.size()-1).getRowData();
         templateName=rowData.get(i).getData().get(2);
         templateOidInExcel=rowData.get(i).getData().get(0);
         //templateOidInExcel = sheetDataSetList.get(sheetDataSetList.size()-1).getColName().get(sheetDataSetList.size()-i);
      }
       /* if(!CollectionUtils.isEmpty(sheetDataSetList)
                && sheetDataSetList.size()>1 && !CollectionUtils.isEmpty(sheetDataSetList.get(sheetDataSetList.size()-1).getColName())){
            List<SheetRowData>  rowData=  sheetDataSetList.get(sheetDataSetList.size()-1).getRowData();
            templateOidInExcel=rowData.get(i).getData().get(0);
           //templateOidInExcel = sheetDataSetList.get(sheetDataSetList.size()-1).getColName().get(sheetDataSetList.size()-i);
        }*/
      if(StringUtils.isBlank(templateOidInExcel) || !templateOidInExcel.equalsIgnoreCase(templateVO.getOid())){
         throw new VciBaseException("模板【"+templateName+"】中的数据获取的模版信息与当前模板不匹配,请确保excel文件里有【模板信息-请勿移动或删除】的工作表,且确保每次导入都是先下载的导入模板后添加的数据");
      }
   }
   /***
    * æ‰¹é‡å¤„理申请数据
    * @param orderDTO
    * @param templateVO
    * @param dataSet
    * @return
    */
   private String batchImportCodes(CodeOrderDTO orderDTO,CodeClassifyTemplateVO templateVO,SheetDataSet dataSet,Map<String,String> errorMap,boolean isEnumType){
      List<String> codeList=new ArrayList<>();
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
      //规则的主键需要去获取
      CodeRuleVO ruleVO = engineService.getCodeRuleByClassifyFullInfo(classifyFullInfo);
      //1.判断规则中除了流水码段,是否有其他码段
      engineService.checkSecValueOnOrder(ruleVO,orderDTO);
      List<SheetRowData> rowDataList = dataSet.getRowData();
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->
         !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      ).collect(Collectors.toList());
      Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap = new HashMap<>();
      List<String> titleRowData = dataSet.getColName();
      Map<String/**中文名称**/, String/**英文名称**/> attrNameIdMap = attrVOS.stream().collect(Collectors.toMap(s -> s.getName(), t -> t.getId().toLowerCase(Locale.ROOT),(o1, o2)->o2));
      getFieldIndexMap(titleRowData,attrNameIdMap,fieldIndexMap);
      //需要判断是否所有的属性都在模板上了
      List<CodeClassifyTemplateAttrVO> unExistAttrVOs = attrVOS.stream().filter(s -> !fieldIndexMap.containsValue(s.getId().toLowerCase(Locale.ROOT))
         && StringUtils.isBlank(s.getComponentRule()) && StringUtils.isBlank(s.getClassifyInvokeAttr())//组合规则和分类注入确实没给用户导出去
      ).collect(Collectors.toList());
      if(!CollectionUtils.isEmpty(unExistAttrVOs)){
         throw new VciBaseException("【" + unExistAttrVOs.stream().map(CodeClassifyTemplateAttrVO::getName) + "】这些属性在列表中没有找到");
      }
      List<ClientBusinessObject> cboList = new ArrayList<>();
      String fullPath = getFullPath(classifyFullInfo);
      excelToCbo(classifyFullInfo,fieldIndexMap,rowDataList,templateVO,cboList,fullPath,true);
      //都转换完了。需要批量检查
      //如果出错了,我们依然执行有效的数据,无效的数据写回到excel中
      //2.判断必输项。。需要全部的属性,如果是必输,但是表单里面不显示的,只能是分类注入或者组合规则
      batchCheckRequiredAttrOnOrder(templateVO,cboList,errorMap);
      //3.判断关键属性
      CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList);
      Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
      Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
      if(!CollectionUtils.isEmpty(selfRepeatRowIndexList)){
         selfRepeatRowIndexList.stream().forEach(rowIndex->{
            errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";在当前处理的数据文件中关键属性重复" );
         });
      }
      if(!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)){
         keyAttrRepeatRowIndexList.stream().forEach(rowIndex->{
            errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";关键属性与系统中的重复" );
         });
      }
      //分类注入
      batchSwitchClassifyAttrOnOrder(attrVOS,cboList,classifyFullInfo,false);
      //boolean
      reSwitchBooleanAttrOnOrder(attrVOS,cboList);
      //4.校验规则
      batchCheckVerifyOnOrder(attrVOS, cboList,errorMap);
      if(isEnumType) {//是否需要校验枚举/参照
         //5.校验枚举是否正确
         batchSwitchEnumAttrOnOrder(attrVOS, cboList, errorMap);
         //7.处理参照的情况
         batchSwitchReferAttrOnOrder(attrVOS,cboList,errorMap);
      }
      //6.时间格式的验证
      //6.时间的,必须统一为yyyy-MM-dd HH:mm:ss
      batchSwitchDateAttrOnOrder(attrVOS,cboList,errorMap);
      //最后弄组合规则
      batchSwitchComponentAttrOnOrder(attrVOS,cboList);
      String uuid=VciBaseUtil.getPk();
      Map<String, ClientBusinessObject> rowIndexCboMap = cboList.stream().filter(cbo -> cbo != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getAttributeValue((IMPORT_ROW_INDEX)), t -> t));
      if(errorMap.size()>0) {
         createRedisDatas(uuid + "-error",templateVO, rowIndexCboMap, dataSet, fieldIndexMap, errorMap,false);
      }
      boolean isCreateUUid=false;
      List<ClientBusinessObject> needSaveCboList = cboList.stream().filter(cbo -> {
         String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
         return !errorMap.containsKey(rowIndex);
      }).collect(Collectors.toList());
      //相似校验
      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;
         if(!CollectionUtils.isEmpty(dataResembleVOS)) {
            bladeRedis.set(uuid + "-resemble-data", dataResembleVOS);
            createRedisDatas(uuid + "-resemble",templateVO, rowIndexCboMap, dataSet, fieldIndexMap, resembleMap, false);
         }
      }
      //排除错误的,剩下正确的
      Map<String,String> newErrorMap=new HashMap<>();
      newErrorMap.putAll(resembleMap);
      newErrorMap.putAll(errorMap);
      needSaveCboList = cboList.stream().filter(cbo -> {
         String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
         return !newErrorMap.containsKey(rowIndex);
      }).collect(Collectors.toList());
      if((errorMap.size()>0&&needSaveCboList.size()>0)||resembleMap.size()>0){
         isCreateUUid=true;
      }
      createRedisByCodeClassify(uuid + "-class",templateVO,dataSet,fieldIndexMap,false);
      if(newErrorMap.size()>0) {
         createRedisDatas(uuid + "-ok",templateVO, rowIndexCboMap, dataSet, fieldIndexMap, newErrorMap,true);
      }else {
         uuid="";
         //要把以上的错误的都抛出后,再继续处理时间和组合规则
         /*dataCBOList = cboList.stream().filter(cbo -> {
            String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
            return !newErrorMap.containsKey(rowIndex);
         }).collect(Collectors.toList());
*/         List<String> dataCBOIdList=new ArrayList<>();
         List<BaseModel> dataCBOList=new ArrayList<>();
         cboList.stream().forEach(clientBusinessObject -> {
            BaseModel baseModel=new BaseModel();
            BeanUtil.convert(clientBusinessObject,baseModel);
            baseModel.setData(VciBaseUtil.objectToMapString(clientBusinessObject));
            dataCBOList.add(baseModel);
            dataCBOIdList.add(baseModel.getOid());
         });
         if (!CollectionUtils.isEmpty(needSaveCboList)) {
            //9.我们处理业务数据
            //生成编码的内容
            try {
               codeList = productCodeService.productCodeAndSaveData(classifyFullInfo,templateVO,ruleVO, orderDTO.getSecDTOList(),dataCBOList);
               //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
               engineService.batchSaveSelectChar(templateVO, dataCBOIdList);
            } catch (Exception e) {
               e.printStackTrace();
               log.error("批了申请时失败");
            }
         }
      }
      if(!isCreateUUid){
         return uuid="";
      }
      return uuid;
   }
   @Override
   public List<CodeImportTemplateVO> gridclassifys(String redisOid) {
      List<CodeImportTemplateVO> codeImportTemplateVOs=new ArrayList<>();
      VciBaseUtil.alertNotNull(redisOid,"分类",redisOid,"分类缓存主键");
      List<CodeImportTemplateVO> redisServiceCacheObjects=bladeRedis.lRange(redisOid,0,-1);
      if(redisServiceCacheObjects!=null){
         codeImportTemplateVOs=  redisServiceCacheObjects;
      }
      return codeImportTemplateVOs;
   }
   /***
    * ä»Žç¼“存里获取到需要导入的相关数据
    * @param codeClssifyOid
    * @param redisOid
    * @return
    */
   @Override
   public DataGrid<Map<String, String>> gridDatas(String codeClssifyOid, String redisOid) {
      VciBaseUtil.alertNotNull(redisOid,"导入相似数据",redisOid,"数据缓存主键");
      List<CodeImprotDataVO> codeImprotDataVOs = bladeRedis.lRange(redisOid+"-"+codeClssifyOid,0,-1);
//      redisService.getCacheList(redisOid+"-"+codeClssifyOid);
      CodeImprotDataVO codeImprotDataVO=new CodeImprotDataVO();
      if(!CollectionUtils.isEmpty(codeImprotDataVOs)){
         if(StringUtils.isNotBlank(codeClssifyOid)){
            Map<String/**分类名称**/, CodeImprotDataVO/**英文名称**/> codeClassifyDatasMap = codeImprotDataVOs.stream().collect(Collectors.toMap(s -> s.getCodeClassifyOid(), t -> t,(o1, o2)->o2));
            if(codeClassifyDatasMap.containsKey(codeClssifyOid)){
               codeImprotDataVO= codeClassifyDatasMap.get(codeClssifyOid);
            }else{
               codeImprotDataVO=  codeImprotDataVOs.get(0);
            }
         }
      }
      DataGrid<Map<String, String>> dataGrid = new DataGrid<>();
      List<Map<String, String>> dataList = new ArrayList<>();
      if(codeImprotDataVO!=null){
         dataList= codeImprotDataVO.getDatas();
      }
      dataGrid.setData(dataList);
      if (!CollectionUtils.isEmpty(dataList)) {
         dataGrid.setTotal(dataList.size());
      }
      return dataGrid;
   }
   /**
    *
    * @param oid
    * @param redisOid
    * @return
    */
   @Override
   public DataGrid<Map<String,String>> gridRowResemble(String oid,String redisOid){
      VciBaseUtil.alertNotNull(redisOid,"导入相似数据",redisOid,"数据缓存主键");
      List<DataResembleVO> codeImprotDataVOs = bladeRedis.lRange(redisOid,0,-1);;
      DataGrid<Map<String, String>> dataGrid = new DataGrid<>();
      List<Map<String, String>> dataList = new ArrayList<>();
      if(!CollectionUtils.isEmpty(codeImprotDataVOs)){
         Map<String/**分类名称**/, DataResembleVO/**数据对象**/> rowResembleDataMap = codeImprotDataVOs.stream().collect(Collectors.toMap(s -> s.getOid(), t -> t,(o1, o2)->o2));
         if(rowResembleDataMap.containsKey(oid)){
            DataResembleVO dataResembleVO=  rowResembleDataMap.get(oid);
            dataList= dataResembleVO.getDataList();
         }
      }
      dataGrid.setData(dataList);
      if (!CollectionUtils.isEmpty(dataList)) {
         dataGrid.setTotal(dataList.size());
      }
      return dataGrid;
   }
   /**
    * é›†æˆæ‰¹é‡ç”³è¯·æ•°æ®
    * @param orderDTO åˆ†ç±»çš„主键
    * @param dataObjectVO æ•°æ®ä¿¡æ¯
    * @param resultDataObjectDetailDOs é”™è¯¯ä¿¡æ¯
    * @return æœ‰é”™è¯¯ä¿¡æ¯çš„excel
    */
   @Override
   public void batchSyncApplyCode(CodeOrderDTO orderDTO, DataObjectVO dataObjectVO, LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs) {
      Map<String,String> errorMap=new HashMap<>();
      VciBaseUtil.alertNotNull(orderDTO,"编码申请相关的数据",orderDTO.getCodeClassifyOid(),"主题库分类主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
      //规则的主键需要去获取
      CodeRuleVO ruleVO = engineService.getCodeRuleByClassifyFullInfo(classifyFullInfo);
      //1.判断规则中除了流水码段,是否有其他码段
      //engineService.checkSecValueOnOrder(ruleVO,orderDTO);
      //查询分类和模板
      //先找到每一行的标题,然后根据标题来获取对应的属性
      List<RowDatas> rowDataList = dataObjectVO.getRowData();
      Map<String , RowDatas>rowDataMap=new LinkedHashMap<>();
      rowDataList.stream().forEach(rowData->{
         rowDataMap.put(rowData.getRowIndex(),rowData);
      });
      //找第一行,为了找标题
      CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(orderDTO.getCodeClassifyOid());
      //校验模板是不是最新的
      //checkTemplateSync(sheetDataSetList,templateVO);
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->!DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      ).collect(Collectors.toList());
      Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap = new HashMap<>();
      List<String> titleRowData = dataObjectVO.getColName();
      Map<String/**中文名称**/, String/**英文名称**/> attrNameIdMap = attrVOS.stream().collect(Collectors.toMap(s -> s.getName(), t -> t.getId().toLowerCase(Locale.ROOT),(o1, o2)->o2));
      getFieldIndexMap(titleRowData,attrNameIdMap,fieldIndexMap);
      //需要判断是否所有的属性都在模板上了
      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)){
         throw new VciBaseException("【" + unExistAttrVOs.stream().map(CodeClassifyTemplateAttrVO::getName) + "】这些属性在excel中没有找到");
      }
      String fullPath = getFullPath(classifyFullInfo);
      // List<CodeClassifyProcessTempVO> codeClassifyProcessTempVOS=codeClassifyProcessTempService.listProcessTemplate(templateVO.getOid(),"code_cls_flow_use_order");
      boolean isProcess=false;
      //注释掉此处下面所有都按照不判断流程存储状态了
      /** if(!CollectionUtils.isEmpty(codeClassifyProcessTempVOS)){
       isProcess=true;
       }***/
      //List<ClientBusinessObject> cboList = new ArrayList<>();
      //Map<String,String> codeOidToSystemOidMap=new HashMap<>();//存储编码数据和集成系统数据oid对照映射
      //excelToCbo(classifyFullInfo,titleRowData,fieldIndexMap,rowDataList,templateVO,cboList,fullPath,isProcess,"create",errorMap,codeOidToSystemOidMap);
      //都转换完了。需要批量检查
      //如果出错了,我们依然执行有效的数据,无效的数据写回到excel中
      //2.判断必输项。。需要全部的属性,如果是必输,但是表单里面不显示的,只能是分类注入或者组合规则
   }
   @Override
   public void batchSyncEditDatas(CodeClassifyVO codeClassifyVO, DataObjectVO dataObjectVO, LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs) {
   }
   /**
    * èŽ·å–åˆ†ç±»çš„å…¨è·¯å¾„
    * @param classifyFullInfo åˆ†ç±»çš„全部信息
    * @return å…¨è·¯å¾„
    */
   private String getFullPath(CodeClassifyFullInfoBO classifyFullInfo){
      String fullPath = "";
      if(!CollectionUtils.isEmpty(classifyFullInfo.getParentClassifyVOs())){
         fullPath = classifyFullInfo.getParentClassifyVOs().stream().sorted(((o1, o2) -> o1.getDataLevel().compareTo(o2.getDataLevel())))
            .map(CodeClassifyVO::getOid).collect(Collectors.joining("##"));
      }else{
         fullPath = classifyFullInfo.getCurrentClassifyVO().getOid();
      }
      return fullPath;
   }
   /**
    * excel转换为cbo的对象
    * @param classifyFullInfo åˆ†ç±»çš„全部信息
    * @param fieldIndexMap å­—段的位置
    * @param rowDataList excel里的行数据
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    * @param cboList æ•°æ®çš„列表
    * @param fullPath å…¨è·¯å¾„
    * @param newCode æ˜¯å¦ä¸ºæ‰¹é‡ç”³è¯·
    */
   private void excelToCbo(CodeClassifyFullInfoBO classifyFullInfo,Map<Integer,String> fieldIndexMap,List<SheetRowData> rowDataList,
                     CodeClassifyTemplateVO templateVO,List<ClientBusinessObject> cboList,
                     String fullPath,boolean newCode){
      rowDataList.stream().forEach(rowData -> {
         ClientBusinessObject cbo=new ClientBusinessObject();
          DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmtypeid());
         rowData.getData().forEach((index,value)->{
            String field = fieldIndexMap.get(index);
            if (StringUtils.isBlank(field)) {
               throw new VciBaseException("第" + (index + 1) + "列的标题在系统中不存在");
            }
            try {
               cbo.setAttributeValueWithNoCheck(field, value);
               if (WebUtil.isDefaultField(field)) {
                  WebUtil.setValueToField(field, cbo, value);
               }
            } catch (VciBaseException e) {
               log.error("设置属性的值错误", e);
            }
         });
         try {
            cbo.setAttributeValue(CODE_TEMPLATE_OID_FIELD,templateVO.getOid());
            cbo.setAttributeValue(IMPORT_ROW_INDEX,rowData.getRowIndex());
            if(newCode){
               cbo.setAttributeValue(CODE_CLASSIFY_OID_FIELD,classifyFullInfo.getCurrentClassifyVO().getOid());
               cbo.setAttributeValue(CODE_FULL_PATH_FILED,fullPath);
               //cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
               int secret = VciBaseUtil.getInt(cbo.getAttributeValue(SECRET_FIELD));
               /*if(secret == 0 || !secretService.checkDataSecret(secret) ){
                  Integer userSecret = VciBaseUtil.getCurrentUserSecret();
                  cbo.setAttributeValue(SECRET_FIELD,String.valueOf((userSecret==null || userSecret ==0)? UserSecretEnum.NONE.getValue():userSecret));
               }*/
            }else{
               //此时还没有转换路径
               //cbo.setAttributeValue(CODE_FULL_PATH_FILED, childOidPathMap.getOrDefault(rowData.getData().getOrDefault(CODE_CLASSIFY_OID_FIELD,""),fullPath));
               cbo.setLcStatus(CodeDefaultLC.RELEASED.getValue());
            }
         }catch (Throwable e){
            log.error("设置默认的属性的值错误",e);
         }
         cboList.add(cbo);
      });
   }
   /**
    * æ£€æŸ¥æ ¡éªŒè§„则没有通过的内容
    * @param attrVOS éœ€è¦æ ¡éªŒçš„属性
    * @param dataList æ•°æ®çš„列表
    * @param errorMap é”™è¯¯çš„信息映射
    * @return æ ¡éªŒä¸é€šè¿‡çš„行数
    */
   private void batchCheckVerifyOnOrder(Collection<CodeClassifyTemplateAttrVO> attrVOS, List<ClientBusinessObject> dataList,Map<String,String> errorMap) {
      Map<String, CodeClassifyTemplateAttrVO> verifyAttrVOMap = attrVOS.stream().filter(s -> StringUtils.isNotBlank(s.getVerifyRule()) && StringUtils.isBlank(s.getComponentRule())
         &&StringUtils.isBlank(s.getClassifyInvokeAttr())
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if(!CollectionUtils.isEmpty(verifyAttrVOMap)){
         Map<String/**行号**/,List<String>/**校验不通过的属性**/> unPassCheckMap = new HashMap<>();
         verifyAttrVOMap.forEach((attrId,attrVO)->{
            dataList.stream().forEach(cbo -> {
               String value = cbo.getAttributeValue(attrId);
               if(StringUtils.isNotBlank(value) && !value.matches(attrVO.getVerifyRule())){
                  String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                  List<String> unPassAttrs = unPassCheckMap.getOrDefault(rowIndex, new ArrayList<>());
                  unPassAttrs.add(attrVO.getName());
                  unPassCheckMap.put(rowIndex,unPassAttrs);
               }
            });
         });
         if(!CollectionUtils.isEmpty(unPassCheckMap)){
            unPassCheckMap.forEach((rowIndex,unPassAttrs)->{
               errorMap.put(rowIndex,";属性[" + unPassAttrs.stream().collect(Collectors.joining(",")) + "]内容不符合校验规则的要求");
            });
         }
      }
   }
   /**
    * æ‰¹é‡è½¬æ¢æ—¶é—´éƒ½ä¸ºæŒ‡å®šçš„æ ¼å¼
    * @param attrVOS æ¨¡æ¿å±žæ€§
    * @param cboList æ•°æ®çš„列表
    * @param errorMap é”™è¯¯çš„信息
    */
   private void batchSwitchDateAttrOnOrder(Collection<CodeClassifyTemplateAttrVO> attrVOS,List<ClientBusinessObject> cboList,Map<String,String> errorMap){
      Map<String, CodeClassifyTemplateAttrVO> dateAttrVOMap =attrVOS.stream().filter(s ->
         StringUtils.isNotBlank(s.getCodeDateFormat()) && VciBaseUtil.getBoolean(s.getCodeDateFormat()) && StringUtils.isBlank(s.getComponentRule())
            && StringUtils.isBlank(s.getClassifyInvokeAttr())
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if(!CollectionUtils.isEmpty(dateAttrVOMap)) {
         dateAttrVOMap.forEach((attrId, attrVO) -> {
            cboList.stream().forEach(cbo -> {
               String value = cbo.getAttributeValue(attrId);
               if (value == null) {
                  value = "";
               }
               if (StringUtils.isNotBlank(value)) {
                  boolean formated = false;
                  if(StringUtils.isNotBlank(attrVO.getCodeDateFormat())){
                     try {
                        Date date = VciDateUtil.str2Date(value, attrVO.getCodeDateFormat());
                        if(date!=null){
                           cbo.setAttributeValue(attrId,value);
                           formated = true;
                        }
                     } catch (Exception e) {
                        //说明不是这个格式
                     }
                  }
                  if(!formated) {
                     try {
                        DateConverter dateConverter = new DateConverter();
                        dateConverter.setAsText(value);
                        value = VciDateUtil.date2Str(dateConverter.getValue(), VciDateUtil.DateTimeMillFormat);
                        cbo.setAttributeValue(attrId,value);
                     }catch (Throwable e){
                        //转换不了
                        String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                        errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";属性[" + attrVO.getName() + "]时间格式不正确" );
                     }
                  }
               }
            });
         });
      }
   }
   /**
    * è½¬ç§»boolean型的属性
    * @param attrVOS å±žæ€§çš„对象
    * @param dataList æ•°æ®
    */
   private void reSwitchBooleanAttrOnOrder(Collection<CodeClassifyTemplateAttrVO> attrVOS,List<ClientBusinessObject> dataList){
      Map<String, CodeClassifyTemplateAttrVO> booleanAttrMap = attrVOS.stream().filter(
         s -> VciFieldTypeEnum.VTBoolean.name().equalsIgnoreCase(s.getAttributeDataType())
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(booleanAttrMap)) {
         booleanAttrMap.forEach((attrId, attrVO) -> {
            dataList.stream().forEach(cbo -> {
               String text = cbo.getAttributeValue(attrId);
               try {
                  if (BooleanEnum.TRUE.getValue().equalsIgnoreCase(text) || "是".equalsIgnoreCase(text)) {
                     cbo.setAttributeValue(attrId, BooleanEnum.TRUE.getValue());
                  } else {
                     cbo.setAttributeValue(attrId, BooleanEnum.FASLE.getValue());
                  }
               }catch (Throwable e){
               }
            });
         });
      }
   }
   /**
    * å¤„理组合规则
    * @param attrVOS æ¨¡æ¿å±žæ€§
    * @param dataList excel的数据内容
    */
   private void batchSwitchComponentAttrOnOrder(Collection<CodeClassifyTemplateAttrVO> attrVOS,List<ClientBusinessObject> dataList) {
      Map<String, CodeClassifyTemplateAttrVO> dateAttrVOMap = attrVOS.stream().filter(s -> StringUtils.isNotBlank(s.getComponentRule())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if(!CollectionUtils.isEmpty(dateAttrVOMap)) {
         dateAttrVOMap.forEach((attrId, attrVO) -> {
            dataList.stream().forEach(cbo -> {
               //从excel上把属性转换为map
               Map<String,String> thisRowDataMap = new HashMap<>();
               copyValueToMapFromCbos(cbo,thisRowDataMap);
               //组合内容
               String value = formulaService.getValueByFormula(thisRowDataMap,attrVO.getComponentRule());
               if(value == null){
                  value = "";
               }
               try {
                  cbo.setAttributeValue(attrId, value);
               }catch (Throwable e){
                  log.error("设置属性的错误",e);
               }
            });
         });
      }
   }
   /**
    * è½¬æ¢å‚照的值
    * @param attrVOS å±žæ€§çš„æ˜¾ç¤ºå¯¹è±¡
    * @param dataList æ•°æ®åˆ—表
    * @param errorMap é”™è¯¯çš„信息
    */
   private void batchSwitchReferAttrOnOrder(Collection<CodeClassifyTemplateAttrVO> attrVOS,List<ClientBusinessObject> dataList,Map<String,String> errorMap){
      Map<String, CodeClassifyTemplateAttrVO> referAttrVOMap = attrVOS.stream().filter(
         s -> (StringUtils.isNotBlank(s.getReferBtmId()) || StringUtils.isNotBlank(s.getReferConfig()))
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if(!CollectionUtils.isEmpty(referAttrVOMap)){
         Map<String/**表格和值的属性**/,Map<String/**显示属性的值**/,List<String>/**表格里的值**/>> linkValueMap = new HashMap<>();
         referAttrVOMap.forEach((attrId,attrVO)->{
            dataList.stream().forEach(cbo -> {
               String text = cbo.getAttributeValue(attrId);
               if(StringUtils.isNotBlank(text)){
                  UIFormReferVO referVO = getReferVO(attrVO);
                  String valueField = getValueField(referVO);
                  String showText = getTextField(referVO);
                  String tableAndAttr = VciBaseUtil.getTableName(referVO.getReferType()) + "#" + valueField;
                  Map<String, List<String>> showTextMap = linkValueMap.getOrDefault(tableAndAttr, new HashMap<>());
                  List<String> textList = showTextMap.getOrDefault(showText, new ArrayList<>());
                  if(!textList.contains(text)) {
                     textList.add(text);
                  }
                  showTextMap.put(showText,textList);
                  linkValueMap.put(tableAndAttr,showTextMap);
               }
            });
         });
         if(!CollectionUtils.isEmpty(linkValueMap)){
            //需要逐个表的值字段,逐个查询
            Map<String/**表格和值属性**/,Map<String/**显示属性**/, Map<String/**值**/,String/**显示的值**/>>> linkCboMap = new HashMap<>();
            linkValueMap.forEach((tableAndAttr,showValueMap)->{
               String[] split = tableAndAttr.split("#");
               String table = split[0];
               String valueField = split[1].toLowerCase(Locale.ROOT);
               Map<String,Map<String,String>> dataMap = new HashMap<>();
               showValueMap.forEach((showText,valueList)->{
                  Map<String,String> valueOidTextMap = new HashMap<>();
                  List<List<String>> valueCollections = VciBaseUtil.switchListForOracleIn(valueList);
                  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);
                     if(!CollectionUtils.isEmpty(cbos)){
                        valueOidTextMap.putAll(cbos.stream().collect(Collectors.toMap(s->s.getAttributeValue(valueField),t->t.getAttributeValue(showText))));
                     }
                  });
                  dataMap.put(showText,valueOidTextMap);
               });
               linkCboMap.put(tableAndAttr,dataMap);
            });
            referAttrVOMap.forEach((attrId,attrVO)->{
               dataList.stream().forEach(cbo -> {
                  String text = cbo.getAttributeValue(attrId);
                  if (StringUtils.isNotBlank(text)) {
                     UIFormReferVO referVO = getReferVO(attrVO);
                     String valueField = getValueField(referVO);
                     String showText = getTextField(referVO);
                     String tableAndAttr = VciBaseUtil.getTableName(referVO.getReferType()) + "#" + valueField;
                     if(!linkCboMap.containsKey(tableAndAttr)){
                        String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                        errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";参数属性[" + attrVO.getName() + "]的值在系统中不存在" );
                     }else{
                        Map<String, Map<String, String>> dataMap = linkCboMap.get(tableAndAttr);
                        if(!dataMap.containsKey(showText)){
                           String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                           errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";参数属性[" + attrVO.getName() + "]的值在系统中不存在" );
                        }else{
                           Map<String, String> data = dataMap.get(showText);
                           final boolean[] fined = {false};
                           data.forEach((key,value)->{
                              if(value.equalsIgnoreCase(text)){
                                 fined[0] = true;
                                 try {
                                    cbo.setAttributeValue(attrId, key);
                                 }catch (Throwable e){
                                 }
                              }
                           });
                           if(!fined[0]){
                              String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                              errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";参数属性[" + attrVO.getName() + "]的值在系统中不存在" );
                           }
                        }
                     }
                  }
               });
            });
         }
      }
   }
   /**
    * ä»Žå±žæ€§ä¸ŠèŽ·å–å‚ç…§çš„å†…å®¹
    * @param attrVO å±žæ€§çš„信息
    * @return å‚照的内容
    */
   private UIFormReferVO getReferVO(CodeClassifyTemplateAttrVO attrVO){
      UIFormReferVO referVO = null;
      if(StringUtils.isNotBlank(attrVO.getReferConfig())){
         referVO = JSONObject.parseObject(attrVO.getReferConfig(),UIFormReferVO.class);
      }else{
         referVO = new UIFormReferVO();
         referVO.setReferType(attrVO.getReferBtmId());
         referVO.setValueField(VciQueryWrapperForDO.OID_FIELD);
         referVO.setTextField("name");
      }
      return referVO;
   }
   /**
    * èŽ·å–å‚ç…§ä¸­çš„å€¼çš„å­—æ®µ
    * @param referVO å‚照的对象
    * @return é»˜è®¤ä¸ºOid,有多个的时候,获取第一个
    */
   private String getValueField(UIFormReferVO referVO){
      String showText = referVO.getValueField();
      if(StringUtils.isBlank(showText)){
         return "oid";
      }
      if(showText.contains(",")){
         //防止万一有多个,看看有没有oid
         List<String> strings = VciBaseUtil.str2List(showText);
         if(strings.contains("oid")){
            showText = "oid";
         }else{
            showText = strings.get(0);
         }
      }
      return showText;
   }
   /**
    * èŽ·å–å‚ç…§ä¸­çš„æ˜¾ç¤ºå†…å®¹çš„å­—æ®µ
    * @param referVO å‚照的对象
    * @return é»˜è®¤ä¸ºname,有多个的时候,获取第一个
    */
   private String getTextField(UIFormReferVO referVO){
      String showText = referVO.getTextField();
      if(StringUtils.isBlank(showText)){
         return "name";
      }
      if(showText.contains(",")){
         //防止万一有多个,看看有没有name
         List<String> strings = VciBaseUtil.str2List(showText);
         if(strings.contains("name")){
            showText = "name";
         }else{
            showText = strings.get(0);
         }
      }
      return showText;
   }
   /**
    * å¤„理枚举的显示对象
    * @param attrVOS æ¨¡æ¿å±žæ€§
    * @param dataList excel的数据内容
    * @param errorMap é”™è¯¯ä¿¡æ¯çš„æ˜ å°„
    */
   private void batchSwitchEnumAttrOnOrder(Collection<CodeClassifyTemplateAttrVO> attrVOS,List<ClientBusinessObject> dataList,
                                 Map<String,String> errorMap ) {
      Map<String, CodeClassifyTemplateAttrVO> dateAttrVOMap = attrVOS.stream().filter(
         s -> (StringUtils.isNotBlank(s.getEnumString()) || StringUtils.isNotBlank(s.getEnumId()))
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(dateAttrVOMap)) {
         dateAttrVOMap.forEach((attrId, attrVO) -> {
            dataList.stream().forEach(cbo -> {
               String text = cbo.getAttributeValue(attrId);
               if(StringUtils.isNotBlank(text)){
                  List<KeyValue> valueList = engineService.listComboboxItems(attrVO);
                  boolean fined = false;
                  for (int i = 0; i < valueList.size(); i++) {
                     KeyValue keyValue = valueList.get(i);
                     //if(keyValue.getValue().equalsIgnoreCase(text)){
                     if(keyValue.getValue().equalsIgnoreCase(text)||keyValue.getKey().equalsIgnoreCase(text)){
                        try {
                           cbo.setAttributeValue(attrId, keyValue.getKey());
                        }catch (Throwable e){
                           log.error("设置属性出错");
                        }
                        fined = true;
                        break;
                     }
                  }
                  if(!fined){
                     String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                     errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";属性[" + attrVO.getName() + "]的值不符合下拉的要求");
                  }
               }
            });
         });
      }
   }
   /**
    * æ‰¹é‡æ ¡éªŒæ•°æ®çš„信息
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    * @param cboList æ•°æ®çš„内容
    */
   private void batchCheckRequiredAttrOnOrder(CodeClassifyTemplateVO templateVO,List<ClientBusinessObject> cboList,Map<String,String> errorMap){
      Map<String, CodeClassifyTemplateAttrVO> requiredAttrMap = templateVO.getAttributes().stream().filter(s ->
         VciBaseUtil.getBoolean(s.getRequireFlag()) && StringUtils.isBlank(s.getComponentRule()) && StringUtils.isBlank(s.getClassifyInvokeLevel())//不能是组合的和分类注入的
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      //与MdmEngineServiceImpl里面的checkRequiredAttrOnOrder é€»è¾‘应该相似
      if(!CollectionUtils.isEmpty(requiredAttrMap)) {
         Set<String> nullRowIndex = cboList.stream().filter(cbo -> requiredAttrMap.keySet().stream().anyMatch(attrId -> StringUtils.isBlank(cbo.getAttributeValue(attrId)))).map(cbo -> cbo.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toSet());
         if(!CollectionUtils.isEmpty(nullRowIndex)){
            String checkAttr = requiredAttrMap.values().stream().map(CodeClassifyTemplateAttrVO::getName).collect(Collectors.joining(","));
            nullRowIndex.stream().forEach(rowIndex->{
               errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";校验规则不通过,有校验的属性为" + checkAttr);
            });
         }
      }
   }
   /**
    * å¤„理分类注入
    * @param attrVOS æ¨¡æ¿å±žæ€§
    * @param dataList excel的数据内容
    * @param classifyFullInfo åˆ†ç±»çš„全路径
    */
   private void batchSwitchClassifyAttrOnOrder(Collection<CodeClassifyTemplateAttrVO> attrVOS,List<ClientBusinessObject> dataList,
                                    CodeClassifyFullInfoBO classifyFullInfo,boolean isImPort) {
      Map<String, CodeClassifyTemplateAttrVO> dateAttrVOMap = attrVOS.stream().filter(
         s -> StringUtils.isNotBlank(s.getClassifyInvokeAttr()) && StringUtils.isNotBlank(s.getClassifyInvokeAttr())
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      Map<String,CodeClassifyFullInfoBO> classifyFullInfoMap=new HashMap<>();
      classifyFullInfoMap.put(classifyFullInfo.getCurrentClassifyVO().getOid(),classifyFullInfo);
      if (!CollectionUtils.isEmpty(dateAttrVOMap)) {
         dataList.stream().forEach(cbo -> {
            dateAttrVOMap.forEach((attrId, attrVO) -> {
               //分类注入的编号或者名称,
               //层级包含指定层和最小层
               CodeClassifyVO classifyVO = null;
               if(!CodeLevelTypeEnum.MIN.getValue().equalsIgnoreCase(attrVO.getClassifyInvokeLevel()) && !"min".equalsIgnoreCase(attrVO.getClassifyInvokeLevel())) {
                  //指定了层级的
                  //注意,因为查询上级分类出来的层级是倒序的,即顶层节点是最大的值
                  if(isImPort){
                     if(!classifyFullInfoMap.containsKey(cbo.getAttributeValue(CODE_CLASSIFY_OID_FIELD))) {
                        CodeClassifyFullInfoBO currentClassifyFullInfo = classifyService.getClassifyFullInfo(cbo.getAttributeValue(CODE_CLASSIFY_OID_FIELD));
                        classifyFullInfoMap.put(currentClassifyFullInfo.getCurrentClassifyVO().getOid(), currentClassifyFullInfo);
                     }
                  }
                  CodeClassifyFullInfoBO newClassifyFullInfo= classifyFullInfoMap.get(cbo.getAttributeValue(CODE_CLASSIFY_OID_FIELD));
                  List<CodeClassifyVO> classifyVOS = newClassifyFullInfo.getParentClassifyVOs().stream().sorted(((o1, o2) -> o2.getDataLevel().compareTo(o1.getDataLevel()))).collect(Collectors.toList());
                  int level = VciBaseUtil.getInt(attrVO.getClassifyInvokeLevel());
                  if (classifyVOS.size()>=level && level > 0 ) {
                     classifyVO = classifyVOS.get(level-1);
                  }
               }else{
                  //当前的分类
                  classifyVO = classifyFullInfo.getCurrentClassifyVO();
               }
               try {
                  if (classifyVO == null) {
                     //说明层级有误
                     cbo.setAttributeValue(attrId, "分类树上没有层级[" + attrVO.getClassifyInvokeLevel() + "]");
                  } else {
                     Map<String, String> classifyDataMap = VciBaseUtil.objectToMapString(classifyVO);
                     String value = classifyDataMap.getOrDefault(attrVO.getClassifyInvokeAttr(), "");
                     cbo.setAttributeValue(attrId, value);
                  }
               } catch (Throwable e) {
                  log.error("设置属性错误", e);
               }
            });
         });
      }
   }
   /**
    * æ ¡éªŒå…³é”®å±žæ€§
    * @param classifyFullInfo åˆ†ç±»çš„全部信息
    * @param templateVO æ¨¡æ¿çš„内容,必须包含模板属性
    * @param cboList æ‰¹é‡çš„æ•°æ®
    */
   private CodeImportResultVO batchCheckKeyAttrOnOrder(CodeClassifyFullInfoBO classifyFullInfo, CodeClassifyTemplateVO templateVO,
                                          List<ClientBusinessObject> cboList) {
      //与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));
      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());
      //1. æˆ‘们需要先判断excel导入的内容是否正确
      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));
      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<ClientBusinessObject>> indexTODataMap=new HashMap<>();
      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)) {
            CodeTemplateAttrSqlBO sqlBO = engineService.getSqlByTemplateVO(classifyFullInfo.getTopClassifyVO().getBtmtypeid(), templateVO, conditionMap, null);
            boolean isKeyCheck= commonsMapper.queryCountBySql(sqlBO.getSqlCount()) > 0;
            if(isKeyCheck){
               List<Map<String,String>> newDataList=  commonsMapper.queryByOnlySqlForMap(sqlBO.getSqlUnPage());
               List<ClientBusinessObject> newCboList=   ChangeMapTOClientBusinessObjects(newDataList);
               indexTODataMap.put(cbo.getAttributeValue(IMPORT_ROW_INDEX),newCboList);
            }
            return isKeyCheck;
         }else{
            return false;
         }
      }).collect(Collectors.toList());
      if(!CollectionUtils.isEmpty(repeatDataMap)){
         resultVO.setKeyAttrRepeatRowIndexList(repeatDataMap.stream().map(s->s.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toSet()));
      }
      //resultVO.setIndexTODataMap(indexTODataMap);
      //resultVO.setSuccess(true);
      return resultVO;
   }
   /**
    * èŽ·å–å¯¼å…¥çš„å†…å®¹ä¸­å…³é”®å±žæ€§é‡å¤çš„è¡Œå·
    * @param ketAttrMap å…³é”®å±žæ€§çš„æ˜ å°„
    * @param dataList å¯¼å…¥çš„æ•°æ®
    * @param keyRuleVO å…³é”®å±žæ€§æŽ§åˆ¶è§„则
    * @return é‡å¤çš„行号
    */
   private Set<String> getSelfRepeatRowIndex(Map<String/**属性的编号**/, CodeClassifyTemplateAttrVO> ketAttrMap,
                                   List<ClientBusinessObject> dataList,CodeKeyAttrRepeatVO keyRuleVO){
      Set<String> selfRepeatRowIndexList = new CopyOnWriteArraySet<>();
      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());
      //必须将属性按照顺序排序好
      List<CodeClassifyTemplateAttrVO> attrVOList = ketAttrMap.values().stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).collect(Collectors.toList());
      Map<String/**行号**/,String/**关键属性的组合内容**/> rowIndexKeyStringMap = new HashMap<>();
      dataList.parallelStream().forEach(cbo-> {
         String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
         StringBuilder sb = new StringBuilder();
         for (int i = 0; i < attrVOList.size(); i++) {
            CodeClassifyTemplateAttrVO attrVO = attrVOList.get(i);
            String attrId = attrVO.getId().toLowerCase(Locale.ROOT);
            String value = cbo.getAttributeValue( attrId);
            if (value == null) {
               value = "";
            }
            if(trim){
               value = value.trim();
            }
            if(trimAll){
               value = value.replace(" ","");
            }
            if(ignoreCase){
               value = value.toLowerCase(Locale.ROOT);
            }
            if(ignoreWidth){
               value = VciBaseUtil.toDBC(value);
            }
            sb.append(value).append("${ks}");
         }
         String keyString = sb.toString();
         if(rowIndexKeyStringMap.containsValue(keyString) && StringUtils.isNotBlank(keyString)){
            selfRepeatRowIndexList.add(rowIndex);
         }else {
            rowIndexKeyStringMap.put(rowIndex, sb.toString());
         }
      });
      //因为只是关键属性重复,所以我们不能重复的多条选一条来报错
      return selfRepeatRowIndexList;
   }
   /**
    * excel的标题上获取字段所在的位置
    * @param titleRowData æ ‡é¢˜çš„内容
    * @param attrNameIdMap æ¨¡æ¿ä¸­å±žæ€§åç§°å’Œè‹±æ–‡çš„æ˜ å°„
    * @param fieldIndexMap ä½ç½®å’Œè‹±æ–‡å­—段的映射
    */
   private void getFieldIndexMap(List<String> titleRowData,Map<String/**名称**/,String/**字段名**/> attrNameIdMap,Map<Integer/**位置**/,String/**英文名字**/> fieldIndexMap){
      for (int i = 0; i < titleRowData.size(); i++) {
         String title = titleRowData.get(i);
         String id = attrNameIdMap.getOrDefault(title.replace(KEY_ATTR_CHAR,"").replace(REQUIRED_CHAR
            ,""),"");
         if(com.alibaba.cloud.commons.lang.StringUtils.isBlank(id) && "分类路径".equalsIgnoreCase(title)){
            id = CODE_CLASSIFY_OID_FIELD;
         }
         if(com.alibaba.cloud.commons.lang.StringUtils.isBlank(id) && "码段宽度".equalsIgnoreCase(title)){
            id = CODE_SEC_LENGTH_FIELD;
         }
         if(com.alibaba.cloud.commons.lang.StringUtils.isBlank(id) && "企业编码".equalsIgnoreCase(title)){
            id = CODE_FIELD;
         }
         if(com.alibaba.cloud.commons.lang.StringUtils.isNotBlank(id)){
            fieldIndexMap.put(i,id);
         }
      }
   }
   private List<ClientBusinessObject> ChangeMapTOClientBusinessObjects(List<Map<String,String>> oldDataMap){
      List<ClientBusinessObject> clientBusinessObjectList=new CopyOnWriteArrayList<>();
      oldDataMap.parallelStream().forEach(dataMap->{
         ClientBusinessObject clientBusinessObject=new ClientBusinessObject();
         DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(dataMap,clientBusinessObject);
         dataMap.forEach((key,value)->{
            clientBusinessObject.setAttributeValue(key,value);
         });
      });
      return clientBusinessObjectList;
   }
   /***
    * æ­£ç¡®é”™è¯¯æ•°æ®redis缓存
    * @param uuid
    * @param templateVO
    * @param rowIndexCbo
    * @param dataSet
    * @param fieldIndexMap
    * @param errorMap
    * @param isok
    */
   private void createRedisDatas(String uuid,CodeClassifyTemplateVO templateVO,Map<String,ClientBusinessObject> rowIndexCbo, SheetDataSet dataSet, Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap,Map<String,String> errorMap,boolean isok){
      List<SheetRowData>  needsheetRowDataList =new ArrayList<>();
      if(errorMap.size()>0) {
         //要把以上的错误的都抛出后,再继续处理时间和组合规则
         needsheetRowDataList = dataSet.getRowData().stream().filter(cbo -> {
            String rowIndex=cbo.getRowIndex();
            return  isok? !errorMap.containsKey(rowIndex):errorMap.containsKey(rowIndex);
         }).collect(Collectors.toList());
      }else{
         needsheetRowDataList= dataSet.getRowData();
      }
      Map<String/**中文名称**/, SheetRowData/**英文名称**/> rowIdexDataMap = needsheetRowDataList.stream().collect(Collectors.toMap(s -> s.getRowIndex(), t -> t,(o1, o2)->o2));
      Map<String,CodeImprotDataVO> clsfDataMap=new HashMap<>();
      rowIndexCbo .forEach((rowIndex, cbo) -> {
         CodeImprotDataVO codeImprotDataVO = new CodeImprotDataVO();
         codeImprotDataVO.setTemplateOid(templateVO.getOid());
         List<Map<String, String>> dataList = new ArrayList<>();
         if(rowIdexDataMap.containsKey(rowIndex)){
            SheetRowData sheetRowData=rowIdexDataMap.get(rowIndex);
            Map<String, String> dataMap = new HashMap<>();
            Map<Integer, String> data = sheetRowData.getData();
            fieldIndexMap.forEach((integer, s) -> {
               String field = fieldIndexMap.get(integer);
               if (data.containsKey(integer)) {
                  String vlues = data.get(integer);
                  dataMap.put(field, vlues);
               }
            });
            dataMap.put("oid",cbo.getOid());
            dataList.add(dataMap);
         }
         if(clsfDataMap.containsKey(templateVO.getOid())){
            codeImprotDataVO=clsfDataMap.get(templateVO.getOid());
            dataList.addAll(codeImprotDataVO.getDatas());
         }
         codeImprotDataVO.setColNames(dataSet.getColName());
         codeImprotDataVO.setDatas(dataList);
         clsfDataMap.put(templateVO.getOid(),codeImprotDataVO);
      });
      if(!CollectionUtils.isEmpty(clsfDataMap)) {
         Collection codeImprotDataVOS=clsfDataMap.values();
         List<CodeImprotDataVO> codeImprotDataVOList=new ArrayList<>();
         codeImprotDataVOList.addAll(codeImprotDataVOS);
         bladeRedis.set(uuid+"-"+templateVO.getOid(), codeImprotDataVOList);
         bladeRedis.expire(uuid+"-"+templateVO.getOid(),BATCHADD_REDIS_TIME);//redis过期时间
      }
   }
   /****
    * æ•°æ®ç›¸ä¼¼é¡¹æ•°æ®æ ¡éªŒredis缓存
    * @param codeClassifyOid
    * @param templateVO
    * @param cboList
    * @param resembleMap
    * @param btmtypeid
    * @param dataResembleVOS
    */
   private void bathcResembleQuery(String codeClassifyOid, CodeClassifyTemplateVO templateVO, List<ClientBusinessObject> cboList,Map<String,String>resembleMap,String btmtypeid,List<DataResembleVO> dataResembleVOS){
      CodeClassifyFullInfoBO fullInfoBO = classifyService.getClassifyFullInfo(codeClassifyOid);
      Map<String, String> conditionMap = new HashMap<>();
      CodeResembleRuleVO resembleRuleVO = Optional.ofNullable(engineService.getUseResembleRule(fullInfoBO, fullInfoBO.getCurrentClassifyVO())).orElseGet(() -> new CodeResembleRuleVO());
      //需要获取是否有相似查询属性
      Map<String, CodeClassifyTemplateAttrVO> attrVOs = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getSameRepeatAttrFlag())).collect(Collectors.toMap(s -> s.getId(), t -> t));
      if (CollectionUtils.isEmpty(attrVOs)) {
         return;
      }
      Map<String,CodeImprotResembleVO> codeImprotResembleVOMap=new HashMap<>();
      List<CodeImprotResembleVO> codeImprotResembleVOList=new ArrayList<>();
      Map<String,String> rowIndePathMap=new HashMap<>();
      cboList.stream().forEach(clientBusinessObject -> {
         CodeImprotResembleVO codeImprotResembleVO=new CodeImprotResembleVO();
         final String[] path = {""};
         List<String> fieldList=new ArrayList<>();
         List<String> rowIndeList=new ArrayList<>();
         String rowIndex = clientBusinessObject.getAttributeValue(IMPORT_ROW_INDEX);
         attrVOs.forEach((attrId, attrVO) -> {
            String value="";
                /*if (VciQueryWrapperForDO.BASIC_FIELD_MAP.containsKey(attrId)) {
                    value = WebUtil.getStringValueFromObject(WebUtil.getValueFromField(WebUtil.getFieldForObject(attrId, orderDTO.getClass()).getName(), orderDTO));
                }else {*/
            value= clientBusinessObject.getAttributeValue(attrId);
            // }
            fieldList.add(attrId);
            value=StringUtils.isBlank(value)?"":value;
            path[0] +=value+"#";
            engineService.wrapperResembleConditionMap(value, resembleRuleVO, attrId, conditionMap);
         });
         List<Map<String,String>> dataMap=new ArrayList<>();
         if(codeImprotResembleVOMap.containsKey(path[0])) {
            codeImprotResembleVO=codeImprotResembleVOMap.get(path[0]);
            rowIndeList=codeImprotResembleVO.getRownIndex();
            dataMap=  codeImprotResembleVO.getDataList();
            resembleMap.put(rowIndex, "存在相似数据");
         }else{
            if (!CollectionUtils.isEmpty(conditionMap)) {
               Map<String, String> andConditionMap = new HashMap<>();
               andConditionMap.put("islastr", "1");
               andConditionMap.put("islastv", "1");
               conditionMap.putAll(andConditionMap);
               PageHelper pageHelper = new PageHelper(-1);
               pageHelper.addDefaultDesc("id");
               CodeTemplateAttrSqlBO sqlBO = engineService.getSqlByTemplateVO(btmtypeid, templateVO, conditionMap, pageHelper);
               List<Map<String,String>> dataMapList=commonsMapper.queryByOnlySqlForMap(sqlBO.getSqlUnPage());
               List<ClientBusinessObject> resembleCboList=   ChangeMapTOClientBusinessObjects(dataMapList);
               if(!CollectionUtils.isEmpty(resembleCboList)) {
                  List<Map<String, String>> finalDataMap = dataMap;
                  resembleCboList.stream().forEach(cbo->{
                     Map<String,String> resembDataMap=new HashMap<>();
                     fieldList.stream().forEach(field->{
                        String value=cbo.getAttributeValue(field);
                        value=StringUtils.isBlank(value)?"":value;
                        resembDataMap.put(field,value);
                     });
                     resembDataMap.put("codetemplateoid",templateVO.getOid());
                     resembDataMap.put("id",StringUtils.isBlank(cbo.getAttributeValue("id"))?"":cbo.getAttributeValue("id"));
                     resembDataMap.put("rowIndex","");
                     resembDataMap.put("oid",cbo.getOid());
                     finalDataMap.add(resembDataMap);
                  });
                  resembleMap.put(rowIndex, "存在相似数据");
               }
            }
         }
         rowIndePathMap.put(rowIndex,path[0]);
         rowIndeList.add(rowIndex);
         codeImprotResembleVO.setPath(path[0]);
         codeImprotResembleVO.setRownIndex(rowIndeList);
         codeImprotResembleVO.setConditionMap(conditionMap);
         codeImprotResembleVO.setFields(fieldList);
         codeImprotResembleVO.setDataList(dataMap);
         codeImprotResembleVOMap.put(path[0],codeImprotResembleVO);
      });
      Map<String, ClientBusinessObject> cboMap = cboList.stream().filter(cbo -> cbo != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getAttributeValue((IMPORT_ROW_INDEX)), t -> t));
      if(!CollectionUtils.isEmpty(rowIndePathMap)){
         rowIndePathMap.forEach((rowIndex, path) -> {
            if(codeImprotResembleVOMap.containsKey(path)){
               CodeImprotResembleVO codeImprotResembleVO=  codeImprotResembleVOMap.get(path);
               List<String> fieldList=codeImprotResembleVO.getFields();
               List<String> rownIndexList= codeImprotResembleVO.getRownIndex();
               List<String> newRownIndexList = rownIndexList.stream().filter(cbo -> {
                  return rowIndex!=cbo;
               }).collect(Collectors.toList());
               newRownIndexList.stream().forEach(s -> {
                  resembleMap.put(s, "存在相似数据");
               });
               List<Map<String, String>>newDataList=new ArrayList<>();
               DataResembleVO dataResembleVO=new DataResembleVO();
               dataResembleVO.setOid(cboMap.get(rowIndex).getOid());
               List<ClientBusinessObject> needSaveCboList = cboList.stream().filter(cbo -> {
                  String newRowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                  return rownIndexList.contains(newRowIndex)&&(!newRowIndex.equalsIgnoreCase(rowIndex));
               }).collect(Collectors.toList());
               if(!CollectionUtils.isEmpty(needSaveCboList)) {
                  needSaveCboList.stream().forEach(cbo -> {
                     String newRowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                     Map<String, String> resembDataMap = new HashMap<>();
                     fieldList.stream().forEach(field -> {
                        String value = cbo.getAttributeValue(field);
                        value = StringUtils.isBlank(value) ? "" : value;
                        resembDataMap.put(field, value);
                     });
                     resembDataMap.put("codetemplateoid",templateVO.getOid());
                     resembDataMap.put("id",StringUtils.isBlank(cbo.getAttributeValue("id"))?"":cbo.getAttributeValue("id"));
                     resembDataMap.put("rowIndex", newRowIndex);
                     resembDataMap.put("oid",cbo.getOid());
                     newDataList.add(resembDataMap);
                  });
               }
               List<Map<String, String>>dataList=codeImprotResembleVO.getDataList();
               newDataList.addAll(dataList);
               dataResembleVO.setDataList(newDataList);
               dataResembleVOS.add(dataResembleVO);
            }
         });
      }
   }
   /***
    * å­˜å‚¨åˆ†ç±»å¯¹è±¡åŠå…¶åˆ—名
    * @param uuid
    * @param templateVOList
    * @param dataSet
    * @param fieldIndexMap
    * @param iscContain
    */
   private  void createRedisByCodeClassify(String uuid,CodeClassifyTemplateVO templateVOList,SheetDataSet dataSet, Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap,boolean iscContain){
      List<ColumnVO> columnVOList = new ArrayList<>();
      List<String> outNameList = dataSet.getColName();
      fieldIndexMap.forEach((integer, s) -> {
         ColumnVO columnVOS = new ColumnVO();
         String field = fieldIndexMap.get(integer);
         String outName = outNameList.get(integer);
         columnVOS.setField(field);
         columnVOS.setTitle(outName);
         columnVOList.add(columnVOS);
      });
      CodeImportTemplateVO codeImportTemplateVO=new CodeImportTemplateVO();
      codeImportTemplateVO.setCodeClassifyTemplateVO(templateVOList);
      codeImportTemplateVO.setCloNamesList(columnVOList);
      List<CodeImportTemplateVO> codeImportTemplateVOs= new ArrayList<>();
      codeImportTemplateVOs.add(codeImportTemplateVO);
      if(codeImportTemplateVOs.size()>0) {
         bladeRedis.set(uuid, codeImportTemplateVOs);
         bladeRedis.expire(uuid, BATCHADD_REDIS_TIME);//redis过期时间
      }
   }
   /**
    * æ‹·è´ä¸šåŠ¡ç±»åž‹åˆ°map
    * @param cbo ä¸šåŠ¡æ•°æ®
    * @param map map
    */
   public static void copyValueToMapFromCbos(ClientBusinessObject cbo,Map<String,String> map){
      if(cbo!=null){
         copyValueToMapFromBos(cbo,map);
      }
   }
   /**
    * æ‹·è´ä¸šåŠ¡ç±»åž‹åˆ°map
    * @param bo ä¸šåŠ¡æ•°æ®
    * @param map map
    */
   public static void copyValueToMapFromBos(ClientBusinessObject bo,Map<String,String> map){
      if(bo!=null ){
         //先把所有的字段映射找到
         AttributeValue[] newAList = bo.newAttrValList;
         AttributeValue[] hisAList = bo.hisAttrValList;
         if(hisAList!=null&&hisAList.length>0){//
            for(int i = 0 ; i < hisAList.length;i++){
               AttributeValue av = hisAList[i];
               String attrName = av.attrName.toLowerCase();
               map.put(attrName, av.attrVal);
            }
         }
         if(newAList!=null&&newAList.length>0){//NEW的优先级高些
            for(int i = 0 ; i < newAList.length;i++){
               AttributeValue av = newAList[i];
               String attrName = av.attrName.toLowerCase();
               map.put(attrName, av.attrVal);
            }
         }
      }
   }
}