xiejun
2023-06-15 694374bb1c6c08e3e79a65f575922e61c5c971fc
历史导入功能添加
已修改7个文件
1851 ■■■■■ 文件已修改
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/pagemodel/CodeImportTemplateVO.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/pagemodel/CodeImprotDataVO.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/controller/MdmEngineController.java 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/ICodeRuleService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/MdmIOService.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeRuleServiceImpl.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmIOServiceImpl.java 1540 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/pagemodel/CodeImportTemplateVO.java
@@ -12,11 +12,13 @@
 */
@Data
public class CodeImportTemplateVO {
    private List<ColumnVO> cloNamesList=new ArrayList<>();
    private CodeClassifyTemplateVO codeClassifyTemplateVO;
    private CodeClassifyVO codeClassifyVO;
    private boolean root;
    private String codeClassifyOid;
    private String codeTemplateOid;
    private String codeRuleOid;
    private List<ColumnVO> cloNamesList=new ArrayList<>();
    private CodeRuleVO codeRuleVO;
    private CodeClassifyTemplateVO codeClassifyTemplateVO;
    private CodeClassifyVO codeClassifyVO;
}
Source/UBCS/ubcs-service-api/ubcs-code-api/src/main/java/com/vci/ubcs/code/vo/pagemodel/CodeImprotDataVO.java
@@ -49,7 +49,7 @@
    private List<Map<String,String>> datas = new ArrayList<>();
    private CodeClassifyTemplateVO codeClstemplateVO;
    private CodeClassifyVO codeClassifyVO;
    private CodeRuleVO codeRuleVO;
    public CodeClassifyTemplateVO getCodeClassifyTemplateVO() {
        return codeClstemplateVO;
    }
