ludc
2023-08-30 d33ba05da2fbe74d8b85d393eca2a336f20f8688
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmIOServiceImpl.java
@@ -2,12 +2,18 @@
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vci.ubcs.code.applyjtcodeservice.feign.IMdmInterJtClient;
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.entity.CodeAllCode;
import com.vci.ubcs.code.enumpack.CodeDefaultLC;
import com.vci.ubcs.code.enumpack.CodeLevelTypeEnum;
import com.vci.ubcs.code.enumpack.sysIntegrationPushTypeEnum;
import com.vci.ubcs.code.lifecycle.CodeAllCodeLC;
import com.vci.ubcs.code.mapper.CommonsMapper;
import com.vci.ubcs.code.service.*;
import com.vci.ubcs.code.util.ClientBusinessObject;
@@ -16,6 +22,10 @@
import com.vci.ubcs.code.vo.webserviceModel.attrmap.DataObjectVO;
import com.vci.ubcs.code.vo.webserviceModel.attrmap.RowDatas;
import com.vci.ubcs.code.vo.webserviceModel.result.xml.XMLResultDataObjectDetailDO;
import com.vci.ubcs.file.util.VciZipUtil;
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.starter.bo.WriteExcelData;
import com.vci.ubcs.starter.exception.VciBaseException;
import com.vci.ubcs.starter.poi.bo.ReadExcelOption;
@@ -26,17 +36,16 @@
import com.vci.ubcs.starter.revision.model.BaseModel;
import com.vci.ubcs.starter.util.DefaultAttrAssimtUtil;
import com.vci.ubcs.starter.util.LocalFileUtil;
import com.vci.ubcs.starter.web.constant.QueryOptionConstant;
import com.vci.ubcs.starter.web.enumpck.BooleanEnum;
import com.vci.ubcs.starter.web.enumpck.UserSecretEnum;
import com.vci.ubcs.starter.web.enumpck.VciFieldTypeEnum;
import com.vci.ubcs.starter.web.pagemodel.DataGrid;
import com.vci.ubcs.starter.web.pagemodel.KeyValue;
import com.vci.ubcs.starter.web.pagemodel.PageHelper;
import com.vci.ubcs.starter.web.pagemodel.UIFormReferVO;
import com.vci.ubcs.starter.web.pagemodel.*;
import com.vci.ubcs.starter.web.toolmodel.DateConverter;
import com.vci.ubcs.starter.web.util.*;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
@@ -44,18 +53,23 @@
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Workbook;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import static com.alibaba.druid.util.FnvHash.Constants.LIMIT;
@@ -66,6 +80,21 @@
@Service
@Slf4j
public class MdmIOServiceImpl implements MdmIOService {
   /**
    * 字段
    */
   public static final String ROW_INDEX = "LAY_TABLE_INDEX";
   /**
    * 错误信息的字段
    */
   public static final String ERROR_MSG = "errorMsg";
   @Value("${batchadd.exportattr.type:基本信息}")
   public String BATCHADD_EXCEPORT_ATTR_TYPE;
   @Value("${batchadd.redis.time:6000000}")
   public int BATCHADD_REDIS_TIME;
   /**
@@ -74,11 +103,17 @@
   @Resource
   private ICodeClassifyService classifyService;
   /**
    * 通用查询
    */
   @Resource
   CommonsMapper commonsMapper;
   private CommonsMapper commonsMapper;
   /****
    * 码值服务
    */
   @Resource
   ICodeAllCodeService codeAllCodeService;
   /**
    * 模板的服务
@@ -111,6 +146,196 @@
    */
   @Autowired
   private FormulaServiceImpl formulaService;
   /**
    * 规则的服务
    */
   @Autowired
   private ICodeRuleService ruleService;
   /**
    * 业务类型的服务
    */
   @Autowired
   private IBtmTypeClient btmTypeClient;
   /***
    * 申请集团编码服务
    */
   @Resource
   private IMdmInterJtClient mdmInterJtClient;
   /***
    * 密级服务
    */
   @Resource
   private IWebSecretClient secretService;
   /**
    * 导出的十万条
    */
   public static final int EXPORT_LIMIT = 100000;
   /**
    * 批量申请:选取选中分类下的所有模板关键属性,相似属性,必填属性,写入execl中
    *
    * @param codeClassifyOid 分类的主键
    * @return excel的文件地址
    */
   @Override
   public String downloadTopImportExcel(String codeClassifyOid){
      List<CodeClassifyTemplateVO> templateVOList=new ArrayList<>();
      VciBaseUtil.alertNotNull("导出模板","导出的配置",codeClassifyOid,"主题库分类的主键");
      CodeClassifyVO codeClassifyVO = classifyService.getObjectByOid(codeClassifyOid);
      templateVOList= templateService.childTemplates(codeClassifyOid);
      List<CodeClassifyVO>  codeClassifyVOS=classifyService.getIdPathToNamePathByParentId(codeClassifyOid,true);
      WriteExcelOption eo = new WriteExcelOption();
      LinkedHashMap<String,CodeClassifyTemplateAttrVO> allFieldToOutNameMap=new LinkedHashMap<>();
      templateVOList.stream().forEach(templateVO -> {
         //组合格式的不导入,
         // 枚举的提供序列的选择
         //时间全部统一为yyyy-MM-dd HH:mm:ss
         //参照的自行输入名称
         //分类注入的不用,都是导入后自动处理的
         //编码,状态等字段不导入
         if(!CollectionUtils.isEmpty(templateVO.getAttributes())) {
            List<CodeClassifyTemplateAttrVO> templateAttrVOS = templateVO.getAttributes().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("模板没有配置任何【表单显示】为【是】的属性");
            }
            templateAttrVOS.stream().forEach(codetemplateAttr -> {
               String field = codetemplateAttr.getId();
               String name = codetemplateAttr.getName();
               CodeClassifyTemplateAttrVO codeBaseAttributeDTO = new CodeClassifyTemplateAttrVO();
               boolean res = (StringUtils.isNotBlank(codetemplateAttr.getAttributeGroup()) && codetemplateAttr.getAttributeGroup().equals(BATCHADD_EXCEPORT_ATTR_TYPE))//基本属性字段显示
                  || (StringUtils.isNotBlank(codetemplateAttr.getKeyAttrFlag()) && Boolean.parseBoolean(codetemplateAttr.getKeyAttrFlag()))//关键属性的存入
                  || (StringUtils.isNotBlank(codetemplateAttr.getSameRepeatAttrFlag()) && Boolean.parseBoolean(codetemplateAttr.getSameRepeatAttrFlag())) //相似属性的存入
                  || (StringUtils.isNotBlank(codetemplateAttr.getRequireFlag()) && Boolean.parseBoolean(codetemplateAttr.getRequireFlag()));
               if (allFieldToOutNameMap.containsKey(name)) {//如果存在的话则需要根据具体的去赋值
                  codeBaseAttributeDTO = allFieldToOutNameMap.get(name);
                  if (StringUtils.isNotBlank(codetemplateAttr.getKeyAttrFlag()) && Boolean.parseBoolean(codetemplateAttr.getKeyAttrFlag())) {
                     codeBaseAttributeDTO.setKeyAttrFlag(codetemplateAttr.getKeyAttrFlag());//属性关键属性
                  }
                  if (StringUtils.isNotBlank(codetemplateAttr.getRequireFlag()) && Boolean.parseBoolean(codetemplateAttr.getRequireFlag())) {
                     codeBaseAttributeDTO.setRequireFlag(codetemplateAttr.getRequireFlag());//属性必填项
                  }
                  if (StringUtils.isNotBlank(codetemplateAttr.getSameRepeatAttrFlag()) && Boolean.parseBoolean(codetemplateAttr.getSameRepeatAttrFlag())) {
                     codeBaseAttributeDTO.setSameRepeatAttrFlag(codetemplateAttr.getSameRepeatAttrFlag());//属性相似属性
                  }
               } else if (res) {
                  allFieldToOutNameMap.put(name, codetemplateAttr);
               }
            });
         }
      });
      //整理好所有模板需要写入execl的属性信息
      Workbook workbook = new HSSFWorkbook();
      LinkedList<WriteExcelData> excelDataList = new LinkedList<>();
      if(!CollectionUtils.isEmpty(allFieldToOutNameMap)){
         excelDataList.add(new WriteExcelData(0,0,"分类路径"));
         final int[] index = {0};
         allFieldToOutNameMap.values().stream().forEach(attrVO -> {
            Object text = attrVO.getName();
            text = exportKeyAndRequired(workbook,attrVO,text);
            int colIndex = 1 + index[0]++;
            WriteExcelData excelData = new WriteExcelData(0, colIndex, text);
            if(StringUtils.isNotBlank(attrVO.getCodeDateFormat())
               || VciFieldTypeEnum.VTDateTime.name().equalsIgnoreCase(attrVO.getAttributeDataType())
               || VciFieldTypeEnum.VTDate.name().equalsIgnoreCase(attrVO.getAttributeDataType())
               ||VciFieldTypeEnum.VTTime.name().equalsIgnoreCase(attrVO.getAttributeDataType())){
               excelData.setDateFormat(VciDateUtil.DateTimeFormat);
            }
            if(text instanceof RichTextString){
               excelData.setFontColor(String.valueOf(HSSFColor.HSSFColorPredefined.RED.getIndex()));
            }
            excelDataList.add(excelData);
            if(StringUtils.isNotBlank(attrVO.getEnumString()) || StringUtils.isNotBlank(attrVO.getEnumId())){
               //添加数据有效性
               List<String> enumValueList = new ArrayList<>();
               enumValueList.add("");
               List<KeyValue> valueList = engineService.listComboboxItems(attrVO);
               if(!CollectionUtils.isEmpty(valueList)){
                  valueList.stream().forEach(kv->{
                     enumValueList.add(kv.getValue());
                  });
               }
               //默认加1万条
               WriteExcelData ed = new WriteExcelData(1,colIndex,"");
               ed.setRowTo(100);
               ed.setColTo(colIndex);
               ed.setValidation(true);
               ed.setValidationDataList(enumValueList);
               ed.setValidationErrorMsg("请在序列中选择正确的值");
               excelDataList.add(ed);
            }
            if(VciFieldTypeEnum.VTBoolean.name().equalsIgnoreCase(attrVO.getAttributeDataType())){
               List<String> booleanList = new ArrayList<>();
               booleanList.add("是");
               booleanList.add("否");
               //默认加1万条
               WriteExcelData ed = new WriteExcelData(1,colIndex,"");
               ed.setRowTo(100);
               ed.setColTo(colIndex);
               ed.setValidation(true);
               ed.setValidationDataList(booleanList);
               ed.setValidationErrorMsg("请在序列中选择正确的值");
               excelDataList.add(ed);
            }
         });
         eo.addSheetDataList(codeClassifyVO.getName()+"导入模板",excelDataList);
      }
      LinkedList<WriteExcelData> classPathList = new LinkedList<>();
      classPathList.add(new WriteExcelData(0,0,"分类层级"));
      WriteExcelData idPathWriteExcelTitle=new WriteExcelData(0,1,"分类ID路径");
      idPathWriteExcelTitle.setWidth(20);
      idPathWriteExcelTitle.setCenter(false);
      classPathList.add(idPathWriteExcelTitle);
      WriteExcelData namePathWriteExcelTitle=new WriteExcelData(0,2,"分类名称路径");
      namePathWriteExcelTitle.setWidth(20);
      namePathWriteExcelTitle.setCenter(false);
      classPathList.add(namePathWriteExcelTitle);
      final int[] rowIndex = {1};
      codeClassifyVOS.stream().forEach(codeClassifyVO1 -> {
         classPathList.add(new WriteExcelData(rowIndex[0],0,codeClassifyVO1.getDataLevel()));
         String idPath=codeClassifyVO1.getIdPath().startsWith("#")?codeClassifyVO1.getIdPath().substring(1):codeClassifyVO1.getIdPath();
         WriteExcelData idPathWriteExcelData=new WriteExcelData(rowIndex[0],1,idPath);
         idPathWriteExcelData.setWidth(30);
         idPathWriteExcelData.setCenter(false);
         classPathList.add(idPathWriteExcelData);
         String namePath=codeClassifyVO1.getNamePath().startsWith("#")?codeClassifyVO1.getNamePath().substring(1):codeClassifyVO1.getNamePath();
         WriteExcelData  namePathWriteExcelData=  new WriteExcelData(rowIndex[0],2,namePath);
         namePathWriteExcelData.setWidth(40);
         namePathWriteExcelData.setCenter(false);
         classPathList.add(namePathWriteExcelData);
         rowIndex[0]++;
      });
      WriteExcelData  excelData=new WriteExcelData();
      excelData.setMerged(true);
      excelData.setRow(1);
      excelData.setRowTo(2);
      excelData.setCol(4);
      excelData.setColTo(9);
      excelData.setCenter(false);
      excelData.setReadOnly(true);
      excelData.setObj("导入数据时,分类路径必须填写叶子节点路径\n(选择叶子节点导入则不需要填写分类路径)");
      excelData.setFontColor(String.valueOf(HSSFColor.HSSFColorPredefined.RED.getIndex()));
      classPathList.add(excelData);
      eo.addSheetDataList(codeClassifyVO.getName()+"分类对照表",classPathList);
      String excelName = LocalFileUtil.getDefaultTempFolder() + File.separator + codeClassifyVO.getName() + "_导入模板.xls";
      // eo.addSheetDataList(templateVOList.size()+"模板信息【请勿删除或移动】",tempEDList);
      ExcelUtil.writeDataToFile(excelName,eo);
      return excelName;
   }
   /**
    * 生成导入的文件
    *
@@ -151,16 +376,23 @@
         //参照的自行输入名称
         //分类注入的不用,都是导入后自动处理的
         //编码,状态等字段不导入
         List<CodeClassifyTemplateAttrVO> templateAttrVOS = codeClassifyTemplateVO.getAttributes().stream().filter(s ->
         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())
               && (isHistory || VciBaseUtil.getBoolean(s.getFormDisplayFlag()))
         ).collect(Collectors.toList());
         if(CollectionUtils.isEmpty(templateAttrVOS)){
         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();
@@ -305,6 +537,644 @@
      }
//      return null;
      return codeImProtRusultVO;
   }
   /***
    * 从顶层批量申请导入方法
    * @param codeClassifyOid 分类的主键
    * @param classifyAttr 分类路径使用的属性
    * @param file excel文件的信息
    * @return
    */
   @Override
   public CodeImProtRusultVO batchTopImportCode(String codeClassifyOid, String classifyAttr, File file) {
      VciBaseUtil.alertNotNull(codeClassifyOid,"分类的主键");
      ReadExcelOption reo = new ReadExcelOption();
      reo.setReadAllSheet(true);
      List<SheetDataSet> sheetDataSetList = ExcelUtil.readDataObjectFromExcel(file,null,reo);
      if(CollectionUtils.isEmpty(sheetDataSetList) || CollectionUtils.isEmpty(sheetDataSetList.get(0).getRowData())
         ||sheetDataSetList.get(0).getRowData().size()<1){
         throw new VciBaseException("没有读取到任何的数据");
      }
      if(sheetDataSetList.size()>LIMIT+1){
         throw new VciBaseException("为了保证系统的稳定性,请一次不要导入超过1万条的数据");
      }
      //先找到每一行的标题,然后根据标题来获取对应的属性
      SheetDataSet dataSet = sheetDataSetList.get(0);
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      //获取当前模板
      CodeClassifyTemplateVO selectCodeClassifyTemplateVO =engineService.getUsedTemplateByClassifyOid(codeClassifyOid);
      Map<String,List<ColumnVO>> templateColumnVOMap=new HashMap<>();
      createTemplate(selectCodeClassifyTemplateVO,templateColumnVOMap);
      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));
      pathMap.put("#current#", classifyFullInfo.getCurrentClassifyVO());
      List<String> titleRowData = dataSet.getColName();
      Map<String, String> errorMap = new ConcurrentHashMap<>();
      //首先将数据以模板的形式分开
      LinkedHashMap<String,List<CodeImprotDataVO>> codeclassifyDataMap=new LinkedHashMap<>();
      List<CodeImprotDataVO> codeClassifyDatas=new ArrayList<>();
      createExeclClassData(dataSet,pathMap,errorMap,codeClassifyDatas);
      //根据模板将数据整合在一起,去校验
      Map<String/**模板oid**/, List<CodeImprotDataVO>/**数据对象**/> templateDatasMap =codeClassifyDatas.stream().collect(Collectors.toMap(CodeImprotDataVO::getTemplateOid,s->{
         List<CodeImprotDataVO> l=new ArrayList<>();
         l.add(s);
         return l;
      },(List<CodeImprotDataVO> s1,List<CodeImprotDataVO> s2)->{
         s1.addAll(s2);
         return s1;
      }));
      String uuid=VciBaseUtil.getPk();
      List<CodeImportTemplateVO> codeImportTemplateVOS=new ArrayList<>();
      Map<String,CodeImportTemplateVO> codeRuleMap=new HashMap<>();
      //相似数据
      // Map<String,String>wpResembleMap=new HashMap<>();
      // List<CodeImprotDataVO> wpCodeImprotDataVOList=new ArrayList<>();
      //按照模板去整理数据
      templateDatasMap.keySet().stream().forEach(templateVOOid->{
         List<CodeImprotDataVO> codeImprotDataVOS= templateDatasMap.get(templateVOOid);
         CodeClassifyTemplateVO templateVO= templateService.getObjectHasAttrByOid(templateVOOid);
         //除去默认的属性.还有只有表单显示的字段才导入
         List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
         ).collect(Collectors.toList());
         Map<String/**模板属性字段oid**/, String /**模板属性外部名称**/> fieldNameMap =attrVOS.stream().collect(Collectors.toMap(CodeClassifyTemplateAttrVO::getId,s->s.getName()));
         List<ClientBusinessObject> allCboList=new ArrayList<>();
         codeImprotDataVOS.stream().forEach(codeImprotDataVO -> {
            List<ColumnVO>columnVOList =new ArrayList();
            String templateOid=selectCodeClassifyTemplateVO.getOid();
            if(templateColumnVOMap.containsKey(templateOid)){
               columnVOList= columnVOList=templateColumnVOMap.get(templateOid);
            }else{
               createTemplate(templateVO,templateColumnVOMap);
               columnVOList= columnVOList=templateColumnVOMap.get(templateOid);
            }
            String codeRuleOid=codeImprotDataVO.getCodeRuleOid();
            if(!codeRuleMap.containsKey(codeRuleOid)){
               CodeImportTemplateVO codeImportTemplateVO=new CodeImportTemplateVO();
               codeImportTemplateVO.setRoot(false);
               codeImportTemplateVO.setCodeClassifyOid(codeImprotDataVO.getCodeClassifyOid());
               codeImportTemplateVO.setCodeRuleOid(codeImprotDataVO.getCodeRuleOid());
               codeImportTemplateVO.setCodeTemplateOid (codeImprotDataVO.getTemplateOid());
               codeImportTemplateVO.setCodeClassifyVO( codeImprotDataVO.getCodeClassifyVO());
               codeImportTemplateVO.setCodeClassifyTemplateVO( codeImprotDataVO.getCodeClassifyTemplateVO());
               codeImportTemplateVO.setCodeRuleVO(codeImprotDataVO.getCodeRuleVO());
               List<String> colNames=codeImprotDataVO.getColNames();
               codeImportTemplateVO.setCloNamesList(columnVOList);
               codeImportTemplateVOS.add(codeImportTemplateVO);
               codeRuleMap.put(codeRuleOid,codeImportTemplateVO);
            }
            List<ClientBusinessObject> cboList=new ArrayList<>();
            excelToCbo(classifyFullInfo,codeImprotDataVO,cboList,true);
            allCboList.addAll(cboList);
            //往选择的节点里面加数据
            // CodeImprotDataVO wpcodeImprotDataVO=new CodeImprotDataVO();
            //   BeanUtilForVCI.copyPropertiesIgnoreCase(codeImprotDataVO,wpcodeImprotDataVO);
               /* wpcodeImprotDataVO.setCodeClassifyOid(codeClassifyOid);
                wpcodeImprotDataVO.setCodeClassifyVO(classifyFullInfo.getCurrentClassifyVO());
                wpcodeImprotDataVO.setCodeClassifyTemplateVO(selectCodeClassifyTemplateVO);
                wpcodeImprotDataVO.setCodeRuleOid(classifyFullInfo.getCurrentClassifyVO().getCoderuleoid());*/
            // wpCodeImprotDataVOList.add(wpcodeImprotDataVO);//往物品对象里添加
         });
         //都转换完了。需要批量检查
         //如果出错了,我们依然执行有效的数据,无效的数据写回到excel中
         //2.判断必输项。。需要全部的属性,如果是必输,但是表单里面不显示的,只能是分类注入或者组合规则
         batchCheckRequiredAttrOnOrder(templateVO,allCboList,errorMap);
         //3.判断关键属性
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, allCboList);
         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,allCboList,classifyFullInfo,false);
         //boolean
         reSwitchBooleanAttrOnOrder(attrVOS,allCboList);
         //4.校验规则
         batchCheckVerifyOnOrder(attrVOS, allCboList,errorMap);
         //是否需要校验枚举/参照
         //5.校验枚举是否正确
         batchSwitchEnumAttrOnOrder(attrVOS, allCboList, errorMap);
         //7.处理参照的情况
         batchSwitchReferAttrOnOrder(attrVOS,allCboList,errorMap);
         //6.时间格式的验证
         //6.时间的,必须统一为yyyy-MM-dd HH:mm:ss
         batchSwitchDateAttrOnOrder(attrVOS,allCboList,errorMap);
         //设置默认值
         batchSwitchAttrDefault(attrVOS, allCboList);
         //最后弄组合规则
         batchSwitchComponentAttrOnOrder(attrVOS,allCboList);
         Map<String, ClientBusinessObject> rowIndexCboMap = allCboList.stream().filter(cbo -> cbo != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getAttributeValue((IMPORT_ROW_INDEX)), t -> t));
         List<ClientBusinessObject> needSaveCboList = allCboList.stream().filter(cbo -> {
            String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
            return !errorMap.containsKey(rowIndex);
         }).collect(Collectors.toList());
         //相似校验
         Map<String,String>resembleMap=new HashMap<>();
         List<DataResembleVO> dataResembleVOS=new ArrayList<>();
         String btmtypeid= classifyFullInfo.getTopClassifyVO().getBtmTypeId();
         bathcResembleQuery(codeClassifyOid,templateVO,needSaveCboList,resembleMap,btmtypeid,dataResembleVOS);
         if(resembleMap.size()>0) {
            if(!CollectionUtils.isEmpty(dataResembleVOS)) {
               bladeRedis.set(uuid + "-resemble-data", dataResembleVOS);
               bladeRedis.expire(uuid + "-resemble-data",BATCHADD_REDIS_TIME);//redis过期时间
               // createRedisDatas(uuid + "-resemble", codeImprotDataVOS, resembleMap, false);
               //  wpResembleMap.putAll(resembleMap);
            }
         }
         //排除错误的,剩下正确的
         Map<String,String> newErrorMap=new HashMap<>();
         newErrorMap.putAll(resembleMap);
         newErrorMap.putAll(errorMap);
         needSaveCboList = allCboList.stream().filter(cbo -> {
            String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
            return !newErrorMap.containsKey(rowIndex);
         }).collect(Collectors.toList());
         if(newErrorMap.size()>0) {
            createRedisDatas(uuid + "-resemble",codeImprotDataVOS, newErrorMap,false);
         }
         createRedisDatas(uuid + "-ok",codeImprotDataVOS, newErrorMap,true);
      });
      //往物品节点上加模板
      List<String> needRowIndexList=new ArrayList<>();
      CodeImProtRusultVO codeImProtRusultVO = new CodeImProtRusultVO();
      if(errorMap.size()>0) {
         String filePath = returnErrorToExcel(dataSet.getRowData(), errorMap, needRowIndexList, dataSet.getColName());
         if (StringUtils.isNotBlank(filePath)) {
            codeImProtRusultVO.setFilePath(filePath);
         }
      }
      if(StringUtils.isNotBlank(uuid)){
         //将所有的分类存入缓存之中
         codeImProtRusultVO.setRedisUuid(uuid);
         /**  List<ColumnVO>columnVOList=new ArrayList<>();
          CodeImportTemplateVO wpCodeImportTemplateVO=new CodeImportTemplateVO();
          wpCodeImportTemplateVO.setRoot(true);
          wpCodeImportTemplateVO.setCodeClassifyTemplateVO(selectCodeClassifyTemplateVO);
          wpCodeImportTemplateVO.setCodeClassifyVO(classifyFullInfo.getCurrentClassifyVO());
          String templateOid=selectCodeClassifyTemplateVO.getOid();
          if(templateColumnVOMap.containsKey(templateOid)){
          columnVOList= columnVOList=templateColumnVOMap.get(templateOid);
          }else{
          createTemplate(selectCodeClassifyTemplateVO,templateColumnVOMap);
          columnVOList= columnVOList=templateColumnVOMap.get(templateOid);
          }
          wpCodeImportTemplateVO.setCloNamesList(columnVOList);
          codeImportTemplateVOS.add(wpCodeImportTemplateVO);
          if(wpResembleMap.size()>0){
          //  redisService.setCacheList(uuid + "-resemble-data", wpDataResembleVOList);
          createRedisDatas(uuid + "-resemble",selectCodeClassifyTemplateVO, wpCodeImprotDataVOList, wpResembleMap, false,codeClassifyOid);
          }
          //排除错误的,剩下正确的
          Map<String,String> newErrorMap=new HashMap<>();
          newErrorMap.putAll(wpResembleMap);
          newErrorMap.putAll(errorMap);
          List<CodeImprotDataVO>  needSaveCboList = wpCodeImprotDataVOList.stream().filter(cbo -> {
          String rowIndex = cbo.getRowIndex();
          return !newErrorMap.containsKey(rowIndex);
          }).collect(Collectors.toList());
          createRedisDatas(uuid + "-ok",selectCodeClassifyTemplateVO,wpCodeImprotDataVOList, newErrorMap,true,codeClassifyOid);****/
         if(codeImportTemplateVOS.size()>0){
            bladeRedis.set(uuid + "-class",codeImportTemplateVOS);
            bladeRedis.expire(uuid + "-class",BATCHADD_REDIS_TIME);
         }
      }
      return codeImProtRusultVO;
   }
   /**
    * 导入历史数据
    *
    * @param codeClassifyOid 分类的主键
    * @param classifyAttr 分类路径使用的属性
    * @param file            excel文件的信息
    * @return 有错误信息的excel
    */
   @Override
   public CodeImProtRusultVO batchImportHistoryData(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万条的数据");
      }
      Map<String,List<WriteExcelData>> shetNameMap=new HashMap<>();
      //相似项目查重
      String uuid=VciBaseUtil.getPk();
      boolean isCreateUUid=false;
      boolean isExport=false;
      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;
         }
         //历史导入的时候不处理编码
         //----逻辑内容----
         //1. 分类的路径可以在页面上选择是分类编号还是分类的名称
         //2. 分类的路径,必须是当前导入选择的分类的节点,以及其下级节点
         //3. 通过数据要导入的分类去查找对应的编码规则
         //4. 数据存储和批量申请一样,
         //5. 需要单独处理企业编码的内容,
         //     5.1 企业编码在当前excel里不能重复
         //     5.2 企业编码在系统中不能重复(可以是已经回收的)
         //     5.3 企业编码的长度,和编码规则的长度要对应上
         //     5.4 获取流水码段的值,去除填充的字符,看流水号是多少,然后将流水号和现在的最大流水号判断,小于就直接录入,大于则修改最大流水号
         //     5.5 存储企业编码到allcode中
         //查询分类和模板
         CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
         //先找到每一行的标题,然后根据标题来获取对应的属性
         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);
         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("导入的数据所选择的分类都没有设置编码规则");
         }
         Map<String, CodeRuleVO> ruleVOMap = ruleService.listCodeRuleByIds(ruleOidMap.values(), true).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;
            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 ArrayList<>();
               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 {
                     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, "") + ";系统错误,存储数据的时候出错了");
                     });
                  }
               }
            });
            if (errorMap.size() > 0) {
               isExport = true;
            }
            createWriteExcelData(rowDataList, errorMap, new ArrayList<>(), titleRowData, shetNameMap, finalTemplateVO);
            engineService.batchSaveSelectChar(templateVO, dataCBOIdList);
         }
      }
      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("");
      }
      if(isCreateUUid){
         codeImProtRusultVO.setRedisUuid(uuid);
      }
      return codeImProtRusultVO;
   }
   /*private void converBaseModels(List<ClientBusinessObject> clientBusinessObjects,List<BaseModel>dataCBOList){
      clientBusinessObjects.stream().forEach(clientBusinessObject -> {
         BaseModel baseModel=new BaseModel();
         BeanUtil.convert(clientBusinessObject,baseModel);
         Map<String,String> dataMap=new HashMap<>();
         clientBusinessObject.getHisAttrValList()
         baseModel.setData(VciBaseUtil.objectToMapString(baseModel));
         AttributeValue[] newAttributeValue=    clientBusinessObject.getNewAttrValList();
         dataCBOList.add(baseModel);
      });
   }*/
   /***
    * 从execl里构建对象
    * @param rowDataList
    * @param errorMap
    * @param needRowIndexList
    * @param titleRowData
    * @param shetNameMap
    * @param templateVO
    */
   private void createWriteExcelData(Collection<SheetRowData> rowDataList, Map<String,String> errorMap,
                             List<String> needRowIndexList, List<String> titleRowData, Map<String,List<WriteExcelData>> shetNameMap, CodeClassifyTemplateVO templateVO){
      List<WriteExcelData> errorDataList=new ArrayList<>();
      Map<String, SheetRowData> rowIndexDataMap = rowDataList.stream().filter(s -> !needRowIndexList.contains(s.getRowIndex())).collect(Collectors.toMap(s -> s.getRowIndex(), t -> t));
      errorDataList.add(new WriteExcelData(0,0,"错误信息"));
      for (int i = 0; i < titleRowData.size(); i++) {
         //错误信息在最后
         errorDataList.add(new WriteExcelData(0,i+1,titleRowData.get(i)));
      }
      Integer[] newRowIndex = new Integer[]{1};
      errorMap.forEach((index,error)->{
         //错误信息全部组合到一起
         SheetRowData rowData = rowIndexDataMap.getOrDefault(index, null);
         if(rowData!=null){
            errorDataList.add(new WriteExcelData(newRowIndex[0],0,error));
            rowData.getData().forEach((colIndex,value)->{
               errorDataList.add(new WriteExcelData(newRowIndex[0],colIndex+1,value));
            });
            newRowIndex[0]++;
         }
      });
      shetNameMap.put(templateVO.getName(),errorDataList);
   }
   /***
    *
    * @param currentTemplateVO
    * @param templateColumnVOMap
    */
   private void createTemplate(CodeClassifyTemplateVO currentTemplateVO,Map<String,List<ColumnVO>>templateColumnVOMap){
      List<CodeClassifyTemplateAttrVO> templateAttrVOS = currentTemplateVO.getAttributes().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<ColumnVO> columnVOList=new ArrayList<>();
      ColumnVO errorMsgColumnVO=new ColumnVO();
      errorMsgColumnVO.setTitle("错误信息");
      errorMsgColumnVO.setField("errorMsg");
      columnVOList.add(errorMsgColumnVO);
      ColumnVO pathColumnVO=new ColumnVO();
      pathColumnVO.setTitle("分类路径");
      pathColumnVO.setField("codeclsfid");
      columnVOList.add(pathColumnVO);
      templateAttrVOS.stream().forEach(codetemplateAttr ->{
         String field=codetemplateAttr.getId();
         String name=codetemplateAttr.getName();
         ColumnVO columnVO=new ColumnVO();
         columnVO.setTitle(name);
         columnVO.setField(field);
         columnVO.setWidth(codetemplateAttr.getAttrTableWidth()==0?columnVO.getWidth():codetemplateAttr.getAttrTableWidth());
         columnVOList.add(columnVO);
      });
      templateColumnVOMap.put(currentTemplateVO.getOid(),columnVOList);
      log.info("模板"+currentTemplateVO.getName()+"对应的属性"+columnVOList.size());
   }
   /**
@@ -465,7 +1335,7 @@
      //相似校验
      Map<String,String>resembleMap=new HashMap<>();
      List<DataResembleVO> dataResembleVOS=new ArrayList<>();
      String btmtypeid= classifyFullInfo.getTopClassifyVO().getBtmtypeid();
      String btmtypeid= classifyFullInfo.getTopClassifyVO().getBtmTypeId();
      bathcResembleQuery(orderDTO.getCodeClassifyOid(),templateVO,needSaveCboList,resembleMap,btmtypeid,dataResembleVOS);
      if(resembleMap.size()>0) {
         isCreateUUid=true;
@@ -492,27 +1362,27 @@
         uuid="";
         //要把以上的错误的都抛出后,再继续处理时间和组合规则
         /*dataCBOList = cboList.stream().filter(cbo -> {
         needSaveCboList = cboList.stream().filter(cbo -> {
            String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
            return !newErrorMap.containsKey(rowIndex);
         }).collect(Collectors.toList());
*/         List<String> dataCBOIdList=new ArrayList<>();
         List<BaseModel> dataCBOList=new ArrayList<>();
         cboList.stream().forEach(clientBusinessObject -> {
            BaseModel baseModel=new BaseModel();
            BeanUtil.convert(clientBusinessObject,baseModel);
            baseModel.setData(VciBaseUtil.objectToMapString(clientBusinessObject));
            dataCBOList.add(baseModel);
            dataCBOIdList.add(baseModel.getOid());
         });
         if (!CollectionUtils.isEmpty(needSaveCboList)) {
            //9.我们处理业务数据
            //生成编码的内容
            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, dataCBOIdList);
               engineService.batchSaveSelectChar(templateVO, dataCBOList);
            } catch (Exception e) {
               e.printStackTrace();
               log.error("批了申请时失败");
@@ -529,8 +1399,7 @@
   public List<CodeImportTemplateVO> gridclassifys(String redisOid) {
      List<CodeImportTemplateVO> codeImportTemplateVOs=new ArrayList<>();
      VciBaseUtil.alertNotNull(redisOid,"分类",redisOid,"分类缓存主键");
      List<CodeImportTemplateVO> redisServiceCacheObjects=bladeRedis.lRange(redisOid,0,-1);
      List<CodeImportTemplateVO> redisServiceCacheObjects=bladeRedis.get(redisOid);
      if(redisServiceCacheObjects!=null){
         codeImportTemplateVOs=  redisServiceCacheObjects;
      }
@@ -546,7 +1415,7 @@
   @Override
   public DataGrid<Map<String, String>> gridDatas(String codeClssifyOid, String redisOid) {
      VciBaseUtil.alertNotNull(redisOid,"导入相似数据",redisOid,"数据缓存主键");
      List<CodeImprotDataVO> codeImprotDataVOs = bladeRedis.lRange(redisOid+"-"+codeClssifyOid,0,-1);
      List<CodeImprotDataVO> codeImprotDataVOs = bladeRedis.get(redisOid+"-"+codeClssifyOid);
//      redisService.getCacheList(redisOid+"-"+codeClssifyOid);
      CodeImprotDataVO codeImprotDataVO=new CodeImprotDataVO();
      if(!CollectionUtils.isEmpty(codeImprotDataVOs)){
@@ -580,7 +1449,7 @@
   @Override
   public DataGrid<Map<String,String>> gridRowResemble(String oid,String redisOid){
      VciBaseUtil.alertNotNull(redisOid,"导入相似数据",redisOid,"数据缓存主键");
      List<DataResembleVO> codeImprotDataVOs = bladeRedis.lRange(redisOid,0,-1);;
      List<DataResembleVO> codeImprotDataVOs = bladeRedis.get(redisOid);;
      DataGrid<Map<String, String>> dataGrid = new DataGrid<>();
      List<Map<String, String>> dataList = new ArrayList<>();
@@ -600,6 +1469,435 @@
   }
   /**
    * 导出主题库的数据
    *
    * @param exportAttrDTO 导出相关的配置,必须要有主题库分类的主键
    * @return 导出的excel的文件
    */
   @Override
   public String exportCode(CodeExportAttrDTO exportAttrDTO) {
      VciBaseUtil.alertNotNull(exportAttrDTO,"导出的配置",exportAttrDTO.getCodeClassifyOid(),"主题库分类的主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(exportAttrDTO.getCodeClassifyOid());
      //获取最新的模板
      CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(exportAttrDTO.getCodeClassifyOid());
      //先查询数据
      String btmTypeId = classifyFullInfo.getTopClassifyVO().getBtmTypeId();
      Map<String, String> conditionMap = exportAttrDTO.getConditionMap();
      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)) + ")");
      }
      PageHelper pageHelper = new PageHelper(exportAttrDTO.getLimit()==null?-1:exportAttrDTO.getLimit());
      pageHelper.setPage(exportAttrDTO.getPage()==null?1:exportAttrDTO.getPage());
      pageHelper.setSort(exportAttrDTO.getSort());
      pageHelper.setOrder(exportAttrDTO.getOrder());
      pageHelper.addDefaultDesc("createTime");
      conditionMap.put("codeclsfpath","*" + exportAttrDTO.getCodeClassifyOid() + "*");
      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);
      }
      String countSql = "select count(*) from " + tableName +" where 1=1" +
         " and lastr = '1'" +
         " and lastv='1'" +
         " and codeclsfpath like '%" + exportAttrDTO.getCodeClassifyOid() + "%'";
      //先查询总数
      int total = 0;
      if(exportAttrDTO.getEndPage()!=null && exportAttrDTO.getEndPage()>0
         &&exportAttrDTO.getPage() !=null && exportAttrDTO.getPage() >0
         &&exportAttrDTO.getEndPage()>exportAttrDTO.getPage()){
         //从多少页到多少页的查询方式,
         for(int i = exportAttrDTO.getPage() ;i <= exportAttrDTO.getEndPage();i++){
            PageHelper thisPage = new PageHelper(exportAttrDTO.getLimit()==null?-1:exportAttrDTO.getLimit());
            thisPage.setPage(exportAttrDTO.getPage()==null?1:exportAttrDTO.getPage());
            thisPage.setSort(exportAttrDTO.getSort());
            thisPage.setOrder(exportAttrDTO.getOrder());
            thisPage.addDefaultDesc("createTime");
            total += commonsMapper.queryCountBySql(countSql);
         }
      }else{
         total = commonsMapper.queryCountBySql(countSql);
      }
      List<String> selectFieldList = new ArrayList<>();
      if(!CollectionUtils.isEmpty(exportAttrDTO.getAttrIdIndexMap())){
         selectFieldList = exportAttrDTO.getAttrIdIndexMap().values().stream().map(s->s.toLowerCase(Locale.ROOT)).collect(Collectors.toList());
      }else{
         selectFieldList = templateVO.getAttributes().stream().filter(s->VciBaseUtil.getBoolean(s.getFormDisplayFlag())
            ||VciBaseUtil.getBoolean(s.getTableDisplayFlag())).map(s->s.getId().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
      }
      //参照让平台直接查询就行
      List<String> finalSelectFieldList = selectFieldList;
      List<CodeClassifyTemplateAttrVO> referAttrVOs = templateVO.getAttributes().stream().filter(
         s -> StringUtils.isNotBlank(s.getReferBtmId())
            &&
            (finalSelectFieldList.size() ==0 || finalSelectFieldList.contains(s.getId().toLowerCase(Locale.ROOT)))
      ).collect(Collectors.toList());
      if(!CollectionUtils.isEmpty(referAttrVOs)){
         for (int i = 0; i < referAttrVOs.size(); i++) {
            selectFieldList.add(referAttrVOs.get(i).getId() + ".name");
         }
      }
      List<String> excelNameList = new CopyOnWriteArrayList<>();
      String tempFolder = LocalFileUtil.getDefaultTempFolder();
      if(total>EXPORT_LIMIT){
         //分组来执行
         int queryCount = (total-total%EXPORT_LIMIT)/EXPORT_LIMIT;
         if(total%EXPORT_LIMIT>0){
            queryCount = queryCount + 1;
         }
         List<Integer> indexList = new ArrayList<>();
         for (int i = 0; i <queryCount ; i++) {
            indexList.add(i);
         }
         Map<String, String> finalConditionMap = conditionMap;
         //并行查询看看
         SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
         indexList.stream().forEach(index->{
            //线程的方式,所以需要设置当前用户
            VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
            PageHelper thisPage = new PageHelper(EXPORT_LIMIT);
            thisPage.setPage(index+1);
            thisPage.setSort(exportAttrDTO.getSort());
            thisPage.setOrder(exportAttrDTO.getOrder());
            thisPage.addDefaultDesc("createTime");
            selectDataAndExportExcelName(btmTypeId, finalConditionMap,thisPage,finalSelectFieldList,
               classifyFullInfo,templateVO,exportAttrDTO,
               excelNameList,tempFolder,index);
         });
      }else{
         pageHelper.setLimit(total);
         pageHelper.setPage(1);
         selectDataAndExportExcelName(btmTypeId,conditionMap,pageHelper,finalSelectFieldList,
            classifyFullInfo,templateVO,exportAttrDTO,
            excelNameList,tempFolder,1);
      }
      if(excelNameList.size() ==0){
         throw new VciBaseException("没有数据可以被导出");
      }
      if(excelNameList.size() == 1){
         return excelNameList.get(0);
      }
      //是多个,我们需要打成压缩包
      String zipFileName = LocalFileUtil.getDefaultTempFolder() + File.separator + classifyFullInfo.getCurrentClassifyVO().getId() + "_" + classifyFullInfo.getCurrentClassifyVO().getName() + "_导出_" + excelNameList.size()+".zip";
      VciZipUtil zipUtil = new VciZipUtil();
      File file = new File(tempFolder);
      zipUtil.addFileToZip(file,zipFileName);
      File[] files = file.listFiles();
      for (int i = 0; i < files.length; i++) {
         LocalFileUtil.deleteTempFile(files[i],false);
      }
      LocalFileUtil.deleteTempFile(file,true);
      return zipFileName;
   }
   /**
    * 查询数据并导出到excel
    * @param btmTypeId 业务类型
    * @param conditionMap 查询条件
    * @param pageHelper 分页
    * @param selectFieldList 查询的字段
    * @param classifyFullInfo 分类的全部信息
    * @param templateVO 模板的信息
    * @param exportAttrDTO 导出的属性
    * @param excelNameList excel的文件名称
    * @param tempFolder 临时文件夹
    * @param excelIndex excel的顺序
    */
   private void selectDataAndExportExcelName(String btmTypeId, Map<String, String> conditionMap, PageHelper pageHelper, List<String> selectFieldList,
                                   CodeClassifyFullInfoBO classifyFullInfo, CodeClassifyTemplateVO templateVO, CodeExportAttrDTO exportAttrDTO,
                                   List<String> excelNameList, String tempFolder,
                                   Integer excelIndex) {
      DataGrid<Map<String, String>> dataGrid = engineService.queryGrid(btmTypeId, templateVO, conditionMap, pageHelper);
      if(dataGrid == null || CollectionUtils.isEmpty(dataGrid.getData())){
         return;
      }
      //转换数据
      List<Map<String, String>> dataMap = dataGrid.getData();
      //封装查询出来的数据
      engineService.wrapperData(dataMap, templateVO, selectFieldList,false);
      //modify by weidy@2022-09-27
      //因为在列表和表单的显示的时候,我们的开关类型页面会处理,但是在导出的时候,我们需要将true和false都替换成中文
      engineService.wrapperBoolean(dataMap,templateVO);
      Map<String, CodeClassifyTemplateAttrVO> attrVOMap = templateVO.getAttributes().stream().filter(s->selectFieldList.contains(s.getId().toLowerCase(Locale.ROOT))).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      Map<Integer, String> attrIdIndexMap = exportAttrDTO.getAttrIdIndexMap();
      if (CollectionUtils.isEmpty(attrIdIndexMap)) {
         attrIdIndexMap = templateVO.getAttributes().stream().filter(s->selectFieldList.contains(s.getId().toLowerCase(Locale.ROOT))).collect(Collectors.toMap(s -> s.getOrderNum(), t -> t.getId()));
      }
      List<Integer> indexList = attrIdIndexMap.keySet().stream().sorted().collect(Collectors.toList());
      String excelName = tempFolder + File.separator +
         classifyFullInfo.getCurrentClassifyVO().getId() + "_" + classifyFullInfo.getCurrentClassifyVO().getName() + "_导出_" + excelIndex + ".xls";
      try {
         new File(excelName).createNewFile();
      } catch (Throwable e) {
         throw new VciBaseException(LangBaseUtil.getErrorMsg(e), new String[]{excelName}, e);
      }
      excelNameList.add(excelName);
      List<WriteExcelData> excelDataList = new ArrayList<>();
      Workbook workbook = new HSSFWorkbook();
      for (int i = 0; i < indexList.size(); i++) {
         String attrId = attrIdIndexMap.get(indexList.get(i)).toLowerCase(Locale.ROOT);
         if (attrVOMap.containsKey(attrId)) {
            CodeClassifyTemplateAttrVO attrVO = attrVOMap.get(attrId);
            Object text = attrVO.getName();
            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};
      Map<Integer, String> finalAttrIdIndexMap = attrIdIndexMap;
      dataMap.stream().forEach(data -> {
         rowIndex[0]++;
         for (int i = 0; i < indexList.size(); i++) {
            Integer index = indexList.get(i);
            String attrId = finalAttrIdIndexMap.get(index).toLowerCase(Locale.ROOT);
            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, data.getOrDefault(attrId, "")));
            }
         }
      });
      WriteExcelOption excelOption = new WriteExcelOption(excelDataList);
      ExcelUtil.writeDataToFile(excelName, excelOption);
   }
   @Override
   public R batchImportData(List<CodeImprotSaveDatVO> codeImprotSaveDatVOList, String classifyAttr, boolean isImprot) {
      WriteExcelOption eo = new WriteExcelOption();
      AtomicBoolean success= new AtomicBoolean(true);
      codeImprotSaveDatVOList.stream().forEach(codeImprotSaveDatVO -> {
         List<SheetRowData> rowDataList = new ArrayList<>();
         List<ClientBusinessObject>cboList=new ArrayList<>();
         List<String> colList=codeImprotSaveDatVO.getClos();
         CodeOrderDTO orderDTO= codeImprotSaveDatVO.getOrderDTO();
         List<Map<String, String>> dataList= codeImprotSaveDatVO.getDataList();
         Map<Integer, String> fieldIndexMap = new HashMap();
         for (int i=0;i<dataList.size();i++){
            SheetRowData sheetRowData=new SheetRowData();
            Map<String,String> dataMap= dataList.get(i);
            Map<Integer, String> data = new HashMap();
            final int[] colIndex = {0};
            Map<Integer, String> finalFieldIndexMap = new HashMap<>();
            dataMap.forEach((field, value)->{
               if(!ROW_INDEX.equalsIgnoreCase(field) && !ERROR_MSG.equalsIgnoreCase(field)){
                  data.put(colIndex[0],value);
                  finalFieldIndexMap.put(colIndex[0]++,field);
               }
            });
            fieldIndexMap=finalFieldIndexMap;
            sheetRowData.setData(data);
            sheetRowData.setRowIndex(i+"");
            rowDataList.add(sheetRowData);
         }
         CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
         log.info("分类:"+classifyFullInfo.getCurrentClassifyVO().getName()+"数据:"+codeImprotSaveDatVO.getDataList().size());
         // CodeClassifyTemplateVO codeClassifyTemplateVO=   engineService.getUsedTemplateByClassifyOid(orderDTO.getCodeClassifyOid());
         CodeClassifyTemplateVO codeClassifyTemplateVO=  templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
         //规则的主键需要去获取
         CodeRuleVO ruleVO = engineService.getCodeRuleByClassifyFullInfo(classifyFullInfo);
         //除去默认的属性.还有只有表单显示的字段才导入
         List<CodeClassifyTemplateAttrVO> attrVOS = codeClassifyTemplateVO.getAttributes().stream().filter(s ->
            !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
         ).collect(Collectors.toList());
         String fullPath = getFullPath(classifyFullInfo);
         excelToCbo(classifyFullInfo,fieldIndexMap,rowDataList, codeClassifyTemplateVO,cboList,fullPath,!isImprot);
         Map<String,String> errorMap=new HashMap<>();
         Map<String/**路径**/, CodeClassifyVO> pathMap=new HashMap<>() ;
         //校验编码规则和码段是否正确
         Map<String, List<String>> ruleRowIndexMap = new ConcurrentHashMap<>();
         Map<String, CodeRuleVO> ruleVOMap =new ConcurrentHashMap<>();
         if(isImprot) {
            Map<String/**主键**/, String/**路径**/> childOidPathMap = getChildClassifyPathMap(classifyFullInfo, fullPath);
            //都转换完了。需要批量检查
            //找所有的分类路径,需要校验路径是否正确,是否都在当前的分类的下级
            List<CodeClassifyVO> childClassifyVOs = classifyService.listChildrenClassify(orderDTO.getCodeClassifyOid(), true, classifyAttr, true);
            pathMap = Optional.ofNullable(childClassifyVOs).orElseGet(() -> new ArrayList<>()).stream().collect(Collectors.toMap(s -> s.getPath().startsWith("#") ? s.getPath().substring(1) : s.getPath(), t -> t));
            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());
            //我们需要判断这些分类的模板是不是一样的,只需要校验,不用获取
            //检查分类的路径
            checkClassifyPathInHistory(cboList, errorMap, pathMap, childOidPathMap);
            //检查规则
            Map<String/**分类主键**/, String/**规则主键**/> ruleOidMap = new ConcurrentHashMap<String, String>();
            List<String> unExistRuleClassifyOidList = new CopyOnWriteArrayList<>();
            checkRuleOidInHistory(classifyVOMap, ruleOidMap, unExistRuleClassifyOidList);
            ruleVOMap = ruleService.listCodeRuleByIds(ruleOidMap.values(), true).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
            checkSecLengthInHistory(cboList, classifyVOMap, ruleVOMap, ruleOidMap, errorMap, ruleRowIndexMap);
         }
         //分类注入
         batchSwitchClassifyAttrOnOrder(attrVOS,cboList,classifyFullInfo,isImprot);
         //boolean
         reSwitchBooleanAttrOnOrder(attrVOS,cboList);
         //4.校验规则
         batchCheckVerifyOnOrder(attrVOS, cboList,errorMap);
         //5.校验枚举是否正确
         batchSwitchEnumAttrOnOrder(attrVOS, cboList, errorMap);
         //7.处理参照的情况
         batchSwitchReferAttrOnOrder(attrVOS,cboList,errorMap);
         //6.时间格式的验证
         //6.时间的,必须统一为yyyy-MM-dd HH:mm:ss
         batchSwitchDateAttrOnOrder(attrVOS,cboList,errorMap);
         //设置默认值
         batchSwitchAttrDefault(attrVOS, cboList);
         //最后弄组合规则
         batchSwitchComponentAttrOnOrder(attrVOS,cboList);
         //3.判断关键属性
         CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, codeClassifyTemplateVO, cboList);
         Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
         Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
         if(!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)){
            keyAttrRepeatRowIndexList.stream().forEach(rowIndex->{
               errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";关键属性与系统中的重复" );
            });
         }
         //4.校验规则
         batchCheckVerifyOnOrder(attrVOS, cboList,errorMap);
         if(isImprot){
            List<ClientBusinessObject> needSaveCboList = cboList.stream().filter(cbo -> {
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
               return !errorMap.containsKey(rowIndex);
            }).collect(Collectors.toList());
            List<ClientBusinessObject> finalNeedSaveCboList = needSaveCboList;
            Map<String, CodeRuleVO> finalRuleVOMap = ruleVOMap;
            ruleRowIndexMap.keySet().parallelStream().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());
               if (!CollectionUtils.isEmpty(thisCbos)) {
                  thisCbos.stream().forEach(clientBusinessObject -> {
                     BaseModel baseModel = new BaseModel();
                     BeanUtil.convert(clientBusinessObject, baseModel);
                     dataCBOList.add(baseModel);
                  });
                  try {
                     productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, finalRuleVOMap.get(ruleOid), null, dataCBOList);
                  } catch (Throwable e) {
                     //success=false;
                     log.error("批量产生编码的时候出错了", e);
                     thisCbos.stream().forEach(cbo -> {
                        String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                        errorMap.put(rowIndex, errorMap.getOrDefault(rowIndex, "") + ";系统错误,存储数据的时候出错了:"+e.getMessage());
                     });
                  }
               }
               engineService.batchSaveSelectChar(codeClassifyTemplateVO, dataCBOList);
            });
         }else {
            List<BaseModel> dataCBOList=new ArrayList<>();
            List<ClientBusinessObject> needSaveCboList = cboList.stream().filter(cbo -> {
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
               return !errorMap.containsKey(rowIndex);
            }).collect(Collectors.toList());
            log.info("分类:" + classifyFullInfo.getCurrentClassifyVO().getName() + "数据:" + needSaveCboList.size());
            if (!CollectionUtils.isEmpty(needSaveCboList)) {
               needSaveCboList.stream().forEach(clientBusinessObject -> {
                  BaseModel baseModel = new BaseModel();
                  BeanUtil.convert(clientBusinessObject, baseModel);
                  dataCBOList.add(baseModel);
               });
               try {
                  productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList);
               } catch (Exception e) {
                  log.error("批量产生编码的时候出错了", e);
                  needSaveCboList.stream().forEach(cbo -> {
                     String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
                     errorMap.put(rowIndex, errorMap.getOrDefault(rowIndex, "") + ";系统错误,存储数据的时候出错了:"+e.getMessage());
                  });
               }
               //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
               engineService.batchSaveSelectChar(codeClassifyTemplateVO, dataCBOList);
            }
         }
         if(errorMap.size()>0) {
            success.set(false);
            LinkedList<WriteExcelData> excelDataList = new LinkedList<>();
            excelDataList.add(new WriteExcelData(0, 0, "错误信息"));
            final int[] index = {1};
            errorMap.forEach((key,v)->{
               excelDataList.add(new WriteExcelData(index[0]++, 0, "第"+(Integer.parseInt(key)+1)+"行数据:"+v));
            });
            eo.addSheetDataList(codeClassifyTemplateVO.getName() + "导入模板", excelDataList);
         }
      });
      if(!success.get()){
         String excelName = LocalFileUtil.getDefaultTempFolder() + File.separator + (isImprot?"批量历史错误信息.xls":"批量申请错误信息.xls");
         ExcelUtil.writeDataToFile(excelName,eo);
         return  R.fail(excelName);
      }else {
         return R.success(isImprot ? "批量历史导入成功" : "批量申请成功");
      }
   }
   /***
    *根据数据oid从缓存中移除数据
    * @param redisOid redisid
    * @param codeClssifyOid 存储规则的oid
    * @param dataOids  所需删除的数据
    * @return
    */
   @Override
   public R deleteDatas(String redisOid,String codeClssifyOid,String dataOids) {
      VciBaseUtil.alertNotNull(redisOid, "数据删除", redisOid, "数据缓存主键");
      VciBaseUtil.alertNotNull(codeClssifyOid, "数据删除", codeClssifyOid, "编码规则缓存主键");
      VciBaseUtil.alertNotNull(dataOids, "数据删除", dataOids, "所需删除的数据主键");
      try {
         List<CodeImprotDataVO> codeImprotDataVOs = bladeRedis.lRange(redisOid + "-" + codeClssifyOid,0,-1);
         List<String> dataOidList = new ArrayList<>();
         codeImprotDataVOs.stream().forEach(codeImprotDataVO -> {
            List<Map<String, String>> newDataList = new ArrayList<>();
            List<Map<String, String>> dataList = codeImprotDataVO.getDatas();
            dataList.stream().forEach(dataMap -> {
               String oid = dataMap.get("oid");
               if (!dataOidList.contains(oid)) {
                  newDataList.add(dataMap);
               }
            });
            codeImprotDataVO.setDatas(newDataList);
         });
         //重新缓存
         bladeRedis.del(redisOid + "-" + codeClssifyOid);
         bladeRedis.set(redisOid + "-" + codeClssifyOid, codeImprotDataVOs);
         bladeRedis.expire(redisOid + "-" + codeClssifyOid, BATCHADD_REDIS_TIME);
         return R.success("删除缓存数据成功");
      }catch (Throwable e){
         return R.fail("删除缓存数据失败!");
      }
   }
   /**
    * 集成批量申请数据
    * @param orderDTO 分类的主键
    * @param dataObjectVO 数据信息
@@ -607,7 +1905,7 @@
    * @return 有错误信息的excel
    */
   @Override
   public void batchSyncApplyCode(CodeOrderDTO orderDTO, DataObjectVO dataObjectVO, LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs) {
   public void batchSyncApplyCode(CodeOrderDTO orderDTO, DataObjectVO dataObjectVO, LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs,boolean isCodeOrGroupCode) {
      Map<String,String> errorMap=new HashMap<>();
      VciBaseUtil.alertNotNull(orderDTO,"编码申请相关的数据",orderDTO.getCodeClassifyOid(),"主题库分类主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
@@ -642,7 +1940,7 @@
      if(!CollectionUtils.isEmpty(unExistAttrVOs)){
         throw new VciBaseException("【" + unExistAttrVOs.stream().map(CodeClassifyTemplateAttrVO::getName) + "】这些属性在excel中没有找到");
      }
      List<ClientBusinessObject> cboList = new ArrayList<>();
      String fullPath = getFullPath(classifyFullInfo);
      // List<CodeClassifyProcessTempVO> codeClassifyProcessTempVOS=codeClassifyProcessTempService.listProcessTemplate(templateVO.getOid(),"code_cls_flow_use_order");
@@ -651,19 +1949,922 @@
      /** if(!CollectionUtils.isEmpty(codeClassifyProcessTempVOS)){
       isProcess=true;
       }***/
      //List<ClientBusinessObject> cboList = new ArrayList<>();
      //Map<String,String> codeOidToSystemOidMap=new HashMap<>();//存储编码数据和集成系统数据oid对照映射
      //excelToCbo(classifyFullInfo,titleRowData,fieldIndexMap,rowDataList,templateVO,cboList,fullPath,isProcess,"create",errorMap,codeOidToSystemOidMap);
      Map<String,String> codeOidToSystemOidMap=new HashMap<>();//存储编码数据和集成系统数据oid对照映射
      excelToCbo(classifyFullInfo,titleRowData,fieldIndexMap,rowDataList,templateVO,cboList,fullPath,isProcess,"create",errorMap,codeOidToSystemOidMap);
      //都转换完了。需要批量检查
      //如果出错了,我们依然执行有效的数据,无效的数据写回到excel中
      //2.判断必输项。。需要全部的属性,如果是必输,但是表单里面不显示的,只能是分类注入或者组合规则
      batchCheckRequiredAttrOnOrder(templateVO,cboList,errorMap);
      /**
       * 关键熟悉错误提示
       */
      Map<String,String> errorKeyMap=new HashMap<>();
      //3.判断关键属性
      CodeImportResultVO keyResultVO = batchCheckKeyAttrOnOrder(classifyFullInfo, templateVO, cboList);
      Set<String> selfRepeatRowIndexList = keyResultVO.getSelfRepeatRowIndexList();
      Set<String> keyAttrRepeatRowIndexList = keyResultVO.getKeyAttrRepeatRowIndexList();
      Map<String,List<String>>keyAttrOkOidTORepeatOidMap= keyResultVO.getKeyAttrOkOidTORepeatOidMap();
      if(!CollectionUtils.isEmpty(selfRepeatRowIndexList)){
         selfRepeatRowIndexList.stream().forEach(rowIndex->{
               /* //传入数据之间关键属性的校验
                RowDatas rowData= rowDataMap.get(rowIndex);
                XMLResultDataObjectDetailDO resultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
                resultDataObjectDetailDO.setCode("");
                resultDataObjectDetailDO.setId(rowData.getOid());
                resultDataObjectDetailDO.setErrorid("1");
                resultDataObjectDetailDO.setMsg(errorMap.getOrDefault(rowIndex,"") + ";关键属性重复");
                resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
                */
            errorKeyMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";传入的数据中关键属性重复");
         });
      }
      /****
       * 关键属性与系统中重复的判断
       */
      if(!CollectionUtils.isEmpty(keyAttrRepeatRowIndexList)){
         keyAttrRepeatRowIndexList.stream().forEach(rowIndex->{
            //传入数据之间关键属性的校验
               /* RowDatas rowData= rowDataMap.get(rowIndex);
                XMLResultDataObjectDetailDO resultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
                resultDataObjectDetailDO.setCode("");
                resultDataObjectDetailDO.setId(rowData.getOid());
                resultDataObjectDetailDO.setErrorid("1");
                resultDataObjectDetailDO.setMsg(errorMap.getOrDefault(rowIndex,"") + ";关键属性与系统中的重复" );
                resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
                */
            errorKeyMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";关键属性与系统中的重复" );
         });
      }
      //分类注入
      batchSwitchClassifyAttrOnOrder(attrVOS,cboList,classifyFullInfo,false);
      //boolean
      reSwitchBooleanAttrOnOrder(attrVOS,cboList);
      // cboList.stream().forEach(cbo->{
      //4.校验规则
      batchCheckVerifyOnOrder(attrVOS, cboList,errorMap);
      //5.校验枚举是否正确
      batchSwitchEnumAttrOnOrder(attrVOS,cboList,errorMap);
      //6.时间格式的验证
      //6.时间的,必须统一为yyyy-MM-dd HH:mm:ss
      batchSwitchDateAttrOnOrder(attrVOS,cboList,errorMap);
      //7.处理参照的情况
      batchSwitchReferAttrOnOrder(attrVOS,cboList,errorMap);
      //校验属性是否正确错误信息
      if(errorMap.size()>0){
         String[] newMsg = {""};
         cboList.stream().forEach(cbo -> {
            String rowIndex =cbo.getAttributeValue(IMPORT_ROW_INDEX);
            if(errorMap.containsKey(rowIndex)){
               String oid=cbo.getOid();
               String sourceOid=oid;
               if(codeOidToSystemOidMap.containsKey(oid)){
                  sourceOid=codeOidToSystemOidMap.get(oid);
               }
               String code="";
               String groupCode="";
               String errorid="103";
               String mes=errorMap.get(rowIndex);
               XMLResultDataObjectDetailDO resultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
               if(isCodeOrGroupCode){
                  resultDataObjectDetailDO.setCode(groupCode);
               }else{
                  resultDataObjectDetailDO.setCode(code);
               }
               resultDataObjectDetailDO.setId(sourceOid);
               resultDataObjectDetailDO.setErrorid(errorid);
               resultDataObjectDetailDO.setMsg(mes);
               resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
            }
         });
      }
      Map<String,String> newKeyMap=new HashedMap();
      if(errorKeyMap.size()>0 ) {
         errorKeyMap.keySet().forEach(key->{
            if(!errorMap.containsKey(key)){
               newKeyMap.put(key,errorKeyMap.get(key));
            }
         });
         if(newKeyMap.size()>0) {
            List<BaseModel> editBoList = new ArrayList<>();
            Map<String, List<BaseModel>> indexTodataMap = keyResultVO.getIndexTODataMap();
            cboList.stream().forEach(cbo -> {
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
               if (indexTodataMap.containsKey(rowIndex)) {
                  String oid = cbo.getOid();
                  String sourceOid = oid;
                  String code = "";
                  String groupCode="";
                  String errorid = "201";
                  if(codeOidToSystemOidMap.containsKey(oid)){
                     sourceOid=codeOidToSystemOidMap.get(oid);
                  }
                  List<BaseModel> newCboList = indexTodataMap.get(rowIndex);
                  if (!CollectionUtils.isEmpty(newCboList)) {
                     BaseModel newCbo= newCboList.get(0);
                     String lcstatus =newCbo.getLcStatus();
                     String newOid =newCbo.getOid();
                     Date ts =newCbo.getTs();
                     code = StringUtils.isBlank(newCbo.getId())?"":newCbo.getId();
                     groupCode=newCbo.getData().getOrDefault("GROUPCODE","");
                     String lastmodifier=newCbo.getLastModifier();
                     if (lcstatus!=null&&!lcstatus.equals(CodeDefaultLC.RELEASED.getValue())) {
                        newCbo.setOid(newOid);
                        newCbo.setLastModifier(lastmodifier);
                        /*if(isCodeOrGroupCode) {
                           newCbo.setId(code);
                        }else{
                           newCbo.getData().put("groupcode",groupCode);
                        }*/
                        newCbo.setTs(ts);
                        cbo.setLastModifier(cbo.getLastModifier());
                        editBoList.add(newCbo);
                     }
                     String mes = errorKeyMap.get(rowIndex);
                     XMLResultDataObjectDetailDO resultDataObjectDetailDO = new XMLResultDataObjectDetailDO();
                     if(isCodeOrGroupCode) {
                        if(StringUtils.isBlank(groupCode)){
                           errorid="1";
                           mes+=";申请的编码类型为集团码,等待集团编码赋值";
                        }
                        resultDataObjectDetailDO.setCode(groupCode);
                     }else{
                        resultDataObjectDetailDO.setCode(code);
                     }
                     resultDataObjectDetailDO.setId(sourceOid);
                     resultDataObjectDetailDO.setErrorid(errorid);
                     resultDataObjectDetailDO.setMsg(mes);
                     resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
                  }
               }
            });
            //关键熟悉更改
            if (!CollectionUtils.isEmpty(editBoList)) {
               engineService.updateBatchByBaseModel(classifyFullInfo.getTopClassifyVO().getBtmTypeId(),editBoList);//保存数据
            }
            errorMap.putAll(errorKeyMap);
         }
      }
      //  });
      //设置默认值
      batchSwitchAttrDefault(attrVOS, cboList);
      //最后弄组合规则
      batchSwitchComponentAttrOnOrder(attrVOS,cboList);
      //要把以上的错误的都抛出后,再继续处理时间和组合规则
      List<ClientBusinessObject> needSaveCboList = cboList.stream().filter(cbo -> {
         String rowIndex =cbo.getAttributeValue(IMPORT_ROW_INDEX);
         return !errorMap.containsKey(rowIndex);
      }).collect(Collectors.toList());
      List<String> needRowIndexList = new ArrayList<>();
      if(!CollectionUtils.isEmpty(needSaveCboList)) {
         //9.我们处理业务数据
         //生成编码的内容
         List<String>allNeedSaveCboList=new ArrayList<>();
         List<BaseModel> dataCBOList=new ArrayList<>();
         needSaveCboList.stream().forEach(clientBusinessObject -> {
            BaseModel baseModel=new BaseModel();
            BeanUtil.convert(clientBusinessObject,baseModel);
            //(VciBaseUtil.objectToMapString(clientBusinessObject));
            dataCBOList.add(baseModel);
            allNeedSaveCboList.add(baseModel.getOid());
         });
         try {
            List<String>applyGroupCodeIdList=new ArrayList<>();
            productCodeService.productCodeAndSaveData(classifyFullInfo, templateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList);
            //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
            engineService.batchSaveSelectChar(templateVO, dataCBOList);
            // if(!isProcess){
            dataCBOList.stream().forEach(needSaveCbo->{
               XMLResultDataObjectDetailDO resultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
               String code=StringUtils.isBlank(needSaveCbo.getId())?" ":needSaveCbo.getId();
               String groupCode=needSaveCbo.getData().getOrDefault("GROUPCODE"," ");
               //resultDataObjectDetailDO.setCode(needSaveCbo.getId());
               String msg="申请编码成功";
               String oid=needSaveCbo.getOid();
               String sourceOid=oid;
               applyGroupCodeIdList.add(oid);
               if(codeOidToSystemOidMap.containsKey(oid)){
                  sourceOid=codeOidToSystemOidMap.get(oid);
               }
               if(isCodeOrGroupCode) {
                  if(StringUtils.isBlank(groupCode)){
                     resultDataObjectDetailDO.setErrorid("1");
                     msg="申请的编码类型为集团码,等待集团编码赋值";
                  }
                  resultDataObjectDetailDO.setCode(groupCode);
               }else{
                  resultDataObjectDetailDO.setCode(code);
                  resultDataObjectDetailDO.setErrorid("0");
               }
               resultDataObjectDetailDO.setId(sourceOid);
               resultDataObjectDetailDO.setMsg(msg);
               resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
               //处理传送的数据中关键属性重复的,直接拿到已经申请到编码的数据编码直接将赋给关键属性重复的数据
               LinkedList<XMLResultDataObjectDetailDO> repeatDataObjectDetailDOS=handleApplyDataKeyAttrRepeat(keyAttrOkOidTORepeatOidMap,codeOidToSystemOidMap,needSaveCbo,isCodeOrGroupCode);
               resultDataObjectDetailDOs.addAll(repeatDataObjectDetailDOS);
            });
               /* }else{
                    needSaveCboList.stream().forEach(needSaveCbo->{
                        XMLResultDataObjectDetailDO resultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
                       // resultDataObjectDetailDO.setCode(needSaveCbo.getId());//不用返回编码
                        String oid=needSaveCbo.getOid();
                        String sourceOid=oid;
                        if(codeOidToSystemOidMap.containsKey(oid)){
                            sourceOid=codeOidToSystemOidMap.get(oid);
                        }
                        resultDataObjectDetailDO.setId(sourceOid);
                        resultDataObjectDetailDO.setErrorid("204");
                        resultDataObjectDetailDO.setMsg("申请编码成功,等待编码系统发布!");
                        resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
                    });
                }*/
            //是否调用集团接口申请接口
            if(isCodeOrGroupCode){
               if(!CollectionUtils.isEmpty(applyGroupCodeIdList)) {
                  this.sendApplyGroupcode(applyGroupCodeIdList, classifyFullInfo.getTopClassifyVO().getId(), sysIntegrationPushTypeEnum.ACCPET_APPCODE.getValue());
               }
            }
         }catch (Throwable e){
            e.printStackTrace();
            needSaveCboList.stream().forEach(needSaveCbo->{
               XMLResultDataObjectDetailDO resultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
               resultDataObjectDetailDO.setCode("");
               String oid=needSaveCbo.getOid();
               String sourceOid=oid;
               if(codeOidToSystemOidMap.containsKey(oid)){
                  sourceOid=codeOidToSystemOidMap.get(oid);
               }
               resultDataObjectDetailDO.setId(sourceOid);
               resultDataObjectDetailDO.setErrorid("1");
               resultDataObjectDetailDO.setMsg("保存出现问题:"+e.getMessage());
               resultDataObjectDetailDOs.add(resultDataObjectDetailDO);
            });
         }
      }
   }
   /***
    *给同一批申请编码存在关键属性的数据赋上一致编码
    * @param keyAttrOkOidTORepeatOidMap 一批申请数据关键属性一致的重复数据映射关系
    * @param codeOidToSystemOidMap
    * @param needSaveCbo
    * @param isCodeOrGroupCode
    */
   private LinkedList<XMLResultDataObjectDetailDO> handleApplyDataKeyAttrRepeat(Map<String,List<String>>keyAttrOkOidTORepeatOidMap,Map<String,String> codeOidToSystemOidMap,BaseModel needSaveCbo,boolean isCodeOrGroupCode){
      LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs=new LinkedList<>();
      String oid=needSaveCbo.getOid();
      if(keyAttrOkOidTORepeatOidMap.containsKey(oid)){
         List<String> repeatOidList= keyAttrOkOidTORepeatOidMap.get(oid);
         if(!CollectionUtils.isEmpty(repeatOidList)){
            String sourceNewOid=needSaveCbo.getOid();
            String sourceOid=sourceNewOid;
            if(codeOidToSystemOidMap.containsKey(oid)){
               sourceOid=codeOidToSystemOidMap.get(oid);
            }
            String code=StringUtils.isBlank(needSaveCbo.getId())?" ":needSaveCbo.getId();
            String groupCode=needSaveCbo.getData().getOrDefault("GROUPCODE"," ");
            String finalSourceOid = sourceOid;
            repeatOidList.stream().forEach(repeatOid->{
               if(codeOidToSystemOidMap.containsKey(repeatOid)){
                  XMLResultDataObjectDetailDO repeatresultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
                  String repeatSourceOid=codeOidToSystemOidMap.get(repeatOid);
                  String repeatMsg="此数据与申请的编码数据id为【"+ finalSourceOid +"】的关键属性一致,则取相同编码";
                  if(isCodeOrGroupCode) {
                     if(StringUtils.isBlank(groupCode)){
                        repeatMsg="申请的编码类型为集团码,等待集团编码赋值";
                     }
                     repeatresultDataObjectDetailDO.setCode(groupCode);
                  }else{
                     repeatresultDataObjectDetailDO.setCode(code);
                  }
                  repeatresultDataObjectDetailDO.setId(repeatSourceOid);
                  repeatresultDataObjectDetailDO.setErrorid("0");
                  repeatresultDataObjectDetailDO.setMsg(repeatMsg);
                  resultDataObjectDetailDOs.add(repeatresultDataObjectDetailDO);
               }
            });
         }
      }
      return  resultDataObjectDetailDOs;
   }
   /***
    * 集成批量同步更新接口
    * @param codeClassifyVO;
    * @param dataObjectVO 数据信息
    * @param resultDataObjectDetailDOs 错误信息
    * @param isCodeOrGroupCode 是否更集团系统数据
    */
   @Transactional(rollbackFor = VciBaseException.class)
   @Override
   public void batchSyncEditDatas(CodeClassifyVO codeClassifyVO, DataObjectVO dataObjectVO, LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs) {
   public void batchSyncEditDatas(CodeClassifyVO codeClassifyVO, DataObjectVO dataObjectVO, LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs,boolean isCodeOrGroupCode) {
      String errorid="";
      String msg="";
      //查询分类和模板
      //先找到每一行的标题,然后根据标题来获取对应的属性
      List<RowDatas> rowDataList = dataObjectVO.getRowData();
      Map<String, RowDatas> rowDataMap = new LinkedHashMap<>();
      Map<String, RowDatas> codeDataMap = new LinkedHashMap<>();
      rowDataList.stream().forEach(rowData -> {
         rowDataMap.put(rowData.getRowIndex(), rowData);
         codeDataMap.put(rowData.getCode(), rowData);
      });
      //找第一行,为了找标题
      CodeClassifyTemplateVO templateVO = engineService.getUsedTemplateByClassifyOid(codeClassifyVO.getOid());
      // 应该都是一个分类下的业务数据,找第一条的就行
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyVO.getOid());
      //校验模板是不是最新的
      //checkTemplateSync(sheetDataSetList,templateVO);
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = templateVO.getAttributes().stream().filter(s -> !DEFAULT_SYNC_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      ).collect(Collectors.toList());
      Map<Integer/**列号**/, String/**字段的名称**/> fieldIndexMap = new HashMap<>();
      List<String> titleRowData = dataObjectVO.getColName();
      Map<String/**中文名称**/, String/**英文名称**/> attrNameIdMap = attrVOS.stream().collect(Collectors.toMap(s -> s.getName(), t -> t.getId().toLowerCase(Locale.ROOT), (o1, o2) -> o2));
      getFieldIndexMap(titleRowData, attrNameIdMap, fieldIndexMap);
      //Map<String, String> cboOidMap = new HashMap<>();
      //cboOidMap.put("id", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(codeDataMap.keySet().toArray(new String[0])) + ")");
      String tableName ="";
      try {
         R<BtmTypeVO> r = btmTypeClient.getAllAttributeByBtmId(templateVO.getBtmTypeId());
         if(!r.isSuccess()) {
            throw new Throwable(r.getMsg());
         }
         BtmTypeVO btmTypeVO = r.getData();
         if (btmTypeVO == null) {
            throw new Throwable("根据业务类型未查询到业务类型对象!");
         }
         tableName = btmTypeVO.getTableName();
         if (StringUtils.isBlank(tableName)) {
            throw new Throwable("根据业务类型未查询到业务类型相关联的表");
         }
      }catch (Throwable e){
         log.error("查询业务对象表"+e);
         XMLResultDataObjectDetailDO xmlResultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
         xmlResultDataObjectDetailDO.setErrorid("103");
         xmlResultDataObjectDetailDO.setMsg("查询业务对象表"+e);
         xmlResultDataObjectDetailDO.setId("");
         xmlResultDataObjectDetailDO.setCode("");
         resultDataObjectDetailDOs.add(xmlResultDataObjectDetailDO);
         return;
      }
      StringBuffer sb=new StringBuffer();
      sb.append(" select * from ");
      sb.append(tableName);
      sb.append(" where 1=1 ");
      sb.append(" and lastr=1 and lastv=1" );
      if(isCodeOrGroupCode) {
         sb.append(" and groupcode in (");
      }else{
         sb.append(" and id in (");
      }
      sb.append(VciBaseUtil.toInSql(codeDataMap.keySet().toArray(new String[0])));
      sb.append(")");
      List<Map<String,String>> dataMapList=commonsMapper.queryByOnlySqlForMap(sb.toString());
      List<ClientBusinessObject> cboList=   ChangeMapTOClientBusinessObjects(dataMapList);
      Map<String, ClientBusinessObject> codeSystemObjectMap = cboList.stream().filter(systeDataObject -> systeDataObject != null && StringUtils.isNotBlank(systeDataObject.getId())).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getId(), t -> t));
      Map<String, String> errorMap = new HashMap<>();
      List<CodeOrderDTO> codeOrderDTOList = new ArrayList<>();
      this.getCodeOrderDTOs(codeClassifyVO, templateVO, codeDataMap, codeSystemObjectMap, codeOrderDTOList, errorMap,isCodeOrGroupCode);
      // List<CodeClassifyProcessTempVO> codeClassifyProcessTempVOS=codeClassifyProcessTempService.listProcessTemplate(templateVO.getOid(),"code_cls_flow_use_order");
      boolean isProcess=false;
      /**  if(!CollectionUtils.isEmpty(codeClassifyProcessTempVOS)){
       isProcess=true;
       }**/
      Map<String, CodeOrderDTO> orderDTOMap = codeOrderDTOList.stream().filter(orderDTO -> orderDTO != null && StringUtils.isNotBlank(orderDTO.getId())).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getId(), t -> t));
      List<BaseModel> updateList = new ArrayList<>();
      List<CodeAllCode> codeAllCodeList = new ArrayList<>();
      List<String> deleteList = new ArrayList<>();
      CodeClassifyTemplateVO firstTemplateVO = templateService.getObjectHasAttrByOid(orderDTOMap.values().stream().findFirst().get().getTemplateOid());
      Map<String, ClientBusinessObject> cboMap = cboList.stream().filter(cbo -> cbo != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getId(), t -> t));
      //  boolean finalIsProcess = isProcess;
      orderDTOMap.keySet().stream().forEach(code -> {
         CodeOrderDTO orderDTO = orderDTOMap.get(code);
         ClientBusinessObject cbo = cboMap.get(code);
         String dataStatus=cbo.getLcStatus();
         RowDatas rowData=codeDataMap.get(code);
         String status=rowData.getStatus();
         String operation=rowData.getOperation();
         if (cbo.getTs().compareTo(orderDTO.getTs())==0?false:true) {
            // throw new VciBaseException("数据不是最新的,可能他人已经修改,请刷新后再试");
            errorMap.put(orderDTO.getId(),errorMap.getOrDefault(orderDTO.getId(),"")+";数据不是最新的,可能他人已经修改,请刷新后再试");
         }
           /* if (!CodeDefaultLC.EDITING.getValue().equalsIgnoreCase(cbo.getLcStatus()) && !orderDTO.isEditInProcess()) {
                throw new VciBaseException("数据不是{0}的状态,不允许修改", new String[]{CodeDefaultLC.EDITING.getText()});
            }*/
         if(operation.equals("update")) {
            //1. 判断必输项
            checkRequiredAttrOnOrder(templateVO, orderDTO, errorMap);
            //2.先注入,再组合,最后校验
            switchClassifyLevelOnOrder(templateVO, classifyFullInfo, orderDTO, errorMap);
            //3.处理组合规则。组合规则不能使用编码的属性,因为编码的生成可能是需要属性的
            switchComponentAttrOnOrder(templateVO, orderDTO);
            //4.校验规则
            checkVerifyOnOrder(templateVO, orderDTO, errorMap);
            //5.判断关键属性
            checkKeyAttrOnOrder(classifyFullInfo, templateVO, orderDTO, errorMap);
            //6.校验枚举的内容是否正确
            checkEnumOnOrder(templateVO, orderDTO, errorMap);
            //7.处理时间格式,在数据库里面不论是字符串还是日期格式,都使用相同的格式存储
            switchDateAttrOnOrder(templateVO, orderDTO);
            //默认的内容不能变,所以只需要拷贝自定义的相关属性即可
            copyValueToCBO(classifyFullInfo, cbo, orderDTO, templateVO, true, errorMap);
            //企业码和集团码的不修改
            cbo.setDescription(StringUtils.isBlank(orderDTO.getDescription())?"":orderDTO.getDescription());
            cbo.setName(orderDTO.getName());
            try {
               cbo.setAttributeValueWithNoCheck("description", orderDTO.getDescription());
               cbo.setAttributeValue("name", orderDTO.getName());
               //  if(finalIsProcess){//在流程中不允许更改
               //     errorMap.put(code,errorMap.getOrDefault(code, errorMap.getOrDefault(code,"")+";数据"+code+"在流程中,不允许更改!"));
               //  }else{
               cbo.setLcStatus(status);
               cbo.setAttributeValue("lcstatus",status);
               //  }
            } catch (VciBaseException e) {
               e.printStackTrace();
            }
            List<CodeAllCode>newCodeAllCodeList= codeAllCodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCreateCodeOid, cbo.getOid()));
            if (!CollectionUtils.isEmpty(newCodeAllCodeList)) {
               CodeAllCode codeCbo = newCodeAllCodeList.get(0);
               log.info("codeCbos code:" + codeCbo.getId());
               codeCbo.setLcStatus(status);
               codeAllCodeList.add(codeCbo);
            }
            BaseModel baseModel=new BaseModel();
            BeanUtil.convert(cbo,baseModel);
            //baseModel.setData(VciBaseUtil.objectToMapString(cbo));
            updateList.add(baseModel);
         }else if(operation.equals("delete")){//如果在流程中不允许删除,不在流程中状态为发布或者停用的数据不允许删除,将其更改为停用,其他的情况直接删除
            //  if(finalIsProcess){
            //    errorMap.put(code,errorMap.getOrDefault(code, errorMap.getOrDefault(code,"")+";数据"+code+"在流程中,不允许删除!"));
            //}else {
            try {
               log.info("oid:" + cbo.getOid());
               List<CodeAllCode>newCodeAllCodeList= codeAllCodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCreateCodeOid, cbo.getOid()));
               log.info("codeCbos size:" + newCodeAllCodeList.size());
               if (!CollectionUtils.isEmpty(newCodeAllCodeList)) {
                  CodeAllCode codeCbo = codeAllCodeList.get(0);
                  log.info("codeCbos code:" + codeCbo.getId());
                  codeCbo.setLcStatus(CodeDefaultLC.TASK_BACK.getValue());
                  codeAllCodeList.add(codeCbo);
               }
               deleteList.add(cbo.getOid());
            }catch (VciBaseException e) {
               e.printStackTrace();
            }
            // }
         }else if(operation.equals("editstatus")){
            try {
               //  if (finalIsProcess) {
               //      errorMap.put(code, errorMap.getOrDefault(code, errorMap.getOrDefault(code, "") + ";数据" + code + "在流程中,不允许更改状态!"));
               //   } else {
               cbo.setLcStatus(status);
               cbo.setAttributeValue("lcstatus", status);
               //  }
               List<CodeAllCode>newCodeAllCodeList= codeAllCodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCreateCodeOid, cbo.getOid()));
               if (!CollectionUtils.isEmpty(newCodeAllCodeList)) {
                  CodeAllCode codeCbo = codeAllCodeList.get(0);
                  log.info("codeCbos code:" + codeCbo.getId());
                  codeCbo.setLcStatus(status);
                  codeAllCodeList.add(codeCbo);
               }
               BaseModel baseModel=new BaseModel();
               BeanUtil.convert(cbo,baseModel);
               //baseModel.setData(VciBaseUtil.objectToMapString(cbo));
               updateList.add(baseModel);
            }catch (VciBaseException e) {
               e.printStackTrace();
            }
         }
      });
      /**
       * 错误信息输出
       */
      if(errorMap.size()>0){
         errorMap.keySet().forEach(code->{
            if(codeDataMap.containsKey(code)){
               RowDatas rowDatas=  codeDataMap.get(code);
               String dataMsg=errorMap.get(code);
               String oid=rowDatas.getOid();
               XMLResultDataObjectDetailDO xmlResultDataObjectDetailDO=new XMLResultDataObjectDetailDO();
               xmlResultDataObjectDetailDO.setErrorid("103");
               xmlResultDataObjectDetailDO.setMsg(dataMsg);
               xmlResultDataObjectDetailDO.setId(oid);
               xmlResultDataObjectDetailDO.setCode(code);
               resultDataObjectDetailDOs.add(xmlResultDataObjectDetailDO);
            }
         });
      }else {
         //存储数据
         try {
            engineService.updateBatchByBaseModel(classifyFullInfo.getTopClassifyVO().getBtmTypeId(),updateList);
            codeAllCodeService.saveOrUpdateBatch(codeAllCodeList);
            if(deleteList.size()>0) {
               commonsMapper.deleteByTaleAndOid(tableName, VciBaseUtil.array2String(deleteList.toArray(new String[]{})));
            }
            //是否调用集团接口申请接口
            if(isCodeOrGroupCode){
               List<String> IdList=resultDataObjectDetailDOs.stream().filter(xMLResultDataObjectDetailDO-> com.alibaba.cloud.commons.lang.StringUtils.isNotBlank(xMLResultDataObjectDetailDO.getId())).map(XMLResultDataObjectDetailDO::getId).distinct().collect(Collectors.toList());
               if(!CollectionUtils.isEmpty(IdList)) {
                  this.sendApplyGroupcode(IdList, classifyFullInfo.getTopClassifyVO().getBtmTypeId(),sysIntegrationPushTypeEnum.ACCPET_EDITCODE.getValue());
               }
            }
            errorid="0";
            msg="更新/状态更改/删除成功!";
         }catch (Throwable e){
            errorid="1";
            msg="保存失败:"+e;
         }finally {
            String finalMsg = msg;
            String finalErrorid = errorid;
            cboList.stream().forEach(cbo->{
               String code =cbo.getId();
               if(codeDataMap.containsKey(code)) {
                  RowDatas rowDatas=codeDataMap.get(code);
                  String oid=rowDatas.getOid();
                  XMLResultDataObjectDetailDO xmlResultDataObjectDetailDO = new XMLResultDataObjectDetailDO();
                  xmlResultDataObjectDetailDO.setErrorid(finalErrorid);
                  xmlResultDataObjectDetailDO.setMsg(finalMsg);
                  xmlResultDataObjectDetailDO.setId(oid);
                  xmlResultDataObjectDetailDO.setCode(code);
                  resultDataObjectDetailDOs.add(xmlResultDataObjectDetailDO);
               }
            });
         }
      }
   }
   /**
    * 校验属性是否为必输
    *
    * @param templateVO 模板的显示对象,需要包含模板属性
    * @param orderDTO   编码申请的信息
    */
   private void checkRequiredAttrOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO,Map<String,String> errorMap) {
      Map<String, CodeClassifyTemplateAttrVO> requiredAttrMap = templateVO.getAttributes().stream().filter(
            s -> VciBaseUtil.getBoolean(s.getRequireFlag()) && StringUtils.isBlank(s.getComponentRule())
               && StringUtils.isBlank(s.getClassifyInvokeAttr()))
         .collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(requiredAttrMap)) {
         requiredAttrMap.forEach((attrId, attrVO) -> {
            //只有企业编码,状态,备注,模板主键,分类主键这几个是固定的,其余都是自行配置的
            if (StringUtils.isBlank(getValueFromOrderDTO(orderDTO, attrId))) {
               errorMap.put(orderDTO.getId(),errorMap.getOrDefault(orderDTO.getId(),"") + ";属性【{"+attrVO.getName()+"}】必须要输入(选择)内容" );
               //  throw new VciBaseException("属性【{0}】必须要输入(选择)内容", new String[]{attrVO.getName()});
            }
         });
      }
   }
   /**
    * 转换组合规则的值
    *
    * @param templateVO 模板的显示对象,需要包含模板属性
    * @param orderDTO   编码申请的信息
    */
   private void switchComponentAttrOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      Map<String, CodeClassifyTemplateAttrVO> compAttrVOMap = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getComponentRule())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(compAttrVOMap)) {
         Map<String, String> dataMap = WebUtil.objectToMapString(orderDTO);
         Map<String, String> dataLowMap = new HashMap<>();
         if (!CollectionUtils.isEmpty(dataMap)) {
            dataMap.forEach((key, value) -> {
               dataLowMap.put(key.toLowerCase(Locale.ROOT), value);
            });
         }
         dataLowMap.putAll(orderDTO.getData());
         compAttrVOMap.forEach((attrId, attrVO) -> {
            dataLowMap.put(attrId, formulaService.getValueByFormula(dataLowMap, attrVO.getComponentRule()));
         });
         dataLowMap.forEach((key, value) -> {
            setValueToOrderDTO(orderDTO, key, value);
         });
      }
   }
   /**
    * 校验正则表达式是否正确
    *
    * @param templateVO 模板的信息,必须包含属性的内容
    * @param orderDTO   编码申请的相关的信息
    */
   private void checkVerifyOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO,Map<String,String> errorMap) {
      Map<String, CodeClassifyTemplateAttrVO> verifyAttrVOMap = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getVerifyRule())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(verifyAttrVOMap)) {
         verifyAttrVOMap.forEach((attrId, attrVO) -> {
            String value = getValueFromOrderDTO(orderDTO, attrId);
            if (StringUtils.isNotBlank(value) && !value.matches(attrVO.getVerifyRule())) {
               errorMap.put(orderDTO.getId(),errorMap.getOrDefault(orderDTO.getId(),"")+";属性["+attrVO.getName()+"]的值不符合校验规则的要求");
               //校验正则表达式
               // throw new VciBaseException("属性[{0}]的值不符合校验规则的要求", new String[]{attrVO.getName()});
            }
         });
      }
   }
   /**
    * 校验关键属性
    *
    * @param classifyFullInfo 分类的全部信息
    * @param templateVO       模板的内容,必须包含模板属性
    * @param orderDTO         编码申请的相关的信息
    */
   private void checkKeyAttrOnOrder(CodeClassifyFullInfoBO classifyFullInfo, CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO,Map<String,String> errorMap) {
      //先获取关键属性的规则,也利用继承的方式
      CodeKeyAttrRepeatVO keyRuleVO = keyRuleService.getRuleByClassifyFullInfo(classifyFullInfo);
      //注意的是keyRuleVO可能为空,表示不使用规则控制
      //获取所有的关键属性
      Map<String, CodeClassifyTemplateAttrVO> ketAttrMap = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getKeyAttrFlag())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      Map<String, String> conditionMap = new HashMap<>();
      boolean trimAll = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnoreallspaceflag());
      //全部去空的优先级大于去空
      boolean trim = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorespaceflag());
      boolean ignoreCase = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorecaseflag());
      boolean ignoreWidth = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorewidthflag());
      ketAttrMap.forEach((attrId, attrVO) -> {
         String value = getValueFromOrderDTO(orderDTO, attrId);
         if (value == null) {
            value = "";
         }
         engineService.wrapperKeyAttrConditionMap(value, keyRuleVO, attrId, trim, ignoreCase, ignoreWidth, trimAll, conditionMap);
      });
      //没有限制分类,但是一个模板只可能在一个业务类型里面,所以直接查询这个业务类型即可
      if (!CollectionUtils.isEmpty(conditionMap)) {
         final String[] sql = {"select count(*) from " + VciBaseUtil.getTableName(classifyFullInfo.getTopClassifyVO().getBtmTypeId()) + " t where 1 = 1 "};
         conditionMap.forEach((key, value) -> {
            if(StringUtils.isBlank(value)||value.equals(QueryOptionConstant.ISNULL)){
               sql[0] += " and " + key + " is null ";
            }else{
               sql[0] += " and " + key + " = " + value;
            }
         });
         if (StringUtils.isNotBlank(orderDTO.getOid())) {
            //修改的时候,需要排除自己
            sql[0] += " and t.oid != '" + orderDTO.getOid() + "'";
         } else if (StringUtils.isNotBlank(orderDTO.getCopyFromVersion())) {
            sql[0] += " and t.oid != '" + orderDTO.getCopyFromVersion() + "'";
         }
         sql[0] += " and t.lastR = '1' and t.lastV = '1' ";
         if (commonsMapper.queryCountBySql(sql[0]) > 0) {
            String ruleInfoMsg = keyRuleVO == null ? "" : "查询规则:去除空格--{0},忽略大小写--{1},忽略全半角--{2},忽略全部空格--{3}";
            String[] objs = new String[]{trim ? "是" : "否", ignoreCase ? "是" : "否", ignoreWidth ? "是" : "否", trimAll ? "是" : "否"};
            String defaultValue=";根据您填写的关键属性的内容,结合关键属性查询规则,发现这个数据已经在系统中存在了。请修正!。";
            String errormsg=defaultValue+ MessageFormat.format(ruleInfoMsg, objs);
            errorMap.put(orderDTO.getId(),errorMap.getOrDefault(orderDTO.getId(),"")+errormsg);
            // throw new VciBaseException("根据您填写的关键属性的内容,结合关键属性查询规则,发现这个数据已经在系统中存在了。请修正!。" + ruleInfoMsg, objs);
         }
      }
   }
   /**
    * 校验枚举的内容
    *
    * @param templateVO 模板的显示对象,需要包含属性
    * @param orderDTO   编码申请的信息
    */
   private void checkEnumOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO,Map<String,String> errorMap) {
      //如果枚举可以修改,则不需要校验是否符合枚举的选项
      Map<String, CodeClassifyTemplateAttrVO> enumAttrVOMap = templateVO.getAttributes().stream().filter(s -> (StringUtils.isNotBlank(s.getEnumString()) || StringUtils.isNotBlank(s.getEnumId())) && !VciBaseUtil.getBoolean(s.getEnumEditFlag())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(enumAttrVOMap)) {
         enumAttrVOMap.forEach((attrId, attrVO) -> {
            String value = getValueFromOrderDTO(orderDTO, attrId);
            if (StringUtils.isNotBlank(value)) {
               //有值才能校验
               List<KeyValue> comboboxKVs = this.engineService.listComboboxItems(attrVO);
               if (!comboboxKVs.stream().anyMatch(s -> value.equalsIgnoreCase(s.getKey()))) {
                  errorMap.put(orderDTO.getId(),errorMap.getOrDefault(orderDTO.getId(),"")+";属性【"+attrVO.getName()+"】的值不符合枚举的要求");
                  //throw new VciBaseException("属性【{0}】的值不符合枚举的要求", new String[]{attrVO.getName()});
               }
            }
         });
      }
   }
   /**
    * 转换时间的格式
    *
    * @param templateVO 模板的显示对象,需要包含属性
    * @param orderDTO   编码申请的信息
    */
   private void switchDateAttrOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      Map<String, CodeClassifyTemplateAttrVO> dateAttrVOMap = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getCodeDateFormat())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(dateAttrVOMap)) {
         dateAttrVOMap.forEach((attrId, attrVO) -> {
            String value = getValueFromOrderDTO(orderDTO, attrId);
            if (StringUtils.isNotBlank(value)) {
               DateConverter dateConverter = new DateConverter();
               dateConverter.setAsText(value);
               value = VciDateUtil.date2Str(dateConverter.getValue(), VciDateUtil.DateTimeMillFormat);
               setValueToOrderDTO(orderDTO, attrId, value);
            }
         });
      }
   }
   /**
    * 拷贝数据到cbo对象上
    *
    * @param classifyFullInfo 分类的全部信息
    * @param cbo              业务数据
    * @param orderDTO         编码申请的信息
    * @param templateVO       模板的显示对象
    * @param edit             是否为修改
    */
   private void copyValueToCBO(CodeClassifyFullInfoBO classifyFullInfo, ClientBusinessObject cbo,
                        CodeOrderDTO orderDTO, CodeClassifyTemplateVO templateVO,
                        boolean edit,Map<String,String> errorMap) {
      String fullPath = "";
      if (!CollectionUtils.isEmpty(classifyFullInfo.getParentClassifyVOs())) {
         fullPath = classifyFullInfo.getParentClassifyVOs().stream().sorted(((o1, o2) -> o2.getDataLevel().compareTo(o1.getDataLevel())))
            .map(CodeClassifyVO::getOid).collect(Collectors.joining("##"));
      } else {
         fullPath = classifyFullInfo.getCurrentClassifyVO().getOid();
      }
      orderDTO.getData().forEach((key, value) -> {
         if (!edit || (!engineService.checkUnAttrUnEdit(key) &&
            !VciQueryWrapperForDO.LC_STATUS_FIELD.equalsIgnoreCase(key))) {
            try {
               cbo.setAttributeValue(key, value);
            } catch (VciBaseException e) {
               log.error("设置属性的值错误", e);
            }
         }
      });
      try {
         cbo.setAttributeValue(CODE_CLASSIFY_OID_FIELD, classifyFullInfo.getCurrentClassifyVO().getOid());
         cbo.setAttributeValue(CODE_TEMPLATE_OID_FIELD, templateVO.getOid());
         cbo.setAttributeValue(CODE_FULL_PATH_FILED, fullPath);
         if (!edit && StringUtils.isBlank(orderDTO.getLcStatus())) {
            //找生命周期的起始状态,
            if (StringUtils.isNotBlank(cbo.getLctid())) {
               //OsLifeCycleVO lifeCycleVO = lifeCycleService.getLifeCycleById(cbo.getLctid());
//               if (lifeCycleVO != null) {
//                  cbo.setLcStatus(lifeCycleVO.getStartStatus());
//               } else {
               cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
//               }
            } else {
               cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
            }
         }
         int secret = VciBaseUtil.getInt(cbo.getAttributeValue(SECRET_FIELD));
         if (secret == 0 || !secretService.checkDataSecret(secret).getData()) {
            Integer userSecret = VciBaseUtil.getCurrentUserSecret();
            cbo.setAttributeValue(SECRET_FIELD, String.valueOf((userSecret == null || userSecret == 0) ? UserSecretEnum.NONE.getValue() : userSecret));
         }
      } catch (Throwable e) {
         log.error("设置默认的属性的值错误", e);
      }
   }
   /**
    * 设置新的值到申请对象上
    *
    * @param orderDTO 编码申请对象
    * @param attrId   属性的编号
    * @param value    值
    */
   private void setValueToOrderDTO(CodeOrderDTO orderDTO, String attrId, String value) {
      attrId = attrId.toLowerCase(Locale.ROOT);
      if (VciQueryWrapperForDO.BASIC_FIELD_MAP.containsKey(attrId)) {
         WebUtil.setValueToField(WebUtil.getFieldForObject(attrId, orderDTO.getClass()).getName(), orderDTO, value);
      } else {
         orderDTO.getData().put(attrId, value);
      }
   }
   /**
    * 从编码申请信息对象上获取某个属性的值
    *
    * @param orderDTO 编码申请对象
    * @param attrId   属性的编号
    * @return 值
    */
   private String getValueFromOrderDTO(CodeOrderDTO orderDTO, String attrId) {
      attrId = attrId.toLowerCase(Locale.ROOT);
      String value = null;
      if (VciQueryWrapperForDO.BASIC_FIELD_MAP.containsKey(attrId)) {
         value = WebUtil.getStringValueFromObject(WebUtil.getValueFromField(WebUtil.getFieldForObject(attrId, orderDTO.getClass()).getName(), orderDTO));
      } else {
         //说明是自行配置的
         //前端必须要传递小写的属性
         value = orderDTO.getData().getOrDefault(attrId, "");
      }
      return value;
   }
   /**
    * 处理分类注入的信息
    *
    * @param templateVO         模板的显示对象,必须要后模板的属性
    * @param classifyFullInfoBO 分类的全路径
    * @param orderDTO           编码申请的信息
    */
   private void switchClassifyLevelOnOrder(CodeClassifyTemplateVO templateVO, CodeClassifyFullInfoBO classifyFullInfoBO, CodeOrderDTO orderDTO,Map<String,String> errorMap) {
      Map<String, CodeClassifyTemplateAttrVO> classifyAttrVOMap = templateVO.getAttributes().stream().filter(
         s -> StringUtils.isNotBlank(s.getClassifyInvokeAttr()) && StringUtils.isNotBlank(s.getClassifyInvokeLevel())
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (classifyFullInfoBO.getTopClassifyVO() == null) {
         //需要重新查询一下,因为这个是指定的分类进来的
      }
      if (!CollectionUtils.isEmpty(classifyAttrVOMap)) {
         classifyAttrVOMap.forEach((attrId, attrVO) -> {
            //分类注入的编号或者名称,
            //层级包含指定层和最小层
            CodeClassifyVO classifyVO = null;
            if (!CodeLevelTypeEnum.MIN.getValue().equalsIgnoreCase(attrVO.getClassifyInvokeLevel()) && !"min".equalsIgnoreCase(attrVO.getClassifyInvokeLevel())) {
               //指定了层级的
               //注意,因为查询上级分类出来的层级是倒序的,即顶层节点是最大的值
               List<CodeClassifyVO> classifyVOS = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> o2.getDataLevel().compareTo(o1.getDataLevel()))).collect(Collectors.toList());
               int level = VciBaseUtil.getInt(attrVO.getClassifyInvokeLevel());
               if (classifyVOS.size() >= level && level > 0) {
                  classifyVO = classifyVOS.get(level - 1);
               }
            } else {
               //当前的分类
               classifyVO = classifyFullInfoBO.getCurrentClassifyVO();
            }
            if (classifyVO == null) {
               //说明层级有误
               errorMap.put(orderDTO.getId(),errorMap.getOrDefault(orderDTO.getId(),"")+";分类树上没有层级[" + attrVO.getClassifyInvokeLevel() + "]");
               //orderDTO.getData().put(attrId, "分类树上没有层级[" + attrVO.getClassifyinvokelevel() + "]");
               // classifyVO = classifyFullInfoBO.getCurrentClassifyVO();
            } else {
               Map<String, String> classifyDataMap = VciBaseUtil.objectToMapString(classifyVO);
               String value = classifyDataMap.getOrDefault(attrVO.getClassifyInvokeAttr(), "");
               orderDTO.getData().put(attrId, value);
            }
         });
      }
   }
   /***
    *
    * @param codeClassifyVO
    * @param templateVO
    * @param codeDataMap
    * @param codeSystemObjectMap
    * @param codeOrderDTOList
    * @param errorMap
    * @return
    */
   private void getCodeOrderDTOs(CodeClassifyVO codeClassifyVO,CodeClassifyTemplateVO templateVO,Map<String ,RowDatas>codeDataMap,Map<String, ClientBusinessObject> codeSystemObjectMap,List<CodeOrderDTO> codeOrderDTOList,Map<String,String> errorMap,boolean isCodeOrGroupCode){
      codeSystemObjectMap.keySet().forEach(code->{
         ClientBusinessObject sysDataObject= codeSystemObjectMap.get(code);
         if(isCodeOrGroupCode){
            code=sysDataObject.getAttributeValue("GROUPCODE");
         }
         CodeOrderDTO orderDTO = new CodeOrderDTO();
         if(codeDataMap.containsKey(code)){
            RowDatas rowDatas=codeDataMap.get(code);
            Map<String, String> data= rowDatas.getFiledValue();
            orderDTO.setCodeClassifyOid(codeClassifyVO.getOid());//分类主键
            orderDTO.setOid(sysDataObject.getOid());//数据oid
            orderDTO.setLcStatus(rowDatas.getStatus());//状态
            if(isCodeOrGroupCode){
               orderDTO.setId(sysDataObject.getId());
            }else{
               orderDTO.setId(code);
            }
            orderDTO.setTs(sysDataObject.getTs());
            orderDTO.setBtmname(codeClassifyVO.getBtmname());//业务类型
            orderDTO.setDescription("集成调用:更新");//数据描述
            if(data.containsKey("name")){
               String name=data.get("name");
               orderDTO.setName(name);//名称属性值
            }
            orderDTO.setData(data);//设置数据
            orderDTO.setSecDTOList(null);//分类码段
            orderDTO.setEditInProcess(false);//是否在流程中
            orderDTO.setTemplateOid(templateVO.getOid());
         }else{
            errorMap.put("code","编码为:【"+code+"】的数据在系统中不存在");
         }
         codeOrderDTOList.add(orderDTO);
      });
   }
   /**
@@ -683,6 +2884,234 @@
   }
   /**
    * 检查码段的长度是否符合要求
    * @param cboList 数据
    * @param classifyVOMap 分类映射
    * @param ruleVOMap 规则对象
    * @param ruleOidMap 分类包含规则
    * @param errorMap 错误的信息
    * @param ruleRowIndexMap 规则包含的行号,key是规则主键,value是包含的全部行号
    */
   private void checkSecLengthInHistory(List<ClientBusinessObject> cboList,Map<String,CodeClassifyVO> classifyVOMap,Map<String,CodeRuleVO> ruleVOMap,
                               Map<String/**分类主键**/,String/**规则主键**/> ruleOidMap,Map<String,String> errorMap,Map<String,List<String>> ruleRowIndexMap){
      cboList.stream().forEach(cbo-> {
         String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
         String secLength = cbo.getAttributeValue(CODE_SEC_LENGTH_FIELD);
         //找分类
         String classifyOid = cbo.getAttributeValue(CODE_CLASSIFY_OID_FIELD);
         CodeClassifyVO classifyVO = classifyVOMap.get(classifyOid);
         if (classifyVO != null) {
            //2#2#4#1这样的方式
            CodeRuleVO ruleVO = ruleVOMap.getOrDefault(ruleOidMap.get(classifyVO.getOid()), null);
            if(ruleVO!=null){
               String[] secValues = secLength.split("#");
               //总长度和编码的长度
               String code = cbo.getAttributeValue(CODE_FIELD);
               if(code.length() != Arrays.stream(secValues).mapToInt(s->VciBaseUtil.getInt(s)).sum()){
                  errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";码段宽度与系统中的编码规则不同" );
               }else if(secValues.length != ruleVO.getSecVOList().size()){
                  errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";码段宽度与系统中的编码规则不同" );
               } else {
                  //每一个长度都不能超过码段的
                  boolean fined = false;
                  for (int j = 0; j < ruleVO.getSecVOList().size(); j++) {
                     CodeBasicSecVO secVO = ruleVO.getSecVOList().get(j);
                     String length= secValues[j];
                     if(StringUtils.isNotBlank(secVO.getCodeSecLength())&&VciBaseUtil.getInt(length)>VciBaseUtil.getInt(secVO.getCodeSecLength())){
                        errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";码段宽度与系统中的编码规则不同" );
                        fined = true;
                        break;
                     }
                  }
                  /**for (int i = 0; i < secValues.length; i++) {
                   for (int j = 0; j < ruleVO.getSecVOList().size(); j++) {
                   CodeBasicSecVO secVO = ruleVO.getSecVOList().get(j);
                   if (VciBaseUtil.getInt(secValues[i]) > VciBaseUtil.getInt(secVO.getCodeSecLength())) {
                   errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";码段宽度与系统中的编码规则不同" );
                   fined = true;
                   break;
                   }
                   }
                   if(fined){
                   break;
                   }
                   }***/
                  if(!fined){
                     //暂时不取流水的内容,因为调用produceCode的时候去处理
                     List<String> rowIndexList = ruleRowIndexMap.getOrDefault(ruleVO.getOid(), new ArrayList<>());
                     rowIndexList.add(rowIndex);
                     ruleRowIndexMap.put(ruleVO.getOid(),rowIndexList);
                  }
               }
            }else{
               errorMap.put(rowIndex,errorMap.getOrDefault(rowIndex,"") + ";分类没有设置编码规则" );
            }
         }
      });
   }
   /**
    * excel转换为cbo的对象
    * @param classifyFullInfo 分类的全部信息
    * @param fieldIndexMap 字段的位置
    * @param rowDataList excel里的行数据
    * @param templateVO 模板的显示对象
    * @param cboList 数据的列表
    * @param fullPath 全路径
    * @param operation 操作类型
    * @param errorMap 错误信息记录
    */
   private void excelToCbo(CodeClassifyFullInfoBO classifyFullInfo,List<String> titleRowData,Map<Integer,String> fieldIndexMap,List<RowDatas> rowDataList,
                     CodeClassifyTemplateVO templateVO,List<ClientBusinessObject> cboList,
                     String fullPath,boolean isProcess,String operation,Map<String,String> errorMap,Map<String,String> codeOidToSystemOidMap){
      rowDataList.stream().forEach(rowData -> {
         String oid=rowData.getOid();
         String rowNumber=rowData.getRowIndex();
         ClientBusinessObject cbo = new ClientBusinessObject();
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId());
         rowData.getData().forEach((index,value)->{
            String field = fieldIndexMap.get(index);
            if(StringUtils.isBlank(field)){
               errorMap.put(rowNumber,"属性:【" +titleRowData.get(index)+ "】在系统中不存在");
            }
            try {
               cbo.setAttributeValueWithNoCheck(field,value);
               if(WebUtil.isDefaultField(field)){
                  WebUtil.setValueToField(field, cbo, value);
               }
            } catch (VciBaseException e) {
               log.error("设置属性的值错误",e);
               errorMap.put(rowNumber,"属性:【" +titleRowData.get(index)+ "】在系统中不存在");
            }
         });
         try {
            cbo.setAttributeValue(IMPORT_ROW_INDEX,rowData.getRowIndex());
            cbo.setAttributeValue(CODE_TEMPLATE_OID_FIELD,templateVO.getOid());
            if(operation.equals("create")){
               log.info("分类对象:"+classifyFullInfo.getCurrentClassifyVO());
               log.info("codeClassoid:"+classifyFullInfo.getCurrentClassifyVO().getOid());
               cbo.setAttributeValue(CODE_CLASSIFY_OID_FIELD,classifyFullInfo.getCurrentClassifyVO().getOid());
               cbo.setAttributeValue(CODE_FULL_PATH_FILED,fullPath);
               int secret = VciBaseUtil.getInt(cbo.getAttributeValue(SECRET_FIELD));
               if(secret == 0 || !secretService.checkDataSecret(secret).getData() ){
                  Integer userSecret = VciBaseUtil.getCurrentUserSecret();
                  String secretValue= String.valueOf((userSecret==null || userSecret ==0)? UserSecretEnum.NONE.getValue():userSecret);
                  cbo.setAttributeValue(SECRET_FIELD,secretValue);
               }
               if(rowData.getStatus().equals(CodeDefaultLC.DISABLE.getValue())){//停用
                  cbo.setLcStatus(CodeDefaultLC.DISABLE.getValue());
               }else if(rowData.getStatus().equals(CodeDefaultLC.EDITING.getValue())){//编辑
                  cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
               }else if(rowData.getStatus().equals(CodeDefaultLC.AUDITING.getValue())) {//审批中
                  cbo.setLcStatus(CodeDefaultLC.AUDITING.getValue());
               }else if(rowData.getStatus().equals(CodeDefaultLC.TASK_BACK.getValue())){//回收
                  cbo.setLcStatus(CodeDefaultLC.TASK_BACK.getValue());
               }else{
                  cbo.setLcStatus(CodeDefaultLC.RELEASED.getValue());//发布
               }
               /**  if(!isProcess){
                cbo.setLcStatus(CodeDefaultLC.RELEASED.getValue());
                }else {
                if(rowData.getStatus().equals(CodeDefaultLC.DISABLE.getValue())){//停用
                cbo.setLcStatus(CodeDefaultLC.DISABLE.getValue());
                }else if(rowData.getStatus().equals(CodeDefaultLC.EDITING.getValue())){//编辑
                cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
                }else {//发布
                cbo.setLcStatus(CodeDefaultLC.RELEASED.getValue());
                }
                }***/
               cbo.setCreator(rowData.getCreator());
               cbo.setLastModifier(rowData.getEditor()==null?"":rowData.getEditor());
            }else if(operation.equals("update")){
               //此时还没有转换路径
               //cbo.setAttributeValue(CODE_FULL_PATH_FILED, childOidPathMap.getOrDefault(rowData.getData().getOrDefault(CODE_CLASSIFY_OID_FIELD,""),fullPath));
               if(rowData.getStatus().equals(CodeDefaultLC.DISABLE.getValue())){//停用
                  cbo.setLcStatus(CodeDefaultLC.DISABLE.getValue());
               }else if(rowData.getStatus().equals(CodeDefaultLC.RELEASED.getValue())){//发布
                  cbo.setLcStatus(CodeDefaultLC.RELEASED.getValue());
               }else if(rowData.getStatus().equals(CodeDefaultLC.EDITING.getValue())){//编辑
                  cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
               }else if(rowData.getStatus().equals(CodeDefaultLC.AUDITING.getValue())) {//审批中
                  cbo.setLcStatus(CodeDefaultLC.AUDITING.getValue());
               }else if(rowData.getStatus().equals(CodeDefaultLC.TASK_BACK.getValue())){//回收
                  cbo.setLcStatus(CodeDefaultLC.TASK_BACK.getValue());
               }
               cbo.setLastModifier(rowData.getEditor() == null ? "" : rowData.getEditor());//修改者
            }else if(operation.equals("delete")){
               if(rowData.getStatus().equals(CodeDefaultLC.TASK_BACK.getValue())){//回收
                  cbo.setLcStatus(CodeDefaultLC.TASK_BACK.getValue());
               }else{
                  cbo.setLcStatus(CodeDefaultLC.DISABLE.getValue());//停用
               }
            }
         }catch (Throwable e){
            log.error("设置默认的属性的值错误",e);
            if(e instanceof  VciBaseException){
               errorMap.put(rowNumber,"设置默认的属性的值错误"+((VciBaseException) e).getMessage());
            }else{
               errorMap.put(rowNumber,"设置默认的属性的值错误"+e.getMessage());
            }
         }finally {
            codeOidToSystemOidMap.put(cbo.getOid(),oid);
         }
         cbo.setDescription("");
         cboList.add(cbo);
      });
   }
   /**
    * excel转换为cbo的对象
    * @param classifyFullInfo 分类的全部信息
    * @param codeImprotDataVO: 分类对应的数据
    * @param cboList 数据的列表
    * @param newCode 是否为批量申请
    */
   private void excelToCbo(CodeClassifyFullInfoBO classifyFullInfo,CodeImprotDataVO codeImprotDataVO,List<ClientBusinessObject> cboList, boolean newCode){
      String fullPath = getFullPath(classifyFullInfo);
      codeImprotDataVO.getDatas().stream().forEach(rowData -> {
         ClientBusinessObject cbo=new ClientBusinessObject();
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId());
         rowData.forEach((field,value)->{
            try {
               cbo.setAttributeValueWithNoCheck(field,value);
               if(WebUtil.isDefaultField(field)){
                  WebUtil.setValueToField(field, cbo, value);
               }
            } catch (VciBaseException e) {
               log.error("设置属性的值错误",e);
            }
         });
         try {
            cbo.setAttributeValue(CODE_TEMPLATE_OID_FIELD,codeImprotDataVO.getTemplateOid());
            cbo.setAttributeValue(IMPORT_ROW_INDEX,rowData.get(IMPORT_ROW_INDEX));
            if(newCode){
               cbo.setAttributeValue(CODE_CLASSIFY_OID_FIELD,classifyFullInfo.getCurrentClassifyVO().getOid());
               cbo.setAttributeValue(CODE_FULL_PATH_FILED,fullPath);
               //cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
               int secret = VciBaseUtil.getInt(cbo.getAttributeValue(SECRET_FIELD));
               if(secret == 0 || !secretService.checkDataSecret(secret).getData() ){
                  Integer userSecret = VciBaseUtil.getCurrentUserSecret();
                  cbo.setAttributeValue(SECRET_FIELD,String.valueOf((userSecret==null || userSecret ==0)? UserSecretEnum.NONE.getValue():userSecret));
               }
               cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
            }else{
               //此时还没有转换路径
               //cbo.setAttributeValue(CODE_FULL_PATH_FILED, childOidPathMap.getOrDefault(rowData.getData().getOrDefault(CODE_CLASSIFY_OID_FIELD,""),fullPath));
               cbo.setLcStatus(CodeDefaultLC.RELEASED.getValue());
            }
            rowData.put("oid",cbo.getOid());
         }catch (Throwable e){
            log.error("设置默认的属性的值错误",e);
         }
         cboList.add(cbo);
      });
   }
   /**
    * excel转换为cbo的对象
    * @param classifyFullInfo 分类的全部信息
    * @param fieldIndexMap 字段的位置
@@ -697,7 +3126,7 @@
                     String fullPath,boolean newCode){
      rowDataList.stream().forEach(rowData -> {
         ClientBusinessObject cbo=new ClientBusinessObject();
          DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmtypeid());
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(cbo, classifyFullInfo.getTopClassifyVO().getBtmTypeId());
         rowData.getData().forEach((index,value)->{
            String field = fieldIndexMap.get(index);
            if (StringUtils.isBlank(field)) {
@@ -720,10 +3149,11 @@
               cbo.setAttributeValue(CODE_FULL_PATH_FILED,fullPath);
               //cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
               int secret = VciBaseUtil.getInt(cbo.getAttributeValue(SECRET_FIELD));
               /*if(secret == 0 || !secretService.checkDataSecret(secret) ){
               if(secret == 0 || !secretService.checkDataSecret(secret).getData() ){
                  Integer userSecret = VciBaseUtil.getCurrentUserSecret();
                  cbo.setAttributeValue(SECRET_FIELD,String.valueOf((userSecret==null || userSecret ==0)? UserSecretEnum.NONE.getValue():userSecret));
               }*/
               }
               cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
            }else{
               //此时还没有转换路径
               //cbo.setAttributeValue(CODE_FULL_PATH_FILED, childOidPathMap.getOrDefault(rowData.getData().getOrDefault(CODE_CLASSIFY_OID_FIELD,""),fullPath));
@@ -817,6 +3247,32 @@
         });
      }
   }
   /**
    * 系统模板中默认值设置
    * @param attrVOS 模板属性
    * @param dataList excel的数据内容
    */
   private void batchSwitchAttrDefault(Collection<CodeClassifyTemplateAttrVO> attrVOS,List<ClientBusinessObject> dataList) {
      Map<String, CodeClassifyTemplateAttrVO> dateAttrVOMap = attrVOS.stream().filter(s -> StringUtils.isNotBlank(s.getDefaultValue())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if(!CollectionUtils.isEmpty(dateAttrVOMap)) {
         dateAttrVOMap.forEach((attrId, attrVO) -> {
            String defaultValue = attrVO.getDefaultValue();
            dataList.stream().forEach(cbo -> {
               String dataValue= cbo.getAttributeValue(attrId);
               if(StringUtils.isBlank(dataValue)){
                  dataValue=defaultValue;
               }
               try {
                  cbo.setAttributeValue(attrId, dataValue);
               }catch (Throwable e){
                  log.error("设置属性的错误",e);
               }
            });
         });
      }
   }
   /**
    * 转移boolean型的属性
    * @param attrVOS 属性的对象
@@ -968,7 +3424,150 @@
      }
   }
   /**
    * 批量检查企业编码是否存在
    * @param templateVO 模板的显示对象
    * @param cboList 数据的列表
    * @param errorMap 错误的信息
    */
   private void batchCheckIdExistOnOrder(CodeClassifyTemplateVO templateVO,List<ClientBusinessObject> cboList,Map<String ,String> errorMap) throws Throwable{
      List<String> existIds = new ArrayList<>();
      String tableName ="";
      try {
         R<BtmTypeVO> r = btmTypeClient.getAllAttributeByBtmId(templateVO.getBtmTypeId());
         if(!r.isSuccess()) {
            throw new Throwable(r.getMsg());
         }
         BtmTypeVO btmTypeVO = r.getData();
         if (btmTypeVO == null) {
            throw new Throwable("根据业务类型未查询到业务类型对象!");
         }
         tableName = btmTypeVO.getTableName();
         if (StringUtils.isBlank(tableName)) {
            throw new Throwable("根据业务类型未查询到业务类型相关联的表");
         }
      }catch (Throwable e){
         throw e;
      }
      String finalTableName = tableName;
      VciBaseUtil.switchCollectionForOracleIn(cboList).stream().forEach(cbos -> {
         Map<String, String> conditionMap = new HashMap<>();
         conditionMap.put("id", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(cbos.stream().map(s -> s.getId()).collect(Collectors.toSet()).toArray(new String[0])) + ")");
         StringBuffer sb=new StringBuffer();
         sb.append(" select id from ");
         sb.append(finalTableName);
         sb.append(" where 1=1 ");
         sb.append(" and id in (");
         sb.append(VciBaseUtil.toInSql(cbos.stream().map(s -> s.getId()).collect(Collectors.toSet()).toArray(new String[0])));
         sb.append(")");
         List<String> idList= commonsMapper.selectById(sb.toString());
         //业务数据如果码值回收会直接删除数据,所以这里直接判断是否存在即可
         existIds.addAll(Optional.ofNullable(idList).orElseGet(() -> new ArrayList<>()).stream().map(s -> s.toLowerCase(Locale.ROOT)).collect(Collectors.toList()));
      });
      if(!CollectionUtils.isEmpty(existIds)){
         String idFieldName = templateVO.getAttributes().stream().filter(s -> VciQueryWrapperForDO.ID_FIELD.equalsIgnoreCase(s.getId())).findFirst().orElseGet(() -> new CodeClassifyTemplateAttrVO()).getName();
         if(StringUtils.isBlank(idFieldName)){
            idFieldName = "企业编码";
         }
         String finalIdFieldName = idFieldName;
         cboList.stream().forEach(cbo->{
            String id = cbo.getId();
            if(StringUtils.isBlank(id)){
               id = cbo.getAttributeValue("id");
            }
            if(existIds.contains(id)){
               String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
               String msg = errorMap.getOrDefault(rowIndex, "");
               msg+=";" + finalIdFieldName + "的值在系统中已经存在";
               errorMap.put(rowIndex,msg);
            }
         });
      }
   }
   /***
    * 校验分类对应的模板信息
    * @param titleRowData
    * @param sheetDataSetList
    * @param shetNumber
    * @param pathMap
    * @param errorMap
    * @return
    * @throws Throwable
    */
   private LinkedList<CodeClassifyTemplateVO> checkSamesTemplate(List<String> titleRowData,  List<SheetDataSet> sheetDataSetList,int shetNumber,Map<String/**路径**/, CodeClassifyVO> pathMap,Map<String,String>errorMap) throws Throwable {
      Map<String,String>pathOidMap =new HashMap<>();
      Map<String,String> templateIdRowIndex=new HashedMap();
      SheetDataSet dataSet=  sheetDataSetList.get(shetNumber);
      LinkedHashMap<String,CodeClassifyTemplateVO> codeClassifyTemplateVOMap=new LinkedHashMap <String,CodeClassifyTemplateVO>();
      for (int i=0; i<titleRowData.size();i++){
         String title= titleRowData.get(i);
         if(title.equals("分类路径")) {
            int finalI = i;
            dataSet.getRowData().stream().forEach(sheetRowData -> {
               String Path = sheetRowData.getData().get(finalI);
               String rowIndex=sheetRowData.getRowIndex();
               if(StringUtils.isBlank(Path)){
                  Path= "#current#";
               }
               CodeClassifyTemplateVO newTemplateVO=new CodeClassifyTemplateVO();
               String templateOid="";
               if(pathOidMap.containsKey(Path)){
                  templateOid= pathOidMap.get(Path) ;
                  newTemplateVO=codeClassifyTemplateVOMap.get(templateOid);
               }else{
                  if (pathMap.containsKey(Path)) {
                     CodeClassifyVO codeClassifyVO = pathMap.get(Path);
                     newTemplateVO = engineService.getUsedTemplateByClassifyOid(codeClassifyVO.getOid());
                     if (newTemplateVO != null) {
                        templateOid = newTemplateVO.getOid();
                     } else {
                        errorMap.put(rowIndex, "第" + rowIndex + "行,分类路径未查询到相应的分类模板");
                     }
                  } else {
                     errorMap.put(rowIndex, "第" + rowIndex + "行,分类路径未查询到相应的分类");
                  }
               }
               pathOidMap.put(Path, templateOid);
               codeClassifyTemplateVOMap.put(templateOid, newTemplateVO);
               templateIdRowIndex.put(templateOid, templateIdRowIndex.getOrDefault(templateOid, "") + "," +rowIndex );
            });
            break;
         }
      }
      LinkedList<CodeClassifyTemplateVO> codeClassifyTemplateVOList=new LinkedList<>();
      StringBuffer sb=new StringBuffer();
      codeClassifyTemplateVOMap.keySet().forEach(tempateOid->{
         String templateOidInExcel="";
         String tempateName="";
         CodeClassifyTemplateVO t= codeClassifyTemplateVOMap.get(tempateOid);
         codeClassifyTemplateVOList.add(t);
         if(!CollectionUtils.isEmpty(sheetDataSetList)
            && sheetDataSetList.size()>1 && !CollectionUtils.isEmpty(sheetDataSetList.get(sheetDataSetList.size()-1).getColName())){
            List<SheetRowData>  rowData=  sheetDataSetList.get(sheetDataSetList.size()-1).getRowData();
            templateOidInExcel=rowData.get(shetNumber).getData().get(0);
            tempateName=rowData.get(shetNumber).getData().get(2);
            //templateOidInExcel = sheetDataSetList.get(sheetDataSetList.size()-1).getColName().get(sheetDataSetList.size()-i);
         }
         if(StringUtils.isBlank(templateOidInExcel) || !templateOidInExcel.equalsIgnoreCase(tempateOid)){
            sb.append("模板【"+tempateName+"】中第"+templateIdRowIndex.get(tempateOid)+"行数据不属于当前模板的数据,请核对!");
         }
      });
      if(StringUtils.isNotBlank(sb.toString())){
         throw  new Throwable(sb.toString());
      }
      if(codeClassifyTemplateVOList.size()>1){
         String message="模板【"+dataSet.getSheetName()+"】根据分类路径判断,分类存在多个模板";
         throw  new Throwable(message);
      }
      if(codeClassifyTemplateVOList.size()==0){
         String message="模板【"+dataSet.getSheetName()+"】根据数据分类路径判断,未匹配到对应模板";
         throw  new Throwable(message);
      }
      return codeClassifyTemplateVOList ;
   }
   /**
    * 从属性上获取参照的内容
    * @param attrVO 属性的信息
@@ -1170,7 +3769,8 @@
      CodeImportResultVO resultVO = new CodeImportResultVO();
      resultVO.setKeyAttrRuleInfo(String.format(keyRuleVO ==null?"":"查询规则:去除空格--{0},忽略大小写--{1},忽略全半角--{2},忽略全部空格--{3}",
         new String[]{trim?"是":"否",ignoreCase?"是":"否",ignoreWidth?"是":"否",trimAll?"是":"否"}));
      resultVO.setSelfRepeatRowIndexList(getSelfRepeatRowIndex(ketAttrMap,cboList,keyRuleVO));
      //resultVO.setSelfRepeatRowIndexList(getSelfRepeatRowIndex(ketAttrMap,cboList,keyRuleVO));
      getSelfRepeatRowIndex(ketAttrMap,cboList,keyRuleVO,resultVO);
      if(!CollectionUtils.isEmpty(resultVO.getSelfRepeatRowIndexList())){
         //我们移除本身重复的数据
         cboList = cboList.stream().filter(s->!resultVO.getSelfRepeatRowIndexList().contains(s.getAttributeValue(IMPORT_ROW_INDEX))).collect(Collectors.toList());
@@ -1178,7 +3778,7 @@
      //2.判断关键属性在系统里是否重复
      //因为数据量很大,所以得想办法并行
      //SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
      Map<String,List<ClientBusinessObject>> indexTODataMap=new HashMap<>();
      Map<String,List<BaseModel>> indexTODataMap=new HashMap<>();
      List<ClientBusinessObject> repeatDataMap = cboList.parallelStream().filter(cbo -> {
         //每行都得查询.如果其中出现了错误,我们就直接抛出异常,其余的显示
         //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
@@ -1192,12 +3792,20 @@
            engineService.wrapperKeyAttrConditionMap(value, keyRuleVO, attrId, trim, ignoreCase, ignoreWidth, trimAll, conditionMap);
         });
         if (!CollectionUtils.isEmpty(ketAttrMap)) {
            CodeTemplateAttrSqlBO sqlBO = engineService.getSqlByTemplateVO(classifyFullInfo.getTopClassifyVO().getBtmtypeid(), templateVO, conditionMap, null);
            CodeTemplateAttrSqlBO sqlBO = engineService.getSqlByTemplateVO(classifyFullInfo.getTopClassifyVO().getBtmTypeId(), templateVO, conditionMap, null);
            boolean isKeyCheck= commonsMapper.queryCountBySql(sqlBO.getSqlCount()) > 0;
            if(isKeyCheck){
               List<Map<String,String>> newDataList=  commonsMapper.queryByOnlySqlForMap(sqlBO.getSqlUnPage());
               List<ClientBusinessObject> newCboList=   ChangeMapTOClientBusinessObjects(newDataList);
               indexTODataMap.put(cbo.getAttributeValue(IMPORT_ROW_INDEX),newCboList);
               //List<ClientBusinessObject> newCboList=   ChangeMapTOClientBusinessObjects(newDataList);
               List<BaseModel> newCboList=new ArrayList<>();
               newDataList.stream().forEach(stringStringMap -> {
                  BaseModel baseModel=new BaseModel();
                  DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(stringStringMap,baseModel);
                  newCboList.add(baseModel);
               });
               if(!CollectionUtils.isEmpty(newCboList)) {
                  indexTODataMap.put(cbo.getAttributeValue(IMPORT_ROW_INDEX), newCboList);
               }
            }
            return isKeyCheck;
         }else{
@@ -1207,10 +3815,113 @@
      if(!CollectionUtils.isEmpty(repeatDataMap)){
         resultVO.setKeyAttrRepeatRowIndexList(repeatDataMap.stream().map(s->s.getAttributeValue(IMPORT_ROW_INDEX)).collect(Collectors.toSet()));
      }
      //resultVO.setIndexTODataMap(indexTODataMap);
      resultVO.setIndexTODataMap(indexTODataMap);
      //resultVO.setSuccess(true);
      return resultVO;
   }
   /**
    * 检查分类的路径是否存在
    * @param cboList 业务数据
    * @param errorMap 错误信息
    * @param pathMap 路径和分类的映射
    */
   private void checkClassifyPathInHistory(List<ClientBusinessObject> cboList,
                                 Map<String,String> errorMap,     Map<String/**路径**/,CodeClassifyVO> pathMap,
                                 Map<String/**主键**/, String/**路径**/> childOidPathMap) {
      cboList.parallelStream().forEach(cbo -> {
         String classifyPath = cbo.getAttributeValue(CODE_CLASSIFY_OID_FIELD);
         //如果path为空,则表示是导入当前分类
         if(StringUtils.isBlank(classifyPath)){
            classifyPath = "#current#";
         }
         if ( !pathMap.containsKey(classifyPath)) {
            String row_index = cbo.getAttributeValue(IMPORT_ROW_INDEX);
            errorMap.put(row_index,errorMap.getOrDefault(row_index,"") + ";分类路径不存在");
         } else {
            //转一下分类的主键
            try {
               String classifyOid = pathMap.get(classifyPath).getOid();
               cbo.setAttributeValueWithNoCheck(CODE_CLASSIFY_OID_FIELD, classifyOid);
               cbo.setAttributeValue(CODE_FULL_PATH_FILED, childOidPathMap.getOrDefault(classifyOid,classifyPath));
            } catch (VciBaseException e) {
               log.error("设置属性的错误", e);
            }
         }
      });
   }
   /**
    * 检查分类以及子分类是否都有编码规则
    * @param classifyVOMap 分类的显示对象映射
    * @param ruleOidMap 规则的主键映射
    * @param unExistRuleClassifyOidList 不存在编码规则的分类的主键
    */
   private void checkRuleOidInHistory( Map<String/**主键**/,CodeClassifyVO> classifyVOMap,  Map<String/**分类主键**/,String/**规则主键**/> ruleOidMap,
                              List<String> unExistRuleClassifyOidList   ){
      if(!CollectionUtils.isEmpty(classifyVOMap)){
         classifyVOMap.values().parallelStream().forEach(classifyVO->{
            if(StringUtils.isNotBlank(classifyVO.getCodeRuleOid())){
               ruleOidMap.put(classifyVO.getOid(),classifyVO.getCodeRuleOid());
            }else{
               //递归找上级
               List<String> ruleOidList = new ArrayList<>();
               recursionRule(classifyVOMap,classifyVO.getParentCodeClassifyOid(),ruleOidList);
               if(!CollectionUtils.isEmpty(ruleOidList)){
                  ruleOidMap.put(classifyVO.getOid(),ruleOidList.get(0));
               }else{
                  unExistRuleClassifyOidList.add(classifyVO.getOid());
               }
            }
         });
      }
      log.info(";;;;");
   }
   /**
    * 递归找编码规则
    * @param classifyVOMap 分类的显示对象映射
    * @param classifyOid 分类的主键
    * @param ruleOidList 规则的主键list
    */
   private void recursionRule(Map<String, CodeClassifyVO> classifyVOMap,String classifyOid,List<String> ruleOidList){
      if(classifyVOMap.containsKey(classifyOid)){
         CodeClassifyVO classifyVO = classifyVOMap.get(classifyOid);
         if(StringUtils.isNotBlank(classifyVO.getCodeRuleOid())){
            ruleOidList.add(classifyVO.getCodeRuleOid());
            return;
         }else{
            recursionRule(classifyVOMap,classifyVO.getParentCodeClassifyOid(),ruleOidList);
         }
      }else{
         Map<String, CodeClassifyVO> parentClassifyVOMap=new HashMap<>();
         CodeClassifyVO codeClassifyVO= this.classifyService.getObjectByOid(classifyOid);
         parentClassifyVOMap.put(codeClassifyVO.getOid(),codeClassifyVO);
         recursionRule(parentClassifyVOMap,codeClassifyVO.getOid(),ruleOidList);
      }
   }
   /**
    * 获取子分类的路径
    * @param classifyFullInfo 分类全部信息
    * @param fullPath 分类的全路径
    * @return 子分类的路径,key是分类的主键
    */
   private Map<String/**分类的主键**/,String/**分类路径**/> getChildClassifyPathMap(CodeClassifyFullInfoBO classifyFullInfo,String fullPath){
      List<CodeClassifyVO> childPathVOs = classifyService.listChildrenClassify(classifyFullInfo.getCurrentClassifyVO().getOid(), true, VciQueryWrapperForDO.OID_FIELD, true);
      Map<String/**分类的主键**/,String/**分类的主键**/> childOidPathMap = new ConcurrentHashMap<>();
      if(!CollectionUtils.isEmpty(childPathVOs)){
         childPathVOs.parallelStream().forEach(childPath->{
            // String thisClassifyPath = fullPath + "##" + childPath.getPath().replace("#" + classifyFullInfo.getCurrentClassifyVO().getOid() + "#","").replace("#","##");
            List<String> list=Arrays.asList(childPath.getPath().split("#"));
            List<String> newPahtList=  list.stream().sorted(Comparator.comparing(s -> s,Comparator.reverseOrder())).collect(Collectors.toList());
            String thisClassifyPath=StringUtils.join(newPahtList,"##")+fullPath;
            childOidPathMap.put(childPath.getOid(),thisClassifyPath);
         });
      }
      return childOidPathMap;
   }
   /**
    * 获取导入的内容中关键属性重复的行号
    * @param ketAttrMap 关键属性的映射
@@ -1218,9 +3929,10 @@
    * @param keyRuleVO 关键属性控制规则
    * @return 重复的行号
    */
   private Set<String> getSelfRepeatRowIndex(Map<String/**属性的编号**/, CodeClassifyTemplateAttrVO> ketAttrMap,
                                   List<ClientBusinessObject> dataList,CodeKeyAttrRepeatVO keyRuleVO){
   private void getSelfRepeatRowIndex(Map<String/**属性的编号**/, CodeClassifyTemplateAttrVO> ketAttrMap,
                              List<ClientBusinessObject> dataList,CodeKeyAttrRepeatVO keyRuleVO,CodeImportResultVO resultVO){
      Set<String> selfRepeatRowIndexList = new CopyOnWriteArraySet<>();
      Map<String,List<String>> keyAttrOkOidTORepeatOidMap=new HashMap<>();
      boolean trimAll =keyRuleVO ==null?false: VciBaseUtil.getBoolean(keyRuleVO.getIgnoreallspaceflag());
      //全部去空的优先级大于去空
      boolean trim =keyRuleVO ==null?false:  VciBaseUtil.getBoolean(keyRuleVO.getIgnorespaceflag());
@@ -1229,8 +3941,10 @@
      //必须将属性按照顺序排序好
      List<CodeClassifyTemplateAttrVO> attrVOList = ketAttrMap.values().stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).collect(Collectors.toList());
      Map<String/**行号**/,String/**关键属性的组合内容**/> rowIndexKeyStringMap = new HashMap<>();
      Map<String/**关键属性的组合内容**/,String/**第一个关键属性的数据oid**/> okOidKeyStringMap = new HashMap<>();
      dataList.parallelStream().forEach(cbo-> {
         String rowIndex = cbo.getAttributeValue(IMPORT_ROW_INDEX);
         String oid=cbo.getOid();
         StringBuilder sb = new StringBuilder();
         for (int i = 0; i < attrVOList.size(); i++) {
            CodeClassifyTemplateAttrVO attrVO = attrVOList.get(i);
@@ -1256,12 +3970,25 @@
         String keyString = sb.toString();
         if(rowIndexKeyStringMap.containsValue(keyString) && StringUtils.isNotBlank(keyString)){
            selfRepeatRowIndexList.add(rowIndex);
            String okOid=okOidKeyStringMap.getOrDefault(keyString,"");
            if(StringUtils.isNotBlank(okOid)){
               List<String>newOidList=new ArrayList<>();
               newOidList.add(oid);
               if(keyAttrOkOidTORepeatOidMap.containsKey(okOid)){
                  List<String> oldOidList=   keyAttrOkOidTORepeatOidMap.get(okOid);
                  newOidList.addAll(oldOidList);
               }
               keyAttrOkOidTORepeatOidMap.put(okOid,newOidList);
            }
         }else {
            okOidKeyStringMap.put(sb.toString(),oid);
            rowIndexKeyStringMap.put(rowIndex, sb.toString());
         }
      });
      //因为只是关键属性重复,所以我们不能重复的多条选一条来报错
      return selfRepeatRowIndexList;
      resultVO.setKeyAttrRepeatRowIndexList(selfRepeatRowIndexList);
      resultVO.setKeyAttrOkOidTORepeatOidMap(keyAttrOkOidTORepeatOidMap);
   }
   /**
    * excel的标题上获取字段所在的位置
@@ -1289,17 +4016,139 @@
      }
   }
   private List<ClientBusinessObject> ChangeMapTOClientBusinessObjects(List<Map<String,String>> oldDataMap){
      List<ClientBusinessObject> clientBusinessObjectList=new CopyOnWriteArrayList<>();
      oldDataMap.parallelStream().forEach(dataMap->{
      List<ClientBusinessObject> clientBusinessObjectList=new ArrayList<>();
      oldDataMap.stream().forEach(dataMap->{
         ClientBusinessObject clientBusinessObject=new ClientBusinessObject();
         DefaultAttrAssimtUtil.copplyDefaultAttrAssimt(dataMap,clientBusinessObject);
         dataMap.forEach((key,value)->{
            clientBusinessObject.setAttributeValue(key,value);
         });
         for (String key:dataMap.keySet()){
            Object value= dataMap.getOrDefault(key,"");
            clientBusinessObject.setAttributeValue(key.toLowerCase(Locale.ROOT),value==null?"":value.toString());
         }
         clientBusinessObjectList.add(clientBusinessObject);
      });
      return clientBusinessObjectList;
   }
   /***
    * 根据不同模板组织execl数据
    * @param dataSet
    * @param pathMap
    * @param errorMap
    */
   private void createExeclClassData(SheetDataSet dataSet,Map<String/**路径**/, CodeClassifyVO> pathMap,Map<String,String>errorMap,List<CodeImprotDataVO> codeClassifyDatas){
      Map<String,CodeImprotDataVO> pathDatas=new HashMap<>();
      List<String> titleRowData= dataSet.getColName();
      List<SheetRowData>  rowDataList= dataSet.getRowData();
      LinkedHashMap<String,CodeClassifyTemplateVO> codeClassifyTemplateVOMap=new LinkedHashMap <String,CodeClassifyTemplateVO>();
      LinkedHashMap<String,CodeRuleVO> codeRuleVOVOMap=new LinkedHashMap <String,CodeRuleVO>();
      for (int i=0;i<titleRowData.size();i++){
         String title= titleRowData.get(i);
         if(title.equals("分类路径")) {
            int finalI = i;
            rowDataList.stream().forEach(sheetRowData -> {
               CodeImprotDataVO dataVO=new CodeImprotDataVO();
               String Path = sheetRowData.getData().get(finalI);
               String rowIndex=sheetRowData.getRowIndex();
               Map<Integer, String> execlData= sheetRowData.getData();
               CodeClassifyTemplateVO newTemplateVO=new CodeClassifyTemplateVO();
               CodeRuleVO codeRuleVO=new CodeRuleVO();
               if(StringUtils.isEmpty(Path)){
                  Path="#current#";
               }
               if(pathMap.containsKey(Path)){
                  CodeClassifyVO codeClassifyVO=pathMap.get(Path);
                  if(codeClassifyTemplateVOMap.containsKey(Path)){
                     newTemplateVO=  codeClassifyTemplateVOMap.get(Path);
                     codeRuleVO=  codeRuleVOVOMap.get(Path);
                     if(newTemplateVO==null||StringUtils.isBlank(newTemplateVO.getOid())){
                        errorMap.put(rowIndex,"第"+rowIndex+"行,分类路径未查询到相应的分类模板");
                     }
                     if(codeRuleVO==null||StringUtils.isBlank(codeRuleVO.getOid())){
                        errorMap.put(rowIndex,"第"+rowIndex+"行,分类路径未查询到相应的分类规则");
                     }
                  }else{
                     newTemplateVO =engineService.getUsedTemplateByClassifyOid(codeClassifyVO.getOid());
                     if(newTemplateVO==null||StringUtils.isBlank(newTemplateVO.getOid())){
                        errorMap.put(rowIndex,"第"+rowIndex+"行,分类路径未查询到相应的分类模板");
                     }
                     codeRuleVO=engineService.getCodeRuleByClassifyOid(codeClassifyVO.getOid());
                     if(codeRuleVO==null||StringUtils.isBlank(codeRuleVO.getOid())){
                        errorMap.put(rowIndex,"第"+rowIndex+"行,分类路径未查询到相应的分类规则");
                     }
                  }
                  if(pathMap.containsKey(Path)){
                     dataVO=pathDatas.getOrDefault(Path,dataVO);
                  }
                  dataVO.setTemplateOid(newTemplateVO==null?"":newTemplateVO.getOid());
                  dataVO.setCodeClassifyTemplateVO(newTemplateVO);
                  dataVO.setCodeClassifyVO(codeClassifyVO);
                  dataVO.setCodeRuleVO(codeRuleVO);
                  dataVO.setRowIndex(rowIndex);
                  dataVO.setCodeClassifyOid(codeClassifyVO.getOid());//设置分类oid
                  dataVO.setCodeRuleOid(codeRuleVO==null?"":codeRuleVO.getOid());
                  createExeclClassData(titleRowData,newTemplateVO,execlData,dataVO);
                  pathDatas.put(Path,dataVO);
                  codeClassifyTemplateVOMap.put(Path, newTemplateVO);
                  codeRuleVOVOMap.put(Path,codeRuleVO);
               }else{
                  errorMap.put(rowIndex,"第"+rowIndex+"行,分类路径未查询到相应的分类");
               }
            });
            break;
         }
      }
      List <CodeImprotDataVO> newCodeImprotDataVO= pathDatas.values().stream().collect(Collectors.toList());
      codeClassifyDatas.addAll(newCodeImprotDataVO);
      log.info("222");
   }
   /***
    *  @param titleRowData
    * @param newTemplateVO
    * @param execlData
    * @param codeImprotDataVO
    */
   private void createExeclClassData(List<String> titleRowData, CodeClassifyTemplateVO newTemplateVO, Map<Integer, String> execlData, CodeImprotDataVO codeImprotDataVO){
      //除去默认的属性.还有只有表单显示的字段才导入
      List<CodeClassifyTemplateAttrVO> attrVOS = newTemplateVO.getAttributes().stream().filter(s ->
         !DEFAULT_ATTR_LIST.contains(s.getId()) && VciBaseUtil.getBoolean(s.getFormDisplayFlag())
      ).collect(Collectors.toList());
      Map<String/**中文名称**/, String/**英文名称**/> attrNameIdMap = attrVOS.stream().collect(Collectors.toMap(s -> s.getName(), t -> t.getId()));
      List<String> fields=new ArrayList<>();
      Map<String,String> filedValueMap=new HashMap<>();
      List<String> colNames=new ArrayList<>();
      for (int i = 0; i < titleRowData.size(); i++) {
         String title = titleRowData.get(i);
         title=title.replace(KEY_ATTR_CHAR,"").replace(REQUIRED_CHAR,"");
         String id = attrNameIdMap.getOrDefault(title,"");
         if(StringUtils.isBlank(id) && "分类路径".equalsIgnoreCase(title)){
            id = CODE_CLASSIFY_OID_FIELD;
         }
         if(StringUtils.isBlank(id) && "码段宽度".equalsIgnoreCase(title)){
            id = CODE_SEC_LENGTH_FIELD;
         }
         if(StringUtils.isBlank(id) && "企业编码".equalsIgnoreCase(title)){
            id = CODE_FIELD;
         }
         if(StringUtils.isNotBlank(id)){
            // fieldIndexMap.put(i,id);id
            fields.add(id);
            colNames.add(title);
            String value= StringUtils.isNotBlank(execlData.get(i))?execlData.get(i):"";
            filedValueMap.put(id,value);
         }
      }
      // filedValueMap.put(CODE_CLASSIFY_OID_FIELD,codeImprotDataVO.getCodeClassifyOid());//将当前分类oid存入字段中
      filedValueMap.put("codeclassifyid",codeImprotDataVO.getCodeClassifyOid());
      filedValueMap.put(IMPORT_ROW_INDEX,codeImprotDataVO.getRowIndex());
      filedValueMap.put("codetemplateoid",newTemplateVO.getOid());
      codeImprotDataVO.setFields(fields);
      codeImprotDataVO.setColNames(colNames);
      codeImprotDataVO.getDatas().add(filedValueMap);
   }
   /***
    * 正确错误数据redis缓存
    * @param uuid
@@ -1359,6 +4208,50 @@
      }
   }
   /******
    * 根据编码规则缓存数据
    * @param uuid
    * @param codeImprotDataVOs
    * @param errorMap
    * @param isok
    */
   private void createRedisDatas(String uuid, List<CodeImprotDataVO> codeImprotDataVOs, Map<String, String> errorMap, boolean isok){
      codeImprotDataVOs.stream().forEach(codeImprotDataVO -> {
         List<Map<String, String>>  dataLists=new ArrayList<>();
         CodeImprotDataVO newCodeImprotDataVO=new CodeImprotDataVO();
         if(errorMap.size()>0) {
            //要把以上的错误的都抛出后,再继续处理时间和组合规则
            dataLists = codeImprotDataVO.getDatas().stream().filter(cbo -> {
               String rowIndex=cbo.get(IMPORT_ROW_INDEX);
               String msg=StringUtils.isBlank(errorMap.get(rowIndex))?"":errorMap.get(rowIndex);
               cbo.put("errorMsg",msg);
               return  isok? !errorMap.containsKey(rowIndex):errorMap.containsKey(rowIndex);
            }).collect(Collectors.toList());
         }else{
            dataLists= codeImprotDataVO.getDatas();
         }
         BeanUtilForVCI.copyPropertiesIgnoreCase(codeImprotDataVO,newCodeImprotDataVO);
         newCodeImprotDataVO.setDatas(dataLists);
         List<CodeImprotDataVO> codeImprotDataVOList=new ArrayList<>();
         codeImprotDataVOList.add(newCodeImprotDataVO);
         /***update 更改成以规则分组*****/
         String codeRuleOid=codeImprotDataVO.getCodeRuleOid();
         log.info(uuid+"-"+codeRuleOid+":条目数"+codeImprotDataVOList.size());
         if(codeImprotDataVOList.size()>0) {
            bladeRedis.set(uuid + "-" + codeRuleOid, codeImprotDataVOList);
            bladeRedis.expire(uuid + "-" + codeRuleOid, BATCHADD_REDIS_TIME);//redis过期时间
         }
         /*** String codeClassifyOid=codeImprotDataVO.getCodeClassifyOid();
          redisService.setCacheList(uuid+"-"+codeClassifyOid,codeImprotDataVOList);
          logger.info(uuid+"-"+codeClassifyOid+":条目数"+codeImprotDataVOList.size());
          redisService.expire(uuid+"-"+codeClassifyOid,BATCHADD_REDIS_TIME);//redis过期时间***/
      });
   }
   /****
    * 数据相似项数据校验redis缓存
    * @param codeClassifyOid
@@ -1407,8 +4300,8 @@
         }else{
            if (!CollectionUtils.isEmpty(conditionMap)) {
               Map<String, String> andConditionMap = new HashMap<>();
               andConditionMap.put("islastr", "1");
               andConditionMap.put("islastv", "1");
               andConditionMap.put("lastr", "1");
               andConditionMap.put("lastv", "1");
               conditionMap.putAll(andConditionMap);
               PageHelper pageHelper = new PageHelper(-1);
               pageHelper.addDefaultDesc("id");
@@ -1556,4 +4449,18 @@
         }
      }
   }
   /***
    * 申请集团编码
    * @param idList
    * @param btmName
    */
   private void sendApplyGroupcode(List<String> idList,String btmName,String operationType){
      String oids=VciBaseUtil.array2String(idList.toArray(new String[]{}));
      if(operationType.equals(sysIntegrationPushTypeEnum.ACCPET_APPCODE.getValue())) {
         mdmInterJtClient.applyGroupCode(oids,btmName);
      }else if(operationType.equals(sysIntegrationPushTypeEnum.ACCPET_EDITCODE)){
         mdmInterJtClient.receiveEditApply(oids,btmName);
      }
   }
}