xiejun
2023-12-06 e9a590e862148092027510b15d33cdd32691a6f5
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmIOServiceImpl.java
@@ -1,15 +1,17 @@
package com.vci.ubcs.code.service.impl;
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;
import com.vci.ubcs.code.applyjtcodeservice.vo.DockingPreAttrMappingVO;
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.CodeExportAttrDTO;
import com.vci.ubcs.code.dto.CodeOrderDTO;
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;
@@ -27,6 +29,7 @@
import com.vci.ubcs.omd.feign.IBtmTypeClient;
import com.vci.ubcs.omd.feign.IWebSecretClient;
import com.vci.ubcs.omd.vo.BtmTypeVO;
import com.vci.ubcs.omd.vo.RevisionRuleVO;
import com.vci.ubcs.starter.bo.WriteExcelData;
import com.vci.ubcs.starter.exception.VciBaseException;
import com.vci.ubcs.starter.poi.bo.ReadExcelOption;
@@ -37,6 +40,7 @@
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.util.SaveLogUtil;
import com.vci.ubcs.starter.web.constant.QueryOptionConstant;
import com.vci.ubcs.starter.web.enumpck.BooleanEnum;
import com.vci.ubcs.starter.web.enumpck.UserSecretEnum;
@@ -46,6 +50,7 @@
import com.vci.ubcs.starter.web.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import oracle.sql.TIMESTAMP;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@@ -53,9 +58,13 @@
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Workbook;
import org.aspectj.apache.bcel.classfile.Code;
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;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -63,10 +72,19 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -175,11 +193,16 @@
    */
   @Resource
   private IWebSecretClient secretService;
   /**
    * 日志保存工具类
    */
   @Autowired
   private SaveLogUtil saveLogUtil;
   /**
    * 导出的十万条
    * 客户现场excel为老版本,导出的总数限制为65535
    */
   public static final int EXPORT_LIMIT = 100000;
   public static final int EXPORT_LIMIT = 65535;
   /**
    * 批量申请:选取选中分类下的所有模板关键属性,相似属性,必填属性,写入execl中
@@ -475,6 +498,123 @@
   }
   /**
    * 生成批量修改导入的文件
    *
    * @param codeClassifyOid 分类的主键
    * @return excel的文件地址
    */
   @Override
   public String downloadImportExcelBatchEdit(String codeClassifyOid) {
      List<CodeClassifyTemplateVO> templateVOList=new ArrayList<>();
      VciBaseUtil.alertNotNull("导出模板","导出的配置",codeClassifyOid,"主题库分类的主键");
      CodeClassifyVO codeClassifyVO = classifyService.getObjectByOid(codeClassifyOid);
      templateVOList= templateService.childTemplates(codeClassifyOid);
      WriteExcelOption eo = new WriteExcelOption();
      eo.setAppend(true);
      //增加模板的信息导入
      LinkedList<WriteExcelData> tempEDList = new LinkedList<>();
      tempEDList.add(new WriteExcelData(0,0,"编号"));
      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> codeClassifyTemplateAttrVOList=codeClassifyTemplateVO.getAttributes();
         if(!CollectionUtils.isEmpty(codeClassifyTemplateAttrVOList)) {
            if (CollectionUtils.isEmpty(codeClassifyTemplateAttrVOList)) {
               throw new VciBaseException("模板没有配置属性");
            }
         }
         List<CodeClassifyTemplateAttrVO> templateAttrVOS = codeClassifyTemplateAttrVOList.stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId())
               && StringUtils.isBlank(s.getComponentRule())
               && StringUtils.isBlank(s.getClassifyInvokeAttr())
               && (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,"编码(id)",""));