@@ -116,18 +116,35 @@
        this.fields = fields;
    }
    @Override
    public String toString() {
        return "CodeImprotDataVO{" +
                "rowIndex='" + rowIndex + '\'' +
                ", codeClassifyOid='" + codeClassifyOid + '\'' +
                ", templateOid='" + templateOid + '\'' +
                ", codeRuleOid='" + codeRuleOid + '\'' +
                ", fields=" + fields +
                ", colNames=" + colNames +
                ", datas=" + datas +
                ", codeClstemplateVO=" + codeClstemplateVO +
                ", codeClassifyVO=" + codeClassifyVO +
                '}';
    }
    public CodeClassifyTemplateVO getCodeClstemplateVO() {
        return codeClstemplateVO;
    }
    public void setCodeClstemplateVO(CodeClassifyTemplateVO codeClstemplateVO) {
        this.codeClstemplateVO = codeClstemplateVO;
    }
    public CodeRuleVO getCodeRuleVO() {
        return codeRuleVO;
    }
    public void setCodeRuleVO(CodeRuleVO codeRuleVO) {
        this.codeRuleVO = codeRuleVO;
    }
    @Override
    public String toString() {
        return "CodeImprotDataVO{" +
            "rowIndex='" + rowIndex + '\'' +
            ", codeClassifyOid='" + codeClassifyOid + '\'' +
            ", templateOid='" + templateOid + '\'' +
            ", codeRuleOid='" + codeRuleOid + '\'' +
            ", fields=" + fields +
            ", colNames=" + colNames +
            ", datas=" + datas +
            ", codeClstemplateVO=" + codeClstemplateVO +
            ", codeClassifyVO=" + codeClassifyVO +
            ", codeRuleVO=" + codeRuleVO +
            '}';
    }
}
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/controller/MdmEngineController.java
@@ -74,7 +74,52 @@
            ControllerUtil.writeDataToResponse(response,msg.getBytes(StandardCharsets.UTF_8),null);
        }
    }
    /**
     * 下载批量申请的导入模板
     * @param codeClassifyOid 分类的主键
     * @param response 响应对象
     * @throws IOException 抛出异常
     */
    @GetMapping("/downloadTopImportExcel")
    @VciBusinessLog(operateName = "下载批量申请编码的导入模板")
    public void downloadTopImportExcel(String codeClassifyOid,HttpServletResponse response) throws IOException{
        String excelName = mdmIOService.downloadTopImportExcel(codeClassifyOid);
        try {
            ControllerUtil.writeFileToResponse(response,excelName);
        } catch (Throwable e) {
            //如果出错,把错误信息写到text
            String msg = LangBaseUtil.getErrorMsg(e);
            if(StringUtils.isBlank(msg)){
                msg = "未知错误";
            }
            ControllerUtil.writeDataToResponse(response,msg.getBytes(StandardCharsets.UTF_8),null);
        }
    }
    /**
     * 下载历史数据导入模板
     * @param codeClassifyOid 分类的主键
     * @param response 响应对象
     * @throws IOException 抛出异常
     */
    @GetMapping("/downloadImportExcelHistory")
    @VciBusinessLog(operateName = "下载历史数据导入模板")
    public void downloadImportExcelHistory(String codeClassifyOid,HttpServletResponse response) throws IOException{
        String excelName = mdmIOService.createImportExcel(codeClassifyOid,true);
        //String excelName = mdmIOService.downloadTopImportExcel(codeClassifyOid);
        try {
            ControllerUtil.writeFileToResponse(response,excelName);
        } catch (Throwable e) {
            //如果出错,把错误信息写到text
            String msg = LangBaseUtil.getErrorMsg(e);
            if(StringUtils.isBlank(msg)){
                msg = "未知错误";
            }
            ControllerUtil.writeDataToResponse(response,msg.getBytes(StandardCharsets.UTF_8),null);
        }
    }
    /**
     * 批量申请编码的信息
@@ -126,6 +171,97 @@
//        return null;
    }
    /**
     * 导入历史数据
     * @param codeClassifyOid 分类的主键
     * @param classifyAttr 分类路径使用的属性
     * @param file 文件的内容
     */
    @VciBusinessLog(operateName = "导入编码的历史数据")
    @PostMapping("/batchImportHistoryData")
    public R batchImportHistoryData(String codeClassifyOid, String classifyAttr,MultipartFile file,HttpServletResponse response) throws Throwable {
        String excelFileName = LocalFileUtil.getDefaultTempFolder() + File.separator + file.getOriginalFilename();
        File file1 = new File(excelFileName);
        try {
            file.transferTo(new File(excelFileName));
            CodeImProtRusultVO codeImProtRusultVO =mdmIOService.batchImportHistoryData(codeClassifyOid, classifyAttr,file1);
            if(StringUtils.isNotBlank(codeImProtRusultVO.getFilePath())||StringUtils.isNotBlank(codeImProtRusultVO.getRedisUuid())){
                //放到map里
                R result = R.fail("导入失败");
                if(StringUtils.isNotBlank(codeImProtRusultVO.getFilePath())) {
                    String filedUUid = ControllerUtil.putErrorFile(codeImProtRusultVO.getFilePath());
                    codeImProtRusultVO.setFileOid(filedUUid);
                }
                result.setData(codeImProtRusultVO);
                return result;
            }else {
                return R.success("操作成功!");
            }
        }catch (Throwable e) {
            logger.error("导入错误",e);
            String errorFile = LocalFileUtil.getDefaultTempFolder() + File.separator + "错误.txt";
            LocalFileUtil.writeContentToFile(LangBaseUtil.getErrorMsg(e),errorFile);
            String uuid=ControllerUtil.putErrorFile(errorFile);
            CodeImProtRusultVO codeImProtRusultVO =new CodeImProtRusultVO();
            codeImProtRusultVO.setRedisUuid("");
            codeImProtRusultVO.setFileOid(uuid);
            codeImProtRusultVO.setFilePath(errorFile);
            R r = R.fail("导入失败");
            r.setData(codeImProtRusultVO);
            return r;
        }finally {
            file1.delete();
        }
    }
    /**
     * 导入历史数据
     * @param codeClassifyOid 分类的主键
     * @param classifyAttr 分类路径使用的属性
     * @param file 文件的内容
     */
    @VciBusinessLog(operateName = "批量申请编码的信息")
    @PostMapping("/batchTopImportCode")
    public R batchTopImportCode(String codeClassifyOid, String classifyAttr,MultipartFile file,HttpServletResponse response) throws Throwable {
        String excelFileName = LocalFileUtil.getDefaultTempFolder() + File.separator + file.getOriginalFilename();
        File file1 = new File(excelFileName);
        try {
            file.transferTo(new File(excelFileName));
            CodeImProtRusultVO codeImProtRusultVO =mdmIOService.batchTopImportCode(codeClassifyOid, classifyAttr,file1);
            if(StringUtils.isNotBlank(codeImProtRusultVO.getFilePath())||StringUtils.isNotBlank(codeImProtRusultVO.getRedisUuid())){
                //放到map里
                R r = R.fail("导入失败!");
                if(StringUtils.isNotBlank(codeImProtRusultVO.getFilePath())) {
                    String filedUUid = ControllerUtil.putErrorFile(codeImProtRusultVO.getFilePath());
                    codeImProtRusultVO.setFileOid(filedUUid);
                    r = R.success("导入成功!");
                }
                r.setData(codeImProtRusultVO);
                return r;
            }else {
                return R.success("导入成功!");
            }
        }catch (Throwable e) {
            e.printStackTrace();
            logger.error("导入错误",e);
            String errorFile = LocalFileUtil.getDefaultTempFolder() + File.separator + "错误.txt";
            LocalFileUtil.writeContentToFile(LangBaseUtil.getErrorMsg(e),errorFile);
            String uuid=ControllerUtil.putErrorFile(errorFile);
            CodeImProtRusultVO codeImProtRusultVO =new CodeImProtRusultVO();
            codeImProtRusultVO.setRedisUuid("");
            codeImProtRusultVO.setFileOid(uuid);
            codeImProtRusultVO.setFilePath(errorFile);
            R r = R.fail("导入失败");
            r.setData(codeImProtRusultVO);
            return r;
        }finally {
            file1.delete();
        }
    }
    /**
     * 修改状态
@@ -256,7 +392,7 @@
    }
    /***
     * 从redis缓存里获取到导入正确的数据
     * 从redis缓存里获取到导入行相似项的数据
     * @param dataOid
     * @param redisOid
     * @return
@@ -276,7 +412,27 @@
    public DataGrid<Map<String,String>> gridResemble(String codeClassifyOid,String redisOid){
        return mdmIOService.gridDatas(codeClassifyOid,redisOid);
    }
    /***
     * 导入数据
     * @param codeImprotSaveDatVO//数据对象
     * @return
     */
    @PostMapping("/batchImportData")
    public R batchImportData(@RequestBody CodeImprotParmaDatVO codeImprotSaveDatVO){
        return  mdmIOService.batchImportData(codeImprotSaveDatVO.getCodeImprotSaveDatVOList(),codeImprotSaveDatVO.getClassifyAttr(),codeImprotSaveDatVO.getImprot());
    }
    /***
     *根据数据oid从缓存中移除数据
     * @param redisOid redisid
     * @param codeClassifyOid 存储规则的oid
     * @param dataOids  所需删除的数据
     * @return
     */
    @GetMapping("/deleteDatas")
    public  R deleteDatas(String redisOid,String codeClassifyOid,String dataOids){
        return mdmIOService.deleteDatas(redisOid,codeClassifyOid,dataOids);
    }
    /**
     * 批量保存流程执行页面修改的内容
     * @param orderDTOList 编码相关的信息,不需要码段的信息
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/ICodeRuleService.java
@@ -108,6 +108,16 @@
    Collection<CodeRuleVO> listCodeRuleByOids(Collection<String> oidCollections) throws VciBaseException;
    /**
     * 主键批量获取主数据编码规则
     *
     * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
     * @param hasSec         是否包含码段
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 查询出现异常时会抛出
     */
    Collection<CodeRuleVO> listCodeRuleByIds(Collection<String> oidCollections,boolean hasSec)throws VciBaseException ;
    /**
     * 参照主数据编码规则列表
     * @param bladeQueryObject 查询条件
     * @return 主数据编码规则显示对象列表,生效的内容
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/MdmIOService.java
@@ -4,9 +4,11 @@
import com.vci.ubcs.code.vo.pagemodel.CodeClassifyVO;
import com.vci.ubcs.code.vo.pagemodel.CodeImProtRusultVO;
import com.vci.ubcs.code.vo.pagemodel.CodeImportTemplateVO;
import com.vci.ubcs.code.vo.pagemodel.CodeImprotSaveDatVO;
import com.vci.ubcs.code.vo.webserviceModel.attrmap.DataObjectVO;
import com.vci.ubcs.code.vo.webserviceModel.result.xml.XMLResultDataObjectDetailDO;
import com.vci.ubcs.starter.web.pagemodel.DataGrid;
import org.springblade.core.tool.api.R;
import java.io.File;
import java.util.LinkedList;
@@ -24,6 +26,14 @@
     */
    String createImportExcel(String codeClassifyOid,boolean isHistory);
    /**
     * 生成导入的文件
     * @param codeClassifyOid 分类的主键
     * @return excel的文件地址
     */
    String downloadTopImportExcel(String codeClassifyOid);
    /**
     * 批量申请编码数据
     * @param orderDTO 编码申请信息,必须包含分类主键和码段的信息
@@ -32,6 +42,23 @@
     */
    CodeImProtRusultVO batchImportCode(CodeOrderDTO orderDTO, File file);
    /***
     *批量申请编码数据
     * @param codeClassifyOid 分类的主键
     * @param classifyAttr 分类路径使用的属性
     * @param file excel文件的信息
     * @return 有错误信息的excel
     */
    CodeImProtRusultVO batchTopImportCode(String codeClassifyOid,String classifyAttr, File file);
    /**
     * 导入历史数据
     * @param codeClassifyOid 分类的主键
     * @param classifyAttr 分类路径使用的属性
     * @param file excel文件的信息
     * @return 有错误信息的excel
     */
    CodeImProtRusultVO batchImportHistoryData(String codeClassifyOid,String classifyAttr, File file);
    /***
     * 从redis缓存里获取到导入的数据
     * @param codeClassifyOid
@@ -48,6 +75,25 @@
     */
    DataGrid<Map<String, String>> gridRowResemble(String dataOid, String redisOid);
    /**
     * 批量申请
     * @param codeImprotSaveDatVOList
     * @param isImprot
     * @return
     */
     R batchImportData(List<CodeImprotSaveDatVO> codeImprotSaveDatVOList, String classifyAttr, boolean isImprot);
    /***
     *
     * @param redisOid redisid
     * @param codeClassifyOid 存储规则的oid
     * @param dataOids  所需删除的数据
     * @return
     */
    R deleteDatas(String redisOid, String codeClassifyOid, String dataOids);
    void batchSyncEditDatas(CodeClassifyVO codeClassifyVO, DataObjectVO dataObjectVO, LinkedList<XMLResultDataObjectDetailDO> resultDataObjectDetailDOs);
    /**
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeRuleServiceImpl.java
@@ -320,6 +320,21 @@
    }
    /**
     * 主键批量获取主数据编码规则
     *
     * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
     * @param hasSec         是否包含码段
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 查询出现异常时会抛出
     */
    @Override
    public Collection<CodeRuleVO> listCodeRuleByIds(Collection<String> oidCollections, boolean hasSec) throws VciBaseException {
        VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
        List<CodeRule> codeRuleDOList = listCodeRuleDOByOidCollections(oidCollections);
        return codeRuleDO2VOs(codeRuleDOList, true);
    }
    /**
     * 使用主键集合查询数据对象
     *
     * @param oidCollections 主键的集合
@@ -438,6 +453,27 @@
    }
    /**
     * 批量数据对象转换为显示对象
     *
     * @param codeRules 数据对象列表
     * @param hasSec      是否包含码段
     * @return 显示对象
     * @throws VciBaseException 参数为空或者不存在的时候会抛出异常
     */
    public List<CodeRuleVO> codeRuleDO2VOs(Collection<CodeRule> codeRules, boolean hasSec) throws VciBaseException {
        List<CodeRuleVO> voList = new ArrayList<CodeRuleVO>();
        if (!CollectionUtils.isEmpty(codeRules)) {
            for (CodeRule s : codeRules) {
                CodeRuleVO vo = codeRuleDO2VO(s,true);
                if (vo != null) {
                    voList.add(vo);
                }
            }
        }
        return voList;
    }
    /**
     * 数据对象转换为显示对象
     *
     * @param codeRuleDO 规则的数据对象
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmIOServiceImpl.java
@@ -2,12 +2,16 @@
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vci.ubcs.code.bo.AttributeValue;
import com.vci.ubcs.code.bo.CodeClassifyFullInfoBO;
import com.vci.ubcs.code.bo.CodeTemplateAttrSqlBO;
import com.vci.ubcs.code.dto.CodeOrderDTO;
import com.vci.ubcs.code.entity.CodeAllCode;
import com.vci.ubcs.code.entity.CodeClassify;
import com.vci.ubcs.code.enumpack.CodeDefaultLC;
import com.vci.ubcs.code.enumpack.CodeLevelTypeEnum;
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 +20,8 @@
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.omd.feign.IBtmTypeClient;
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,6 +32,8 @@
import com.vci.ubcs.starter.revision.model.BaseModel;
import com.vci.ubcs.starter.util.DefaultAttrAssimtUtil;
import com.vci.ubcs.starter.util.LocalFileUtil;
import com.vci.ubcs.starter.util.MdmBtmTypeConstant;
import com.vci.ubcs.starter.web.constant.QueryOptionConstant;
import com.vci.ubcs.starter.web.enumpck.BooleanEnum;
import com.vci.ubcs.starter.web.enumpck.VciFieldTypeEnum;
import com.vci.ubcs.starter.web.pagemodel.DataGrid;
@@ -36,6 +44,7 @@
import com.vci.ubcs.starter.web.util.*;
import lombok.AllArgsConstructor;
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;
@@ -43,17 +52,17 @@
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.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;
@@ -66,6 +75,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 +98,17 @@
    @Resource
    private ICodeClassifyService classifyService;
    /**
     * 通用查询
     */
    @Resource
    private CommonsMapper commonsMapper;
    /****
     * 码值服务
     */
    @Resource
    ICodeAllCodeService codeAllCodeService;
    /**
     * 模板的服务
@@ -111,6 +141,178 @@
     */
    @Autowired
    private FormulaServiceImpl formulaService;
    /**
     * 规则的服务
     */
    @Autowired
    private ICodeRuleService ruleService;
    /**
     * 业务类型的服务
     */
    @Autowired
    private IBtmTypeClient btmTypeClient;
    /**
     * 批量申请:选取选中分类下的所有模板关键属性,相似属性,必填属性,写入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
            //参照的自行输入名称
            //分类注入的不用,都是导入后自动处理的
            //编码,状态等字段不导入
            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=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;
    }
    /**
     * 生成导入的文件
     *
@@ -307,6 +509,627 @@
        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) {
        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<String> 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.getOid());
                    });
                    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, "") + ";系统错误,存储数据的时候出错了");
                            });
                        }
                    }
                });
                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;
    }
    /***
     * 从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());
    }
    /**
     * 错误信息返回excel
     * @param rowDataList 所有的导入数据
@@ -492,23 +1315,23 @@
            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里面
@@ -599,6 +1422,161 @@
        return dataGrid;
    }
    @Override
    public R batchImportData(List<CodeImprotSaveDatVO> codeImprotSaveDatVOList, String classifyAttr, boolean isImprot) {
        List<String> allNeedSaveCboList=new ArrayList<>();
        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<>();
            if(isImprot) {
                Map<String/**主键**/, String/**路径**/> childOidPathMap = getChildClassifyPathMap(classifyFullInfo, fullPath);
                //都转换完了。需要批量检查
                //找所有的分类路径,需要校验路径是否正确,是否都在当前的分类的下级
                List<CodeClassifyVO> childClassifyVOs = classifyService.listChildrenClassify(orderDTO.getCodeClassifyOid(), 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));
                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);
            }
            //分类注入
            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);
            //SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
            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)) {
                List<BaseModel> dataCBOList=new ArrayList<>();
                needSaveCboList.stream().forEach(clientBusinessObject -> {
                    BaseModel baseModel=new BaseModel();
                    BeanUtil.convert(clientBusinessObject,baseModel);
                    baseModel.setData(VciBaseUtil.objectToMapString(clientBusinessObject));
                    dataCBOList.add(baseModel);
                    allNeedSaveCboList.add(baseModel.getOid());
                });
                try {
                //9.我们处理业务数据
                    if (isImprot) {
                        productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, ruleVO, null, dataCBOList);
                    }else {
                        productCodeService.productCodeAndSaveData(classifyFullInfo, codeClassifyTemplateVO, ruleVO, orderDTO.getSecDTOList(), dataCBOList);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            //如果是编码生成失败,则直接就失败了,其他的判断出来有错误的我们都统一返回到excel里面
            engineService.batchSaveSelectChar(codeClassifyTemplateVO, allNeedSaveCboList);
        });
        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 分类的主键
