ludc
2024-01-05 b2302526b15194a7d9efb09ad10e632e3cff7443
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/CodeRuleServiceImpl.java
@@ -1,685 +1,760 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.vci.ubcs.code.service.impl;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.vci.ubcs.code.constant.FrameWorkDefaultValueConstant;
import com.vci.ubcs.code.constant.MdmBtmTypeConstant;
import com.vci.ubcs.code.dao.CodeBasicSecDaoI;
import com.vci.ubcs.code.dao.CodeRuleDaoI;
import com.vci.ubcs.code.lifecycle.CodeRuleLC;
import com.vci.ubcs.code.model.CodeAllCodeDO;
import com.vci.ubcs.code.model.CodeBasicSecDO;
import com.vci.ubcs.code.model.CodeClassifyDO;
import com.vci.ubcs.code.model.CodeRuleDO;
import com.vci.ubcs.code.service.CodeBasicSecServiceI;
import com.vci.ubcs.code.service.CodeClassifyServiceI;
import com.vci.ubcs.code.service.CodeRuleServiceI;
import com.vci.corba.common.VCIError;
import com.vci.starter.revision.service.RevisionModelUtil;
import com.vci.starter.web.exception.VciBaseException;
import com.vci.starter.web.pagemodel.BaseResult;
import com.vci.starter.web.pagemodel.DataGrid;
import com.vci.starter.web.pagemodel.KeyValue;
import com.vci.starter.web.pagemodel.PageHelper;
import com.vci.starter.web.util.BeanUtilForVCI;
import com.vci.starter.web.util.VciBaseUtil;
import com.vci.starter.web.wrapper.VciQueryWrapperForDO;
import com.vci.web.pageModel.BatchCBO;
import com.vci.web.service.WebBoServiceI;
import com.vci.web.util.WebUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vci.ubcs.code.dto.CodeBasicSecDTO;
import com.vci.ubcs.code.dto.CodeRuleDTO;
import com.vci.ubcs.code.vo.pagemodel.CodeBasicSecVO;
import com.vci.ubcs.code.vo.pagemodel.CodeClassifyVO;
import com.vci.ubcs.code.vo.pagemodel.CodeRuleVO;
import org.springframework.beans.factory.annotation.Autowired;
import com.vci.ubcs.code.entity.*;
import com.vci.ubcs.code.enumpack.CodeSecTypeEnum;
import com.vci.ubcs.code.lifecycle.CodeRuleLC;
import com.vci.ubcs.code.mapper.CodeRuleMapper;
import com.vci.ubcs.code.mapper.CodeSerialValueMapper;
import com.vci.ubcs.code.mapper.CommonsMapper;
import com.vci.ubcs.code.service.*;
import com.vci.ubcs.code.vo.pagemodel.*;
import com.vci.ubcs.code.wrapper.CodeClassifyWrapper;
import com.vci.ubcs.code.wrapper.CodeRuleWrapper;
import com.vci.ubcs.omd.cache.EnumCache;
import com.vci.ubcs.omd.enums.EnumEnum;
import com.vci.ubcs.starter.exception.VciBaseException;
import com.vci.ubcs.starter.revision.model.TreeQueryObject;
import com.vci.ubcs.starter.revision.service.RevisionModelUtil;
import com.vci.ubcs.starter.util.DefaultAttrAssimtUtil;
import com.vci.ubcs.starter.util.MdmBtmTypeConstant;
import com.vci.ubcs.starter.util.UBCSCondition;
import com.vci.ubcs.starter.web.pagemodel.*;
import com.vci.ubcs.starter.web.util.BeanUtilForVCI;
import com.vci.ubcs.starter.web.util.VciBaseUtil;
import com.vci.ubcs.starter.web.util.WebUtil;
import com.vci.ubcs.system.cache.NacosConfigCache;
import com.vci.ubcs.system.entity.Strategy;
import com.vci.ubcs.system.feign.ISysClient;
import com.vci.ubcs.system.user.entity.User;
import com.vci.ubcs.system.user.feign.IUserClient;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.IResultCode;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.api.ResultCode;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Value;
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 plm.bs.bom.clientobject.ClientBusinessObjectOperation;
import javax.annotation.Resource;
import java.rmi.ServerException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.vci.frameworkcore.constant.FrameWorkBusLangCodeConstant.*;
import static com.vci.ubcs.code.constant.FrameWorkDefaultValueConstant.FRAMEWORK_RELEASE_EDITING;
import static com.vci.ubcs.code.constant.FrameWorkLangCodeConstant.DATA_OID_NOT_EXIST;
import static com.vci.ubcs.code.constant.MdmLifeCycleConstant.CODE_RULE_LC;
/**
 * 主数据编码规则服务
 * 编码规则 服务实现类
 *
 * @author weidy
 * @date 2022-01-24
 * @author ludc
 * @since 2023-04-03
 */