//            excelDataList.add(new WriteExcelData(0,1,"码段宽度",""));
//         excelDataList.add(new WriteExcelData(0,1,!CollectionUtils.isEmpty(idAttrVOList)?idAttrVOList.get(0).getName():"企业编码",idAttrVOList.get(0).getId()));
//         }
         for (int i = 0; i < templateAttrVOS.size(); i++) {
            CodeClassifyTemplateAttrVO attrVO = templateAttrVOS.get(i);
            Object text = attrVO.getName();
            text = exportKeyAndRequired(workbook,attrVO,text);
            int colIndex = 1 + i;
            WriteExcelData excelData = new WriteExcelData(0, colIndex, text,attrVO.getId());
            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() + ("_属性批量修改模板.xls");
      eo.addSheetDataList(templateVOList.size()+"模板信息【请勿删除或移动】",tempEDList);
      ExcelUtil.writeDataToFile(excelName,eo);
      return excelName;
   }
   /**
    * 获取码段宽度
    * @param codeClassifyOid
    * @return
@@ -538,7 +678,7 @@
    * @return  有错误信息的excel的文件
    */
   @Override
   public CodeImProtRusultVO batchImportCode(CodeOrderDTO orderDTO, File file) {
   public CodeImProtRusultVO batchImportCode(CodeOrderDTO orderDTO, File file) throws Exception {
      VciBaseUtil.alertNotNull(orderDTO,"编码申请相关的数据",orderDTO.getCodeClassifyOid(),"主题库分类主键");
      ReadExcelOption reo = new ReadExcelOption();
      reo.setReadAllSheet(true);
@@ -683,7 +823,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)){
@@ -810,19 +950,357 @@
    */
   @Override
   public CodeImProtRusultVO batchImportHistoryData(String codeClassifyOid, String classifyAttr,File file) throws  Throwable{
      try {
         VciBaseUtil.alertNotNull(codeClassifyOid,"分类的主键");
         ReadExcelOption reo = new ReadExcelOption();
         reo.setReadAllSheet(true);
         List<SheetDataSet> sheetDataSetList = ExcelUtil.readDataObjectFromExcel(file,null,reo);
         if (sheetDataSetList.size() > LIMIT + 1) {
            throw new VciBaseException("为了保证系统的稳定性,请一次不要导入超过1万条的数据");
         }
         Map<String,List<WriteExcelData>> shetNameMap=new HashMap<>();
         //相似项目查重
         String uuid=VciBaseUtil.getPk();
         boolean isCreateUUid=false;
         boolean isExport=false;
         //long start = System.currentTimeMillis();
         // 记录导入成功的总数
         List<Integer> importCount = new ArrayList<>();
         CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
         for(int i=0;i<sheetDataSetList.size()-1;i++) {
            if (CollectionUtils.isEmpty(sheetDataSetList) || CollectionUtils.isEmpty(sheetDataSetList.get(i).getRowData())
               || sheetDataSetList.get(i).getRowData().size() < 1) {
               continue;
            }
            // 单次导入数量限制
            if(sheetDataSetList.get(i).getRowData().size() > IMPORT_DATA_LIMIT){
               throw new ServiceException(StringUtil.format("为了保证系统的稳定性,请一次不要导入超过{}条的数据",IMPORT_DATA_LIMIT));
            }
            //历史导入的时候不处理编码
            //----逻辑内容----
            //1. 分类的路径可以在页面上选择是分类编号还是分类的名称
            //2. 分类的路径,必须是当前导入选择的分类的节点,以及其下级节点
            //3. 通过数据要导入的分类去查找对应的编码规则
            //4. 数据存储和批量申请一样,
            //5. 需要单独处理企业编码的内容,
            //     5.1 企业编码在当前excel里不能重复
            //     5.2 企业编码在系统中不能重复(可以是已经回收的)
            //     5.3 企业编码的长度,和编码规则的长度要对应上
            //     5.4 获取流水码段的值,去除填充的字符,看流水号是多少,然后将流水号和现在的最大流水号判断,小于就直接录入,大于则修改最大流水号
            //     5.5 存储企业编码到allcode中
            //查询分类和模板
            //先找到每一行的标题,然后根据标题来获取对应的属性
            SheetDataSet dataSet = sheetDataSetList.get(i);
            List<SheetRowData> rowDataList = dataSet.getRowData();
            //找第一行,为了找标题
            CodeClassifyTemplateVO templateVO = new CodeClassifyTemplateVO();
            /**  if (!templateService.checkChildHasSameTemplate(classifyFullInfo.getCurrentClassifyVO().getOid())) {
             throw new VciBaseException("当前的分类以及下级分类的模板不相同");
             }***/
            //都转换完了。需要批量检查
            //找所有的分类路径,需要校验路径是否正确,是否都在当前的分类的下级
            List<CodeClassifyVO> childClassifyVOs = classifyService.listChildrenClassify(codeClassifyOid, true, classifyAttr, true);
            Map<String/**路径**/, CodeClassifyVO> pathMap = Optional.ofNullable(childClassifyVOs).orElseGet(() -> new ArrayList<>()).stream().collect(Collectors.toMap(s -> s.getPath().startsWith("#") ? s.getPath().substring(1) : s.getPath(), t -> t));
            List<String> titleRowData = dataSet.getColName();
            Map<String, String> errorMap = new ConcurrentHashMap<>();
            pathMap.put("#current#",classifyFullInfo.getCurrentClassifyVO());
            try {
               List<CodeClassifyTemplateVO> templateVOList= checkSamesTemplate(titleRowData,sheetDataSetList,i,pathMap,errorMap);
               templateVO= templateVOList.get(0);
            }catch (Throwable e){
               throw  new VciBaseException(e.getMessage());
            }
            List<SheetRowData> needowDataList = rowDataList.stream().filter(cbo -> {
               String rowIndex = cbo.getRowIndex();
               return !errorMap.containsKey(rowIndex);
            }).collect(Collectors.toList());
            //checkTemplateSync(sheetDataSetList, templateVO,i);
            //这里不除去默认的属性
            List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes();
            Map<Integer/**列号**/, String/**字段的名称**/> fieldIndexMap = new HashMap<>();
            Map<String/**中文名称**/, String/**英文名称**/> attrNameIdMap = attrVOS.stream().collect(Collectors.toMap(s -> s.getName(), t -> t.getId()));
            String idFieldName = attrVOS.stream().filter(s -> VciQueryWrapperForDO.ID_FIELD.equalsIgnoreCase(s.getId())).findFirst().orElseGet(() -> new CodeClassifyTemplateAttrVO()).getName();
            getFieldIndexMap(titleRowData, attrNameIdMap, fieldIndexMap);
            //先不用管属性是否都存在,先转换一下数据
            List<ClientBusinessObject> cboList = new ArrayList<>();
            String fullPath = getFullPath(classifyFullInfo);
            //我们需要获取到所有的下级分类的oid的路径,因为后面需要
            Map<String/**主键**/, String/**路径**/> childOidPathMap = getChildClassifyPathMap(classifyFullInfo, fullPath);
            excelToCbo(classifyFullInfo, fieldIndexMap, needowDataList, templateVO, cboList, fullPath, false);
            Map<String/**主键**/, CodeClassifyVO> classifyVOMap = Optional.ofNullable(childClassifyVOs).orElseGet(() -> new ArrayList<>()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
            classifyVOMap.put(classifyFullInfo.getCurrentClassifyVO().getOid(), classifyFullInfo.getCurrentClassifyVO());
            pathMap.put("#current#", classifyFullInfo.getCurrentClassifyVO());
            //判断编号在excel里本身就重复的
            Map<String, Long> idCountMap = cboList.stream().collect(Collectors.groupingBy(ClientBusinessObject::getId, Collectors.counting()));
            List<String> repeatIdList = new ArrayList<>();
            idCountMap.forEach((id, count) -> {
               if (count > 1) {
                  repeatIdList.add(id);
               }
            });
            if (!CollectionUtils.isEmpty(repeatIdList)) {
               cboList.stream().filter(s -> repeatIdList.contains(s.getId())).map(s -> s.getAttributeValue(IMPORT_ROW_INDEX)).forEach(rowIndex -> {
                  errorMap.put(rowIndex, "编号在当前excel中重复;");
               });
            }
            //我们需要判断这些分类的模板是不是一样的,只需要校验,不用获取
            //检查分类的路径
            checkClassifyPathInHistory(cboList, errorMap, pathMap, childOidPathMap);
            //检查规则
            Map<String/**分类主键**/, String/**规则主键**/> ruleOidMap = new ConcurrentHashMap<String, String>();
            List<String> unExistRuleClassifyOidList = new CopyOnWriteArrayList<>();
            checkRuleOidInHistory(classifyVOMap, ruleOidMap, unExistRuleClassifyOidList);
            //如果出错了,我们依然执行有效的数据,无效的数据写回到excel中
            //我们根据出错的分类的主键,去找行号
            if (!CollectionUtils.isEmpty(unExistRuleClassifyOidList)) {
               cboList.stream().forEach(cbo -> {
                  if (unExistRuleClassifyOidList.contains(cbo.getAttributeValue(CODE_CLASSIFY_OID_FIELD))) {
                     String row_index = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                     errorMap.put(row_index, errorMap.getOrDefault(row_index, "") + ";根据分类路径对应的分类,没有设置编码规则");
                  }
               });
            }
            //判断必输项
            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,true);
            //设置默认值
            batchSwitchAttrDefault(attrVOS, cboList);
            //7.处理组合规则
            batchSwitchComponentAttrOnOrder(attrVOS, cboList);
            //3.判断关键属性
            CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,false,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文件中关键属性重复");
               });
            }
            if (!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)) {
               keyAttrRepeatRowIndexList.stream().forEach(rowIndex -> {
                  errorMap.put(rowIndex, "关键属性与系统中的重复;" + errorMap.getOrDefault(rowIndex, ""));
               });
            }
            //4.校验规则
            batchCheckVerifyOnOrder(attrVOS, cboList, errorMap);
            //6.时间的,必须统一为yyyy-MM-dd HH:mm:ss
            batchSwitchDateAttrOnOrder(attrVOS, cboList, errorMap);
            if (CollectionUtils.isEmpty(ruleOidMap.values())) {
               throw new VciBaseException("导入的数据所选择的分类都没有设置编码规则");
            }
            // TODO: 该用oid查询规则的,别用id
            Map<String, CodeRuleVO> ruleVOMap = ruleService.listCodeRuleByOids(ruleOidMap.values()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
            //校验编码规则和码段是否正确
            Map<String, List<String>> ruleRowIndexMap = new ConcurrentHashMap<>();
            checkSecLengthInHistory(cboList, classifyVOMap, ruleVOMap, ruleOidMap, errorMap, ruleRowIndexMap);
            ruleRowIndexMap.keySet().parallelStream().forEach(ruleOid -> {
               List<String> rowIndexList = ruleRowIndexMap.get(ruleOid);
               List<ClientBusinessObject> thisCbos = cboList.stream().filter(cbo -> rowIndexList.contains(cbo.getAttributeValue(IMPORT_ROW_INDEX)) && !errorMap.containsKey(cbo.getAttributeValue(IMPORT_ROW_INDEX))).collect(Collectors.toList());
               //我们需要先查询一下,内容是否已经存在
               if(!CollectionUtils.isEmpty(thisCbos)){
                  List<String> existIds = new ArrayList<>();
                  VciBaseUtil.switchCollectionForOracleIn(thisCbos).stream().forEach(cbos -> {
                     List<CodeAllCode> codeAllCodeList= codeAllCodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCodeRuleOid, ruleOid)
                        .notIn(CodeAllCode::getId,cbos.stream().map(s -> s.getId()).collect(Collectors.toSet()).toArray(new String[0]))
                        .notIn(CodeAllCode::getLcStatus,CodeAllCodeLC.TASK_BACK.getValue() + "','" + CodeAllCodeLC.OBSOLETED.getValue())
                     );
                     existIds.addAll(Optional.ofNullable(codeAllCodeList).orElseGet(() -> new ArrayList<>()).stream().map(s -> {
                        String id = s.getId();
                        if (StringUtils.isBlank(id)) {
                           id = s.getId();
                        }
                        return id;
                     }).collect(Collectors.toList()));
                  });
                  List<String> existIdCbos = thisCbos.stream().filter(s -> {
                     String id = s.getId();
                     if (StringUtils.isBlank(id)) {
                        id = s.getAttributeValue("id");
                     }
                     return existIds.contains(id);
                  }).map(s -> s.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toList());
                  if (!CollectionUtils.isEmpty(existIdCbos)) {
                     thisCbos = thisCbos.stream().filter(s -> {
                        String id = s.getId();
                        if (StringUtils.isBlank(id)) {
                           id = s.getAttributeValue("id");
                        }
                        return !existIdCbos.contains(id);
                     }).collect(Collectors.toList());
                     existIdCbos.stream().forEach(rowIndex -> {
                        errorMap.put(rowIndex, errorMap.getOrDefault(rowIndex, "") + ";【" + idFieldName + "】在系统中已经被占用");
                     });
                  }
               }
            });
            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) {
               isExport=true;
               createRedisDatas(uuid + "-error", templateVO, rowIndexCboMap, dataSet, fieldIndexMap, errorMap, false);
            }
            createWriteExcelData(rowDataList, errorMap, new ArrayList<>(), titleRowData, shetNameMap, templateVO);
            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(templateVO.getCodeclassifyoid(), templateVO, needSaveCboList, resembleMap, btmtypeid, dataResembleVOS);
            if (resembleMap.size() > 0) {
               if (!CollectionUtils.isEmpty(dataResembleVOS)) {
                  bladeRedis.set(uuid + "-resemble-data", dataResembleVOS);
                  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);
            //获取编码,查询在系统中是否被其他的引用了
            //排除错误的,剩下正确的
            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;
            }
            List<String> needRowIndexList = needSaveCboList.stream().filter(s -> errorMap.containsKey(s.getAttributeValue(IMPORT_ROW_INDEX))).map(s -> s.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toList());
            if (isExport||newErrorMap.size() > 0) {
               createRedisDatas(uuid + "-ok", templateVO, rowIndexCboMap, dataSet, fieldIndexMap, newErrorMap, true);
            } else {
               List<BaseModel> dataCBOIdList=new ArrayList<>();
               //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);
                  List<ClientBusinessObject> thisCbos = finalNeedSaveCboList.stream().filter(cbo -> rowIndexList.contains(cbo.getAttributeValue(IMPORT_ROW_INDEX)) && !errorMap.containsKey(cbo.getAttributeValue(IMPORT_ROW_INDEX))).collect(Collectors.toList());
                  List<BaseModel> dataCBOList=new CopyOnWriteArrayList<>();
                  thisCbos.stream().forEach(clientBusinessObject -> {
                     BaseModel baseModel=new BaseModel();
                     BeanUtil.convert(clientBusinessObject,baseModel);
                     //baseModel.setData(VciBaseUtil.objectToMapString(clientBusinessObject));
                     dataCBOList.add(baseModel);
                     dataCBOIdList.add(baseModel);
                  });
                  if (!CollectionUtils.isEmpty(thisCbos)) {
                     try {
                        // TODO 多线程流问题
                        productCodeService.productCodeAndSaveData(classifyFullInfo, finalTemplateVO, ruleVOMap.get(ruleOid), null, dataCBOList,user);
                        importCount.add(dataCBOList.size());
                     } catch (Throwable e) {
                        log.error("批量产生编码的时候出错了", e);
                        thisCbos.stream().forEach(cbo -> {
                           String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                           errorMap.put(rowIndex, errorMap.getOrDefault(rowIndex, "") + ";系统错误,存储数据的时候出错了:"+e.getMessage());
                        });
                     }
                  }
               });
               if (errorMap.size() > 0) {
                  isExport = true;
               }
               createWriteExcelData(rowDataList, errorMap, new ArrayList<>(), titleRowData, shetNameMap, finalTemplateVO);
               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";
            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);
         }
         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);
         }
         return codeImProtRusultVO;
      }catch (Exception e){
         saveLogUtil.operateLog("历史数据导入",true,e.toString());
         throw e;
      }
   }
   /**
    * 导入批量编辑数据
    *
    * @param codeClassifyOid 分类的主键
    * @param classifyAttr 分类路径使用的属性
    * @param file            excel文件的信息
    * @return 有错误信息的excel
    */
   @Transactional
   @Override
   public CodeImProtRusultVO batchImportEdit(String codeClassifyOid, String classifyAttr,File file) throws  Throwable{
      VciBaseUtil.alertNotNull(codeClassifyOid,"分类的主键");
      ReadExcelOption reo = new ReadExcelOption();
      reo.setReadAllSheet(true);
      List<SheetDataSet> sheetDataSetList = ExcelUtil.readDataObjectFromExcel(file,null,reo);
      if (sheetDataSetList.size() > LIMIT + 1) {
         throw new VciBaseException("为了保证系统的稳定性,请一次不要导入超过1万条的数据");
      if (sheetDataSetList.get(0).getRowData().size() > LIMIT + 1) {
         throw new ServiceException("为了保证系统的稳定性,请一次不要导入超过1万条的数据");
      }
      Map<String,List<WriteExcelData>> shetNameMap=new HashMap<>();
      //相似项目查重
      String uuid=VciBaseUtil.getPk();
      boolean isCreateUUid=false;
      if (sheetDataSetList.get(0).getRowData().size() == 0) {
         throw new ServiceException("未读取到excle相关数据,请确认!!!");
      }
      boolean isExport=false;
      //long start = System.currentTimeMillis();
      Map<String,List<WriteExcelData>> shetNameMap=new HashMap<>();
      for(int i=0;i<sheetDataSetList.size()-1;i++) {
         if (CollectionUtils.isEmpty(sheetDataSetList) || CollectionUtils.isEmpty(sheetDataSetList.get(i).getRowData())
            || sheetDataSetList.get(i).getRowData().size() < 1) {
@@ -832,18 +1310,6 @@
         if(sheetDataSetList.get(i).getRowData().size() > IMPORT_DATA_LIMIT){
            throw new ServiceException("为了保证系统的稳定性,请一次不要导入超过"+IMPORT_DATA_LIMIT+"条的数据");
         }
         //历史导入的时候不处理编码
         //----逻辑内容----
         //1. 分类的路径可以在页面上选择是分类编号还是分类的名称
         //2. 分类的路径,必须是当前导入选择的分类的节点,以及其下级节点
         //3. 通过数据要导入的分类去查找对应的编码规则
         //4. 数据存储和批量申请一样,
         //5. 需要单独处理企业编码的内容,
         //     5.1 企业编码在当前excel里不能重复
         //     5.2 企业编码在系统中不能重复(可以是已经回收的)
         //     5.3 企业编码的长度,和编码规则的长度要对应上
         //     5.4 获取流水码段的值,去除填充的字符,看流水号是多少,然后将流水号和现在的最大流水号判断,小于就直接录入,大于则修改最大流水号
         //     5.5 存储企业编码到allcode中
         //查询分类和模板
         CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
@@ -852,10 +1318,7 @@
         List<SheetRowData> rowDataList = dataSet.getRowData();
         //找第一行,为了找标题
         CodeClassifyTemplateVO templateVO = new CodeClassifyTemplateVO();
         /**  if (!templateService.checkChildHasSameTemplate(classifyFullInfo.getCurrentClassifyVO().getOid())) {
             throw new VciBaseException("当前的分类以及下级分类的模板不相同");
          }***/
         CodeClassifyTemplateVO templateVO ;
         //都转换完了。需要批量检查
         //找所有的分类路径,需要校验路径是否正确,是否都在当前的分类的下级
         List<CodeClassifyVO> childClassifyVOs = classifyService.listChildrenClassify(codeClassifyOid, true, classifyAttr, true);
@@ -865,243 +1328,56 @@
         pathMap.put("#current#",classifyFullInfo.getCurrentClassifyVO());
         try {
            titleRowData.add("分类路径");
            List<CodeClassifyTemplateVO> templateVOList= checkSamesTemplate(titleRowData,sheetDataSetList,i,pathMap,errorMap);
            titleRowData.remove(titleRowData.size()-1);
            templateVO= templateVOList.get(0);
         }catch (Throwable e){
            throw  new VciBaseException(e.getMessage());
            throw new ServiceException(e.getMessage());
         }
         CodeClassifyTemplateVO finalTemplateVO = templateVO;
         List<SheetRowData> needowDataList = rowDataList.stream().filter(cbo -> {
            String rowIndex = cbo.getRowIndex();
            return !errorMap.containsKey(rowIndex);
         }).collect(Collectors.toList());
         //checkTemplateSync(sheetDataSetList, templateVO,i);
         //这里不除去默认的属性
         List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes();
         Map<Integer/**列号**/, String/**字段的名称**/> fieldIndexMap = new HashMap<>();
         Map<String/**中文名称**/, String/**英文名称**/> attrNameIdMap = attrVOS.stream().collect(Collectors.toMap(s -> s.getName(), t -> t.getId()));
         String idFieldName = attrVOS.stream().filter(s -> VciQueryWrapperForDO.ID_FIELD.equalsIgnoreCase(s.getId())).findFirst().orElseGet(() -> new CodeClassifyTemplateAttrVO()).getName();
         fieldIndexMap.put(0,"id");
         getFieldIndexMap(titleRowData, attrNameIdMap, fieldIndexMap);
         //先不用管属性是否都存在,先转换一下数据
         List<ClientBusinessObject> cboList = new ArrayList<>();
         String fullPath = getFullPath(classifyFullInfo);
         //我们需要获取到所有的下级分类的oid的路径,因为后面需要
         Map<String/**主键**/, String/**路径**/> childOidPathMap = getChildClassifyPathMap(classifyFullInfo, fullPath);
         excelToCbo(classifyFullInfo, fieldIndexMap, needowDataList, templateVO, cboList, fullPath, false);
         Map<String/**主键**/, CodeClassifyVO> classifyVOMap = Optional.ofNullable(childClassifyVOs).orElseGet(() -> new ArrayList<>()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
         classifyVOMap.put(classifyFullInfo.getCurrentClassifyVO().getOid(), classifyFullInfo.getCurrentClassifyVO());
         pathMap.put("#current#", classifyFullInfo.getCurrentClassifyVO());
         //判断编号在excel里本身就重复的
         Map<String, Long> idCountMap = cboList.stream().collect(Collectors.groupingBy(ClientBusinessObject::getId, Collectors.counting()));
         List<String> repeatIdList = new ArrayList<>();
         idCountMap.forEach((id, count) -> {
            if (count > 1) {
               repeatIdList.add(id);
         CodeOrderDTO orderDTO = new CodeOrderDTO();
         for (SheetRowData sheetRowData : needowDataList) {
            //查询数据
            Map<String, String> conditionMap = new HashMap<>();
            conditionMap.put("t.id", sheetRowData.getData().get(0));
            conditionMap.put("t.lastv", "1");
            CodeTemplateAttrSqlBO sqlBO = mdmEngineService.getSqlByTemplateVO(classifyFullInfo.getTopClassifyVO().getBtmTypeId(), templateVO, conditionMap, new PageHelper(-1));
            //我们使用和业务类型的来查询
            List<Map> cbosB = commonsMapper.selectBySql(sqlBO.getSqlUnPage());
            if(cbosB.size() == 0){
               throw new ServiceException("编码:"+ sheetRowData.getData().get(0) + ",未能查询到相关数据。");
            }
         });
         if (!CollectionUtils.isEmpty(repeatIdList)) {
            cboList.stream().filter(s -> repeatIdList.contains(s.getId())).map(s -> s.getAttributeValue(IMPORT_ROW_INDEX)).forEach(rowIndex -> {
               errorMap.put(rowIndex, "编号在当前excel中重复;");
            });
         }
         //我们需要判断这些分类的模板是不是一样的,只需要校验,不用获取
         //检查分类的路径
         checkClassifyPathInHistory(cboList, errorMap, pathMap, childOidPathMap);
         //检查规则
         Map<String/**分类主键**/, String/**规则主键**/> ruleOidMap = new ConcurrentHashMap<String, String>();
         List<String> unExistRuleClassifyOidList = new CopyOnWriteArrayList<>();
         checkRuleOidInHistory(classifyVOMap, ruleOidMap, unExistRuleClassifyOidList);
         //如果出错了,我们依然执行有效的数据,无效的数据写回到excel中
         //我们根据出错的分类的主键,去找行号
         if (!CollectionUtils.isEmpty(unExistRuleClassifyOidList)) {
            cboList.stream().forEach(cbo -> {
               if (unExistRuleClassifyOidList.contains(cbo.getAttributeValue(CODE_CLASSIFY_OID_FIELD))) {
                  String row_index = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                  errorMap.put(row_index, errorMap.getOrDefault(row_index, "") + ";根据分类路径对应的分类,没有设置编码规则");
               }
            });
         }
         //判断必输项
         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,true);
         //设置默认值
         batchSwitchAttrDefault(attrVOS, cboList);
         //7.处理组合规则
         batchSwitchComponentAttrOnOrder(attrVOS, cboList);
         //3.判断关键属性
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList,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文件中关键属性重复");
            });
         }
         if (!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)) {
            keyAttrRepeatRowIndexList.stream().forEach(rowIndex -> {
               errorMap.put(rowIndex, "关键属性与系统中的重复;" + errorMap.getOrDefault(rowIndex, ""));
            });
         }
         //4.校验规则
         batchCheckVerifyOnOrder(attrVOS, cboList, errorMap);
         //6.时间的,必须统一为yyyy-MM-dd HH:mm:ss
         batchSwitchDateAttrOnOrder(attrVOS, cboList, errorMap);
         if (CollectionUtils.isEmpty(ruleOidMap.values())) {
            throw new VciBaseException("导入的数据所选择的分类都没有设置编码规则");
         }
         // TODO: 该用oid查询规则的,别用id
         Map<String, CodeRuleVO> ruleVOMap = ruleService.listCodeRuleByOids(ruleOidMap.values()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
         //校验编码规则和码段是否正确
         Map<String, List<String>> ruleRowIndexMap = new ConcurrentHashMap<>();
         checkSecLengthInHistory(cboList, classifyVOMap, ruleVOMap, ruleOidMap, errorMap, ruleRowIndexMap);
         ruleRowIndexMap.keySet().parallelStream().forEach(ruleOid -> {
            List<String> rowIndexList = ruleRowIndexMap.get(ruleOid);
            List<ClientBusinessObject> thisCbos = cboList.stream().filter(cbo -> rowIndexList.contains(cbo.getAttributeValue(IMPORT_ROW_INDEX)) && !errorMap.containsKey(cbo.getAttributeValue(IMPORT_ROW_INDEX))).collect(Collectors.toList());
            //我们需要先查询一下,内容是否已经存在
            if(!CollectionUtils.isEmpty(thisCbos)){
               List<String> existIds = new ArrayList<>();
               VciBaseUtil.switchCollectionForOracleIn(thisCbos).stream().forEach(cbos -> {
                  List<CodeAllCode> codeAllCodeList= codeAllCodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCodeRuleOid, ruleOid)
                     .notIn(CodeAllCode::getId,cbos.stream().map(s -> s.getId()).collect(Collectors.toSet()).toArray(new String[0]))
                     .notIn(CodeAllCode::getLcStatus,CodeAllCodeLC.TASK_BACK.getValue() + "','" + CodeAllCodeLC.OBSOLETED.getValue())
                  );
                  existIds.addAll(Optional.ofNullable(codeAllCodeList).orElseGet(() -> new ArrayList<>()).stream().map(s -> {
                     String id = s.getId();
                     if (StringUtils.isBlank(id)) {
                        id = s.getId();
                     }
                     return id;
                  }).collect(Collectors.toList()));
               });
               List<String> existIdCbos = thisCbos.stream().filter(s -> {
                  String id = s.getId();
                  if (StringUtils.isBlank(id)) {
                     id = s.getAttributeValue("id");
                  }
                  return existIds.contains(id);
               }).map(s -> s.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toList());
               if (!CollectionUtils.isEmpty(existIdCbos)) {
                  thisCbos = thisCbos.stream().filter(s -> {
                     String id = s.getId();
                     if (StringUtils.isBlank(id)) {
                        id = s.getAttributeValue("id");
                     }
                     return !existIdCbos.contains(id);
                  }).collect(Collectors.toList());
                  existIdCbos.stream().forEach(rowIndex -> {
                     errorMap.put(rowIndex, errorMap.getOrDefault(rowIndex, "") + ";【" + idFieldName + "】在系统中已经被占用");
                  });
               }
            excelToCboEdit(fieldIndexMap, sheetRowData, orderDTO, cbosB.get(0));
            orderDTO.setCopyFromVersion(orderDTO.getOid());
            orderDTO.setOid(null);
            try {
               mdmEngineService.upSaveCode(orderDTO);
            } catch (Throwable e) {
               log.error("批量产生编码的时候出错了", e);
               errorMap.put(sheetRowData.getRowIndex(), ";系统错误,存储数据的时候出错了:"+e.getMessage());
            }
         });
         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) {
            isExport=true;
            createRedisDatas(uuid + "-error", templateVO, rowIndexCboMap, dataSet, fieldIndexMap, errorMap, false);
            isExport = true;
         }
         createWriteExcelData(rowDataList, errorMap, new ArrayList<>(), titleRowData, shetNameMap, templateVO);
         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(templateVO.getCodeclassifyoid(), templateVO, needSaveCboList, resembleMap, btmtypeid, dataResembleVOS);
         if (resembleMap.size() > 0) {
            if (!CollectionUtils.isEmpty(dataResembleVOS)) {
               bladeRedis.set(uuid + "-resemble-data", dataResembleVOS);
               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);
         //获取编码,查询在系统中是否被其他的引用了
         //排除错误的,剩下正确的
         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;
         }
         createWriteExcelData(rowDataList, errorMap, new ArrayList<>(), titleRowData, shetNameMap, finalTemplateVO);
         List<String> needRowIndexList = needSaveCboList.stream().filter(s -> errorMap.containsKey(s.getAttributeValue(IMPORT_ROW_INDEX))).map(s -> s.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toList());
         if (isExport||newErrorMap.size() > 0) {
            createRedisDatas(uuid + "-ok", templateVO, rowIndexCboMap, dataSet, fieldIndexMap, newErrorMap, true);
         } else {
            List<BaseModel> dataCBOIdList=new ArrayList<>();
            //SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
            List<ClientBusinessObject> finalNeedSaveCboList = needSaveCboList;
            CodeClassifyTemplateVO finalTemplateVO = templateVO;
            ruleRowIndexMap.keySet().parallelStream().forEach(ruleOid -> {
               //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
               List<String> rowIndexList = ruleRowIndexMap.get(ruleOid);
               List<ClientBusinessObject> thisCbos = finalNeedSaveCboList.stream().filter(cbo -> rowIndexList.contains(cbo.getAttributeValue(IMPORT_ROW_INDEX)) && !errorMap.containsKey(cbo.getAttributeValue(IMPORT_ROW_INDEX))).collect(Collectors.toList());
               List<BaseModel> dataCBOList=new CopyOnWriteArrayList<>();
               thisCbos.stream().forEach(clientBusinessObject -> {
                  BaseModel baseModel=new BaseModel();
                  BeanUtil.convert(clientBusinessObject,baseModel);
                  //baseModel.setData(VciBaseUtil.objectToMapString(clientBusinessObject));
                  dataCBOList.add(baseModel);
                  dataCBOIdList.add(baseModel);
               });
               if (!CollectionUtils.isEmpty(thisCbos)) {
                  try {
                     // TODO 多线程流问题
                     productCodeService.productCodeAndSaveData(classifyFullInfo, finalTemplateVO, ruleVOMap.get(ruleOid), null, dataCBOList);
                  } catch (Throwable e) {
                     log.error("批量产生编码的时候出错了", e);
                     thisCbos.stream().forEach(cbo -> {
                        String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                        errorMap.put(rowIndex, errorMap.getOrDefault(rowIndex, "") + ";系统错误,存储数据的时候出错了:"+e.getMessage());
                     });
                  }
               }
            });
            if (errorMap.size() > 0) {
               isExport = true;
            }
            createWriteExcelData(rowDataList, errorMap, new ArrayList<>(), titleRowData, shetNameMap, finalTemplateVO);
            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";
@@ -1120,14 +1396,13 @@
      if(StringUtils.isNotBlank(excelFileName)) {
         codeImProtRusultVO.setFilePath(excelFileName);
         codeImProtRusultVO.setFileOid("");
         saveLogUtil.operateLog("数据批量更改",true, StringUtil.format("错误信息:{}",JSON.toJSONString(shetNameMap)) );
      }else{
         saveLogUtil.operateLog("数据批量更改",false, StringUtil.format("导入成功总数为:{}",
            sheetDataSetList.size()-1));
      }
      if(isCreateUUid){
         codeImProtRusultVO.setRedisUuid(uuid);
      }
      return codeImProtRusultVO;
   }
   /*private void converBaseModels(List<ClientBusinessObject> clientBusinessObjects,List<BaseModel>dataCBOList){
      clientBusinessObjects.stream().forEach(clientBusinessObject -> {
         BaseModel baseModel=new BaseModel();
@@ -1291,7 +1566,6 @@
   }
   /***
    * 批量处理申请数据
    * @param orderDTO
@@ -1299,140 +1573,148 @@
    * @param dataSet
    * @return
    */
   private String batchImportCodes(CodeOrderDTO orderDTO,CodeClassifyTemplateVO templateVO,SheetDataSet dataSet,Map<String,String> errorMap,boolean isEnumType){
   private String batchImportCodes(CodeOrderDTO orderDTO,CodeClassifyTemplateVO templateVO,SheetDataSet dataSet,Map<String,String> errorMap,boolean isEnumType) throws Exception {
      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();
      String uuid = "";
      try {
         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> 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,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,"") + ";在当前处理的数据文件中关键属性重复" );
         });
      }
      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);
         //需要判断是否所有的属性都在模板上了
         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) + "】这些属性在列表中没有找到");
         }
      }
      //排除错误的,剩下正确的
      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="";
         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,false,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,"") + ";在当前处理的数据文件中关键属性重复" );
            });
         }
         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);
         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="";
            final BladeUser user = AuthUtil.getUser();
            //要把以上的错误的都抛出后,再继续处理时间和组合规则
            needSaveCboList = cboList.stream().filter(cbo -> {
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
               return !newErrorMap.containsKey(rowIndex);
            }).collect(Collectors.toList());
         if (!CollectionUtils.isEmpty(needSaveCboList)) {
            //9.我们处理业务数据
            //生成编码的内容
            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());
            });
            try {
               codeList = productCodeService.productCodeAndSaveData(classifyFullInfo,templateVO,ruleVO, orderDTO.getSecDTOList(),dataCBOList);
               //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
               engineService.batchSaveSelectChar(templateVO, dataCBOList);
            } catch (Exception e) {
               e.printStackTrace();
               log.error("批了申请时失败");
            if (!CollectionUtils.isEmpty(needSaveCboList)) {
               //9.我们处理业务数据
               //生成编码的内容
               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());
               });
               try {
                  codeList = productCodeService.productCodeAndSaveData(classifyFullInfo,templateVO,ruleVO, orderDTO.getSecDTOList(),dataCBOList,user);
                  //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
                  engineService.batchSaveSelectChar(templateVO, dataCBOList);
               } catch (Exception e) {
                  e.printStackTrace();
                  log.error("批量申请时失败");
                  throw e;
               }
            }
         }
      }
      if(!isCreateUUid){
         return uuid="";
         if(!isCreateUUid){
            return uuid="";
         }
         saveLogUtil.operateLog("批量申请编码",false, StringUtil.format("批量导入申请成功共{}条数据,生成的码值如下【{}】",codeList.size(),codeList));
      }catch (Exception e){
         saveLogUtil.operateLog("批量申请编码",true,e.toString());
         throw e;
      }
      return uuid;
   }