@@ -682,6 +1660,122 @@
        return fullPath;
    }
    /**
     * 检查码段的长度是否符合要求
     * @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 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) ){
                        Integer userSecret = VciBaseUtil.getCurrentUserSecret();
                        cbo.setAttributeValue(SECRET_FIELD,String.valueOf((userSecret==null || userSecret ==0)? UserSecretEnum.NONE.getValue():userSecret));
                    }*/
                }else{
                    //此时还没有转换路径
                    //cbo.setAttributeValue(CODE_FULL_PATH_FILED, childOidPathMap.getOrDefault(rowData.getData().getOrDefault(CODE_CLASSIFY_OID_FIELD,""),fullPath));
                    cbo.setLcStatus(CodeDefaultLC.RELEASED.getValue());
                }
                rowData.put("oid",cbo.getOid());
            }catch (Throwable e){
                log.error("设置默认的属性的值错误",e);
            }
            cboList.add(cbo);
        });
    }
    /**
     * excel转换为cbo的对象
     * @param classifyFullInfo 分类的全部信息
@@ -817,6 +1911,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 +2088,136 @@
        }
    }
    /**
     * 批量检查企业编码是否存在
     * @param templateVO 模板的显示对象
     * @param cboList 数据的列表
     * @param errorMap 错误的信息
     */
    private void batchCheckIdExistOnOrder(CodeClassifyTemplateVO templateVO,List<ClientBusinessObject> cboList,Map<String ,String> errorMap){
        List<String> existIds = new ArrayList<>();
        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])) + ")");
            R<BtmTypeVO>  r= btmTypeClient.getDetail(templateVO.getBtmTypeId());
            BtmTypeVO btmTypeVO =r.getData();
            String tableName=btmTypeVO.getTableName();
            StringBuffer sb=new StringBuffer();
            sb.append(" select id from ");
            sb.append(tableName);
            sb.append(" where 1=1 ");
            sb.append(" 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 属性的信息
@@ -1211,6 +2460,109 @@
        //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 关键属性的映射
@@ -1301,6 +2653,126 @@
    }
    /***
     * 根据不同模板组织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
     * @param templateVO
@@ -1359,6 +2831,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