田源
2024-09-29 d8f51c40544ae278095e991ed00ec297842d4332
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmProductCodeServiceImpl.java
@@ -1,743 +1,1443 @@
package com.vci.ubcs.code.service.impl;
import com.vci.ubcs.code.constant.MdmEngineConstant;
import com.vci.ubcs.code.dao.CodeAllCodeDaoI;
import com.vci.ubcs.code.mapper.CodeSerialValueMapper;
import com.alibaba.fastjson.JSON;
import com.vci.ubcs.code.algorithm.CustomSerialEnum;
import com.vci.ubcs.code.annotation.MdmSerialAlgorithm;
import com.vci.ubcs.code.annotation.MdmSerialAlgorithmMethod;
import com.vci.ubcs.code.dto.CodeCustomSerialDTO;
import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vci.ubcs.code.bo.CodeClassifyFullInfoBO;
import com.vci.ubcs.code.dto.CodeOrderSecDTO;
import com.vci.ubcs.code.entity.CodeAllCode;
import com.vci.ubcs.code.entity.CodeClassifyValue;
import com.vci.ubcs.code.entity.CodeSerialValue;
import com.vci.ubcs.code.enumpack.CodeCutTypeEnum;
import com.vci.ubcs.code.enumpack.CodeGetValueTypeEnum;
import com.vci.ubcs.code.enumpack.CodeLevelTypeEnum;
import com.vci.ubcs.code.enumpack.CodeSecTypeEnum;
import com.vci.ubcs.code.lifecycle.CodeAllCodeLC;
import com.vci.ubcs.code.entity.CodeAllCodeDO;
import com.vci.ubcs.code.entity.CodeSerialValueDO;
import com.vci.ubcs.code.service.MdmProductCodeServiceI;
import com.vci.corba.common.VCIError;
import com.vci.starter.web.constant.QueryOptionConstant;
import com.vci.starter.web.constant.RegExpConstant;
import com.vci.starter.web.exception.VciBaseException;
import com.vci.starter.web.pagemodel.PageHelper;
import com.vci.starter.web.pagemodel.SessionInfo;
import com.vci.starter.web.util.VciBaseUtil;
import com.vci.starter.web.util.VciDateUtil;
import com.vci.web.enumpck.OsCodeFillTypeEnum;
import com.vci.web.pageModel.BatchCBO;
import com.vci.web.service.WebBoServiceI;
import com.vci.web.service.impl.FormulaServiceImpl;
import com.vci.web.util.WebUtil;
import org.apache.commons.lang3.StringUtils;
import com.vci.ubcs.code.bo.CodeClassifyFullInfoBO;
import com.vci.ubcs.code.dto.CodeOrderSecDTO;
import com.vci.ubcs.code.mapper.CodeClassifyValueMapper;
import com.vci.ubcs.code.mapper.CodeSerialValueMapper;
import com.vci.ubcs.code.service.MdmEngineService;
import com.vci.ubcs.code.service.MdmProductCodeService;
import com.vci.ubcs.code.vo.pagemodel.CodeBasicSecVO;
import com.vci.ubcs.code.vo.pagemodel.CodeClassifyTemplateVO;
import com.vci.ubcs.code.vo.pagemodel.CodeClassifyVO;
import com.vci.ubcs.code.vo.pagemodel.CodeRuleVO;
import com.vci.ubcs.starter.exception.VciBaseException;
import com.vci.ubcs.starter.revision.model.BaseModel;
import com.vci.ubcs.starter.util.DefaultAttrAssimtUtil;
import com.vci.ubcs.starter.util.MdmBtmTypeConstant;
import com.vci.ubcs.starter.web.constant.QueryOptionConstant;
import com.vci.ubcs.starter.web.constant.RegExpConstant;
import com.vci.ubcs.starter.web.enumpck.OsCodeFillTypeEnum;
import com.vci.ubcs.starter.web.util.ApplicationContextProvider;
import com.vci.ubcs.starter.web.util.VciBaseUtil;
import com.vci.ubcs.starter.web.util.VciDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import plm.bs.bom.clientobject.ClientBusinessObject;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static com.vci.web.other.BdSelectInputCharAspect.SEP;
import static com.vci.ubcs.code.constant.MdmEngineConstant.*;
import static com.vci.ubcs.code.enumpack.CodeSecTypeEnum.CODE_SERIAL_SEC;
/**
 * 生成编码的服务
 * @author weidy
 * @date 2022-3-6
 */