@Service
public class CodeRuleServiceImpl implements CodeRuleServiceI {
public class CodeRuleServiceImpl extends ServiceImpl<CodeRuleMapper, CodeRule> implements ICodeRuleService {
    /**
     * 日志
     */
    private Logger logger = LoggerFactory.getLogger(getClass());
   /**
    * 数据操作层
    */
   @Resource
   private CodeRuleMapper codeRuleMapper;
   @Resource
   private CommonsMapper commonsMapper;
   @Resource
   private CodeSerialValueMapper codeSerialValueMapper;
    /**
     * 数据操作层
     */
    @Resource
    private CodeRuleDaoI codeRuleMapper;
   /**
    * 其他服务层
    */
   @Resource
   @Lazy
   private ICodeClassifyService codeClassifyServcie;
   @Resource
   private ICodeAllCodeService codeAllcodeService;
   @Resource
   private ICodeBasicSecService codeBasicSecService;
   @Resource
   private ICodeClassifyValueService iCodeClassifyValueService;
    /**
     * 业务类型操作的服务
     */
    @Autowired
    @Lazy
   private WebBoServiceI boService;
   /**
    * 对象的操作
    */
   @Resource
   private RevisionModelUtil revisionModelUtil;
    /**
     * 对象的操作
     */
    @Autowired
    private RevisionModelUtil revisionModelUtil;
   @Resource
   private ICodeFixedValueService codeFixedValueService;
    /**
     * 主题库分类数据操作层
     */
    @Autowired
    private CodeClassifyServiceI codeClassifyService;
   /**
    * 系统服务
    */
   @Resource
   private IUserClient userClient;
    /**
     * 码段基础信息服务
     */
    @Autowired
    private CodeBasicSecServiceI codeBasicSecService;
   /**
    * 分页查询
    * @param query
    * @param conidtionMap
    * @return
    */
   @Override
   public IPage<CodeRuleVO> gridCodeRule(Query query, Map<String,Object> conidtionMap) throws VciBaseException {
      //int i = 1 / 0;
      //如果等于自己配置的管理组租户id和管理组超管账号,就不需要按照规则所有者来进行查询
      /*if(!(AuthUtil.getTenantId().equals(NacosConfigCache.getAdminUserInfo().getTenantId())
         && AuthUtil.getUserId().toString().equals(NacosConfigCache.getAdminUserInfo().getUserId().toString()))
      ){
         // 按照规则所有者来查询
         conidtionMap.put("owner",AuthUtil.getUserId().toString());
      }*/
      IPage<CodeRule> codeRuleIPage = this.codeRuleMapper.selectPage(Condition.getPage(query), UBCSCondition.getQueryWrapper(conidtionMap, CodeRule.class));
      //do转vo同时setLcStatusText生命周期值,并包装成分页对象返回
      return CodeRuleWrapper.build().pageVO(codeRuleIPage);
   }
    /**
     * 码段基础信息数据操作层
     */
    @Resource
    private CodeBasicSecDaoI codeBasicSecMapper;
   /**
    * 增加主数据编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象
    * @return 执行结果
    * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
    */
   @Override
   public R addSave(CodeRuleDTO codeRuleDTO) throws VciBaseException {
      VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
      if(checkCodeRuleRepeat(codeRuleDTO)){
         return R.fail("规则编号已存在!");
      }
      // 将DTO转换为DO
      CodeRule codeRule = Objects.requireNonNull(BeanUtil.copy(codeRuleDTO, CodeRule.class));
      // 填充默认值
      DefaultAttrAssimtUtil.addDefaultAttrAssimt(codeRule, MdmBtmTypeConstant.CODE_RULE);
      codeRule.setLctid(CODE_RULE_LC);
      codeRule.setLcStatus(FRAMEWORK_RELEASE_EDITING);
      codeRule.setOwnerText(AuthUtil.getUserAccount()+"("+AuthUtil.getNickName()+")");
      return R.status(codeRuleMapper.insert(codeRule)>0);
   }
   /**
    * 检查id编号是否重复
    * @param codeRuleDTO 当前判断是否重复的对象
    * @return 返回false表示未重复
    */
   @Override
   public boolean checkCodeRuleRepeat(CodeRuleDTO codeRuleDTO)throws VciBaseException {
      LambdaQueryWrapper<CodeRule> wrapper = Wrappers.<CodeRule>query()
         .lambda().eq(CodeRule::getId, codeRuleDTO.getId());
      if(AuthUtil.getTenantId().equals(NacosConfigCache.getAdminUserInfo().getTenantId())){
         wrapper.eq(CodeRule::getTenantId,AuthUtil.getTenantId());
      }
      // 根据规则id查询编号
      List<CodeRule> codeRulesList = this.codeRuleMapper.selectList(wrapper);
      if(!codeRulesList.isEmpty()){
         return codeRulesList.parallelStream().anyMatch(codeRule -> {
            if(StringUtils.isNotBlank(codeRuleDTO.getOid())){
               // 代表是修改规则,不是将编号修改为已存在的的编号
               return !codeRule.getOid().equals(codeRuleDTO.getOid());
            }else {
               return true;
            }
         });
      }
      return false;
   }
    /**
     * 查询所有的主数据编码规则
     *
     * @param conditionMap 查询条件
     * @param pageHelper   分页和排序
     * @return 执行结果
     * @throws VciBaseException 查询条件和分页出错的时候会抛出异常
     */
    @Override
    public DataGrid<CodeRuleVO> gridCodeRule(Map<String, String> conditionMap, PageHelper pageHelper) throws VciBaseException {
        if (pageHelper == null) {
            pageHelper = new PageHelper(-1);
        }
        pageHelper.addDefaultDesc("createTime");
        List<CodeRuleDO> doList = codeRuleMapper.selectByCondition(conditionMap, pageHelper);
        DataGrid<CodeRuleVO> dataGrid = new DataGrid<CodeRuleVO>();
        if (!CollectionUtils.isEmpty(doList)) {
            dataGrid.setData(codeRuleDO2VOs(doList));
            dataGrid.setTotal(VciBaseUtil.getInt(String.valueOf(codeRuleMapper.countByCondition(conditionMap))));
        }
        return dataGrid;
    }
   /**
    * 校验编码规则的状态是否可以编辑或删除
    *
    * @param lcStatus 编码规则
    * @return true表示可以编辑或删除,false表示不可以
    */
   @Override
   public boolean checkEditDelStatus(String lcStatus) throws VciBaseException {
      if (CodeRuleLC.RELEASED.getValue().equals(lcStatus) || CodeRuleLC.DISABLED.getValue().equals(lcStatus)) {
         return false;
      }
      return true;
   }
    /**
     * 批量数据对象转换为显示对象
     *
     * @param codeRuleDOs 数据对象列表
     * @return 显示对象
     * @throws VciBaseException 参数为空或者不存在的时候会抛出异常
     */
    @Override
    public List<CodeRuleVO> codeRuleDO2VOs(Collection<CodeRuleDO> codeRuleDOs) throws VciBaseException {
        return codeRuleDO2VOs(codeRuleDOs, false);
    }
   /**
    * 修改主数据编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象
    * @return 执行结果
    * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
    */
   @Override
   public R editSave(CodeRuleDTO codeRuleDTO) throws VciBaseException{
      VciBaseUtil.alertNotNull(codeRuleDTO, "数据对象", codeRuleDTO.getOid(), "主数据编码规则主键");
      if(checkCodeRuleRepeat(codeRuleDTO)){
         return R.fail("规则编号已存在!");
      }
      if (!checkEditDelStatus(codeRuleDTO.getLcStatus())) {
         throw new VciBaseException("编码规则已发布,不允许编辑或删除");
      }
      //将DTO转换为DO
      CodeRule codeRule = selectByOid(codeRuleDTO.getOid());
      revisionModelUtil.copyFromDTOIgnore(codeRuleDTO, codeRule);
      if(!codeRule.getOwner().equals(codeRuleDTO.getOwner())){
         codeRule.setOwner(codeRuleDTO.getOwner());
         R<User> userR = userClient.userInfoById(Func.toLong(codeRuleDTO.getOwner()));
         if(!userR.isSuccess() || Func.isEmpty(userR.getData())){
            codeRule.setOwnerText(codeRuleDTO.getOwner());
         }else{
            codeRule.setOwnerText(userR.getData().getAccount()+"("+userR.getData().getRealName()+")");
         }
      }
      DefaultAttrAssimtUtil.updateDefaultAttrAssimt(codeRule);
      return R.status(codeRuleMapper.updateById(codeRule)>0);
   }
    /**
     * 批量数据对象转换为显示对象
     *
     * @param codeRuleDOs 数据对象列表
     * @param hasSec      是否包含码段
     * @return 显示对象
     * @throws VciBaseException 参数为空或者不存在的时候会抛出异常
     */
    @Override
    public List<CodeRuleVO> codeRuleDO2VOs(Collection<CodeRuleDO> codeRuleDOs, boolean hasSec) throws VciBaseException {
        List<CodeRuleVO> voList = new ArrayList<CodeRuleVO>();
        if (!CollectionUtils.isEmpty(codeRuleDOs)) {
            for (CodeRuleDO s : codeRuleDOs) {
                CodeRuleVO vo = codeRuleDO2VO(s);
                if (vo != null) {
                    voList.add(vo);
                }
            }
            if (hasSec) {
                List<CodeBasicSecVO> secVOList = codeBasicSecService.listCodeBasicSecByRuleOids(voList.stream().map(CodeRuleVO::getOid).collect(Collectors.toList()));
                if (!CollectionUtils.isEmpty(secVOList)) {
                    Map<String, List<CodeBasicSecVO>> secVOMap = secVOList.stream().collect(Collectors.groupingBy(CodeBasicSecVO::getPkCodeRule));
                    voList.stream().forEach(vo -> {
                        vo.setSecVOList(secVOMap.getOrDefault(vo.getOid(), new ArrayList<>()));
                    });
                }
            }
        }
        return voList;
    }
   /**
    * 删除主数据编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
    * @return 删除结果反馈::success:成功,fail:失败
    * @throws VciBaseException 参数为空,被引用时抛出异常
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public R deleteCodeRule(CodeRuleDTO codeRuleDTO) throws VciBaseException {
      VciBaseUtil.alertNotNull(codeRuleDTO, "主数据编码规则数据对象", codeRuleDTO.getOid(), "主数据编码规则的主键");
      CodeRule codeRule = selectByOid(codeRuleDTO.getOid());
      if (!checkEditDelStatus(codeRule.getLcStatus())) {
         return R.fail("编码规则已发布,不允许编辑或删除");
      } else {
         if (isAlreadyInUse(codeRule.getOid())) {
            return R.fail("编码规则已被引用,不允许编辑或删除!");
         }
      }
      List<CodeAllCode> codeDOList = codeAllcodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCodeRuleOid, codeRuleDTO.getOid()));
      if (!CollectionUtils.isEmpty(codeDOList)) {
         return R.fail("编码规则已生成编码,不允许删除");
      }
      //执行删除操作
      //WebUtil.setPersistence(false);
      boolean resBoolean = codeBasicSecService.batchDeleteSecByCodeRuleOid(codeRule.getOid());
      boolean resBoolean1 = codeRuleMapper.deleteById(codeRule.getOid()) > 0;
      //WebUtil.setPersistence(true);
      return R.status(resBoolean&&resBoolean1);
   }
    /**
     * 数据对象转换为显示对象
     *
     * @param codeRuleDO 数据对象
     * @return 显示对象
     * @throws VciBaseException 拷贝属性出错的时候会抛出异常
     */
    @Override
    public CodeRuleVO codeRuleDO2VO(CodeRuleDO codeRuleDO) throws VciBaseException {
        CodeRuleVO vo = new CodeRuleVO();
        if (codeRuleDO != null) {
            BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDO, vo);
            //如果有lcstatus的类的话
            vo.setLcStatusText(CodeRuleLC.getTextByValue(vo.getLcStatus()));
   /**
    * 编码规则清空所有已生成的编码
    *
    * @param oid 编码规则主键
    * @return 执行结果
    */
   @Override
   public R clearAllCode(String oid) {
      WebUtil.alertNotNull(oid, "编码规则主键");
      List<CodeAllCode> codeDOList = codeAllcodeService.selectByWrapper(Wrappers.<CodeAllCode>query().lambda().eq(CodeAllCode::getCodeRuleOid, oid));
      if (CollectionUtils.isEmpty(codeDOList)) {
         return R.fail("当前编码规则没有生成编码,无需清空");
      }
      //是否需要进行btm不统一的判断?
      String btmType = codeDOList.get(0).getCreateCodeBtm();
      //多种类型下的查询
      Set<String> btmTypeSet = codeDOList.stream().filter(s -> {
         return !btmType.equalsIgnoreCase(s.getCreateCodeBtm());
      }).map(s -> s.getCreateCodeBtm()).collect(Collectors.toSet());
      List<Map<String,String>> businessDataList = new ArrayList<>();
      if (btmTypeSet.size() > 1) {
         for (String btm : btmTypeSet) {
            Map<String,String> businessData = commonsMapper.selectByCount("PL_CODE_"+btm,oid,btm);
            businessDataList.add(businessData);
         }
      }else {
         Map<String,String> businessData = commonsMapper.selectByCount("PL_CODE_"+btmType,oid,btmType);
         businessDataList.add(businessData);
      }
      if (CollectionUtils.isEmpty(businessDataList) || StringUtils.isBlank(businessDataList.get(0).get("count"))) {
         //无效查询
         return R.fail("查询失败");
      } else if (!"0".equalsIgnoreCase(businessDataList.get(0).get("count"))) {
         return R.fail("编码规则生成的编码已在业务数据中应用,不允许清空");
      }
      //没有数据,可以安全删除
      WebUtil.setPersistence(false);
      //删除码值表中的数据,但不够,如果有流水的码段,需要重新计算流水
      List<CodeSerialValue> serialValueList = codeSerialValueMapper.selectByCodeRoleId(oid);
      /*BatchCBO batchCBO = boService.batchDelete(codeDOList);
      batchCBO.getDeleteCbos().addAll(serialValueList);
      WebUtil.setPersistence(true);
      boService.persistenceBatch(batchCBO);*/
      return R.success("清空码值成功!");
   }
        }
        return vo;
    }
   /**
    * 主键查询数据对象
    *
    * @param oid 主键
    * @return 数据对象
    * @throws VciBaseException 参数为空,并且数据不存在的时候会抛出异常
    */
   private CodeRule selectByOid(String oid) throws VciBaseException {
      VciBaseUtil.alertNotNull(oid, "主键");
      CodeRule codeRuleDO = codeRuleMapper.selectById(oid.trim());
      if (codeRuleDO == null || StringUtils.isBlank(codeRuleDO.getOid())) {
         throw new VciBaseException(DATA_OID_NOT_EXIST);
      }
      return codeRuleDO;
   }
    /**
     * 数据对象转换为显示对象
     *
     * @param codeRuleDO 规则的数据对象
     * @param hasSec     是否查询码段
     * @return 显示对象
     * @throws VciBaseException 拷贝属性出错的时候会抛出异常
     */
    public CodeRuleVO codeRuleDO2VO(CodeRuleDO codeRuleDO, boolean hasSec) throws VciBaseException {
        CodeRuleVO vo = new CodeRuleVO();
        if (codeRuleDO != null) {
            BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDO, vo);
            //如果有lcstatus的类的话
            vo.setLcStatusText(CodeRuleLC.getTextByValue(vo.getLcStatus()));
            if (hasSec) {
                //查询码段
                vo.setSecVOList(codeBasicSecService.listCodeBasicSecByRuleOid(vo.getOid()));
            }
        }
        return vo;
    }
   /**
    * 检验编码规则是否已经被使用
    *
    * @param oid 编码规则主键
    * @return true表示已经使用,false表示未被使用
    */
   @Override
   public boolean isAlreadyInUse(String oid) throws VciBaseException {
      Collection<CodeClassifyVO> codeClassifyVOS = listUseRangeInCodeClassify(oid);
      if (codeClassifyVOS.size() > 0) {
         return true;
      } else {
         return false;
      }
   }
    /**
     * 增加主数据编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象
     * @return 执行结果
     * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
     */
    @Override
    public CodeRuleVO addSave(CodeRuleDTO codeRuleDTO) throws VciBaseException {
        VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
        //将DTO转换为DO
        CodeRuleDO codeRuleDO = new CodeRuleDO();
        BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDTO, codeRuleDO);
        codeRuleMapper.insert(codeRuleDO);
        return codeRuleDO2VO(codeRuleDO);
    }
   /**
    * 查看主数据编码规则的使用范围
    *
    * @param oid 编码规则主键
    * @return 主题库分类使用到该编码规则的所有集合
    */
   @Override
   public Collection<CodeClassifyVO> listUseRangeInCodeClassify(String oid) throws VciBaseException {
      List<CodeClassify> codeClassifies = codeClassifyServcie.selectByWrapper(Wrappers.<CodeClassify>query().lambda().eq(CodeClassify::getCodeRuleOid, oid));
      return CodeClassifyWrapper.build().listVO(codeClassifies);
   }
    /**
     * 修改主数据编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象
     * @return 执行结果
     * @throws VciBaseException 参数为空,唯一项,必输项不通过时会抛出异常
     */
    @Override
    public CodeRuleVO editSave(CodeRuleDTO codeRuleDTO) throws VciBaseException {
        VciBaseUtil.alertNotNull(codeRuleDTO, "数据对象", codeRuleDTO.getOid(), "主数据编码规则主键");
        if (!checkEditDelStatus(codeRuleDTO.getLcStatus())) {
            throw new VciBaseException("编码规则已发布,不允许编辑或删除");
        }
        //将DTO转换为DO
        CodeRuleDO codeRuleDO = selectByOid(codeRuleDTO.getOid());
        revisionModelUtil.copyFromDTOIgnore(codeRuleDTO, codeRuleDO);
        codeRuleMapper.updateByPrimaryKey(codeRuleDO);
        return codeRuleDO2VO(codeRuleDO);
    }
   /**
    * 主键获取主数据编码规则
    *
    * @param oid 主键
    * @return 主数据编码规则显示对象
    * @throws VciBaseException 参数为空,数据不存在时会抛出异常
    */
   @Override
   public CodeRuleVO getObjectByOid(String oid) throws VciBaseException {
      CodeRule codeRule = selectByOid(oid);
      return CodeRuleWrapper.build().entityVO(codeRule);
   }
   /**
    * 主键批量获取主数据编码规则
    *
    * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
    * @return 主数据编码规则显示对象
    * @throws VciBaseException 查询出现异常时会抛出
    */
   @Override
   public Collection<CodeRuleVO> listCodeRuleByOids(Collection<String> oidCollections) throws VciBaseException {
      VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
      List<CodeRule> codeRuleDOList = listCodeRuleDOByOidCollections(oidCollections);
      return codeRuleDO2VOs(codeRuleDOList,true);
   }
    /**
     * 校验是否可以删除,如果存在下级,并且下级有数据引用则不能删除
     *
     * @param codeRuleDTO 数据传输对象
     * @param codeRuleDO  数据库中的数据对象
     * @return success为true为可以删除,false表示有数据引用,obj为true表示有下级
     */
    private BaseResult checkIsCanDeleteForDO(CodeRuleDTO codeRuleDTO, CodeRuleDO codeRuleDO) {
        boService.checkTs(codeRuleDTO);
        if (!checkIsLinked(codeRuleDO.getOid())) {
            return BaseResult.success();
        } else {
            return BaseResult.fail(DATA_LINKED_NOT_DELETE, new String[]{""});
        }
    }
   /**
    * 主键批量获取主数据编码规则
    *
    * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
    * @param hasSec         是否包含码段
    * @return 主数据编码规则显示对象
    * @throws VciBaseException 查询出现异常时会抛出
    */
   @Override
   public Collection<CodeRuleVO> listCodeRuleByIds(Collection<String> oidCollections, boolean hasSec) throws VciBaseException {
      VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
      List<CodeRule> codeRuleDOList = listCodeRuleDOByIdCollections(oidCollections);
      return codeRuleDO2VOs(codeRuleDOList, hasSec);
   }
    /**
     * 校验是否被引用
     *
     * @param oid 主键
     * @throws VciBaseException 被引用的时候会抛出异常
     */
    private boolean checkIsLinked(String oid) throws VciBaseException {
        //TODO 添加需要校验引用的地方
        return false;
    }
   /**
    * 使用主键集合查询数据对象
    *
    * @param oidCollections 主键的集合
    * @return 数据对象列表
    */
   private List<CodeRule> listCodeRuleDOByOidCollections(Collection<String> oidCollections) throws VciBaseException {
      List<CodeRule> codeRuleDOList = new ArrayList<CodeRule>();
      if (!CollectionUtils.isEmpty(oidCollections)) {
         Collection<Collection<String>> oidCollectionsList = VciBaseUtil.switchCollectionForOracleIn(oidCollections);
         for (Collection<String> oids : oidCollectionsList) {
            List<CodeRule> tempDOList = codeRuleMapper.selectBatchIds(oids);
            if (!CollectionUtils.isEmpty(tempDOList)) {
               codeRuleDOList.addAll(tempDOList);
            }
         }
      }
      return codeRuleDOList;
   }
    /**
     * 删除主数据编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
     * @return 删除结果反馈::success:成功,fail:失败
     * @throws VciBaseException 参数为空,被引用时抛出异常
     */
    @Override
    public BaseResult deleteCodeRule(CodeRuleDTO codeRuleDTO) throws VciBaseException {
        VciBaseUtil.alertNotNull(codeRuleDTO, "主数据编码规则数据对象", codeRuleDTO.getOid(), "主数据编码规则的主键");
        CodeRuleDO codeRuleDO = selectByOid(codeRuleDTO.getOid());
        //BaseResult baseResult = checkIsCanDeleteForDO(codeRuleDTO,codeRuleDO);
        // if(baseResult.isSuccess()) {
        //             }else{
        //     return baseResult;
        // }
        if (!checkEditDelStatus(codeRuleDO.getLcStatus())) {
            return BaseResult.fail("编码规则已发布,不允许编辑或删除");
        } else {
            if (isAlreadyInUse(codeRuleDO.getOid())) {
                return BaseResult.fail("编码规则已被引用,不允许编辑或删除!");
            }
        }
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("codeRuleOid", codeRuleDTO.getOid());
        List<CodeAllCodeDO> codeDOList = boService.queryObject(CodeAllCodeDO.class, conditionMap);
        if (!CollectionUtils.isEmpty(codeDOList)) {
            return BaseResult.fail("编码规则已生成编码,不允许删除");
        }
        //执行删除操作
        WebUtil.setPersistence(false);
        BatchCBO batchCBO = codeBasicSecService.batchDeleteSecByCodeRuleOid(codeRuleDO.getOid());
        BatchCBO mainCBO = codeRuleMapper.deleteByPrimaryKey(codeRuleDO.getOid());
        WebUtil.setPersistence(true);
        Set<ClientBusinessObject> deleteSet = new HashSet<>();
        deleteSet.addAll(batchCBO.getDeleteCbos());
        deleteSet.addAll(mainCBO.getDeleteCbos());
        batchCBO.setDeleteCbos(deleteSet);
        boService.persistenceBatch(batchCBO);
        return (batchCBO != null && batchCBO.getDeleteCbos() != null && batchCBO.getDeleteCbos().size() > 0) ? BaseResult.successMsg(DELETE_SUCCESS) : BaseResult.fail(DELETE_FAIL);
    }
   /**
    * 使用规则id集合查询数据对象
    *
    * @param idCollections id的集合
    * @return 数据对象列表
    */
   private List<CodeRule> listCodeRuleDOByIdCollections(Collection<String> idCollections) throws VciBaseException {
      List<CodeRule> codeRuleDOList = new ArrayList<CodeRule>();
      if (!CollectionUtils.isEmpty(idCollections)) {
         Collection<Collection<String>> idCollectionsList = VciBaseUtil.switchCollectionForOracleIn(idCollections);
         for (Collection<String> ids : idCollectionsList) {
            List<CodeRule> tempDOList = codeRuleMapper.selectList(
               Wrappers.<CodeRule>query()
                  .lambda().in(CodeRule::getId,ids)
            );
            if (!CollectionUtils.isEmpty(tempDOList)) {
               codeRuleDOList.addAll(tempDOList);
            }
         }
      }
      return codeRuleDOList;
   }
    /**
     * 校验编码规则的状态是否可以编辑或删除
     *
     * @param lcStatus 编码规则
     * @return true表示可以编辑或删除,false表示不可以
     */
    @Override
    public boolean checkEditDelStatus(String lcStatus) {
        if (CodeRuleLC.RELEASED.getValue().equals(lcStatus) || CodeRuleLC.DISABLED.getValue().equals(lcStatus)) {
            return false;
        }
        return true;
    }
   /**
    * 参照主数据编码规则列表
    *
    * @param bladeQueryObject 查询条件
    * @return 主数据编码规则显示对象列表,生效的内容
    * @throws VciBaseException 查询条件和分页出错的时候会抛出异常
    */
   @Override
   public IPage<CodeRuleVO> refDataGridCodeRule(BladeQueryObject bladeQueryObject) throws VciBaseException {
      return gridCodeRule(bladeQueryObject.getQuery(), bladeQueryObject.getConditionMap());
   }
   /**
    * 停用与启用编码规则
    *
    * @param oid    编码规则主键
    * @param update enable:启用 disable:停用 release:发布
    * @return 执行结果
    */
   @Override
   public R updateStatus(String oid, String update) throws VciBaseException {
      int count = 0;
      //先查询对象
      CodeRule codeRuleDO = selectByOid(oid);
      //创建修改对象的的wrapper条件
      LambdaUpdateWrapper<CodeRule> wrapper = Wrappers.<CodeRule>update()
         .lambda()
         .eq(CodeRule::getOid, oid);
      if ("enable".equalsIgnoreCase(update)) {
         if (!CodeRuleLC.DISABLED.getValue().equals(codeRuleDO.getLcStatus())) {
            return R.fail("非停用状态的编码规则无需点击启用");
         }
         count = codeRuleMapper.update(null,wrapper.set(CodeRule::getLcStatus, CodeRuleLC.RELEASED.getValue()));
      } else if ("disable".equalsIgnoreCase(update)) {
         if (!CodeRuleLC.RELEASED.getValue().equals(codeRuleDO.getLcStatus())) {
            return R.fail("非发布状态的编码规则无法停用");
         }
         count = codeRuleMapper.update(null,wrapper.set(CodeRule::getLcStatus, CodeRuleLC.DISABLED.getValue()));
      } else if ("release".equalsIgnoreCase(update)) {
         if (!CodeRuleLC.EDITING.getValue().equals(codeRuleDO.getLcStatus())) {
            return R.fail("非编辑状态的编码规则无法发布");
         }
         // 发布时将码段类型按照字符串分隔的形式拼接并存储
         String secTypeStr = codeBasicSecService.listCodeBasicSecByRuleOid(codeRuleDO.getOid()).stream().map(CodeBasicSecVO::getSecType).collect(Collectors.joining(","));
         count = codeRuleMapper.update(null,wrapper.set(CodeRule::getLcStatus, CodeRuleLC.RELEASED.getValue()).set(CodeRule::getBasicSecTypes,secTypeStr));
      } else {
         return R.fail("暂不支持的操作类型");
      }
      if (count > 0) {
         return R.success("更新状态成功");
      } else {
         return R.fail("更新状态失败");
      }
   }
    /**
     * 主键获取主数据编码规则
     *
     * @param oid 主键
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 参数为空,数据不存在时会抛出异常
     */
    @Override
    public CodeRuleVO getObjectByOid(String oid) throws VciBaseException {
        return codeRuleDO2VO(selectByOid(oid));
    }
   /**
    * 克隆编码规则
    *
    * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
    * @return 主数据编码规则显示对象
    */
   @Override
   @Transactional(rollbackFor = Exception.class)
   public R cloneCodeRule(CodeRuleDTO codeRuleDTO) throws ServerException {
      if(checkCodeRuleRepeat(codeRuleDTO)){
         return R.fail("规则编号已存在!");
      }
      VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
      CodeRule codeRuleDO = new CodeRule();
      BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDTO, codeRuleDO);
      DefaultAttrAssimtUtil.addDefaultAttrAssimt(codeRuleDO,MdmBtmTypeConstant.CODE_RULE);
      boolean exFlag = SqlHelper.retBool(codeRuleMapper.insert(codeRuleDO));
    /**
     * 主键查询数据对象
     *
     * @param oid 主键
     * @return 数据对象
     * @throws VciBaseException 参数为空,并且数据不存在的时候会抛出异常
     */
    private CodeRuleDO selectByOid(String oid) throws VciBaseException {
        VciBaseUtil.alertNotNull(oid, "主键");
        CodeRuleDO codeRuleDO = codeRuleMapper.selectByPrimaryKey(oid.trim());
        if (codeRuleDO == null || StringUtils.isBlank(codeRuleDO.getOid())) {
            throw new VciBaseException(DATA_OID_NOT_EXIST);
        }
        return codeRuleDO;
    }
      List<CodeBasicSecDTO> secList = codeRuleDTO.getElements();
      List<CodeBasicSec> codeBasicSecs = new ArrayList<>();
      List<CodeBasicSec> codeClassifySec = new ArrayList<>();
      // 固定码值映射关系
      Map<String,List<CodeFixedValue>> codeFixedValueMaps = new HashMap<>();
      for (CodeBasicSecDTO codeBasicSecDTO : secList) {
         codeBasicSecDTO.setPkCodeRule(codeRuleDO.getOid());
         KeyValue attrKv = codeBasicSecService.checkAttrNullableBySecType(codeBasicSecDTO);
         if (!"success".equals(attrKv.getKey())) {
            throw new VciBaseException(attrKv.getValue() + "不能为空");
         }
         CodeBasicSec codeBasicSecDO = new CodeBasicSec();
         BeanUtilForVCI.copyPropertiesIgnoreCase(codeBasicSecDTO, codeBasicSecDO);
         String oldBasicOid = codeBasicSecDO.getOid(); //被克隆的码段的oid
         // 判断是否是分类码段
         if(codeBasicSecDO.getSecType().equals(CodeSecTypeEnum.CODE_CLASSIFY_SEC.getValue())){
            // 存储旧的码段oid和新的码段的oid的关联关系
            codeClassifySec.add(codeBasicSecDO);
            continue;
         }
         // 更改创建时间,修改时间等默认值
         DefaultAttrAssimtUtil.addDefaultAttrAssimt(codeBasicSecDO,MdmBtmTypeConstant.CODE_BASIC_SEC);
         // 固定码段
         if(codeBasicSecDO.getSecType().equals(CodeSecTypeEnum.CODE_FIXED_SEC.getValue())){
            // 固定码段存储好oid和码值的关联关系
            codeFixedValueMaps.put(codeBasicSecDO.getOid(),codeFixedValueService.list(Wrappers.<CodeFixedValue>query()
               .lambda().eq(CodeFixedValue::getCodeFixedSecOid, oldBasicOid)
            ));
         }
         codeBasicSecs.add(codeBasicSecDO);
      }
      // 处理分类码段的oid,因为oid关联parentClassifyOid,与码值codeClassifyOid,码值又需要通过旧的码段oid来查询,所以不能直接改变oid
      boolean resChangeAssn = codeBasicSecService.changeParentOidAssnOid(codeClassifySec);
      // 将处理过的分类码段也添加进要做新增处理的码段集合中
      codeBasicSecs.addAll(codeClassifySec);
      // 新增码段
      boolean exFlag1 = this.codeBasicSecService.saveBatch(codeBasicSecs);
      // 最终要存入码值表中的,码值对象
      List<CodeFixedValue> codeFixedDOValues = new ArrayList<>();
      // 构造码值对象,与码段主键关联关系,以及改变码值的oid
      codeFixedValueMaps.forEach((key, value) -> {
         value.stream().forEach(item -> {
            item.setOid("");
            item.setCodeFixedSecOid(key);
            DefaultAttrAssimtUtil.updateDefaultAttrAssimt(item);
            codeFixedDOValues.add(item);
         });
      });
      boolean exFlag2 = codeFixedValueService.saveBatch(codeFixedDOValues) && resChangeAssn;
      return R.data(exFlag&&exFlag1&&exFlag2);
   }
    /**
     * 主键批量获取主数据编码规则
     *
     * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 查询出现异常时会抛出
     */
    @Override
    public Collection<CodeRuleVO> listCodeRuleByOids(Collection<String> oidCollections) throws VciBaseException {
        VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
        List<CodeRuleDO> codeRuleDOList = listCodeRuleDOByOidCollections(oidCollections);
        return codeRuleDO2VOs(codeRuleDOList);
    }
   /**
    * 使用主键获取编码规则的内容
    *
    * @param oid 主键
    * @return 规则的显示对象
    */
   @Override
   public CodeRuleVO getObjectHasSecByOid(String oid) throws VciBaseException {
      CodeRule ruleDO = selectByOid(oid);
      return codeRuleDO2VO(ruleDO, true);
   }
    /**
     * 主键批量获取主数据编码规则
     *
     * @param oidCollections 主键集合,但是受性能影响,建议一次查询不超过10000个
     * @param hasSec         是否包含码段
     * @return 主数据编码规则显示对象
     * @throws VciBaseException 查询出现异常时会抛出
     */
    @Override
    public Collection<CodeRuleVO> listCodeRuleByOids(Collection<String> oidCollections, boolean hasSec) throws VciBaseException {
        VciBaseUtil.alertNotNull(oidCollections, "数据对象主键集合");
        List<CodeRuleDO> codeRuleDOList = listCodeRuleDOByOidCollections(oidCollections);
        return codeRuleDO2VOs(codeRuleDOList, true);
    }
   /**
    * 检查相似编码规则,并返回对应的结果
    * @param oid 主键
    * @return 执行结果
    */
   @Override
   public R checkLikeCodeRule(String oid) throws VciBaseException {
      // 1、查询出当前要发布的规则
      CodeRuleVO releaseCodeRule = getObjectHasSecByOid(oid);
      // 当前发布的规则不存在码段信息,直接空信息返回
      if(Func.isEmpty(releaseCodeRule.getSecVOList())){
         return R.fail("规则信息不存在,请刷新后重试!");
      }
      // 2、找出与当前发布的规则码段顺序一致的规则
      String secTypes = releaseCodeRule.getSecVOList().stream().map(CodeBasicSecVO::getSecType).collect(Collectors.joining(","));
      // 查询出所有已发布的编码规则中码段类型顺序与当前要发布的规则顺序一致的编码规则,此时已近过滤掉大部分规则,运算量减小
      List<CodeRule> codeRuleList = codeRuleMapper.selectList(Wrappers.<CodeRule>query().lambda()
         .eq(CodeRule::getLcStatus, CodeRuleLC.RELEASED.getValue())
         .eq(CodeRule::getBasicSecTypes,secTypes)
      );
      // 为空,证明不存在类同的编码规则直接返回
      if(Func.isEmpty(codeRuleList)){
         return R.data(new ResultDataVO(true));
      }
      // 查询出基础码段列表(按照orderNum升序排序)
      List<CodeRuleVO> codeRuleVOS = codeRuleDO2VOs(codeRuleList, true);
      // 3、各类码段分别进行比对
      List<CodeRuleVO> lastCodeRule = new ArrayList<>();
      codeRuleVOS.stream().forEach(item->{
         List<CodeBasicSecVO> secVOList = item.getSecVOList();
         boolean flag = true;
         for (int index = 0; index < secVOList.size(); index++) {
            // 当前要发布的规则包含的码段信息
            CodeBasicSecVO releaseBasicSec = releaseCodeRule.getSecVOList().get(index);
            // 已发布的规则包含的码段信息
            CodeBasicSecVO releasedBasicSec = secVOList.get(index);
            // 因为码段顺序都是按照OrderNum排序的,所以直接按照下标两两比较就可以了
            switch (releasedBasicSec.getSecType()){
               // 属性码段,比对属性和属性所在分类(referCodeClassifyOid)
               case "codeattrsec":
                  if(!releasedBasicSec.getReferCodeClassifyOid().equals(releaseBasicSec.getReferCodeClassifyOid())){
                     flag = false;
                  }
                  break;
               // 可变码段,比对码段长度,编码补位方式和补位时的字符
               case "codevariablesec":
                  if(!(releasedBasicSec.getCodeSecLength().equals(releaseBasicSec.getCodeSecLength())
                     && releasedBasicSec.getCodeFillType().equals(releaseBasicSec.getCodeFillType())
                     && releasedBasicSec.getCodeFillSeparator().equals(releaseBasicSec.getCodeFillSeparator()))){
                     flag = false;
                  }
                  break;
               // 固定码段比对按升序排序的码值,
               case "codefixedsec":
                  if(Func.isNotEmpty(releasedBasicSec.getFixedValueVOList()) && Func.isNotEmpty(releaseBasicSec.getFixedValueVOList())){
                     // 将fixedValue按照逗号分隔拼接起来,以便比较,由于查询时已按照orderNum排过序了,所以不需要再次排序
                     String reledFixedValues = releasedBasicSec.getFixedValueVOList().stream().map(CodeFixedValueVO::getId).collect(Collectors.joining(","));
                     String releFixedValues = releaseBasicSec.getFixedValueVOList().stream().map(CodeFixedValueVO::getId).collect(Collectors.joining(","));
                     if(reledFixedValues.equals(releFixedValues)){
                        flag = false;
                     }
                  }
                  break;
               // 分类码段比对按升序排序码值
               case "codeclassifysec":
                  String classifyValueStr = this.iCodeClassifyValueService.getClassifyValueStr(releasedBasicSec.getOid());
                  String classifyValueStr1 = this.iCodeClassifyValueService.getClassifyValueStr(releaseBasicSec.getOid());
                  if(classifyValueStr.equals(classifyValueStr1)){
                     flag = false;
                  }
                  break;
               // 日期码段比对日期格式
               case "codedatesec":
                  if(!releasedBasicSec.getCodeDateFormatStr().equals(releaseBasicSec.getCodeDateFormatStr())){
                     flag = false;
                  }
                  break;
               // 引用码段,比对参照引用的业务类型
               case "coderefersec":
                  if(!releasedBasicSec.getReferBtmId().equals(releaseBasicSec.getReferBtmId())){
                     flag = false;
                  }
                  break;
               // 层级码段,比对层级类型、层级的值、字符截取类型、取值类型
               case "codelevelsec":
                  if(!(releasedBasicSec.getCodeLevelType().equals(releaseBasicSec.getCodeLevelType())
                     /*先做非空判断,因为改属性不是必填属性*/
                     && (Func.isNotEmpty(releasedBasicSec.getCodeLevelValue()) && Func.isNotEmpty(releaseBasicSec.getCodeLevelValue()))
                     && releasedBasicSec.getCodeLevelValue().equals(releaseBasicSec.getCodeLevelValue())
                     && releasedBasicSec.getValueCutType().equals(releaseBasicSec.getValueCutType())
                     && releasedBasicSec.getCodeGetValueType().equals(releaseBasicSec.getCodeGetValueType()))){
                     flag = false;
                  }
                  break;
               // 流水码段比对码段的长度
               case "codeserialsec":
                  if(!releasedBasicSec.getCodeFillLength().equals(releaseBasicSec.getCodeFillLength())){
                     flag = false;
                  }
                  break;
            }
            if (!flag) {
               break;
            }
         }
         // 满足所有码段类型比对条件的规则
         if (flag) {
            lastCodeRule.add(item);
         }
      });
      // 为空时说明步骤3没比对出类似的编码规则
      if(lastCodeRule.isEmpty()){
         return R.data(new ResultDataVO(true));
      }
      StringBuffer resMsg = new StringBuffer();
      resMsg.append("存在如下相似规则,是否继续发布?\n");
      // 最后将结果进行处理并返回
      lastCodeRule.stream().forEach(item->{
         resMsg.append(item.getName());
         resMsg.append(item.getId());
         resMsg.append("编码规则;\n");
      });
      ResultDataVO resultDataVO = new ResultDataVO(false,resMsg.toString());
      return R.data(resultDataVO);
   }
    /**
     * 使用编号的集合获取规则的内容
     *
     * @param idCollection 编号的集合
     * @return 规则的内容
     */
    @Override
    public List<CodeRuleVO> listCodeRuleByIds(Collection<String> idCollection) {
        return codeRuleDO2VOs(listCodeRuleDOByIdCollections(idCollection));
    }
   /**
    * 批量数据对象转换为显示对象
    *
    * @param codeRules 数据对象列表
    * @param hasSec      是否包含码段
    * @return 显示对象
    * @throws VciBaseException 参数为空或者不存在的时候会抛出异常
    */
   public List<CodeRuleVO> codeRuleDO2VOs(Collection<CodeRule> codeRules, boolean hasSec) throws VciBaseException {
      List<CodeRuleVO> voList = new ArrayList<CodeRuleVO>();
      if (!CollectionUtils.isEmpty(codeRules)) {
         for (CodeRule s : codeRules) {
            CodeRuleVO vo = codeRuleDO2VO(s,true);
            if (vo != null) {
               voList.add(vo);
            }
         }
      }
      return voList;
   }
    /**
     * 使用主键集合查询数据对象
     *
     * @param oidCollections 主键的集合
     * @return 数据对象列表
     */
    private List<CodeRuleDO> listCodeRuleDOByOidCollections(Collection<String> oidCollections) {
        List<CodeRuleDO> codeRuleDOList = new ArrayList<CodeRuleDO>();
        if (!CollectionUtils.isEmpty(oidCollections)) {
            Collection<Collection<String>> oidCollectionsList = VciBaseUtil.switchCollectionForOracleIn(oidCollections);
            for (Collection<String> oids : oidCollectionsList) {
                List<CodeRuleDO> tempDOList = codeRuleMapper.selectByPrimaryKeyCollection(oids);
                if (!CollectionUtils.isEmpty(tempDOList)) {
                    codeRuleDOList.addAll(tempDOList);
                }
            }
        }
        return codeRuleDOList;
    }
   /**
    * 数据对象转换为显示对象
    *
    * @param codeRuleDO 规则的数据对象
    * @param hasSec     是否查询码段
    * @return 显示对象
    * @throws VciBaseException 拷贝属性出错的时候会抛出异常
    */
   public CodeRuleVO codeRuleDO2VO(CodeRule codeRuleDO, boolean hasSec) throws VciBaseException {
      CodeRuleVO vo = new CodeRuleVO();
      if (codeRuleDO != null) {
         BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDO, vo);
         //如果有lcstatus的类的话
         vo.setLcStatusText(CodeRuleLC.getTextByValue(vo.getLcStatus()));
         if (hasSec) {
            List<CodeBasicSecVO> codeBasicSecVOS = codeBasicSecService.listCodeBasicSecByRuleOid(vo.getOid());
            //查询码段
            vo.setSecVOList(codeBasicSecVOS);
         }
      }
      return vo;
   }
    /**
     * 使用编号集合查询数据对象
     *
     * @param idCollections 编号的集合
     * @return 数据对象列表
     */
    private List<CodeRuleDO> listCodeRuleDOByIdCollections(Collection<String> idCollections) {
        List<CodeRuleDO> codeRuleDOList = new ArrayList<CodeRuleDO>();
        if (!CollectionUtils.isEmpty(idCollections)) {
            Collection<Collection<String>> idCollectionsList = VciBaseUtil.switchCollectionForOracleIn(idCollections);
            for (Collection<String> ids : idCollectionsList) {
                List<CodeRuleDO> tempDOList = codeRuleMapper.selectByIdCollection(ids);
                if (!CollectionUtils.isEmpty(tempDOList)) {
                    codeRuleDOList.addAll(tempDOList);
                }
            }
        }
        return codeRuleDOList;
    }
    /**
     * 参照主数据编码规则列表
     *
     * @param conditionMap 查询条件
     * @param pageHelper   分页和排序
     * @return 主数据编码规则显示对象列表,生效的内容
     * @throws VciBaseException 查询条件和分页出错的时候会抛出异常
     */
    @Override
    public DataGrid<CodeRuleVO> refDataGridCodeRule(Map<String, String> conditionMap, PageHelper pageHelper) throws VciBaseException {
        if (conditionMap == null) {
            conditionMap = new HashMap<String, String>();
        }
        return gridCodeRule(conditionMap, pageHelper);
    }
    /**
     * 查看主数据编码规则的使用范围
     *
     * @param oid 编码规则主键
     * @return 主题库分类使用到该编码规则的所有集合
     */
    @Override
    public Collection<CodeClassifyVO> listUseRangeInCodeClassify(String oid) {
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("codeRuleOid", oid);
        VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(conditionMap, CodeClassifyDO.class);
        List<CodeClassifyDO> dos = codeClassifyService.selectByWrapper(queryWrapper);
        return codeClassifyService.codeClassifyDO2VOs(dos);
    }
    /**
     * 检验编码规则是否已经被使用
     *
     * @param oid 编码规则主键
     * @return true表示已经使用,false表示未被使用
     */
    @Override
    public boolean isAlreadyInUse(String oid) {
        Collection<CodeClassifyVO> codeClassifyVOS = listUseRangeInCodeClassify(oid);
        if (codeClassifyVOS.size() > 0) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 停用与启用编码规则
     *
     * @param oid    编码规则主键
     * @param update enable:启用 disable:停用 release:发布
     * @return 执行结果
     */
    @Override
    public BaseResult updateStatus(String oid, String update) {
        int count = 0;
        CodeRuleDO codeRuleDO = selectByOid(oid);
        if ("enable".equalsIgnoreCase(update)) {
            if (!CodeRuleLC.DISABLED.getValue().equals(codeRuleDO.getLcStatus())) {
                return BaseResult.fail("非停用状态的编码规则无需点击启用");
            }
            count = codeRuleMapper.updateLcStatus(oid, CodeRuleLC.RELEASED.getValue());
        } else if ("disable".equalsIgnoreCase(update)) {
            if (!CodeRuleLC.RELEASED.getValue().equals(codeRuleDO.getLcStatus())) {
                return BaseResult.fail("非发布状态的编码规则无法停用");
            }
            count = codeRuleMapper.updateLcStatus(oid, CodeRuleLC.DISABLED.getValue());
        } else if ("release".equalsIgnoreCase(update)) {
            if (!CodeRuleLC.EDITING.getValue().equals(codeRuleDO.getLcStatus())) {
                return BaseResult.fail("非编辑状态的编码规则无法发布");
            }
            count = codeRuleMapper.updateLcStatus(oid, CodeRuleLC.RELEASED.getValue());
        } else {
            return BaseResult.fail("暂不支持的操作类型");
        }
        if (count > 0) {
            return BaseResult.success();
        } else {
            return BaseResult.fail("更新状态失败");
        }
    }
    /**
     * 克隆编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
     * @return 主数据编码规则显示对象
     */
    public BaseResult cloneCodeRule_v1(CodeRuleDTO codeRuleDTO) {
        VciBaseUtil.alertNotNull(codeRuleDTO.getOid(), "编码规则主键");
        ClientBusinessObjectOperation operation = new ClientBusinessObjectOperation();
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("pkCodeRule", codeRuleDTO.getOid());
        List<CodeBasicSecDO> basicSecDOS = boService.queryObject(CodeBasicSecDO.class, conditionMap);
        List<String> secOidList = new ArrayList<>();
        for (CodeBasicSecDO secDO : basicSecDOS) {
            secOidList.add(secDO.getOid());
        }
        List<ClientBusinessObject> cboList = new ArrayList<>();
        try {
            ClientBusinessObject templateCbo = operation.readBusinessObjectById(codeRuleDTO.getOid(), MdmBtmTypeConstant.CODE_RULE);
            ClientBusinessObject codeRuleCbo = operation.initBusinessObject(templateCbo.getBtmName());
            String curOid = codeRuleCbo.getOid();
            String curRevisionId = codeRuleCbo.getRevisionid();
            String curNameOid = codeRuleCbo.getNameoid();
            BeanUtilForVCI.copyPropertiesIgnoreCase(templateCbo, codeRuleCbo);
            codeRuleCbo.setOid(curOid);
            codeRuleCbo.setRevisionid(curRevisionId);
            codeRuleCbo.setNameoid(curNameOid);
            codeRuleCbo.setId(templateCbo.getId() + "_copy");
            codeRuleCbo.setName(templateCbo.getName() + "_copy");
            if (!CollectionUtils.isEmpty(secOidList)) {
                ClientBusinessObject[] secCboArr = operation.readBusinessObjectById(secOidList.toArray(new String[0]), MdmBtmTypeConstant.CODE_BASIC_SEC);
                for (ClientBusinessObject cbo : secCboArr) {
                    ClientBusinessObject newSecCbo = operation.initBusinessObject(cbo.getBtmName());
                    String newSecCboOid = newSecCbo.getOid();
                    String newSecCboRevisionId = newSecCbo.getRevisionid();
                    String newSecCboNameOid = newSecCbo.getNameoid();
                    BeanUtilForVCI.copyPropertiesIgnoreCase(cbo, newSecCbo);
                    newSecCbo.setOid(newSecCboOid);
                    newSecCbo.setRevisionid(newSecCboRevisionId);
                    newSecCbo.setNameoid(newSecCboNameOid);
                    newSecCbo.setId(newSecCbo.getId() + "_copy");
                    newSecCbo.setName(newSecCbo.getName() + "_copy");
                    newSecCbo.setAttributeValue("pkCodeRule", codeRuleCbo.getOid());
                    cboList.add(newSecCbo);
                }
            }
            cboList.add(codeRuleCbo);
            ClientBusinessObject[] saveList = operation.batchSaveCreateBuinessObject(cboList.toArray(new ClientBusinessObject[0]));
            if (saveList.length == 0) {
                return BaseResult.fail("克隆出错了……");
            }
        } catch (VCIError vciError) {
            vciError.printStackTrace();
        }
        return BaseResult.success();
    }
    /**
     * 克隆编码规则
     *
     * @param codeRuleDTO 主数据编码规则数据传输对象,oid和ts需要传输
     * @return 主数据编码规则显示对象
     */
    @Override
    public BaseResult cloneCodeRule(CodeRuleDTO codeRuleDTO) {
        VciBaseUtil.alertNotNull(codeRuleDTO, "需要添加的数据对象");
        CodeRuleDO codeRuleDO = new CodeRuleDO();
        BeanUtilForVCI.copyPropertiesIgnoreCase(codeRuleDTO, codeRuleDO);
        WebUtil.setPersistence(false);
        BatchCBO batchInsertCBO = codeRuleMapper.insert(codeRuleDO);
        List<CodeBasicSecDTO> secList = codeRuleDTO.getElements();
        secList.forEach(codeBasicSecDTO -> {
            codeBasicSecDTO.setPkCodeRule(codeRuleDO.getOid());
            KeyValue attrKv = codeBasicSecService.checkAttrNullableBySecType(codeBasicSecDTO);
            if (!"success".equals(attrKv.getKey())) {
                throw new VciBaseException(attrKv.getValue() + "不能为空");
            }
            CodeBasicSecDO codeBasicSecDO = new CodeBasicSecDO();
            BeanUtilForVCI.copyPropertiesIgnoreCase(codeBasicSecDTO, codeBasicSecDO);
            codeBasicSecDO.setOid("");
            codeBasicSecDO.setRevisionOid("");
            codeBasicSecDO.setNameOid("");
            BatchCBO cbo = codeBasicSecMapper.insert(codeBasicSecDO);
            batchInsertCBO.addCreateCbo(cbo.getCreateCboArray()[0]);
        });
        boService.persistenceBatch(batchInsertCBO);
        return BaseResult.success();
    }
    /**
     * 使用主键获取编码规则的内容
     *
     * @param oid 主键
     * @return 规则的显示对象
     */
    @Override
    public CodeRuleVO getObjectHasSecByOid(String oid) {
        CodeRuleDO ruleDO = selectByOid(oid);
        return codeRuleDO2VO(ruleDO, true);
    }
    /**
     * 编码规则清空所有已生成的编码
     *
     * @param oid 编码规则主键
     * @return 执行结果
     */
    @Override
    public BaseResult clearAllCode(String oid) {
        WebUtil.alertNotNull(oid, "编码规则主键");
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("codeRuleOid", oid);
        List<CodeAllCodeDO> codeDOList = boService.queryObject(CodeAllCodeDO.class, conditionMap);
        if (CollectionUtils.isEmpty(codeDOList)) {
            return BaseResult.fail("当前编码规则没有生成编码,无需清空");
        }
        //是否需要进行btm不统一的判断?
        String btmType = codeDOList.get(0).getCreateCodeBtm();
        /*boolean flag = codeDOList.stream().anyMatch(s -> !StringUtils.equalsIgnoreCase(btmType, s.getCreateCodeBtm()));
        if (flag) {
            return BaseResult.fail("当前编码规则生成编码在不同类型下使用过");
        }*/
        //多种类型下的查询
        Set<String> btmTypeSet = codeDOList.stream().filter(s -> {
            return !StringUtils.equalsIgnoreCase(btmType, s.getCreateCodeBtm());
        }).map(s -> s.getCreateCodeBtm()).collect(Collectors.toSet());
        List<ClientBusinessObject> businessDataList = new ArrayList<>();
        if (btmTypeSet.size() > 1) {
            for (String btm : btmTypeSet) {
                String sql = "select COUNT(w.OID) from PLATFORMBTM_" + btm + "  w\n" +
                        "join PLATFORMBTM_" + MdmBtmTypeConstant.CODE_ALL_CODE + " c on w.OID = c.CREATECODEOID\n" +
                        "where c.CREATECODEBTM = '" + btm + "' and c.CODERULEOID = '" + oid + "'" +
                        "and w.ISLASTR = '1' and w.ISLASTV = '1'";
                List<ClientBusinessObject> businessData = boService.queryByOnlySql(sql);
                businessDataList.addAll(businessData);
            }
        }else {
            String sql = "select COUNT(w.OID) from PLATFORMBTM_" + btmType + "  w\n" +
                    "join PLATFORMBTM_" + MdmBtmTypeConstant.CODE_ALL_CODE + " c on w.OID = c.CREATECODEOID\n" +
                    "where c.CREATECODEBTM = '" + btmType + "' and c.CODERULEOID = '" + oid + "'" +
                    "and w.ISLASTR = '1' and w.ISLASTV = '1'";
            List<ClientBusinessObject> businessData = boService.queryByOnlySql(sql);
            businessDataList.addAll(businessData);
        }
        if (CollectionUtils.isEmpty(businessDataList) || StringUtils.isBlank(businessDataList.get(0).getAttributeValue("COUNT(w.OID)"))) {
            //无效查询
            return BaseResult.fail("查询失败");
        } else if (!StringUtils.equalsIgnoreCase("0", businessDataList.get(0).getAttributeValue("COUNT(w.OID)"))) {
            return BaseResult.fail("编码规则生成的编码已在业务数据中应用,不允许清空");
        }
        //没有数据,可以安全删除
        WebUtil.setPersistence(false);
        //删除码值表中的数据,但不够,如果有流水的码段,需要重新计算流水
        conditionMap.clear();
        conditionMap.put("codeRuleOid", oid);
        List<ClientBusinessObject> serialValueList = boService.queryCBO("codeserialvalue", conditionMap);
        BatchCBO batchCBO = boService.batchDelete(codeDOList);
        batchCBO.getDeleteCbos().addAll(serialValueList);
        WebUtil.setPersistence(true);
        boService.persistenceBatch(batchCBO);
        return BaseResult.success();
    }
}