@@ -1549,10 +1831,10 @@
         tableName = VciBaseUtil.getTableName(btmTypeId);
      }
      String countSql = "select count(*) from " + tableName +" where 1=1" +
      String countSql = "select count(*) from (select * FROM " + tableName +" where 1=1" +
         " and lastr = '1'" +
         " and lastv='1'" +
         " and codeclsfpath like '%" + exportAttrDTO.getCodeClassifyOid() + "%'";
         " and codeclsfpath like '%" + exportAttrDTO.getCodeClassifyOid() + "%' {}";
      //先查询总数
      int total = 0;
@@ -1566,8 +1848,7 @@
            thisPage.setSort(exportAttrDTO.getSort());
            thisPage.setOrder(exportAttrDTO.getOrder());
            thisPage.addDefaultDesc("createTime");
            total += commonsMapper.queryCountBySql(countSql);
            total += commonsMapper.queryCountBySql(StringUtil.format(countSql," limit " + exportAttrDTO.getLimit() +" offset "+ i +")subquery;"));
         }
      }else{
         total = commonsMapper.queryCountBySql(countSql);
@@ -1605,10 +1886,10 @@
         }
         Map<String, String> finalConditionMap = conditionMap;
         //并行查询看看
         SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
         //SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
         indexList.stream().forEach(index->{
            //线程的方式,所以需要设置当前用户
            VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
            //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
            PageHelper thisPage = new PageHelper(EXPORT_LIMIT);
            thisPage.setPage(index+1);
            thisPage.setSort(exportAttrDTO.getSort());
@@ -1814,7 +2095,7 @@
         //最后弄组合规则
         batchSwitchComponentAttrOnOrder(attrVOS,cboList);
         //3.判断关键属性
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, codeClassifyTemplateVO, cboList,errorMap);
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, codeClassifyTemplateVO, cboList,false,errorMap);
         Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
         Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
         if(!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)){
@@ -1832,7 +2113,9 @@
            }).collect(Collectors.toList());
            List<ClientBusinessObject> finalNeedSaveCboList = needSaveCboList;
            Map<String, CodeRuleVO> finalRuleVOMap = ruleVOMap;
            ruleRowIndexMap.keySet().parallelStream().forEach(ruleOid -> {
            // TODO: 多线程流套多线程流,有坑,我把这儿改成单线程了
            final BladeUser user = AuthUtil.getUser();
            ruleRowIndexMap.keySet().stream().forEach(ruleOid -> {
               List <BaseModel>dataCBOList=new CopyOnWriteArrayList<>();
               List<String> rowIndexList = ruleRowIndexMap.get(ruleOid);
               List<ClientBusinessObject> thisCbos = needSaveCboList.stream().filter(cbo -> rowIndexList.contains(cbo.getAttributeValue(IMPORT_ROW_INDEX)) && !errorMap.containsKey(cbo.getAttributeValue(IMPORT_ROW_INDEX))).collect(Collectors.toList());
@@ -1843,7 +2126,7 @@
                     dataCBOList.add(baseModel);
                  });
                  try {
                     productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, finalRuleVOMap.get(ruleOid), null, dataCBOList);
                     productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, finalRuleVOMap.get(ruleOid), null, dataCBOList, user);
                  } catch (Throwable e) {
                     //success=false;
                     log.error("批量产生编码的时候出错了", e);
@@ -1856,6 +2139,7 @@
               engineService.batchSaveSelectChar(codeClassifyTemplateVO, 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);
@@ -1869,7 +2153,7 @@
                  dataCBOList.add(baseModel);
               });
               try {
                  productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList);
                  productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList,user);
               } catch (Exception e) {
                  log.error("批量产生编码的时候出错了", e);
                  needSaveCboList.stream().forEach(cbo -> {
@@ -2020,7 +2304,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();
@@ -2177,6 +2461,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);
@@ -2186,7 +2471,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){
@@ -2214,7 +2499,6 @@
                  resultDataObjectDetailDO.setErrorid("0");
               }
               resultDataObjectDetailDO.setId(sourceOid);
               resultDataObjectDetailDO.setMsg(msg);
               resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
               //处理传送的数据中关键属性重复的,直接拿到已经申请到编码的数据编码直接将赋给关键属性重复的数据
@@ -3263,6 +3547,106 @@
   }
   /**
    * excel转换为cbo的对象
    * @param fieldIndexMap 字段的位置
    * @param rowDataList excel里的行数据
    * @param orderDTO 整理的数据
    * @param map 数据的列表
    */
   private void excelToCboEdit(Map<Integer,String> fieldIndexMap,SheetRowData rowDataList,
                     CodeOrderDTO orderDTO,
                     Map map){
      rowDataList.getData().forEach((index,value)->{
            String field = fieldIndexMap.get(index);
            if (StringUtils.isBlank(field)) {
               throw new VciBaseException("第" + (index + 1) + "列的标题在系统中不存在");
            }
            map.put(field.toUpperCase(),value);
         });
      try {
//         for (Map map : cbos) {
//         Object obj = CodeOrderDTO.class.newInstance();
         BeanInfo beanInfo = Introspector.getBeanInfo(orderDTO.getClass());
         PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
         for (PropertyDescriptor property : propertyDescriptors) {
            Method setter = property.getWriteMethod();
            if (setter != null) {
               //oracle的时间为TIMESTAMP的,需要进行转换成data,否则将报错
               if (map.get(property.getName().toUpperCase()) instanceof TIMESTAMP) {
                  LocalDateTime localDateTime = ((TIMESTAMP) map.get(property.getName().toUpperCase())).toLocalDateTime();
                  ZoneId zoneId = ZoneId.systemDefault();
                  ZonedDateTime zdt = localDateTime.atZone(zoneId);
                  Date date = Date.from(zdt.toInstant());
                  setter.invoke(orderDTO, date);
                  map.remove(property.getName().toUpperCase());
               } //oracle的数字为BigDecimal的,需要进行转换成Integer,否则将报错
               else if (map.get(property.getName().toUpperCase()) instanceof BigDecimal
                  && ("Integer").equals(setter.getParameterTypes()[0].getSimpleName())) {
                  setter.invoke(orderDTO, ((BigDecimal) map.get(property.getName().toUpperCase())).intValue());
                  map.remove(property.getName().toUpperCase());
               } else if (map.containsKey(property.getName().toUpperCase())) {
                  if(setter.getParameterTypes()[0].getSimpleName().equals("String")){
                     setter.invoke(orderDTO, map.get(property.getName().toUpperCase()) == null ? null:String.valueOf(map.get(property.getName().toUpperCase())));
                  }else{
                     setter.invoke(orderDTO, map.get(property.getName().toUpperCase()));
                  }
                  map.remove(property.getName().toUpperCase());
               }
            }
         }
         for (Object key : map.keySet()) {
            map.put(key, map.get(key) == null ? null : String.valueOf(map.get(key)));
         }
      } catch (Exception e) {
         throw new VciBaseException("查询失败:" + e.getMessage());
      }
//      Iterator<Map.Entry<String, String>> iterator = cbos.entrySet().iterator();
//
//      Map.Entry<String, String> entry;
//      while (iterator.hasNext()) {
//         entry = iterator.next();
////         if (WebUtil.isDefaultField(entry.getKey())) {
//            Object obj = BaseModel.class.newInstance();
//            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
//            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//            for (PropertyDescriptor property : propertyDescriptors) {
//               Method setter = property.getWriteMethod();
//               if (setter != null) {
//                  //oracle的时间为TIMESTAMP的,需要进行转换成data,否则将报错
//                  if (map.get(property.getName().toUpperCase()) instanceof TIMESTAMP) {
//                     LocalDateTime localDateTime = ((TIMESTAMP) map.get(property.getName().toUpperCase())).toLocalDateTime();
//                     ZoneId zoneId = ZoneId.systemDefault();
//                     ZonedDateTime zdt = localDateTime.atZone(zoneId);
//                     Date date = Date.from(zdt.toInstant());
//                     setter.invoke(obj, date);
//                     map.remove(property.getName().toUpperCase());
//                  } //oracle的数字为BigDecimal的,需要进行转换成Integer,否则将报错
//                  else if (map.get(property.getName().toUpperCase()) instanceof BigDecimal
//                     && ("Integer").equals(setter.getParameterTypes()[0].getSimpleName())) {
//                     setter.invoke(obj, ((BigDecimal) map.get(property.getName().toUpperCase())).intValue());
//                     map.remove(property.getName().toUpperCase());
//                  } else if (map.containsKey(property.getName().toUpperCase())) {
//                     if(setter.getParameterTypes()[0].getSimpleName().equals("String")){
//                        setter.invoke(obj, map.get(property.getName().toUpperCase()) == null ? null:String.valueOf(map.get(property.getName().toUpperCase())));
//                     }else{
//                        setter.invoke(obj, map.get(property.getName().toUpperCase()));
//                     }
//                     map.remove(property.getName().toUpperCase());
//                  }
//               }
//            }
//            WebUtil.setValueToField(entry.getKey(), orderDTO, entry.getValue());
//            iterator.remove();
////         }
//      }
      orderDTO.setData(map);
   }
   /**
    * 检查校验规则没有通过的内容
    * @param attrVOS 需要校验的属性
    * @param dataList 数据的列表
@@ -3799,7 +4183,7 @@
   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())
         s -> 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);
@@ -3836,6 +4220,7 @@
                  } else {
                     Map<String, String> classifyDataMap = VciBaseUtil.objectToMapString(classifyVO);
                     String value = classifyDataMap.getOrDefault(attrVO.getClassifyInvokeAttr(), "");
                     log.error("================================当前分类注入的value值为:==========================",value);
                     cbo.setAttributeValue(attrId, value);
                  }
               } catch (Throwable e) {
@@ -3852,7 +4237,7 @@
    * @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);
@@ -3882,6 +4267,7 @@
      Map<String,List<BaseModel>> indexTODataMap=new ConcurrentHashMap<>();
      // 查询不需要参与关键属性校验的除自己以外的所有分类oid
      final String isParticipateCheckOids = classifyService.selectLeafByParentClassifyOid(classifyFullInfo.getTopClassifyVO().getOid(), classifyFullInfo.getCurrentClassifyVO().getOid());
      final BladeUser user = AuthUtil.getUser();
      List<ClientBusinessObject> repeatDataMap = cboList.parallelStream().filter(cbo -> {
         //每行都得查询.如果其中出现了错误,我们就直接抛出异常,其余的显示
         //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
@@ -3899,6 +4285,12 @@
            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()){
@@ -3907,7 +4299,7 @@
               List<BaseModel> newCboList = new ArrayList<>();
               newDataList.stream().forEach(stringStringMap -> {
                  BaseModel baseModel=new BaseModel();
                  DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(stringStringMap,baseModel);
                  DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(stringStringMap,baseModel,true,user);
                  baseModel.setData(stringStringMap);
                  newCboList.add(baseModel);
               });
@@ -4580,4 +4972,500 @@
      }
   }
   /***
    * @param codeClassifyOid
    * @return
    */
   @Override
   public String exportGroupCodeExcel(String codeClassifyOid) throws VciBaseException {
      VciBaseUtil.alertNotNull(codeClassifyOid,"主题库分类的主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      CodeClassifyVO codeClassifyVO= classifyFullInfo.getCurrentClassifyVO();
      //获取最新的模板
      CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(codeClassifyOid);
      LinkedList<String> colName=new LinkedList<>();//列头
      LinkedList<String> fieldList=new LinkedList<>();//列字段
      ExecGroupCodePortDataDTO execGroupCodePortDataDTO=new ExecGroupCodePortDataDTO();
      createExportGroupCodeMapConfig(templateVO,execGroupCodePortDataDTO);//组织数据
      if(!CollectionUtils.isEmpty(execGroupCodePortDataDTO.getCodeAttrMapGroupAttrDTOS())){
         throw new ServiceException("集团属性映射未配置");
      }
      fieldList=execGroupCodePortDataDTO.getFieldList();
      List<Map<String,String>>dataList=new ArrayList<>();
      getDatas(classifyFullInfo,templateVO,fieldList,dataList,null);
      execGroupCodePortDataDTO.setDataList(dataList);//放数据
      execGroupCodePortDataDTO.setSheetName(codeClassifyVO.getName()+"集团码导入模板");
      String tempFolder = LocalFileUtil.getDefaultTempFolder();
      String excelName = tempFolder + File.separator +
         classifyFullInfo.getCurrentClassifyVO().getId() + "_" + classifyFullInfo.getCurrentClassifyVO().getName() + "_集团码导出模板.xls";
      try {
         new File(excelName).createNewFile();
      } catch (Throwable e) {
         throw new VciBaseException(LangBaseUtil.getErrorMsg(e), new String[]{excelName}, e);
      }
      LinkedList<String> finalFieldList = fieldList;
      Map<String, CodeClassifyTemplateAttrVO> attrVOMap = templateVO.getAttributes().stream().filter(s-> finalFieldList.contains(s.getId().toLowerCase(Locale.ROOT))).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      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);
      excelDataList.add(groupExcelData);
      for (int i = 0; i < fieldList.size(); i++) {
         String attrId=fieldList.get(i);
         if(attrId.equals(CODE_FIELD)||attrId.equals(CODE_GROUP_FIELD)){
            continue;
         }
         if (attrVOMap.containsKey(attrId)) {
            CodeClassifyTemplateAttrVO attrVO = attrVOMap.get(attrId);
            //Object text = attrVO.getName();
            CodeAndGroupCodeAttrMappingDTO codeAttrMappingDTO = jAttrVOMap.get(attrId);
            Object text = codeAttrMappingDTO.getSourceAttrName();
            text = exportKeyAndRequired(workbook, attrVO, text);
            WriteExcelData excelData = new WriteExcelData(0, i, text);
            if (text instanceof RichTextString) {
               excelData.setFontColor(String.valueOf(HSSFColor.HSSFColorPredefined.RED.getIndex()));
            }
            excelDataList.add(excelData);
         }
      }
      final Integer[] rowIndex = {0};
      dataList.stream().forEach(data -> {
         rowIndex[0]++;
         String id=data.getOrDefault("id", "");
         excelDataList.add(new WriteExcelData(rowIndex[0], 0, id));
         String groupCode=data.getOrDefault("groupcode", "");
         excelDataList.add(new WriteExcelData(rowIndex[0], 1, groupCode));
         List<String> newFieldList = finalFieldList.stream().filter(e -> !e.equals("id") &&!e.equals("groupcode")).collect(Collectors.toList());
         for (int i = 0; i < newFieldList.size(); i++) {
            String attrId = newFieldList.get(i).toLowerCase(Locale.ROOT);
            if(attrId.equals("id")){
            }else if(attrId.equals("groupcode")){
            }else{
               if (attrVOMap.containsKey(attrId)) {
                  CodeClassifyTemplateAttrVO attrVO = attrVOMap.get(attrId);
                  if (StringUtils.isNotBlank(attrVO.getEnumId()) || StringUtils.isNotBlank(attrVO.getEnumString())) {
                     attrId = attrId + "Text";
                  }
                  if (StringUtils.isNotBlank(attrVO.getReferBtmId()) || StringUtils.isNotBlank(attrVO.getReferConfig())) {
                     attrId = attrId + "name";
                  }
                  if (VciQueryWrapperForDO.LC_STATUS_FIELD.equalsIgnoreCase(attrId)) {
                     attrId = VciQueryWrapperForDO.LC_STATUS_FIELD_TEXT.toLowerCase(Locale.ROOT);
                  }
                  excelDataList.add(new WriteExcelData(rowIndex[0], i+2, data.getOrDefault(attrId, "")));
               }
            }
         }
      });
      WriteExcelOption excelOption = new WriteExcelOption();
      excelOption.addSheetDataList(execGroupCodePortDataDTO.getSheetName(),excelDataList);
      //增加模板的信息导入
      LinkedList<WriteExcelData> tempEDList = new LinkedList<>();
      tempEDList.add(new WriteExcelData(0,0,"模板主键"));
      tempEDList.add(new WriteExcelData(0,1,"模板代号"));
      tempEDList.add(new WriteExcelData(0,2,"模板名称"));
      tempEDList.add(new WriteExcelData(1,0,templateVO.getOid()));
      tempEDList.add(new WriteExcelData(1,1,templateVO.getId()));
      tempEDList.add(new WriteExcelData(1,2,templateVO.getName()));
      excelOption.addSheetDataList("模板信息【请勿删除或移动】",tempEDList);
      ExcelUtil.writeDataToFile(excelName, excelOption);
      log.info("文件路径"+excelName);
      return excelName;
   }
   /***
    * 导入集团码
    * @param codeClassifyOid
    * @param file
    * @return
    */
   @Transactional(rollbackFor = VciBaseException.class)
   @Override
   public String importGroupCode(String codeClassifyOid, File file) throws Throwable {
      VciBaseUtil.alertNotNull(codeClassifyOid,"分类的主键");
      ReadExcelOption reo = new ReadExcelOption();
      reo.setReadAllSheet(true);
      List<SheetDataSet> sheetDataSetList = ExcelUtil.readDataObjectFromExcel(file,null,reo);
      if (sheetDataSetList.size() > LIMIT + 1) {
         throw new ServiceException("为了保证系统的稳定性,请一次不要导入超过1万条的数据");
      }
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      //获取最新的模板
      CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(codeClassifyOid);      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->!DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      ).collect(Collectors.toList());
      ExecGroupCodePortDataDTO execGroupCodePortDataDTO=new ExecGroupCodePortDataDTO();
      createExportGroupCodeMapConfig(templateVO,execGroupCodePortDataDTO);//组织数据
      List<CodeAndGroupCodeAttrMappingDTO> codeAttrMapGroupAttrDTOS=execGroupCodePortDataDTO.getCodeAttrMapGroupAttrDTOS();
      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));
      SheetDataSet dataSet= sheetDataSetList.get(0);
      List<String> titleRowData = dataSet.getColName();
      Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap = new HashMap<>();
      getGroupCodeFieldIndexMap(titleRowData,codeAttrMapGroupAttrDTOS,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)){
         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<>();
      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文件中关键属性重复");
         });
      }
      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<>();
            cboList.stream().forEach(clientBusinessObject -> {
               BaseModel newBaseModel=new BaseModel();
               DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(clientBusinessObject.getData(),newBaseModel,true);
               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<>();
      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));
         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);
            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()) && 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
    * @param rowDataList
    * @param cboList
    */
   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)->{
            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);
            }
         });
         cboList.add(cbo);
      });
   }
   /***
    * 集团导出模板属性映射信息获取
    * @param templateVO
    * @param execGroupCodePortDataDTO
    */
   private void createExportGroupCodeMapConfig(CodeClassifyTemplateVO templateVO,ExecGroupCodePortDataDTO execGroupCodePortDataDTO){
      String classOid=templateVO.getCodeclassifyoid();
      String templateOid=templateVO.getOid();
      R r=mdmInterJtClient.list_mapping(classOid);
      if(r.isSuccess()){
         List<DockingPreAttrMappingVO>dockingPreAttrMappingVOList= (List<DockingPreAttrMappingVO>) r.getData();
         List<CodeAndGroupCodeAttrMappingDTO> codeAttrMapGroupAttrDTOS=new ArrayList<>();
         LinkedList<String> fieldList=new LinkedList<>();
         LinkedList<String> colNameList=new LinkedList<>();
         dockingPreAttrMappingVOList.stream().forEach(dockingPreAttrMappingVO -> {
            CodeAndGroupCodeAttrMappingDTO codeAndGroupCodeAttrMappingDTO=new CodeAndGroupCodeAttrMappingDTO();
            if(StringUtils.isNotBlank(dockingPreAttrMappingVO.getTargetAttrId())){
               codeAndGroupCodeAttrMappingDTO.setDefaultValue(dockingPreAttrMappingVO.getDefaultValue());
               codeAndGroupCodeAttrMappingDTO.setMetaListId(dockingPreAttrMappingVO.getMetaListId());
               codeAndGroupCodeAttrMappingDTO.setSourceAttrKey(dockingPreAttrMappingVO.getSourceAttrKey());
               codeAndGroupCodeAttrMappingDTO.setSourceAttrName(dockingPreAttrMappingVO.getSourceAttrName());
               codeAndGroupCodeAttrMappingDTO.setTargetAttrId(dockingPreAttrMappingVO.getTargetAttrId());
               codeAndGroupCodeAttrMappingDTO.setTargetAttrKey(dockingPreAttrMappingVO.getTargetAttrKey());
               codeAndGroupCodeAttrMappingDTO.setTargetAttrName(dockingPreAttrMappingVO.getTargetAttrName());
               fieldList.add(dockingPreAttrMappingVO.getTargetAttrKey());
               colNameList.add(dockingPreAttrMappingVO.getSourceAttrName());
            }
            codeAttrMapGroupAttrDTOS.add(codeAndGroupCodeAttrMappingDTO);
         });
         execGroupCodePortDataDTO.setCodeAttrMapGroupAttrDTOS(codeAttrMapGroupAttrDTOS);
         execGroupCodePortDataDTO.setFieldList(fieldList);
         execGroupCodePortDataDTO.setColName(colNameList);
      }
   }
   /***
    * 集团码属性转换
    * @param titleRowData
    * @param codeAttrMapGroupAttrDTOS
    * @param fieldIndexMap
    */
   private void getGroupCodeFieldIndexMap(List<String> titleRowData,List<CodeAndGroupCodeAttrMappingDTO> codeAttrMapGroupAttrDTOS,Map<Integer/**列号**/,String/**字段的名称**/> fieldIndexMap){
      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);
         String id = "";
         if ("集团码".equalsIgnoreCase(title)) {
            id = CODE_GROUP_FIELD;
         }
         if ("企业编码".equalsIgnoreCase(title)) {
            id = CODE_FIELD;
         }
         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);
         }
      }
   }
   /***
    * 查询未有集团码的数据
    * @param classifyFullInfo
    * @param templateVO
    * @param selectFieldList
    * @param dataList
    */
   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();
      Map<String, String> conditionMap=new HashMap<>();
      if(conditionMap == null){
         conditionMap = new HashMap<>();
      }
      if(conditionMap.containsKey(VciQueryWrapperForDO.OID_FIELD)){
         conditionMap.put(VciQueryWrapperForDO.OID_FIELD,QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(conditionMap.get(VciQueryWrapperForDO.OID_FIELD)) + ")");
      }
      if(!CollectionUtils.isEmpty(codeList)){
         conditionMap.put("id_in",VciBaseUtil.array2String(codeList.toArray(new String[]{})));
      }
      conditionMap.put("codeclsfpath","*" + codeClassifyOid + "*");
      conditionMap.put("groupcode_null", "null");
      conditionMap.put("lastr", "1");
      conditionMap.put("lastv", "1");
      R<List<BtmTypeVO>> listR = btmTypeClient.selectByIdCollection(Arrays.asList(btmTypeId));
      String tableName = "";
      if(listR.isSuccess() && !listR.getData().isEmpty()){
         tableName = Func.isNotBlank(listR.getData().get(0).getTableName()) ? listR.getData().get(0).getTableName():VciBaseUtil.getTableName(btmTypeId);
      }else{
         tableName = VciBaseUtil.getTableName(btmTypeId);
      }
      PageHelper pageHelper = new PageHelper();
      pageHelper.setLimit(1000000);
      pageHelper.setPage(1);
      pageHelper.addDefaultDesc("createTime");
      DataGrid<Map<String, String>> dataGrid = engineService.queryGrid(btmTypeId, templateVO, conditionMap, pageHelper);
      //转换数据
      if(!CollectionUtils.isEmpty(dataGrid.getData())){
         dataList.addAll(dataGrid.getData());
      }
      //封装查询出来的数据
      engineService.wrapperData(dataList, templateVO, selectFieldList,false);
      //modify by weidy@2022-09-27
      //因为在列表和表单的显示的时候,我们的开关类型页面会处理,但是在导出的时候,我们需要将true和false都替换成中文
      engineService.wrapperBoolean(dataList,templateVO);
      log.info("导出模板的数据条目数:"+dataList.size());
   }
}