@Service
public class MdmProductCodeServiceImpl implements MdmProductCodeServiceI {
@Slf4j
public class MdmProductCodeServiceImpl  implements MdmProductCodeService {
    /**
     * 业务数据的服务
     */
    @Autowired
    @Lazy
   private WebBoServiceI boService;
   /**
    * 流水号的相关的信息
    */
   @Resource
   private CodeSerialValueMapper serialValueMapper;
    /**
     * 所有的编码的内容
     */
    @Autowired
    private CodeAllCodeDaoI allCodeMapper;
   /**
    * 流水号的相关的信息
    */
   @Resource
   private CodeClassifyValueMapper codeClassifyValueMapper;
    /**
     * 流水号的相关的信息
     */
    @Autowired
    private CodeSerialValueMapper serialValueMapper;
   /**
    * 所有的编码的内容
    */
   @Resource
   private CodeAllCodeServiceImpl codeAllCodeService;
    /**
     * 公式的服务
     */
    @Autowired
    private FormulaServiceImpl formulaService;
    /**
     * 生成编码--并且保存数据
     *
     * @param classifyFullInfoBO 分类的全部信息
     * @param templateVO         模板的显示对象
     * @param ruleVO             编码规则的显示对象
     * @param secDTOList         各个码段的值
     * @param dataCBOList        业务数据
     */
    @Override
    public synchronized List<String> productCodeAndSaveData(CodeClassifyFullInfoBO classifyFullInfoBO, CodeClassifyTemplateVO templateVO,
                                             CodeRuleVO ruleVO, List<CodeOrderSecDTO> secDTOList, List<ClientBusinessObject> dataCBOList) {
        BatchCBO batchCBO = new BatchCBO();
        WebUtil.setPersistence(false);
        dataCBOList = dataCBOList.stream().sorted(((o1, o2) -> o1.getCreateTime().compareTo(o2.getCreateTime()))).collect(Collectors.toList());
        batchCBO.getCreateCbos().addAll(dataCBOList);
        List<String> codeList = new ArrayList<>();
   /**
    * 所有的编码的内容
    */
   @Resource
   @Lazy
   private MdmEngineService mdmEngineService;
        /*****
         * 保证并发的时候,最大流水号都对的,但是这种加锁有弊端
         *
         */
   /**
    * 公式的服务
    */
   @Autowired
   private FormulaServiceImpl formulaService;
        if(dataCBOList.stream().anyMatch(cbo->StringUtils.isNotBlank(cbo.getId()) && StringUtils.isNotBlank(cbo.getAttributeValue(MdmEngineConstant.CODE_SEC_LENGTH_FIELD)))){
            //是历史数据导入
            //历史数据执行的时候,这个系统会很卡
            //主要是为了录入最大流水号和allcode
            SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
            List<CodeAllCodeDO> allCodeDOList = new ArrayList<>();
            Map<String/**流水依据**/,Map<String/**码段的主键**/,Double/**最大流水号**/>> maxSerialMap = new HashMap<>();
            dataCBOList.parallelStream().forEach(cbo->{
                VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
                String code = cbo.getId();
                List<String> serialUnitList = new ArrayList<>();
                String[] secLengths = cbo.getAttributeValue(MdmEngineConstant.CODE_SEC_LENGTH_FIELD).split("#");
                List<CodeBasicSecVO> secVOList = ruleVO.getSecVOList().stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).collect(Collectors.toList());
                Map<String/**码段的主键**/,String/**码段的值**/> serialValueMap = new HashMap<>();
                Map<String, CodeBasicSecVO> secVOMap = secVOList.stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
                for (int i = 0; i < secLengths.length; i++) {
                    CodeBasicSecVO secVO = secVOList.get(i);
                    String thisSecValue  = "";
                    if(i == 0){
                        thisSecValue = code.contains("#")?code.substring(0,code.indexOf("#")):code;
                    } else if(i == secLengths.length-1){
                        //最后
                        thisSecValue =  code.contains("#")?code.substring(code.lastIndexOf("#")):code;
                    }else {
                        int start = 0;
                        for (int j = 0; j < i; j++) {
                            start += VciBaseUtil.getInt(secLengths[j]) + 1;
                        }
                        thisSecValue = code.substring(start,start+VciBaseUtil.getInt(secLengths[1]));
                    }
                    if(VciBaseUtil.getBoolean(secVO.getSerialDependFlag())){
                        serialUnitList.add(thisSecValue);
                    }
                    if(CodeSecTypeEnum.CODE_SERIAL_SEC.getValue().equalsIgnoreCase(secVO.getSectype())){
                        serialValueMap.put(secVO.getOid(),thisSecValue);
                    }
                }
                String serialUnitString = serialUnitList.size() == 0 ? MdmEngineConstant.EMPTY_SERIAL_UNIT : serialUnitList.stream().collect(Collectors.joining(MdmEngineConstant.SERIAL_UNIT_SPACE));
                List<String> serialUnFileStringList = new ArrayList<>();
                if(!CollectionUtils.isEmpty(serialValueMap)){
                    serialValueMap.forEach((secOid,secValue)->{
                        //要看是不是补位的
                        CodeBasicSecVO secVO = secVOMap.get(secOid);
                        Double serialDb = null;
                        if(OsCodeFillTypeEnum.NONE.getValue().equalsIgnoreCase(secVO.getCodeFillType())){
                            //不补码
                            //把所有不是数字的去掉,因为可能会是老数据,新规则
                            serialDb = VciBaseUtil.getDouble(killUnNumberChar(secValue));
                        }else {
                            //左右填充的,我们需要
                            serialDb = VciBaseUtil.getDouble(killUnNumberChar(killFillChar(secValue,secVO.getCodeFillSeparator(),
                                    OsCodeFillTypeEnum.LEFT.getValue().equalsIgnoreCase(secVO.getCodeFillType()))));
                        }
                        Map<String, Double> thisUnitMaxMap = maxSerialMap.getOrDefault(serialUnitString, new HashMap<>());
                        thisUnitMaxMap.put(secOid,serialDb);
                        maxSerialMap.put(serialUnitString,thisUnitMaxMap);
                        serialUnFileStringList.add(String.valueOf(serialDb));
                    });
                }
                CodeAllCodeDO allCodeDO = new CodeAllCodeDO();
                allCodeDO.setCodeClassifyOid(classifyFullInfoBO.getCurrentClassifyVO().getOid());
                allCodeDO.setCodeRuleOid(ruleVO.getOid());
                allCodeDO.setId(cbo.getId());
                allCodeDO.setCodeClassifyTemplateOid(templateVO.getOid());
                allCodeDO.setCreateCodeBtm(cbo.getBtmName());
                allCodeDO.setCreateCodeOid(cbo.getOid());
                allCodeDO.setSerialUnit(serialUnitString);
                allCodeDO.setUnFillSerial(serialUnFileStringList.stream().collect(Collectors.joining(MdmEngineConstant.SERIAL_VALUE_SPACE)));
                allCodeDO.setLcStatus(cbo.getLcStatus());
                allCodeDOList.add(allCodeDO);
            });
            //处理最大的流水号
            List<CodeSerialValueDO> addSerialValueList = new ArrayList<>();
            List<CodeSerialValueDO> editSerialValueList = new ArrayList<>();
            maxSerialMap.forEach((serialUnit,secOidMaxMap)->{
                secOidMaxMap.forEach((secOid,maxSerial)->{
                    Map<String, String> conditionMap = new HashMap<>();
                    conditionMap.put("codeRuleOid", ruleVO.getOid());
                    conditionMap.put("serialUnit", serialUnit);
                    //这个字段是为了解决多个流水的问题
                    conditionMap.put("codeSecOid", secOid);
                    List<CodeSerialValueDO> serialValueDOS = serialValueMapper.selectByCondition(conditionMap, new PageHelper(-1));
                    if (!CollectionUtils.isEmpty(serialValueDOS)) {
                        CodeSerialValueDO serialValueDO = serialValueDOS.get(0);
                        if(VciBaseUtil.getDouble(serialValueDO.getMaxSerial())<maxSerial){
                            serialValueDO.setMaxSerial(String.valueOf(maxSerial));
                            editSerialValueList.add(serialValueDO);
                        }
                    }else{
                        //没有
                        CodeSerialValueDO serialValueDO = new CodeSerialValueDO();
                        serialValueDO.setCodeRuleOid(ruleVO.getOid());
                        serialValueDO.setSerialUnit(serialUnit);
                        serialValueDO.setCodeSecOid(secOid);
                        serialValueDO.setMaxSerial(maxSerial.toString());
                        addSerialValueList.add(serialValueDO);
                    }
                });
            });
            if(!CollectionUtils.isEmpty(addSerialValueList)){
                batchCBO.copyFromOther(serialValueMapper.batchInsert(addSerialValueList));
            }
            if(!CollectionUtils.isEmpty(editSerialValueList)){
                batchCBO.copyFromOther(serialValueMapper.batchUpdate(editSerialValueList));
            }
            //处理allCode
            if(!CollectionUtils.isEmpty(allCodeDOList)){
                    Map<String, List<CodeAllCodeDO>> ruleGroup = allCodeDOList.stream().collect(Collectors.groupingBy(s -> s.getCodeRuleOid()));
                Map<String, CodeAllCodeDO> codeDOMap = allCodeDOList.stream().collect(Collectors.toMap(s -> s.getCodeRuleOid() + SEP + s.getId(), t -> t));
                List<CodeAllCodeDO> addCodeDOs = new ArrayList<>();
                List<CodeAllCodeDO> editCodeDOs = new ArrayList<>();
                ruleGroup.forEach((ruleOid,allCodeDOS)->{
                    VciBaseUtil.switchCollectionForOracleIn(allCodeDOS).stream().forEach(codeDOs->{
                        Map<String,String> conditionMap = new HashMap<>();
                        conditionMap.put("coderuleoid",ruleOid);
                        conditionMap.put("id",QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(codeDOs.stream().map(s->s.getId()).collect(Collectors.toList()).toArray(new String[0])) + ")");
                        List<CodeAllCodeDO> existCodes = allCodeMapper.selectByCondition(conditionMap, new PageHelper(-1));
                        if(!CollectionUtils.isEmpty(existCodes)){
                            existCodes.stream().forEach(existCode->{
                                String rule_id = existCode.getCodeRuleOid() + SEP + existCode.getId();
                                if(codeDOMap.containsKey(rule_id)){
                                    CodeAllCodeDO newCodeDO = codeDOMap.get(rule_id);
                                    existCode.setCreateCodeOid(newCodeDO.getOid());
                                    existCode.setCreateCodeBtm(newCodeDO.getCreateCodeBtm());
                                    existCode.setCodeClassifyTemplateOid(newCodeDO.getCodeClassifyTemplateOid());
                                    existCode.setCodeClassifyOid(newCodeDO.getCodeClassifyOid());
                                    existCode.setLcStatus(newCodeDO.getLcStatus());
                                    editCodeDOs.add(existCode);
                                }
                            });
                        }
                    });
                });
                if(!CollectionUtils.isEmpty(editCodeDOs)){
                    Set<String> exitIds = editCodeDOs.stream().map(s -> s.getCodeRuleOid() + SEP + s.getId()).collect(Collectors.toSet());
                    addCodeDOs = allCodeDOList.stream().filter(s -> !exitIds.contains(s.getCodeRuleOid() + SEP + s.getId())).collect(Collectors.toList());
                }else{
                    addCodeDOs = allCodeDOList;
                }
                if(!CollectionUtils.isEmpty(editCodeDOs)){
                    batchCBO.copyFromOther(allCodeMapper.batchUpdate(editCodeDOs));
                }
                if(!CollectionUtils.isEmpty(addCodeDOs)){
                    batchCBO.copyFromOther(allCodeMapper.batchInsert(addCodeDOs));
                    Map<String, String> statusMap = addCodeDOs.stream().collect(Collectors.toMap(s -> s.getOid(), s -> s.getLcStatus()));
                    batchCBO.getCreateCbos().stream().filter(s -> StringUtils.equalsIgnoreCase("codeallcode",s.getBtmName())).forEach(s -> {
                        s.setLcStatus(statusMap.get(s.getOid()));
                        try {
                            s.setAttributeValue("lcstatus",statusMap.get(s.getOid()));
                        } catch (VCIError e) {
                            e.printStackTrace();
                        }
                    });
                }
            }
            WebUtil.setPersistence(true);
            boService.persistenceBatch(batchCBO);
            return codeList;
        }else {
            List<CodeBasicSecVO> secVOList = ruleVO.getSecVOList().stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).collect(Collectors.toList());
            List<String> serialUnitList = new LinkedList<>();
            List<String> secValueList = new ArrayList<>();
            Map<String, String> secValueMap = secDTOList.stream().collect(Collectors.toMap(s -> s.getSecOid(), s -> s.getSecValue()));
            List<CodeBasicSecVO> serialSecVOList = new ArrayList<>();
            List<CodeBasicSecVO> attrSecVOList = new ArrayList<>();
            for (int i = 0; i < secVOList.size(); i++) {
                CodeBasicSecVO secVO = secVOList.get(i);
                switchSecValue(secVO, secValueMap, classifyFullInfoBO, serialSecVOList, attrSecVOList, serialUnitList, secValueList);
            }
            //处理属性码段和流水码段
            Map<String/**流水码段的主键**/, Map<String/**流水依据**/, Double>> lastMaxSerialValueMap = new HashMap<>();
            List<CodeAllCodeDO> allCodeDOList = new ArrayList<>();
   @Override
   @Transactional(rollbackFor = Exception.class)
   public List<String> productCodeAndSaveData(CodeClassifyFullInfoBO classifyFullInfoBO, CodeClassifyTemplateVO templateVO, CodeRuleVO ruleVO, List<CodeOrderSecDTO> secDTOList, List<BaseModel> dataCBOList,BladeUser user) throws Exception {
      dataCBOList = dataCBOList.stream().sorted(((o1, o2) -> o1.getCreateTime().compareTo(o2.getCreateTime()))).collect(Collectors.toList());
      List<String> codeList = new ArrayList<>();
      final CodeRuleVO finalRuleVO = ruleVO;
      /*****
       * 保证并发的时候,最大流水号都对的,但是这种加锁有弊端
       */
      if(dataCBOList.stream().anyMatch(cbo-> StringUtils.isNotBlank(cbo.getId()))
         // && StringUtils.isNotBlank(cbo.getAttributeValue(CODE_SEC_LENGTH_FIELD))
      ){
         //是历史数据导入
         //主要是为了录入最大流水号和allcode
         //SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
         List<CodeAllCode> allCodeDOList = new CopyOnWriteArrayList<>();
         Map<String/**流水依据**/, HashMap<String/**码段的主键**/,String/**最大流水号**/>> maxSerialMap = new HashMap<>();
         // TODO 多线程流引发的问题已修改
         dataCBOList.parallelStream().forEach(cbo->{
            log.info("code:----->"+cbo.getId());
            //VciBaseUtil.setCurrentUserSessionInfo(sessionInfo);
            String code = cbo.getId();
            List<String> serialUnitList = new CopyOnWriteArrayList<>();
            //String seclenghStr=cbo.getData().get(CODE_SEC_LENGTH_FIELD);
            String[] secLengths = cbo.getData().get(CODE_SEC_LENGTH_FIELD).split("#");
            cbo.getData().remove(CODE_SEC_LENGTH_FIELD);//将此key除去
            cbo.getData().remove(IMPORT_ROW_INDEX);//将此key除去
            cbo.getData().remove("codeclassifyid");//将此key除去
            List<CodeBasicSecVO> secVOList = finalRuleVO.getSecVOList().stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).collect(Collectors.toList());
            Map<String/**码段的主键**/,String/**码段的值**/> serialValueMap = new HashMap<>();
            Map<String, CodeBasicSecVO> secVOMap = secVOList.stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
            Map<String,Integer> serialSecOidIndexMap=new HashMap<>();
            LinkedList<String> codeValueList=new LinkedList<>();
            for (int i = 0; i < secLengths.length; i++) {
               CodeBasicSecVO secVO = secVOList.get(i);
               String thisSecValue  = "";
               /*if(i == 0){
                  thisSecValue = seclenghStr.contains("#")?code.substring(0,VciBaseUtil.getInt(secLengths[i])):code;
               } else if(i == secLengths.length-1){
                  //最后
                  thisSecValue =  seclenghStr.contains("#")?code.substring(VciBaseUtil.getInt(secLengths[i-1]),code.length()):code;
               }else {*/
               int start = 0;
               for (int j = 0; j < i; j++) {
                  start += VciBaseUtil.getInt(secLengths[j]);
               }
               thisSecValue = code.substring(start,start+VciBaseUtil.getInt(secLengths[i]));
               //   }
               if(VciBaseUtil.getBoolean(secVO.getSerialDependFlag())){
                  serialUnitList.add(thisSecValue);
                  serialSecOidIndexMap.put(secVO.getOid(),i);
               }
               if(CODE_SERIAL_SEC.getValue().equalsIgnoreCase(secVO.getSecType())){
                  serialValueMap.put(secVO.getOid(),thisSecValue);
               }
               codeValueList.add(thisSecValue);
            }
            List<String> serialUnFileStringList = new ArrayList<>();
            AtomicReference<String> newSerialUnitString = new AtomicReference<>("");
            if(!CollectionUtils.isEmpty(serialValueMap)){
               AtomicInteger index = new AtomicInteger();
               serialValueMap.forEach((secOid,secValue)->{
                  //要看是不是补位的
                  CodeBasicSecVO secVO = secVOMap.get(secOid);
                  List<String >newSerialUnitList=new ArrayList<>();
                  newSerialUnitList.addAll(serialUnitList);
                  if(index.get() ==0){
                     if(serialSecOidIndexMap.containsKey(secOid)) {
                        int num = serialSecOidIndexMap.get(secOid);
                        newSerialUnitList.set(num, "");
                     }
                  }
                  String serialUnitString = newSerialUnitList.size() == 0 ? EMPTY_SERIAL_UNIT : newSerialUnitList.stream().collect(Collectors.joining(SERIAL_UNIT_SPACE));
                  newSerialUnitString.set(serialUnitString);
                  index.getAndIncrement();
                  String serialDb = "";
                  // 截取掉前后缀之后的码段
                  String subSecValue = killPriffixSuffix(secValue, secVO.getPrefixCode(), secVO.getSuffixCode());
                  if(OsCodeFillTypeEnum.NONE.getValue().equalsIgnoreCase(secVO.getCodeFillType())){
                     //不补码
                     //把所有不是数字的去掉,因为可能会是老数据,新规则
                     //serialDb = VciBaseUtil.getDouble(killUnNumberChar(subSecValue));
                     //serialDb = killUnNumberChar(subSecValue);
                     serialDb=subSecValue;
                  }else {
                     //左右填充的,我们需要
                     serialDb = killFillChar(subSecValue,secVO.getCodeFillSeparator(),
                        OsCodeFillTypeEnum.LEFT.getValue().equalsIgnoreCase(secVO.getCodeFillType()));
                  }
                  Double newSerialDb = CustomSerialEnum.getDoubleCustomSerialValue(serialDb,secVO.getCustomCodeSerialType());
                  //TODO: 20240822需要这块代码是同步性的,maxSerialMap这儿会因为线程受影响,修改后测试多次总数为5000条一次导入耗费时间为3分30秒左右
                  synchronized(this) {
                     HashMap<String, String> thisUnitMaxMap = maxSerialMap.getOrDefault(serialUnitString, new HashMap<>());
                     Double maxValue=newSerialDb;
                     if(thisUnitMaxMap.containsKey(secOid)){
                        String newMaxValue = thisUnitMaxMap.getOrDefault(secOid,"");
                        maxValue = StringUtils.isBlank(newMaxValue)?-1:VciBaseUtil.getDouble(newMaxValue);
                        if(maxValue < newSerialDb){
                           maxValue = newSerialDb;
                        }
                     }
                     String newMaxValue=CustomSerialEnum.getStringCustomSerialValue(maxValue,secVO.getCustomCodeSerialType());
                     serialDb=CustomSerialEnum.getStringCustomSerialValue(newSerialDb,secVO.getCustomCodeSerialType());
                     thisUnitMaxMap.put(secOid,newMaxValue);
                     maxSerialMap.put(serialUnitString,thisUnitMaxMap);
                     serialUnFileStringList.add(String.valueOf(serialDb));
                  }
               });
            }
            CodeAllCode allCodeDO = new CodeAllCode();
            DefaultAttrAssimtUtil.addDefaultAttrAssimt(allCodeDO, MdmBtmTypeConstant.CODE_ALL_CODE,user);
            allCodeDO.setCodeClassifyOid(classifyFullInfoBO.getCurrentClassifyVO().getOid());
            allCodeDO.setCodeRuleOid(finalRuleVO.getOid());
            allCodeDO.setId(cbo.getId());
            allCodeDO.setCodeClassifyTemplateOid(templateVO.getOid());
            allCodeDO.setCreateCodeBtm(cbo.getBtmname());
            allCodeDO.setCreateCodeOid(cbo.getOid());
            allCodeDO.setSerialUnit(newSerialUnitString.get());
            String unFillSerial =serialUnFileStringList.size()==1?serialUnFileStringList.get(0)+ SERIAL_VALUE_SPACE:serialUnFileStringList.stream().collect(Collectors.joining(SERIAL_VALUE_SPACE));
            allCodeDO.setUnFillSerial(unFillSerial);
            allCodeDO.setLcStatus(cbo.getLcStatus());
            allCodeDO.setLctid("codeAllCodeLC");
            allCodeDO.setCodeDelimit(codeValueList.stream().collect(Collectors.joining(SERIAL_VALUE_SPACE)));//添加链接符
            allCodeDOList.add(allCodeDO);
         });
         //处理最大的流水号
         List<CodeSerialValue> addSerialValueList = new ArrayList<>();
         List<CodeSerialValue> editSerialValueList = new ArrayList<>();
         log.info("maxSerialMap:----->"+maxSerialMap.size());
         maxSerialMap.forEach((serialUnit,secOidMaxMap)->{
            secOidMaxMap.forEach((secOid,maxSerial)->{
               QueryWrapper<CodeSerialValue> queryWrapper = new QueryWrapper<>();
               queryWrapper.eq("codeRuleOid", finalRuleVO.getOid());
               queryWrapper.eq("serialUnit", serialUnit);
               //这个字段是为了解决多个流水的问题
               queryWrapper.eq("codeSecOid", secOid);
            //已经存储的最大流水号的内容
            Map<String/**码段的主键**/, Map<String, CodeSerialValueDO>> maxSerialValueMap = new HashMap<>();
               List<CodeSerialValue> serialValueDOS = serialValueMapper.selectList(queryWrapper);
               log.info("serialValueDOS--->"+serialValueDOS.size());
               if (!CollectionUtils.isEmpty(serialValueDOS)) {
                  CodeSerialValue serialValueDO = serialValueDOS.get(0);
                  log.info("oldmaxSerial--->"+serialValueDO.getMaxSerial()+"---- newmaxSerial---->"+maxSerial);
                  if(VciBaseUtil.getDouble(serialValueDO.getMaxSerial())<VciBaseUtil.getDouble(maxSerial)){
                     serialValueDO.setMaxSerial(String.valueOf(maxSerial));
                     DefaultAttrAssimtUtil.updateDefaultAttrAssimt(serialValueDO,user);
                     editSerialValueList.add(serialValueDO);
                  }
               }else{
                  //没有
                  CodeSerialValue serialValueDO = new CodeSerialValue();
                  DefaultAttrAssimtUtil.addDefaultAttrAssimt(serialValueDO, MdmBtmTypeConstant.CODE_SERIAL_VALUE,user);
                  serialValueDO.setCodeRuleOid(finalRuleVO.getOid());
                  serialValueDO.setSerialUnit(serialUnit);
                  serialValueDO.setCodeSecOid(secOid);
                  serialValueDO.setMaxSerial(maxSerial.toString());
                  addSerialValueList.add(serialValueDO);
               }
            });
         });
         if(!CollectionUtils.isEmpty(addSerialValueList)){
            for (CodeSerialValue codeSerialValue : addSerialValueList) {
               serialValueMapper.insert(codeSerialValue);
            }
         }
         if(!CollectionUtils.isEmpty(editSerialValueList)){
            for (CodeSerialValue codeSerialValue : editSerialValueList) {
               serialValueMapper.updateById(codeSerialValue);
            }
         }
         //处理allCode
         if(!CollectionUtils.isEmpty(allCodeDOList)){
            Map<String,List<CodeAllCode>> ruleGroup = allCodeDOList.stream().collect(Collectors.groupingBy(s -> s.getCodeRuleOid()));
            Map<String, CodeAllCode> codeDOMap = allCodeDOList.stream().collect(Collectors.toMap(s -> s.getCodeRuleOid() + "${SEP}" + s.getId(), t -> t));
            List<CodeAllCode> addCodeDOs = new CopyOnWriteArrayList<>();
            List<CodeAllCode> editCodeDOs = new CopyOnWriteArrayList<>();
            ruleGroup.forEach((ruleOid,allCodeDOS)->{
               VciBaseUtil.switchCollectionForOracleIn(allCodeDOS).stream().forEach(codeDOs->{
                  QueryWrapper<CodeAllCode> allCodeWrapper = new QueryWrapper<>();
                  allCodeWrapper.eq("coderuleoid",ruleOid);
                  allCodeWrapper.in("id", QueryOptionConstant.IN + "(" +
                     VciBaseUtil.toInSql(codeDOs.stream().map(s->s.getId()).collect(Collectors.toList()).toArray(new String[0])) + ")");
                  List<CodeAllCode> existCodes = codeAllCodeService.selectByWrapper(allCodeWrapper);
            for (int i = 0; i < dataCBOList.size(); i++) {
                ClientBusinessObject cbo = dataCBOList.get(i);
                List<String> thisSecValueList = new LinkedList<>();
                for (int j = 0; j < secValueList.size(); j++) {
                    thisSecValueList.add(secValueList.get(j));
                }
                List<String> thisSerialUnitList = new LinkedList<>();
                //因为流水依据每次可能不一样,所以每次都拷贝一份
                for (int j = 0; j < serialUnitList.size(); j++) {
                    thisSerialUnitList.add(serialUnitList.get(j));
                }
                //先看看有没有属性的码段
                boolean attrSevIsSerialDepend = CollectionUtils.isEmpty(attrSecVOList) ? false : (attrSecVOList.stream().anyMatch(s -> VciBaseUtil.getBoolean(s.getSerialDependFlag())));
                switchAttrSecValue(attrSecVOList, cbo, thisSecValueList, attrSevIsSerialDepend, thisSerialUnitList);
                  if(!CollectionUtils.isEmpty(existCodes)){
                     existCodes.stream().forEach(existCode->{
                        String rule_id = existCode.getCodeRuleOid() + "${SEP}" + existCode.getId();
                        if(codeDOMap.containsKey(rule_id)){
                           CodeAllCode newCodeDO = codeDOMap.get(rule_id);
                           existCode.setCreateCodeOid(newCodeDO.getOid());
                           existCode.setCreateCodeBtm(newCodeDO.getCreateCodeBtm());
                           existCode.setCodeClassifyTemplateOid(newCodeDO.getCodeClassifyTemplateOid());
                           existCode.setCodeClassifyOid(newCodeDO.getCodeClassifyOid());
                           existCode.setLcStatus(newCodeDO.getLcStatus());
                           editCodeDOs.add(existCode);
                        }
                     });
                  }
               });
            });
            if(!CollectionUtils.isEmpty(editCodeDOs)){
               Set<String> exitIds = editCodeDOs.stream().map(s -> s.getCodeRuleOid() + "${SEP}" + s.getId()).collect(Collectors.toSet());
               addCodeDOs = allCodeDOList.stream().filter(s -> !exitIds.contains(s.getCodeRuleOid() + "${SEP}" + s.getId())).collect(Collectors.toList());
            }else{
               addCodeDOs = allCodeDOList;
            }
            if(!CollectionUtils.isEmpty(editCodeDOs)){
               codeAllCodeService.updateBatchById(editCodeDOs);
            }
            if(!CollectionUtils.isEmpty(addCodeDOs)){
               Map<String, String> statusMap = addCodeDOs.stream().collect(Collectors.toMap(s -> s.getOid(), s -> s.getLcStatus()));
               addCodeDOs.stream().filter(s -> StringUtils.equalsIgnoreCase("codeallcode",s.getBtmname())).forEach(s -> {
                  s.setLcStatus(statusMap.get(s.getOid()));
               });
               //通过ID来进行去重
               List<CodeAllCode> distinctCodeAllCOdes = addCodeDOs.stream().collect(Collectors
                  .collectingAndThen(
                     Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CodeAllCode::getId))),
                     ArrayList::new));
               if(distinctCodeAllCOdes.size() != addCodeDOs.size() ){
                  throw new VciBaseException("编码数据重复,无法保存,请注意!");
               }
               QueryWrapper<CodeAllCode> wrapper = new QueryWrapper<>();
               wrapper.eq("CREATECODEBTM",addCodeDOs.get(0).getCreateCodeBtm());
               wrapper.in("ID",addCodeDOs.stream().map(CodeAllCode::getId).collect(Collectors.toList()));
               List<CodeAllCode> codeAllCodes = codeAllCodeService.selectByWrapper(wrapper);
               List<CodeAllCode> takeBack = codeAllCodes.stream().filter(e -> e.getLcStatus().equals("TakeBack")).collect(Collectors.toList());
               if(codeAllCodes.size()>takeBack.size()){
                  throw new ServiceException("生成编码数据ID已有历史记录,请确认如下生成的ID数据:"+ addCodeDOs.stream().map(CodeAllCode::getId).collect(Collectors.toList()));
               }
               for (CodeAllCode codeAllCode : takeBack) {
                  codeAllCode.setTs(new Date());
                  codeAllCode.setLastModifyTime(new Date());
                  codeAllCode.setLastModifier(Func.isNotEmpty(user) ? user.getAccount():AuthUtil.getUserAccount());
                  for (int i = 0; i < addCodeDOs.size(); i++) {
                     if(codeAllCode.getId().equals(addCodeDOs.get(i).getId())){
                        codeAllCode.setCreateCodeOid(addCodeDOs.get(i).getCreateCodeOid());
                        codeAllCode.setLcStatus(addCodeDOs.get(i).getLcStatus());
                        addCodeDOs.remove(i);
                     }
                  }
                  /*Iterator<CodeAllCode> iterator = addCodeDOs.iterator();
                  while (iterator.hasNext()){
                     CodeAllCode next = iterator.next();
                     if(codeAllCode.getId().equals(next.getId())){
                        codeAllCode.setCreateCodeOid(next.getCreateCodeOid());
                        codeAllCode.setLcStatus(next.getLcStatus());
                        // TODO: 这儿先暂时注释掉,没看懂这儿为什么要这样做,导致报错
                        iterator.remove();
                     }
                  }*/
               }
               if(takeBack.size()>0){
                  codeAllCodeService.updateBatchById(takeBack);
               }
                String serialUnitString = thisSerialUnitList.size() == 0 ? MdmEngineConstant.EMPTY_SERIAL_UNIT : thisSerialUnitList.stream().collect(Collectors.joining(MdmEngineConstant.SERIAL_UNIT_SPACE));
                switchSerialSecValue(serialSecVOList, attrSevIsSerialDepend, ruleVO, serialUnitString, maxSerialValueMap, thisSecValueList, lastMaxSerialValueMap, i == 0);
               codeAllCodeService.saveBatch(addCodeDOs);
            }
            mdmEngineService.insertBatchByType(dataCBOList.get(0).getBtmname(),dataCBOList);
         }
         return codeList;
      }else {
         List<CodeBasicSecVO> secVOList = finalRuleVO.getSecVOList().stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).collect(Collectors.toList());
         List<String> serialUnitList = new LinkedList<>();
         List<String> secValueList = new ArrayList<>();
         Map<String, String> secValueMap = secDTOList.stream().collect(Collectors.toMap(s -> s.getSecOid(), s -> s.getSecValue()==null?"":s.getSecValue()));
         List<CodeBasicSecVO> serialSecVOList = new ArrayList<>();
         List<CodeBasicSecVO> attrSecVOList = new ArrayList<>();
         for (int i = 0; i < secVOList.size(); i++) {
            CodeBasicSecVO secVO = secVOList.get(i);
            try{
               switchSecValue(secVO, secValueMap, classifyFullInfoBO, serialSecVOList, attrSecVOList, serialUnitList, secValueList);
            }catch (Exception e){
               throw new ServiceException("码值转换时出现错误,原因:"+e.getMessage());
            }
         }
         //处理属性码段和流水码段
         Map<String/**流水码段的主键**/, Map<String/**流水依据**/, String>> lastMaxSerialValueMap = new HashMap<>();
         List<CodeAllCode> allCodeDOList = new ArrayList<>();
                //组装编码的值
                cbo.setId(thisSecValueList.stream().collect(Collectors.joining()));
                codeList.add(cbo.getId());
                StringBuilder sb = new StringBuilder();
                //把码段里面都找一下流水号
                for (int j = 0; j < serialSecVOList.size(); j++) {
                    CodeBasicSecVO secVO = serialSecVOList.get(j);
                    Double serialValue = lastMaxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>()).getOrDefault(serialUnitString, 0d);
                    if (serialValue != null) {
                        sb.append(String.valueOf(serialValue.longValue())).append(MdmEngineConstant.SERIAL_VALUE_SPACE);
                    }
                }
                //要存储最后的全部allcode
                wrapperAllCode(classifyFullInfoBO, ruleVO, cbo, templateVO, allCodeDOList, serialUnitString, sb.toString());
            }
            batchCBO.copyFromOther(allCodeMapper.batchInsert(allCodeDOList));
            saveSerialValue(batchCBO, ruleVO, lastMaxSerialValueMap, maxSerialValueMap);
         //已经存储的最大流水号的内容
         Map<String/**码段的主键**/, Map<String, CodeSerialValue>> maxSerialValueMap = new HashMap<>();
            Map<String, String> statusMap = allCodeDOList.stream().collect(Collectors.toMap(s -> s.getOid(), s -> s.getLcStatus()));
            batchCBO.getCreateCbos().stream().filter(s -> StringUtils.equalsIgnoreCase("codeallcode",s.getBtmName())).forEach(s -> {
                s.setLcStatus(statusMap.get(s.getOid()));
                try {
                    s.setAttributeValue("lcstatus",statusMap.get(s.getOid()));
                } catch (VCIError e) {
                    e.printStackTrace();
                }
            });
         for (int i = 0; i < dataCBOList.size(); i++) {
            BaseModel cbo = dataCBOList.get(i);
            cbo.getData().remove(CODE_SEC_LENGTH_FIELD);//将此key除去
            cbo.getData().remove(IMPORT_ROW_INDEX);//将此key除去
            cbo.getData().remove("codeclassifyid");//将此key除去
            List<String> thisSecValueList = new LinkedList<>();
            for (int j = 0; j < secValueList.size(); j++) {
               thisSecValueList.add(secValueList.get(j));
            }
            List<String> thisSerialUnitList = new LinkedList<>();
            //因为流水依据每次可能不一样,所以每次都拷贝一份
            for (int j = 0; j < serialUnitList.size(); j++) {
               thisSerialUnitList.add(serialUnitList.get(j));
            }
            //先看看有没有属性的码段
            boolean attrSevIsSerialDepend = CollectionUtils.isEmpty(attrSecVOList) ? false : (attrSecVOList.stream().anyMatch(s -> VciBaseUtil.getBoolean(s.getSerialDependFlag())));
            switchAttrSecValue(attrSecVOList, cbo, thisSecValueList, attrSevIsSerialDepend, thisSerialUnitList);
            String serialUnitString = thisSerialUnitList.size() == 0 ? EMPTY_SERIAL_UNIT : thisSerialUnitList.stream().collect(Collectors.joining(SERIAL_UNIT_SPACE));
            switchSerialSecValue(cbo,serialSecVOList, attrSevIsSerialDepend, finalRuleVO, serialUnitString, maxSerialValueMap, thisSecValueList, lastMaxSerialValueMap, i == 0);
        }
        WebUtil.setPersistence(true);
        boService.persistenceBatch(batchCBO);
        return codeList;
    }
            //组装编码的值
            cbo.setId(thisSecValueList.stream().collect(Collectors.joining()));
            codeList.add(cbo.getId());
            StringBuilder sb = new StringBuilder();
            //把码段里面都找一下流水号
            for (int j = 0; j < serialSecVOList.size(); j++) {
               CodeBasicSecVO secVO = serialSecVOList.get(j);
               String serialValue = lastMaxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>()).getOrDefault(serialUnitString, "");
               if (serialValue != null) {
                  sb.append(serialValue).append(SERIAL_VALUE_SPACE);
               }
            }
            String codeDelimiter=thisSecValueList.stream().collect(Collectors.joining(SERIAL_VALUE_SPACE));
            //要存储最后的全部allcode
            wrapperAllCode(classifyFullInfoBO, finalRuleVO, cbo, templateVO, allCodeDOList, serialUnitString, sb.toString(),codeDelimiter);
         }
         //处理最大流水
         saveSerialValue( finalRuleVO, lastMaxSerialValueMap, maxSerialValueMap);
    /**
     * 去除补位字符
     * @param s 字符
     * @param fillString 补位字符
     * @param left 是否左补位
     * @return 替换后的值
     */
    private String killFillChar(String s, String fillString,boolean left){
        Integer index = 0;
        String value = s;
        if(left){
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if((new String(new char[]{c})).equalsIgnoreCase(fillString)){
                    index = i;
                }
            }
            if(index >0){
                value = value.substring(index);
            }
        }else{
            //从右往左找
            for (int i = s.length()-1; i >=0; i++) {
                char c = s.charAt(i);
                if((new String(new char[]{c})).equalsIgnoreCase(fillString)){
                    index = i;
                }
            }
            if(index >0){
                value = value.substring(0,index);
            }
        }
        return value;
         allCodeDOList.stream().forEach(
            allCode -> {DefaultAttrAssimtUtil.addDefaultAttrAssimt(allCode,"codeallcode",user);allCode.setLctid("codeAllCodeLC");}
         );
    }
         Map<String, String> statusMap = allCodeDOList.stream().collect(Collectors.toMap(s -> s.getOid(), s -> s.getLcStatus()));
         allCodeDOList.stream().filter(s -> StringUtils.equalsIgnoreCase("codeallcode",s.getBtmname())).forEach(s -> {
            s.setLcStatus(statusMap.get(s.getOid()));
         });
    /**
     * 去掉不是数字的字符
     * @param s 字符
     * @return 替换后的值
     */
    private String killUnNumberChar(String s){
        Integer lastUnNumberIndex = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if(!(new String(new char[]{c})).matches(RegExpConstant.NUMBER)){
                lastUnNumberIndex = i;
            }
        }
        String value = s;
        if(lastUnNumberIndex >0){
            value = value.substring(lastUnNumberIndex);
        }
        return value;
    }
         //通过ID来进行去重
         List<CodeAllCode> distinctCodeAllCOdes = allCodeDOList.stream().collect(Collectors
            .collectingAndThen(
               Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CodeAllCode::getId))),
               ArrayList::new));
         if(distinctCodeAllCOdes.size() != allCodeDOList.size() ){
            throw new ServiceException("编码数据重复,无法保存,请注意!");
         }
         QueryWrapper<CodeAllCode> wrapper = new QueryWrapper<>();
         wrapper.eq("CREATECODEBTM",allCodeDOList.get(0).getCreateCodeBtm());
         wrapper.in("ID",allCodeDOList.stream().map(CodeAllCode::getId).collect(Collectors.toList()));
         List<CodeAllCode> codeAllCodes = codeAllCodeService.selectByWrapper(wrapper);
         List<CodeAllCode> takeBack = codeAllCodes.stream().filter(e -> e.getLcStatus().equals("TakeBack")).collect(Collectors.toList());
         if(codeAllCodes.size()>takeBack.size()){
            throw new ServiceException("生成编码数据ID已有历史记录,请确认如下生成的ID数据:"+ allCodeDOList.stream().map(CodeAllCode::getId).collect(Collectors.toList()));
         }
    /**
     * 回收码值
     *
     * @param btmId                 业务数据的业务类型
     * @param businessOidCollection 业务数据的主键
     * @return 受影响的数据内容
     */
    @Override
    public BatchCBO recycleCode(String btmId, Collection<String> businessOidCollection) {
        boolean oldPersistence =  WebUtil.isPersistence();
        WebUtil.setPersistence(false);
        BatchCBO batchCBO = new BatchCBO();
        VciBaseUtil.switchCollectionForOracleIn(businessOidCollection).stream().forEach(oids-> {
            Map<String, String> conditionMap = new HashMap<>();
            //编码要记录为回收的状态
            conditionMap.put("createcodeoid", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(oids.toArray(new String[0])) + ")");
            conditionMap.put("createcodebtm", btmId);
            List<CodeAllCodeDO> allCodeDOS = allCodeMapper.selectByCondition(conditionMap, new PageHelper(-1));
            if (!CollectionUtils.isEmpty(allCodeDOS)) {
                allCodeDOS.stream().forEach(codeDO->{
                    codeDO.setLcStatus(CodeAllCodeLC.TASK_BACK.getValue());
                });
                batchCBO.copyFromOther(allCodeMapper.batchUpdate(allCodeDOS));
            }
        });
        WebUtil.setPersistence(oldPersistence);
        return batchCBO;
    }
         for (CodeAllCode codeAllCode : takeBack) {
            codeAllCode.setTs(new Date());
            codeAllCode.setLastModifyTime(new Date());
            codeAllCode.setLastModifier(Func.isNotEmpty(user) ? user.getAccount():AuthUtil.getUserAccount());
            for (int i = 0; i < allCodeDOList.size(); i++) {
               if(codeAllCode.getId().equals(allCodeDOList.get(i).getId())){
                  codeAllCode.setCreateCodeOid(allCodeDOList.get(i).getCreateCodeOid());
                  codeAllCode.setLcStatus(allCodeDOList.get(i).getLcStatus());
                  allCodeDOList.remove(i);
               }
            }
            /*while (iterator.hasNext()){
               CodeAllCode next = iterator.next();
               if(codeAllCode.getId().equals(next.getId())){
                  codeAllCode.setCreateCodeOid(next.getCreateCodeOid());
                  codeAllCode.setLcStatus(next.getLcStatus());
                  //iterator.remove();
               }
            }*/
         }
         if(takeBack.size()>0){
            codeAllCodeService.updateBatchById(takeBack);
         }
         codeAllCodeService.saveBatch(allCodeDOList);
         mdmEngineService.insertBatchByType(dataCBOList.get(0).getBtmname(),dataCBOList);
      }
      return codeList;
   }
    /**
     * 转换码值的内容
     * @param secVO 码段的内容
     * @param secValueMap 码值的内容,key是码段的主键,value是码值
     * @param classifyFullInfoBO 分类的全部信息
     * @param serialSecVOList 流水码段
     * @param attrSecVOList 属性码段
     * @param serialUnitList 流水依据
     * @param secValueList 码值列表
     */
    private void switchSecValue(CodeBasicSecVO secVO,Map<String,String> secValueMap,
                                CodeClassifyFullInfoBO classifyFullInfoBO,List<CodeBasicSecVO> serialSecVOList,
                                List<CodeBasicSecVO> attrSecVOList, List<String> serialUnitList,
                                List<String> secValueList ){
        CodeSecTypeEnum secType = CodeSecTypeEnum.forValue(secVO.getSectype());
        String secValue = secValueMap.getOrDefault(secVO.getOid(), "");
        switch (secType) {
            case CODE_FIXED_SEC:
                //固定码段的,直接用码值,不论码值的长度是多少,因为可变长度和固定长度是控制在码段管理里面的码值定义的
                break;
            case CODE_DATE_SEC:
                //时间码段,需要将当前时间依据时间格式进行转换.
                //时间码段不涉及到是否补位
                secValue = VciDateUtil.date2Str(new Date(), secVO.getCodeDateFormatStr());
                break;
            case CODE_CLASSIFY_SEC:
                //分类码段的,也是从前端选择了码值即可,不论码值的长度是多少
                break;
            case CODE_LEVEL_SEC:
                //层级码段,需要从分类上获取相应的信息
                if (CodeLevelTypeEnum.MIN.getValue().equalsIgnoreCase(secVO.getCodeLevelType())) {
                    //最小层,因为我们只能在叶子节点上申请编码,所以这个就是当前分类的
                    if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType()) || CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                        //就是当前分类的
                        secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                    } else {
                        //我们需要从顶层开始找到当前分类为止
                        secValue = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
                    }
                } else {
                    //指定层,我们需要通过上级的来获取
                    if (CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                        //说明当前已经是最高的了
                        secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                    } else {
                        //这个我们需要看看,层级是不是大于了最大层级的数
                        List<CodeClassifyVO> parentClassifyVOList = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> o1.getDataLevel().compareTo(o2.getDataLevel()))).collect(Collectors.toList());
                        if (secVO.getCodeLevelValue() > (parentClassifyVOList.size() + 1)) {
                            //指定的层级比当前的层级还大了,所以只能获取当前层级了
                            if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType())) {
                                secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                            } else {
                                secValue = parentClassifyVOList.stream().map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
                            }
                        } else {
                            //我们获取其中指定层的内容
                            if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType())) {
                                CodeClassifyVO classifyVO = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() == secVO.getCodeLevelValue().intValue()).findFirst().orElseGet(() -> null);
                                if (classifyVO != null) {
                                    secValue = classifyVO.getId();
                                }
                            } else {
                                //小于等于的全部拿出来
                                secValue = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() <= secVO.getCodeLevelValue().intValue()).sorted(((o1, o2) -> o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining());
                            }
                        }
                    }
                }
                //看看长度是否需要截断
                if (!CodeCutTypeEnum.NONE.getValue().equalsIgnoreCase(secVO.getValueCutType()) &&
                        secVO.getValueCutLength() != null && secVO.getValueCutLength() > 0 && secValue.length() > secVO.getValueCutLength()) {
                    if (CodeCutTypeEnum.RIGHT.getValue().equalsIgnoreCase(secVO.getValueCutType())) {
                        //左截取是从左边剪掉,右截取是从右边剪掉--保留左边
                        secValue = secValue.substring(0, secVO.getValueCutLength());
                    } else {
                        secValue = secValue.substring(secValue.length() - secVO.getValueCutLength());
                    }
                }
                break;
            case CODE_REFER_SEC:
                //引用的在页面上已经选择了,所以直接使用前端上传递的值
                //引用就是参照,可能是其他的分类(业务类型)下的数据,所以只在页面上选择
                break;
            case CODE_ATTR_SEC:
                //属性与引用的区别是,属性是当前数据里的属性,而引用可能是引用其他的分类的(业务类型)
                //因为可能是批量的数据的操作,所以我们这里不能直接处理属性,需要后边一边处理
                secValue = "${attr_" + secVO.getOid() + "}";
                attrSecVOList.add(secVO);
                break;
            case CODE_VARIABLE_SEC:
                //可变码段,是在页面上输入内容
                if (secValue.length() > VciBaseUtil.getInt(secVO.getCodeSecLength())) {
                    throw new VciBaseException("【{0}】这个码段是可变码段,但是现在输入的码值的长度({1})超过了规定的长度{2}", new String[]{secVO.getName(), String.valueOf(secValue.length()), secVO.getCodeSecLength()});
                }
                OsCodeFillTypeEnum fillTypeEnum = OsCodeFillTypeEnum.forValue(secVO.getCodeFillType());
                secValue = fillString(VciBaseUtil.getInt(secVO.getCodeSecLength()), fillTypeEnum, secValue, secVO.getCodeFillSeparator());
                break;
            case CODE_SERIAL_SEC:
                //流水码段
                serialSecVOList.add(secVO);
                secValue = "${" + secVO.getOid() + "}";
            default:
                break;
        }
        if (VciBaseUtil.getBoolean(secVO.getSerialDependFlag())) {
            serialUnitList.add(secValue);
        }
        secValueList.add(secValue);
    }
    /**
     * 补位
     * @param totalLength 总长度
     * @param fillTypeEnum 补位方式
     * @param text 当前的内容
     * @param fillChar 补位的字符
     * @return 不填充位置和长度已经达到/超过的时候不会填充
     */
    private String fillString(int totalLength,OsCodeFillTypeEnum fillTypeEnum,String text,String fillChar){
        if(text.length() >= totalLength || OsCodeFillTypeEnum.NONE.equals(fillTypeEnum)){
            //不用补位了
            return  text;
        }
        int balance = totalLength - text.length();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < balance; i++) {
            sb.append(fillChar);
        }
        if(OsCodeFillTypeEnum.LEFT.equals(fillTypeEnum)) {
            text = sb.toString() + text;
        }else {
            text = text + sb.toString();
        }
        return  text;
    }
    /**
     * 转换属性码段的值
     * @param attrSecVOList 属性码段的显示对象
     * @param cbo 业务数据,用于获取码段的值
     * @param thisSecValueList 码值的列表
     * @param attrSevIsSerialDepend 是否有作为流水依据
     * @param serialUnitList 流水依据的内容
     */
    private void switchAttrSecValue(List<CodeBasicSecVO> attrSecVOList,ClientBusinessObject cbo,
                                    List<String> thisSecValueList,boolean attrSevIsSerialDepend,
   /**
    * 转换属性码段的值
    * @param attrSecVOList 属性码段的显示对象
    * @param cbo 业务数据,用于获取码段的值
    * @param thisSecValueList 码值的列表
    * @param attrSevIsSerialDepend 是否有作为流水依据
    * @param serialUnitList 流水依据的内容
    *                       还需要后续的一个移植将会涉及到其他的服务
    */
   private void switchAttrSecValue(List<CodeBasicSecVO> attrSecVOList, BaseModel cbo,
                                    List<String> thisSecValueList, boolean attrSevIsSerialDepend,
                                    List<String> serialUnitList){
        if (!CollectionUtils.isEmpty(attrSecVOList)) {
            attrSecVOList.stream().forEach(attrSevVO -> {
                String value = "";
                if (StringUtils.isNotBlank(attrSevVO.getGetValueClass())) {
                    //使用组合规则来处理的
                    value = getValueByFormulaForCBO(cbo, attrSevVO.getGetValueClass());
                } else {
                    value = cbo.getAttributeValue(attrSevVO.getReferAttributeId());
                }
                if (value == null) {
                    value = "";
                }
                //替换secValueList里面的内容
                for (int j = 0; j < thisSecValueList.size(); j++) {
                    String secValue = thisSecValueList.get(j);
                    if (secValue.equalsIgnoreCase("${attr_" + attrSevVO.getOid() + "}")) {
                        thisSecValueList.set(j, value);
                    }
                }
                if (attrSevIsSerialDepend) {
                    //是流水依赖的话,需要去替换一下
                    for (int j = 0; j < serialUnitList.size(); j++) {
                        String secValue = serialUnitList.get(j);
                        if (secValue.equalsIgnoreCase("${attr_" + attrSevVO.getOid() + "}")) {
                            serialUnitList.set(j, value);
                        }
                    }
                }
            });
        }
    }
      if (!CollectionUtils.isEmpty(attrSecVOList)) {
         attrSecVOList.stream().forEach(attrSevVO -> {
            String value = "";
            if (StringUtils.isNotBlank(attrSevVO.getGetValueClass())) {
               //使用组合规则来处理的
               value = getValueByFormulaForCBO(cbo, attrSevVO.getGetValueClass());
            } else {
               value = cbo.getData().get(attrSevVO.getReferAttributeId());
            }
            if (value == null) {
               value = "";
            }
            //替换secValueList里面的内容
            for (int j = 0; j < thisSecValueList.size(); j++) {
               String secValue = thisSecValueList.get(j);
               if (secValue.equalsIgnoreCase("${attr_" + attrSevVO.getOid() + "}")) {
                  // TODO: 属性码段生成码值后,拼接前后缀
                  thisSecValueList.set(j, joinPreffixAndSuffix(attrSevVO,value));
               }
            }
            if (attrSevIsSerialDepend) {
               //是流水依赖的话,需要去替换一下
               for (int j = 0; j < serialUnitList.size(); j++) {
                  String secValue = serialUnitList.get(j);
                  if (secValue.equalsIgnoreCase("${attr_" + attrSevVO.getOid() + "}")) {
                     serialUnitList.set(j, joinPreffixAndSuffix(attrSevVO,value));
                  }
               }
            }
         });
      }
   }
    /**
     * 使用CBO处理组合规则的内容
     * @param cbo 数据的内容
     * @param rule 规则的内容
     * @return 转换后的
     */
    private String getValueByFormulaForCBO(ClientBusinessObject cbo,String rule){
        Map<String,String> dataMap = new HashMap<>();
        WebUtil.copyValueToMapFromCbos(cbo,dataMap);
        return formulaService.getValueByFormula(dataMap,rule);
    }
   /**
    * 转换流水码段的值
    * @param serialSecVOList 流水码段
    * @param secDTOS;流水值
    * @param attrSevIsSerialDepend 是否有属性码段参与流水
    * @param ruleVO 规则的内容
    * @param serialUnitMap 流水依据
    * @param maxSerialValueMap 最大的流水号
    * @param thisSecValueList 本次的码值
    * @param lastMaxSerialValueMap 封装后
    * @param firstData 是否为第一条数据
    */
   private void switchSerialSecValueBZ(BaseModel cbo,List<CodeOrderSecDTO> secDTOS, List<CodeBasicSecVO> serialSecVOList,boolean attrSevIsSerialDepend,
                             CodeRuleVO ruleVO,Map<String,String> serialUnitMap,
                             Map<String/**码段的主键**/,Map<String/**流水依据**/,CodeSerialValue>> maxSerialValueMap,List<String> thisSecValueList,
                             Map<String/**码段的主键**/,Map<String/**流水依据**/, String>> lastMaxSerialValueMap,boolean firstData){
      if (!CollectionUtils.isEmpty(serialSecVOList)) {
         Map<String/**码段oid**/, String/**码段码值**/> attrNameIdMap = secDTOS.stream().collect(Collectors.toMap(s -> s.getSecOid(), t -> t.getSecValue().toLowerCase(Locale.ROOT),(o1, o2)->o2));
         Map<String,String> secIdserialValueMap=new LinkedHashMap<>();
         for (int j = 0; j < serialSecVOList.size(); j++) {
            AtomicReference<String> serialUnitString= new AtomicReference<>("");
            CodeBasicSecVO secVO = serialSecVOList.get(j);
            String secVOValue="";
            if(attrNameIdMap.containsKey(secVO.getOid())){
               secVOValue=attrNameIdMap.get(secVO.getOid());
               if(StringUtils.isNotBlank(secVOValue)){
                  continue;
               }
            }
            if(serialUnitMap.containsKey(secVO.getOid())){
               serialUnitString.set(serialUnitMap.get(secVO.getOid()));
               secIdserialValueMap.forEach((key,vaule)->{
                  serialUnitString.set(serialUnitString.get().replace("${"+key+"}", vaule));
               });
               if (attrSevIsSerialDepend || firstData) {
                  QueryWrapper<CodeSerialValue> codeSerialWrapper = new QueryWrapper<>();
                  codeSerialWrapper.eq("codeRuleOid", ruleVO.getOid());
                  codeSerialWrapper.eq("serialUnit", serialUnitString.get());
                  codeSerialWrapper.eq("codeSecOid", secVO.getOid());
                  List<CodeSerialValue> serialValueDOS = serialValueMapper.selectList(codeSerialWrapper);
                  if (!CollectionUtils.isEmpty(serialValueDOS)) {
                     Map<String, CodeSerialValue> unitSerialMap = maxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>());
                     CodeSerialValue serialValueDO = serialValueDOS.get(0);
                     unitSerialMap.put(serialValueDO.getSerialUnit(),serialValueDO);
                     maxSerialValueMap.put(secVO.getOid(), unitSerialMap);
                  }
               }
               String serialString="";
               String thisSerialValue = "";
               String startValue = null;
               if (maxSerialValueMap.containsKey(secVO.getOid()) && maxSerialValueMap.get(secVO.getOid()).containsKey(serialUnitString.get())) {
                  startValue = maxSerialValueMap.get(secVO.getOid()).get(serialUnitString.get()).getMaxSerial();
               }
               if (lastMaxSerialValueMap.containsKey(secVO.getOid()) && lastMaxSerialValueMap.get(secVO.getOid()).containsKey(serialUnitString.get())) {
                  //说明多个申请,之前已经加了流水号了
                  startValue = lastMaxSerialValueMap.get(secVO.getOid()).get(serialUnitString.get());
               }
               if(StringUtils.isNotBlank(secVO.getCustomCodeSerialClass())){//自定义流水处理
                  String currentFlowValue=startValue;
                  CodeCustomSerialDTO codeCustomSerialDTO=new CodeCustomSerialDTO();
                  codeCustomSerialDTO.setSerialUnitString(serialUnitString.get());
                  codeCustomSerialDTO.setSerialCodeCodeBasicSec(secVO);
                  codeCustomSerialDTO.setCurrentFlowValue(startValue);
                  codeCustomSerialDTO.setCodeBasicSecVOList(ruleVO.getSecVOList());
                  codeCustomSerialDTO.setCodeRuleOid(ruleVO.getOid());
                  codeCustomSerialDTO.setBaseModel(cbo);
                  codeCustomSerialDTO.setSerialUnitString(serialUnitString.get());
                  codeCustomSerialDTO.setSecValueList(thisSecValueList);
                  thisSerialValue=customCodeSerial(secVO.getCustomCodeSerialClass(),codeCustomSerialDTO);
                  serialUnitString.set(codeCustomSerialDTO.getSerialUnitString());
                  log.info(secVO.getCustomCodeSerialClassText()+"---->"+thisSerialValue);
               }else {
                  Double newThisSerialValue = 0d;
                  if (startValue == null) {
                     //第一个编码
                     newThisSerialValue = VciBaseUtil.getDouble(secVO.getSerialStart());
                  } else {
                     //流水号肯定是数字
                     newThisSerialValue = Double.parseDouble(startValue) + (j + 1) * secVO.getSerialStep();
                  }
                  //要看是否超过最大的流水值
                  if (newThisSerialValue >= secVO.getCodeFillLimit()) {
                     throw new VciBaseException("流水号已经超过允许的最大流水值{0}", new String[]{secVO.getCodeFillLimit().toString()});
                  }
                  thisSerialValue=String.valueOf(newThisSerialValue.intValue());
               }
               //要看补位的内容
               Integer fillLength = VciBaseUtil.getInt(secVO.getCodeFillLength());
               if (fillLength == 0 || fillLength > VciBaseUtil.getInt(secVO.getCodeSecLength())) {
                  //防止在添加的地方没有控制正确
                  fillLength = VciBaseUtil.getInt(secVO.getCodeSecLength());
               }
               serialString = thisSerialValue;
               serialString = fillString(fillLength, OsCodeFillTypeEnum.forValue(secVO.getCodeFillType()), serialString, secVO.getCodeFillSeparator());
               for (int z = 0; z < thisSecValueList.size(); z++) {
                  String secValue = thisSecValueList.get(z);
                  if (secValue.equalsIgnoreCase("${" + secVO.getOid() + "}")) {
                     // TODO: 流水生成码值后拼接前后缀
                     thisSecValueList.set(z, joinPreffixAndSuffix(secVO, serialString));
                  }
               }
               secIdserialValueMap.put(secVO.getOid(),thisSerialValue);//记录流水码段当前的值
               if(StringUtils.isNotBlank(thisSerialValue)) {
                  Map<String, String> unitSerialMap = lastMaxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>());
                  unitSerialMap.put(serialUnitString.get(), String.valueOf(thisSerialValue));
                  lastMaxSerialValueMap.put(secVO.getOid(), unitSerialMap);
               }
            }
         }
      }
   }
    /**
     * 转换流水码段的值
     * @param serialSecVOList 流水码段
     * @param attrSevIsSerialDepend 是否有属性码段参与流水
     * @param ruleVO 规则的内容
     * @param serialUnitString 流水依据
     * @param maxSerialValueMap 最大的流水号
     * @param thisSecValueList 本次的码值
     * @param lastMaxSerialValueMap 封装后
     * @param firstData 是否为第一条数据
     */
    private void switchSerialSecValue(List<CodeBasicSecVO> serialSecVOList,boolean attrSevIsSerialDepend,
                                      CodeRuleVO ruleVO,String serialUnitString,
                                      Map<String/**码段的主键**/,Map<String/**流水依据**/,CodeSerialValueDO>> maxSerialValueMap,List<String> thisSecValueList,
                                      Map<String/**码段的主键**/,Map<String/**流水依据**/, Double>> lastMaxSerialValueMap,boolean firstData){
        if (!CollectionUtils.isEmpty(serialSecVOList)) {
            for (int j = 0; j < serialSecVOList.size(); j++) {
                CodeBasicSecVO secVO = serialSecVOList.get(j);
                if (attrSevIsSerialDepend || firstData) {
                    //如果属性码段也是依赖,则每次都要查询,如果属性码段不是依赖,则只查询一次
                    Map<String, String> conditionMap = new HashMap<>();
                    conditionMap.put("codeRuleOid", ruleVO.getOid());
                    conditionMap.put("serialUnit", serialUnitString);
                    //这个字段是为了解决多个流水的问题
                    conditionMap.put("codeSecOid", secVO.getOid());
                    List<CodeSerialValueDO> serialValueDOS = serialValueMapper.selectByCondition(conditionMap, new PageHelper(-1));
                    if (!CollectionUtils.isEmpty(serialValueDOS)) {
                        Map<String, CodeSerialValueDO> unitSerialMap = maxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>());
                        CodeSerialValueDO serialValueDO = serialValueDOS.get(0);
                        unitSerialMap.put(serialValueDO.getSerialUnit(),serialValueDO);
                        maxSerialValueMap.put(secVO.getOid(), unitSerialMap);
                    }
                }
                Double startValue = null;
                if(maxSerialValueMap.containsKey(secVO.getOid()) && maxSerialValueMap.get(secVO.getOid()).containsKey(serialUnitString)){
                    startValue = VciBaseUtil.getDouble(maxSerialValueMap.get(secVO.getOid()).get(serialUnitString).getMaxSerial());
                }
                if(lastMaxSerialValueMap.containsKey(secVO.getOid()) && lastMaxSerialValueMap.get(secVO.getOid()).containsKey(serialUnitString)){
                    //说明多个申请,之前已经加了流水号了
                    startValue = lastMaxSerialValueMap.get(secVO.getOid()).get(serialUnitString);
                }
                Double thisSerialValue = 0d;
                if (startValue == null) {
                    //第一个编码
                    thisSerialValue = VciBaseUtil.getDouble(secVO.getSerialStart());
                } else {
                    //流水号肯定是数字
                    thisSerialValue = startValue + (j + 1) * secVO.getSerialStep();
                }
                //要看是否超过最大的流水值
                if (thisSerialValue >= secVO.getCodeFillLimit()) {
                    throw new VciBaseException("流水号已经超过允许的最大流水值{0}",new String[]{secVO.getCodeFillLimit().toString()});
                }
                //要看补位的内容
                Integer fillLength = VciBaseUtil.getInt(secVO.getCodeFillLength());
                if (fillLength == 0 || fillLength > VciBaseUtil.getInt(secVO.getCodeSecLength())) {
                    //防止在添加的地方没有控制正确
                    fillLength = VciBaseUtil.getInt(secVO.getCodeSecLength());
                }
                String serialString = String.valueOf(thisSerialValue.longValue());
                serialString = fillString(fillLength, OsCodeFillTypeEnum.forValue(secVO.getCodeFillType()), serialString, secVO.getCodeFillSeparator());
                for (int z = 0; z < thisSecValueList.size(); z++) {
                    String secValue = thisSecValueList.get(z);
                    if (secValue.equalsIgnoreCase("${" + secVO.getOid() + "}")) {
                        thisSecValueList.set(z, serialString);
                    }
                }
                Map<String, Double> unitSerialMap = lastMaxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>());
                unitSerialMap.put(serialUnitString, thisSerialValue);
                lastMaxSerialValueMap.put(secVO.getOid(),unitSerialMap);
            }
        }
    }
   /**
    * 转换流水码段的值
    * @param serialSecVOList 流水码段
    * @param attrSevIsSerialDepend 是否有属性码段参与流水
    * @param ruleVO 规则的内容
    * @param serialUnitString 流水依据
    * @param maxSerialValueMap 最大的流水号
    * @param thisSecValueList 本次的码值
    * @param lastMaxSerialValueMap 封装后
    * @param firstData 是否为第一条数据
    */
   private void switchSerialSecValue(BaseModel cbo, List<CodeBasicSecVO> serialSecVOList,boolean attrSevIsSerialDepend,
                             CodeRuleVO ruleVO,String serialUnitString,
                             Map<String/**码段的主键**/,Map<String/**流水依据**/,CodeSerialValue>> maxSerialValueMap,List<String> thisSecValueList,
                             Map<String/**码段的主键**/,Map<String/**流水依据**/, String>> lastMaxSerialValueMap,boolean firstData){
      if (!CollectionUtils.isEmpty(serialSecVOList)) {
         Map<String,String> secIdserialValueMap=new LinkedHashMap<>();
         for (int j = 0; j < serialSecVOList.size(); j++) {
            CodeBasicSecVO secVO = serialSecVOList.get(j);
            String secVOValue="";
            AtomicReference<String> newSerialUnitString= new AtomicReference<>(serialUnitString);
            if(j==0){
               secVOValue="";
               newSerialUnitString.set(serialUnitString.replace("${" + secVO.getOid() + "}", secVOValue));
            }else{
               CodeBasicSecVO upSecVO =serialSecVOList.get(j-1);
               secIdserialValueMap.forEach((key,vaule)->{
                  newSerialUnitString.set(serialUnitString.replace("${"+key+"}", vaule));
               });
            }
    /**
     * 封装存储码值的对象
     * @param classifyFullInfoBO 分类全部的信息
     * @param ruleVO 规则的内容
     * @param cbo 业务数据
     * @param templateVO 模板的信息
     * @param allCodeDOList 所有的码值的对象列表
     */
    private void wrapperAllCode(CodeClassifyFullInfoBO classifyFullInfoBO,CodeRuleVO ruleVO,
                                ClientBusinessObject cbo,CodeClassifyTemplateVO templateVO,
                                List<CodeAllCodeDO> allCodeDOList,String serialUnitString,String serialValueString){
        CodeAllCodeDO allCodeDO = new CodeAllCodeDO();
        allCodeDO.setCodeClassifyOid(classifyFullInfoBO.getCurrentClassifyVO().getOid());
        allCodeDO.setCodeRuleOid(ruleVO.getOid());
        allCodeDO.setId(cbo.getId());
        allCodeDO.setCodeClassifyTemplateOid(templateVO.getOid());
        allCodeDO.setCreateCodeBtm(cbo.getBtmName());
        allCodeDO.setCreateCodeOid(cbo.getOid());
        allCodeDO.setSerialUnit(serialUnitString);
        allCodeDO.setUnFillSerial(serialValueString);
        allCodeDO.setLcStatus(cbo.getLcStatus());
        allCodeDOList.add(allCodeDO);
    }
            if (attrSevIsSerialDepend || firstData) {
               //如果属性码段也是依赖,则每次都要查询,如果属性码段不是依赖,则只查询一次
//               Map<String, String> conditionMap = new HashMap<>();
//               conditionMap.put("codeRuleOid", ruleVO.getOid());
//               conditionMap.put("serialUnit", serialUnitString);
//               //这个字段是为了解决多个流水的问题
//               conditionMap.put("codeSecOid", secVO.getOid());
               QueryWrapper<CodeSerialValue> codeSerialWrapper = new QueryWrapper<>();
    /**
     * 保存流水的信息
     * @param batchCBO 数据存储容器
     * @param ruleVO 规则的显示对象
     * @param lastMaxSerialValueMap 最大的流水值映射
     * @param maxSerialValueMap 依据存储的最大流水的内容
     */
    private void saveSerialValue(BatchCBO batchCBO,CodeRuleVO ruleVO,
                                 Map<String/**码段的主键**/,Map<String, Double>> lastMaxSerialValueMap,
                                 Map<String/**码段的主键**/,Map<String, CodeSerialValueDO>> maxSerialValueMap){
        List<CodeSerialValueDO> editSerialValueDOList = new ArrayList<>();
        List<CodeSerialValueDO> addSerialValueDOList = new ArrayList<>();
        //存储最大流水号
        lastMaxSerialValueMap.forEach((secOid,maxSerialMap)->{
            maxSerialMap.forEach((unit,maxSerial)->{
                CodeSerialValueDO serialValueDO = null;
                if(maxSerialValueMap.containsKey(secOid) && maxSerialValueMap.get(secOid).containsKey(unit)){
                    //说明有
                    serialValueDO = maxSerialValueMap.get(secOid).get(unit);
                    serialValueDO.setMaxSerial(maxSerial.toString());
                    editSerialValueDOList.add(serialValueDO);
                }else{
                    serialValueDO = new CodeSerialValueDO();
                    serialValueDO.setCodeRuleOid(ruleVO.getOid());
                    serialValueDO.setSerialUnit(unit);
                    serialValueDO.setCodeSecOid(secOid);
                    serialValueDO.setMaxSerial(maxSerial.toString());
                    addSerialValueDOList.add(serialValueDO);
                }
            });
        });
        if(!CollectionUtils.isEmpty(editSerialValueDOList)){
            batchCBO.copyFromOther(serialValueMapper.batchUpdate(editSerialValueDOList));
        }
        if(!CollectionUtils.isEmpty(addSerialValueDOList)){
            batchCBO.copyFromOther(serialValueMapper.batchInsert(addSerialValueDOList));
        }
    }
               codeSerialWrapper.eq("codeRuleOid", ruleVO.getOid());
               codeSerialWrapper.eq("serialUnit", newSerialUnitString.get());
               codeSerialWrapper.eq("codeSecOid", secVO.getOid());
               List<CodeSerialValue> serialValueDOS = serialValueMapper.selectList(codeSerialWrapper);
               if (!CollectionUtils.isEmpty(serialValueDOS)) {
                  Map<String, CodeSerialValue> unitSerialMap = maxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>());
                  CodeSerialValue serialValueDO = serialValueDOS.get(0);
                  unitSerialMap.put(serialValueDO.getSerialUnit(),serialValueDO);
                  maxSerialValueMap.put(secVO.getOid(), unitSerialMap);
               }
            }
            String serialString="";
            String thisSerialValue = "";
            String startValue = null;
            if (maxSerialValueMap.containsKey(secVO.getOid()) && maxSerialValueMap.get(secVO.getOid()).containsKey(newSerialUnitString.get())) {
               startValue = maxSerialValueMap.get(secVO.getOid()).get(newSerialUnitString.get()).getMaxSerial();
            }
            if (lastMaxSerialValueMap.containsKey(secVO.getOid()) && lastMaxSerialValueMap.get(secVO.getOid()).containsKey(newSerialUnitString.get())) {
               //说明多个申请,之前已经加了流水号了
               startValue = lastMaxSerialValueMap.get(secVO.getOid()).get(newSerialUnitString.get());
            }
            if(StringUtils.isNotBlank(secVO.getCustomCodeSerialClass())){//自定义流水处理
               String currentFlowValue=startValue;
               CodeCustomSerialDTO codeCustomSerialDTO=new CodeCustomSerialDTO();
               codeCustomSerialDTO.setSerialUnitString(newSerialUnitString.get());
               codeCustomSerialDTO.setSerialCodeCodeBasicSec(secVO);
               codeCustomSerialDTO.setCurrentFlowValue(startValue);
               codeCustomSerialDTO.setCodeBasicSecVOList(ruleVO.getSecVOList());
               codeCustomSerialDTO.setCodeRuleOid(ruleVO.getOid());
               codeCustomSerialDTO.setBaseModel(cbo);
               codeCustomSerialDTO.setSerialUnitString(newSerialUnitString.get());
               codeCustomSerialDTO.setSecValueList(thisSecValueList);
               thisSerialValue=customCodeSerial(secVO.getCustomCodeSerialClass(),codeCustomSerialDTO);
               newSerialUnitString.set(codeCustomSerialDTO.getSerialUnitString());
               log.info(secVO.getCustomCodeSerialClassText()+"---->"+thisSerialValue);
            }else {
               Double newThisSerialValue = 0d;
               if (startValue == null) {
                  //第一个编码
                  newThisSerialValue = VciBaseUtil.getDouble(secVO.getSerialStart());
               } else {
                  //流水号肯定是数字
                  newThisSerialValue = Double.parseDouble(startValue) + (j + 1) * secVO.getSerialStep();
               }
               //要看是否超过最大的流水值
               if (newThisSerialValue >= secVO.getCodeFillLimit()) {
                  throw new VciBaseException("流水号已经超过允许的最大流水值{0}", new String[]{secVO.getCodeFillLimit().toString()});
               }
               thisSerialValue=String.valueOf(newThisSerialValue.intValue());
            }
            //要看补位的内容
            Integer fillLength = VciBaseUtil.getInt(secVO.getCodeFillLength());
            if (fillLength == 0 || fillLength > VciBaseUtil.getInt(secVO.getCodeSecLength())) {
               //防止在添加的地方没有控制正确
               fillLength = VciBaseUtil.getInt(secVO.getCodeSecLength());
            }
            serialString = thisSerialValue;
            serialString = fillString(fillLength, OsCodeFillTypeEnum.forValue(secVO.getCodeFillType()), serialString, secVO.getCodeFillSeparator());
            for (int z = 0; z < thisSecValueList.size(); z++) {
               String secValue = thisSecValueList.get(z);
               if (secValue.equalsIgnoreCase("${" + secVO.getOid() + "}")) {
                  // TODO: 流水生成码值后拼接前后缀
                  thisSecValueList.set(z, joinPreffixAndSuffix(secVO, serialString));
               }
            }
            secIdserialValueMap.put(secVO.getOid(),thisSerialValue);//记录流水码段当前的值
            Map<String, String> unitSerialMap = lastMaxSerialValueMap.getOrDefault(secVO.getOid(), new HashMap<>());
            unitSerialMap.put(newSerialUnitString.get(), String.valueOf(thisSerialValue));
            lastMaxSerialValueMap.put(secVO.getOid(),unitSerialMap);
         }
      }
   }
   private String customCodeSerial(String beanName, CodeCustomSerialDTO codeCustomSerialDTO){
      AtomicReference<String> result = new AtomicReference<>("");
      //BusAnnotationUtil.callForAnnotation(FlowNotifyWeb.class, FlowNotifyBefore.class,noticeInfo);
      //在登录之前,看看是否有插件
      Map<String, Object> beanMap = ApplicationContextProvider.getApplicationContext().getBeansWithAnnotation(MdmSerialAlgorithm.class);
      if (!CollectionUtils.isEmpty(beanMap)) {
         if(beanMap.containsKey(beanName)){
            Object v=beanMap.get(beanName);
            Method[] methods = v.getClass().getDeclaredMethods();
            if (methods != null && methods.length > 0) {
               for (Method method : methods) {
                  if (method.isAnnotationPresent(MdmSerialAlgorithmMethod.class)) {
                     try {
                        Object  o=   method.invoke(v, codeCustomSerialDTO);
                        result.set(Func.isEmpty(o) ?"":o.toString());
                     } catch (Throwable e) {
                        if (log.isErrorEnabled()) {
                           log.error("调用插件出错", e);
                        }
                        throw new VciBaseException("调用插件出错,{0},{1}", new String[]{v.getClass().getName(), method.getName()}, e);
                     }
                  }
               }
            }
         }
      }
      /*
      String result = "";
      try {
         Class classInstance=Class.forName(className);
         Object obj =classInstance.newInstance();
         Method method= classInstance.getMethod("serialGenerate",CodeCustomSerialDTO.class);
         method.setAccessible(Boolean.TRUE);
         //method.invoke(obj);
         Object  o= method.invoke(obj,codeCustomSerialDTO);
         result= Func.isEmpty(o) ?"":o.toString();
      } catch (ClassNotFoundException e) {
         throw new VciBaseException("未找到自定义流水算法类文件");
      } catch (InvocationTargetException e) {
         throw new VciBaseException("执行自定义流水算法处理方法出现异常");
      } catch (NoSuchMethodException e) {
         throw new VciBaseException("未找到自定义流水算法处理方法");
      } catch (IllegalAccessException e) {
         throw new VciBaseException("执行自定义流水算法处理方法出现异常");
      } catch (InstantiationException e) {
         e.printStackTrace();
      }*/
      return result.get();
   }
   /**
    * 转换码值的内容
    * @param secVO 码段的内容
    * @param secValueMap 码值的内容,key是码段的主键,value是码值
    * @param classifyFullInfoBO 分类的全部信息
    * @param serialSecVOList 流水码段
    * @param attrSecVOList 属性码段
    * @param serialUnitList 流水依据
    * @param secValueList 码值列表
    */
   private void switchSecValue(CodeBasicSecVO secVO,Map<String,String> secValueMap,
                        CodeClassifyFullInfoBO classifyFullInfoBO,List<CodeBasicSecVO> serialSecVOList,
                        List<CodeBasicSecVO> attrSecVOList, List<String> serialUnitList,
                        List<String> secValueList ){
      CodeSecTypeEnum secType = CodeSecTypeEnum.forValue(secVO.getSecType());
      String secValue = secValueMap.getOrDefault(secVO.getOid(), "");
      switch (secType) {
         case CODE_FIXED_SEC:
            secValue = joinPreffixAndSuffix(secVO, secValue);
            //固定码段的,直接用码值,不论码值的长度是多少,因为可变长度和固定长度是控制在码段管理里面的码值定义的
            break;
         case CODE_DATE_SEC:
            //时间码段,需要将当前时间依据时间格式进行转换.
            //时间码段不涉及到是否补位
            secValue =joinPreffixAndSuffix(secVO, VciDateUtil.date2Str(new Date(), secVO.getCodeDateFormatStr()));
            break;
         case CODE_CLASSIFY_SEC:
            //分类码段的,也是从前端选择了码值即可,不论码值的长度是多少
            CodeClassifyValue codeClassifyValueDO= codeClassifyValueMapper.selectById(secValue);
            if(codeClassifyValueDO!=null) {
               secValue = joinPreffixAndSuffix(secVO, codeClassifyValueDO.getId());
            }
            break;
         case CODE_LEVEL_SEC:
            //层级码段,需要从分类上获取相应的信息
            if (CodeLevelTypeEnum.MIN.getValue().equalsIgnoreCase(secVO.getCodeLevelType())) {
               //最小层,因为我们只能在叶子节点上申请编码,所以这个就是当前分类的
               if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType()) || CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                  //就是当前分类的
                  secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
               } else {
                  //我们需要从顶层开始找到当前分类为止
                  secValue = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
               }
            } else {
               //指定层,我们需要通过上级的来获取
               if (CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                  //说明当前已经是最高的了
                  secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
               } else {
                  //这个我们需要看看,层级是不是大于了最大层级的数
                  List<CodeClassifyVO> parentClassifyVOList = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).collect(Collectors.toList());
                  if (secVO.getCodeLevelValue() > (parentClassifyVOList.size() + 1)) {
                     //指定的层级比当前的层级还大了,所以只能获取当前层级了
                     if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType())) {
                        secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                     } else {
                        secValue = parentClassifyVOList.stream().map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
                     }
                  } else {
                     //我们获取其中指定层的内容
                     if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType())) {
                        CodeClassifyVO classifyVO = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() == secVO.getCodeLevelValue().intValue()).findFirst().orElseGet(() -> null);
                        if (classifyVO != null) {
                           secValue = classifyVO.getId();
                        }
                     } else {
                        //小于等于的全部拿出来
                        secValue = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() <= secVO.getCodeLevelValue().intValue()).sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining());
                     }
                  }
               }
            }
            //看看长度是否需要截断
            if (!CodeCutTypeEnum.NONE.getValue().equalsIgnoreCase(secVO.getValueCutType()) &&
               secVO.getValueCutLength() != null && secVO.getValueCutLength() > 0 && secValue.length() > secVO.getValueCutLength()) {
               if (CodeCutTypeEnum.RIGHT.getValue().equalsIgnoreCase(secVO.getValueCutType())) {
                  //左截取是从左边剪掉,右截取是从右边剪掉--保留左边
                  secValue = secValue.substring(0, secVO.getValueCutLength());
               } else {
                  secValue = secValue.substring(secValue.length() - secVO.getValueCutLength());
               }
            }
            secValue = joinPreffixAndSuffix(secVO,secValue);
            break;
         case CODE_REFER_SEC:
            //引用的在页面上已经选择了,所以直接使用前端上传递的值
            //引用就是参照,可能是其他的分类(业务类型)下的数据,所以只在页面上选择
            secValue = joinPreffixAndSuffix(secVO,secValue);
            break;
         case CODE_ATTR_SEC:
            //属性与引用的区别是,属性是当前数据里的属性,而引用可能是引用其他的分类的(业务类型)
            //因为可能是批量的数据的操作,所以我们这里不能直接处理属性,需要后边一边处理
            secValue = "${attr_" + secVO.getOid() + "}";
            attrSecVOList.add(secVO);
            break;
         case CODE_VARIABLE_SEC:
            //可变码段,是在页面上输入内容
            if (secValue.length() > VciBaseUtil.getInt(secVO.getCodeSecLength())) {
               throw new ServiceException(String.format("【{%s}】这个码段是可变码段,但是现在输入的码值的长度({%s})超过了规定的长度{%s}", secVO.getName(), secValue.length(), secVO.getCodeSecLength()));
            }
            OsCodeFillTypeEnum fillTypeEnum = OsCodeFillTypeEnum.forValue(secVO.getCodeFillType());
            secValue = fillString(VciBaseUtil.getInt(secVO.getCodeSecLength()), fillTypeEnum, secValue, secVO.getCodeFillSeparator());
            secValue = joinPreffixAndSuffix(secVO,secValue);
            break;
         case CODE_SERIAL_SEC:
            //流水码段
            serialSecVOList.add(secVO);
            secValue = "${" + secVO.getOid() + "}";
         default:
            break;
      }
      if (VciBaseUtil.getBoolean(secVO.getSerialDependFlag())) {
         serialUnitList.add(secValue);
      }
      secValueList.add(secValue);
   }
   /**
    * 拼接前后缀
    * @param secVO 码段
    * @param secValue 码值
    * @return
    */
   public String joinPreffixAndSuffix(CodeBasicSecVO secVO, String secValue){
      StringBuilder joinSecValue = new StringBuilder();
      // 拼接前缀
      if (Func.isNotEmpty(secVO.getPrefixCode()) && Func.isNotEmpty(secValue)) {
         joinSecValue = joinSecValue.append(secVO.getPrefixCode());
      }
      // 在中间拼接值
      joinSecValue.append(secValue);
      // 拼接后缀
      if(Func.isNotEmpty(secVO.getSuffixCode()) && Func.isNotEmpty(secValue)){
         joinSecValue = joinSecValue.append(secVO.getSuffixCode());
      }
      return joinSecValue.toString();
   }
   /**
    * 补位
    * @param totalLength 总长度
    * @param fillTypeEnum 补位方式
    * @param text 当前的内容
    * @param fillChar 补位的字符
    * @return 不填充位置和长度已经达到/超过的时候不会填充
    */
   private String fillString(int totalLength,OsCodeFillTypeEnum fillTypeEnum,String text,String fillChar){
      if(text.length() >= totalLength || OsCodeFillTypeEnum.NONE.equals(fillTypeEnum)){
         //不用补位了
         return  text;
      }
      int balance = totalLength - text.length();
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < balance; i++) {
         sb.append(fillChar);
      }
      if(OsCodeFillTypeEnum.LEFT.equals(fillTypeEnum)) {
         text = sb.toString() + text;
      }else {
         text = text + sb.toString();
      }
      return  text;
   }
   /**
    * 封装存储码值的对象
    * @param classifyFullInfoBO 分类全部的信息
    * @param ruleVO 规则的内容
    * @param cbo 业务数据
    * @param templateVO 模板的信息
    * @param allCodeDOList 所有的码值的对象列表
    * @param codeDelimiter 码值分割符
    */
   private void wrapperAllCode(CodeClassifyFullInfoBO classifyFullInfoBO, CodeRuleVO ruleVO,
                                BaseModel cbo, CodeClassifyTemplateVO templateVO,
                                List<CodeAllCode> allCodeDOList, String serialUnitString, String serialValueString,String codeDelimiter){
      CodeAllCode allCodeDO = new CodeAllCode();
      DefaultAttrAssimtUtil.addDefaultAttrAssimt(allCodeDO, MdmBtmTypeConstant.CODE_ALL_CODE);
      allCodeDO.setCodeClassifyOid(classifyFullInfoBO.getCurrentClassifyVO().getOid());
      allCodeDO.setCodeRuleOid(ruleVO.getOid());
      allCodeDO.setId(cbo.getId());
      allCodeDO.setCodeClassifyTemplateOid(templateVO.getOid());
      allCodeDO.setCreateCodeBtm(cbo.getBtmname());
      allCodeDO.setCreateCodeOid(cbo.getOid());
      allCodeDO.setSerialUnit(serialUnitString);
      allCodeDO.setUnFillSerial(serialValueString);
      allCodeDO.setLcStatus(cbo.getLcStatus());
      allCodeDO.setCodeDelimit(codeDelimiter);
      allCodeDOList.add(allCodeDO);
   }
   /**
    * 保存流水的信息
    * @param ruleVO 规则的显示对象
    * @param lastMaxSerialValueMap 最大的流水值映射
    * @param maxSerialValueMap 依据存储的最大流水的内容
    */
   private void saveSerialValue(CodeRuleVO ruleVO,
                         Map<String/**码段的主键**/,Map<String, String>> lastMaxSerialValueMap,
                         Map<String/**码段的主键**/,Map<String, CodeSerialValue>> maxSerialValueMap){
      List<CodeSerialValue> editSerialValueDOList = new ArrayList<>();
      List<CodeSerialValue> addSerialValueDOList = new ArrayList<>();
      //存储最大流水号
      lastMaxSerialValueMap.forEach((secOid,maxSerialMap)->{
         maxSerialMap.forEach((unit,maxSerial)->{
            CodeSerialValue serialValueDO = null;
            if(maxSerialValueMap.containsKey(secOid) && maxSerialValueMap.get(secOid).containsKey(unit)){
               //说明有
               serialValueDO = maxSerialValueMap.get(secOid).get(unit);
               serialValueDO.setMaxSerial(maxSerial.toString());
               DefaultAttrAssimtUtil.updateDefaultAttrAssimt(serialValueDO);
               editSerialValueDOList.add(serialValueDO);
            }else{
               serialValueDO = new CodeSerialValue();
               DefaultAttrAssimtUtil.addDefaultAttrAssimt(serialValueDO, MdmBtmTypeConstant.CODE_SERIAL_VALUE);
               serialValueDO.setCodeRuleOid(ruleVO.getOid());
               serialValueDO.setSerialUnit(unit);
               serialValueDO.setCodeSecOid(secOid);
               serialValueDO.setMaxSerial(maxSerial.toString());
               addSerialValueDOList.add(serialValueDO);
            }
         });
      });
      if(!CollectionUtils.isEmpty(editSerialValueDOList)){
//         batchCBO.copyFromOther(serialValueMapper.batchUpdate(editSerialValueDOList));
         for (CodeSerialValue codeSerialValue : editSerialValueDOList) {
            serialValueMapper.updateById(codeSerialValue);
         }
      }
      if(!CollectionUtils.isEmpty(addSerialValueDOList)){
         for (CodeSerialValue codeSerialValue : addSerialValueDOList) {
            serialValueMapper.insert(codeSerialValue);
         }
//         batchCBO.copyFromOther(serialValueMapper.batchInsert(addSerialValueDOList));
      }
   }
   /**
    * 去掉不是数字的字符
    * @param s 字符
    * @return 替换后的值
    */
   private String killUnNumberChar(String s){
      Integer lastUnNumberIndex = 0;
      for (int i = 0; i < s.length(); i++) {
         char c = s.charAt(i);
         if(!(new String(new char[]{c})).matches(RegExpConstant.NUMBER)){
            lastUnNumberIndex = i;
         }
      }
      String value = s;
      if(lastUnNumberIndex >0){
         value = value.substring(lastUnNumberIndex);
      }
      return value;
   }
   /**
    * 去掉前后缀
    * @param secValue 字符
    * @param priffix 前缀
    * @param suffix 后缀
    * @return 替换后的值
    */
   private String killPriffixSuffix(String secValue, String priffix,String suffix){
      if (priffix != null && secValue.startsWith(priffix)) {
         secValue = secValue.substring(priffix.length());
      }
      if (suffix != null && secValue.endsWith(suffix)) {
         secValue = secValue.substring(0, secValue.length() - suffix.length());
      }
      return secValue;
   }
   /**
    * 去除补位字符
    * @param s 字符
    * @param fillString 补位字符
    * @param left 是否左补位
    * @return 替换后的值
    */
   private String killFillChar(String s, String fillString,boolean left){
      Integer index = 0;
      String value = s;
      if(left){
         for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if(!(new String(new char[]{c})).equalsIgnoreCase(fillString)){
               break;
            }
            index = i;
         }
         if(index >0){
            value = value.substring(index);
         }
      }else{
         //从右往左找
         for (int i = s.length()-1; i >=0; i++) {
            char c = s.charAt(i);
            if(!(new String(new char[]{c})).equalsIgnoreCase(fillString)){
               break;
            }
            index = i;
         }
         if(index >0){
            value = value.substring(0,index);
         }
      }
      return value;
   }
   /**
    * 回收码值
    *
    * @param btmId                 业务数据的业务类型
    * @param businessOidCollection 业务数据的主键
    * @return 是否更新成功
    */
   @Override
   public Boolean recycleCode(String btmId, Collection<String> businessOidCollection) {
//      boolean oldPersistence =  WebUtil.isPersistence();
//      WebUtil.setPersistence(false);
//      BatchCBO batchCBO = new BatchCBO();
      AtomicReference<Boolean> updateFlag = new AtomicReference<>(false);
      VciBaseUtil.switchCollectionForOracleIn(businessOidCollection).stream().forEach(oids-> {
//         Map<String, String> conditionMap = new HashMap<>();
//         //编码要记录为回收的状态
//         conditionMap.put("createcodeoid", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(oids.toArray(new String[0])) + ")");
//         conditionMap.put("createcodebtm", btmId);
         QueryWrapper<CodeAllCode> wrapper = new QueryWrapper<>();
         wrapper.in("createcodeoid",QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(oids.toArray(new String[0])) + ")");
         wrapper.eq("createcodebtm", btmId);
         List<CodeAllCode> allCodeDOS = codeAllCodeService.selectByWrapper(wrapper);
//         allCodeMapper.selectByCondition(conditionMap, new PageHelper(-1));
         if (!CollectionUtils.isEmpty(allCodeDOS)) {
            allCodeDOS.stream().forEach(codeDO->{
               codeDO.setLcStatus(CodeAllCodeLC.TASK_BACK.getValue());
            });
            updateFlag.set(codeAllCodeService.updateBatchById(allCodeDOS));
//            batchCBO.copyFromOther(allCodeMapper.batchUpdate(allCodeDOS));
         }
      });
//      WebUtil.setPersistence(oldPersistence);
      return updateFlag.get();
   }
   /***
    *
    * @param classifyFullInfoBO 分类的全部信息
    * @param templateVO 模板的显示对象
    * @param ruleVO 编码规则的显示对象
    * @param secDTOList 各个码段的值
    * @param dataCBOList 业务数据
    * @return
    * @throws Exception
    */
   @Override
   public List<String> productCodeAndSaveDataBZ(CodeClassifyFullInfoBO classifyFullInfoBO, CodeClassifyTemplateVO templateVO, CodeRuleVO ruleVO, List<CodeOrderSecDTO> secDTOList, List<BaseModel> dataCBOList) throws Exception {
      dataCBOList = dataCBOList.stream().sorted(((o1, o2) -> o1.getCreateTime().compareTo(o2.getCreateTime()))).collect(Collectors.toList());
      List<String> codeList = new ArrayList<>();
      final CodeRuleVO finalRuleVO = ruleVO;
      List<CodeBasicSecVO> secVOList = finalRuleVO.getSecVOList().stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).collect(Collectors.toList());
      List<String> serialUnitList = new LinkedList<>();
      List<String> secValueList = new ArrayList<>();
      Map<String, String> secValueMap = secDTOList.stream().collect(Collectors.toMap(s -> s.getSecOid(), s -> s.getSecValue()==null?"":s.getSecValue()));
      List<CodeBasicSecVO> serialSecVOList = new ArrayList<>();
      List<CodeBasicSecVO> attrSecVOList = new ArrayList<>();
      Map<String,String> secOdserialUnitMap=new HashMap<>();
      LinkedHashMap<String,String> newSecValueMap=new LinkedHashMap<>();
      for (int i = 0; i < secVOList.size(); i++) {
         CodeBasicSecVO secVO = secVOList.get(i);
         String secValue="";
         String secOid=secVO.getOid();
         if(secValueMap.containsKey(secOid)){
            secValue=secValueMap.get(secOid);
         }
         newSecValueMap.put(secOid,secValue);
         switchSecValueBZ(secVO, secValueMap, classifyFullInfoBO, serialSecVOList, attrSecVOList, serialUnitList, secValueList);
         //分段存储流水依赖
         if(secVO.getSecType().equals(CodeSecTypeEnum.CODE_SERIAL_SEC.getValue())){
            int finalI = i;
            final int[] index = {0};
            List<String> newSerialUnitList= serialUnitList.stream().filter(secValueStr -> {
               return index[0]++< finalI;//除去流水的
            }).collect(Collectors.toList());
            String serialUnitString = newSerialUnitList.size() == 0 ? EMPTY_SERIAL_UNIT : newSerialUnitList.stream().collect(Collectors.joining(SERIAL_UNIT_SPACE));
            secOdserialUnitMap.put(secVO.getOid(),serialUnitString);
         }
      }
      //处理属性码段和流水码段
      Map<String/**流水码段的主键**/, Map<String/**流水依据**/, String>> lastMaxSerialValueMap = new HashMap<>();
      List<CodeAllCode> allCodeDOList = new ArrayList<>();
      //已经存储的最大流水号的内容
      Map<String/**码段的主键**/, Map<String, CodeSerialValue>> maxSerialValueMap = new HashMap<>();
      for (int i = 0; i < dataCBOList.size(); i++) {
         BaseModel cbo = dataCBOList.get(i);
         cbo.getData().remove(CODE_SEC_LENGTH_FIELD);//将此key除去
         cbo.getData().remove(IMPORT_ROW_INDEX);//将此key除去
         cbo.getData().remove("codeclassifyid");//将此key除去
         List<String> thisSecValueList = new LinkedList<>();
         for (int j = 0; j < secValueList.size(); j++) {
            thisSecValueList.add(secValueList.get(j));
         }
         List<String> thisSerialUnitList = new LinkedList<>();
         //因为流水依据每次可能不一样,所以每次都拷贝一份
         for (int j = 0; j < serialUnitList.size(); j++) {
            thisSerialUnitList.add(serialUnitList.get(j));
         }
         //先看看有没有属性的码段
         boolean attrSevIsSerialDepend = CollectionUtils.isEmpty(attrSecVOList) ? false : (attrSecVOList.stream().anyMatch(s -> VciBaseUtil.getBoolean(s.getSerialDependFlag())));
         switchAttrSecValue(attrSecVOList, cbo, thisSecValueList, attrSevIsSerialDepend, thisSerialUnitList);
         switchSerialSecValueBZ(cbo,secDTOList,serialSecVOList, attrSevIsSerialDepend, finalRuleVO, secOdserialUnitMap, maxSerialValueMap, thisSecValueList, lastMaxSerialValueMap, i == 0);
         //组装编码的值
         cbo.setId(thisSecValueList.stream().collect(Collectors.joining()));
         codeList.add(cbo.getId());
         StringBuilder sb = new StringBuilder();
         //把码段里面都找一下流水号
         AtomicReference<String> serialUnitString= new AtomicReference<>("");
         for (int j = 0; j < serialSecVOList.size(); j++) {
            CodeBasicSecVO secVO = serialSecVOList.get(j);
            if(lastMaxSerialValueMap.containsKey(secVO.getOid())){//此为最后需要存入流水依赖的最大流水
               Map<String/**流水依据**/, String> serialValueMap = lastMaxSerialValueMap.get(secVO.getOid());
               serialValueMap.forEach((maxSerialUnitString,serialValue)->{
                  if(StringUtils.isNotBlank(serialValue)){
                     serialUnitString.set(maxSerialUnitString);
                     sb.append(serialValue).append(SERIAL_VALUE_SPACE);
                  }
               });
            }else{
               if(secValueMap.containsKey(secVO.getOid())) {//企业标准处理修订顺序号已经存在的数据则不需要动流水依赖表的数据
                  serialUnitString.set(secOdserialUnitMap.get(secVO.getOid()));
                  sb.append(secValueMap.get(secVO.getOid())).append(SERIAL_VALUE_SPACE);
               }
            }
         }
         String codeDelimiter=thisSecValueList.stream().collect(Collectors.joining(SERIAL_VALUE_SPACE));
         //要存储最后的全部allcode
         wrapperAllCode(classifyFullInfoBO, finalRuleVO, cbo, templateVO, allCodeDOList, serialUnitString.get(), sb.toString(),codeDelimiter);
      }
      //处理最大流水
      saveSerialValue( finalRuleVO, lastMaxSerialValueMap, maxSerialValueMap);
      allCodeDOList.stream().forEach(
         allCode -> {DefaultAttrAssimtUtil.addDefaultAttrAssimt(allCode,"codeallcode");allCode.setLctid("codeAllCodeLC");}
      );
      Map<String, String> statusMap = allCodeDOList.stream().collect(Collectors.toMap(s -> s.getOid(), s -> s.getLcStatus()));
      allCodeDOList.stream().filter(s -> StringUtils.equalsIgnoreCase("codeallcode",s.getBtmname())).forEach(s -> {
         s.setLcStatus(statusMap.get(s.getOid()));
      });
      //通过ID来进行去重
      List<CodeAllCode> distinctCodeAllCOdes = allCodeDOList.stream().collect(Collectors
         .collectingAndThen(
            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(CodeAllCode::getId))),
            ArrayList::new));
      if( distinctCodeAllCOdes.size() != allCodeDOList.size() ){
         throw new ServiceException("编码数据重复,无法保存,请注意!");
      }
      QueryWrapper<CodeAllCode> wrapper = new QueryWrapper<>();
      wrapper.eq("CREATECODEBTM",allCodeDOList.get(0).getCreateCodeBtm());
      wrapper.in("ID",allCodeDOList.stream().map(CodeAllCode::getId).collect(Collectors.toList()));
      List<CodeAllCode> codeAllCodes = codeAllCodeService.selectByWrapper(wrapper);
      List<CodeAllCode> takeBack = codeAllCodes.stream().filter(e -> e.getLcStatus().equals("TakeBack")).collect(Collectors.toList());
      if(codeAllCodes.size()>takeBack.size()){
         throw new ServiceException("生成编码数据ID已有历史记录,请确认如下生成的ID数据:"+ allCodeDOList.stream().map(CodeAllCode::getId).collect(Collectors.toList()));
      }
      for (CodeAllCode codeAllCode : takeBack) {
         codeAllCode.setTs(new Date());
         codeAllCode.setLastModifyTime(new Date());
         codeAllCode.setLastModifier(AuthUtil.getUserId().toString());
         Iterator<CodeAllCode> iterator = allCodeDOList.iterator();
         for (int i = 0; i < allCodeDOList.size(); i++) {
            if(codeAllCode.getId().equals(allCodeDOList.get(i).getId())){
               codeAllCode.setCreateCodeOid(allCodeDOList.get(i).getCreateCodeOid());
               codeAllCode.setLcStatus(allCodeDOList.get(i).getLcStatus());
               allCodeDOList.remove(i);
            }
         }
         /*while (iterator.hasNext()){
            CodeAllCode next = iterator.next();
            if(codeAllCode.getId().equals(next.getId())){
               codeAllCode.setCreateCodeOid(next.getCreateCodeOid());
               codeAllCode.setLcStatus(next.getLcStatus());
               //iterator.remove();
            }
         }*/
      }
      if(takeBack.size()>0){
         codeAllCodeService.updateBatchById(takeBack);
      }
      codeAllCodeService.saveBatch(allCodeDOList);
      mdmEngineService.insertBatchByType(dataCBOList.get(0).getBtmname(),dataCBOList);
      return codeList;
   }
   /**
    * 转换码值的内容
    * @param secVO 码段的内容
    * @param secValueMap 码值的内容,key是码段的主键,value是码值
    * @param classifyFullInfoBO 分类的全部信息
    * @param serialSecVOList 流水码段
    * @param attrSecVOList 属性码段
    * @param serialUnitList 流水依据
    * @param secValueList 码值列表
    */
   private void switchSecValueBZ(CodeBasicSecVO secVO,Map<String,String> secValueMap,
                        CodeClassifyFullInfoBO classifyFullInfoBO,List<CodeBasicSecVO> serialSecVOList,
                        List<CodeBasicSecVO> attrSecVOList, List<String> serialUnitList,
                        List<String> secValueList ){
      CodeSecTypeEnum secType = CodeSecTypeEnum.forValue(secVO.getSecType());
      String secValue = secValueMap.getOrDefault(secVO.getOid(), "");
      switch (secType) {
         case CODE_FIXED_SEC:
            secValue = joinPreffixAndSuffix(secVO, secValue);
            //固定码段的,直接用码值,不论码值的长度是多少,因为可变长度和固定长度是控制在码段管理里面的码值定义的
            break;
         case CODE_DATE_SEC:
            //时间码段,需要将当前时间依据时间格式进行转换.
            //时间码段不涉及到是否补位
            secValue =joinPreffixAndSuffix(secVO, VciDateUtil.date2Str(new Date(), secVO.getCodeDateFormatStr()));
            break;
         case CODE_CLASSIFY_SEC:
            //分类码段的,也是从前端选择了码值即可,不论码值的长度是多少
            CodeClassifyValue codeClassifyValueDO= codeClassifyValueMapper.selectById(secValue);
            if(codeClassifyValueDO!=null) {
               secValue = joinPreffixAndSuffix(secVO, codeClassifyValueDO.getId());
            }
            break;
         case CODE_LEVEL_SEC:
            //层级码段,需要从分类上获取相应的信息
            if (CodeLevelTypeEnum.MIN.getValue().equalsIgnoreCase(secVO.getCodeLevelType())) {
               //最小层,因为我们只能在叶子节点上申请编码,所以这个就是当前分类的
               if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType()) || CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                  //就是当前分类的
                  secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
               } else {
                  //我们需要从顶层开始找到当前分类为止
                  secValue = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
               }
            } else {
               //指定层,我们需要通过上级的来获取
               if (CollectionUtils.isEmpty(classifyFullInfoBO.getParentClassifyVOs())) {
                  //说明当前已经是最高的了
                  secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
               } else {
                  //这个我们需要看看,层级是不是大于了最大层级的数
                  List<CodeClassifyVO> parentClassifyVOList = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).collect(Collectors.toList());
                  if (secVO.getCodeLevelValue() > (parentClassifyVOList.size() + 1)) {
                     //指定的层级比当前的层级还大了,所以只能获取当前层级了
                     if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType())) {
                        secValue = classifyFullInfoBO.getCurrentClassifyVO().getId();
                     } else {
                        secValue = parentClassifyVOList.stream().map(CodeClassifyVO::getId).collect(Collectors.joining()) + classifyFullInfoBO.getCurrentClassifyVO().getId();
                     }
                  } else {
                     //我们获取其中指定层的内容
                     if (CodeGetValueTypeEnum.CURRENT.getValue().equalsIgnoreCase(secVO.getCodeGetValueType())) {
                        CodeClassifyVO classifyVO = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() == secVO.getCodeLevelValue().intValue()).findFirst().orElseGet(() -> null);
                        if (classifyVO != null) {
                           secValue = classifyVO.getId();
                        }
                     } else {
                        //小于等于的全部拿出来
                        secValue = parentClassifyVOList.stream().filter(s -> s.getDataLevel().intValue() <= secVO.getCodeLevelValue().intValue()).sorted(((o1, o2) -> -o1.getDataLevel().compareTo(o2.getDataLevel()))).map(CodeClassifyVO::getId).collect(Collectors.joining());
                     }
                  }
               }
            }
            //看看长度是否需要截断
            if (!CodeCutTypeEnum.NONE.getValue().equalsIgnoreCase(secVO.getValueCutType()) &&
               secVO.getValueCutLength() != null && secVO.getValueCutLength() > 0 && secValue.length() > secVO.getValueCutLength()) {
               if (CodeCutTypeEnum.RIGHT.getValue().equalsIgnoreCase(secVO.getValueCutType())) {
                  //左截取是从左边剪掉,右截取是从右边剪掉--保留左边
                  secValue = secValue.substring(0, secVO.getValueCutLength());
               } else {
                  secValue = secValue.substring(secValue.length() - secVO.getValueCutLength());
               }
            }
            secValue = joinPreffixAndSuffix(secVO,secValue);
            break;
         case CODE_REFER_SEC:
            //引用的在页面上已经选择了,所以直接使用前端上传递的值
            //引用就是参照,可能是其他的分类(业务类型)下的数据,所以只在页面上选择
            secValue = joinPreffixAndSuffix(secVO,secValue);
            break;
         case CODE_ATTR_SEC:
            //属性与引用的区别是,属性是当前数据里的属性,而引用可能是引用其他的分类的(业务类型)
            //因为可能是批量的数据的操作,所以我们这里不能直接处理属性,需要后边一边处理
            secValue = "${attr_" + secVO.getOid() + "}";
            attrSecVOList.add(secVO);
            break;
         case CODE_VARIABLE_SEC:
            //可变码段,是在页面上输入内容
            if (secValue.length() > VciBaseUtil.getInt(secVO.getCodeSecLength())) {
               throw new VciBaseException("【{0}】这个码段是可变码段,但是现在输入的码值的长度({1})超过了规定的长度{2}", new String[]{secVO.getName(), String.valueOf(secValue.length()), secVO.getCodeSecLength()});
            }
            OsCodeFillTypeEnum fillTypeEnum = OsCodeFillTypeEnum.forValue(secVO.getCodeFillType());
            secValue = fillString(VciBaseUtil.getInt(secVO.getCodeSecLength()), fillTypeEnum, secValue, secVO.getCodeFillSeparator());
            secValue = joinPreffixAndSuffix(secVO,secValue);
            break;
         case CODE_SERIAL_SEC:
            //流水码段
            serialSecVOList.add(secVO);
            if(secValueMap.containsKey(secVO.getOid())){
               secValue=secValueMap.get(secVO.getOid());
            }else{
               secValue = "${" + secVO.getOid() + "}";
            }
         default:
            break;
      }
      if (VciBaseUtil.getBoolean(secVO.getSerialDependFlag())) {
         serialUnitList.add(secValue);
      }
      secValueList.add(secValue);
   }
   /**
    * 使用CBO处理组合规则的内容
    * @param cbo 数据的内容
    * @param rule 规则的内容
    * @return 转换后的
    */
   private String getValueByFormulaForCBO(BaseModel cbo,String rule)  {
      Map<String, Object> dataMap = null;
      try{
         dataMap = VciBaseUtil.convertBean2Map(cbo,null);
      }catch(Exception e){
         throw new VciBaseException("mapToBeanError:"+e);
      }
      Map<String, String> map = new HashMap<String, String>();
      for (String i : dataMap.keySet()) {
         map.put(i, String.valueOf(dataMap.get(i)).trim());
      }
//      WebUtil.copyValueToMapFromCbos(cbo,dataMap);
      return formulaService.getValueByFormula(map,rule);
   }
}