yuxc
2023-05-19 029b101d319812460441d3d706c0654d8b0dcda6
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmEngineServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2852 @@
package com.vci.ubcs.code.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vci.ubcs.code.bo.CodeClassifyFullInfoBO;
import com.vci.ubcs.code.bo.CodeTemplateAttrSqlBO;
import com.vci.ubcs.code.constant.FrameWorkDefaultValueConstant;
import com.vci.ubcs.code.constant.MdmBtmTypeConstant;
import com.vci.ubcs.code.dto.CodeDeleteBatchDTO;
import com.vci.ubcs.code.dto.CodeOrderDTO;
import com.vci.ubcs.code.dto.datapush.BaseModelDTO;
import com.vci.ubcs.code.entity.*;
import com.vci.ubcs.code.enumpack.*;
import com.vci.ubcs.code.mapper.CodeAllCodeMapper;
import com.vci.ubcs.code.mapper.CodeOsbtmtypeMapper;
import com.vci.ubcs.code.mapper.CodeWupinMapper;
import com.vci.ubcs.code.mapper.CommonsMapper;
import com.vci.ubcs.code.service.*;
import com.vci.ubcs.code.vo.CodeKeyAttrRepeatVO;
import com.vci.ubcs.code.vo.pagemodel.*;
import com.vci.ubcs.code.vo.pagemodel.UITableFieldVO;
import com.vci.ubcs.code.vo.pagemodel.UITablePageVO;
import com.vci.ubcs.starter.exception.VciBaseException;
import com.vci.ubcs.starter.revision.model.TreeWrapperOptions;
import com.vci.ubcs.starter.revision.service.RevisionModelUtil;
import com.vci.ubcs.starter.web.constant.QueryOptionConstant;
import com.vci.ubcs.starter.web.constant.RegExpConstant;
import com.vci.ubcs.starter.web.enumpck.BooleanEnum;
import com.vci.ubcs.starter.web.enumpck.UserSecretEnum;
import com.vci.ubcs.starter.web.enumpck.VciFieldTypeEnum;
import com.vci.ubcs.starter.web.pagemodel.*;
import com.vci.ubcs.starter.web.toolmodel.DateConverter;
import com.vci.ubcs.starter.web.util.VciBaseUtil;
import com.vci.ubcs.starter.web.util.VciDateUtil;
import com.vci.ubcs.starter.web.util.VciQueryWrapperForDO;
import com.vci.ubcs.starter.web.util.WebUtil;
import com.vci.ubcs.system.entity.DictBiz;
import com.vci.ubcs.system.feign.IDictBizClient;
import net.logstash.logback.encoder.org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static com.vci.ubcs.code.constant.FrameWorkLangCodeConstant.DATA_OID_NOT_EXIST;
import static com.vci.ubcs.code.constant.MdmEngineConstant.*;
import static com.vci.ubcs.starter.web.constant.EnumIdConstant.LC_STATUS_SUBFIX;
/**
 * ä¸»æ•°æ®å¼•擎服务
 *
 * @author weidy
 * @date 2022-2-22
 */
@Service
public class MdmEngineServiceImpl extends ServiceImpl<CodeWupinMapper, CodeWupinEntity> implements MdmEngineService {
   /**
    * æ¨¡æ¿çš„æœåŠ¡
    */
   @Resource
   private CodeClstemplateServiceImpl templateService;
   /**
    * æ¨¡æ¿çš„æœåŠ¡
    */
   @Resource
   private CodeOsbtmtypeMapper codeOsbtmtypeMapper;
   @Resource
   private CodeOsattributeServiceImpl attributeService;
   /**
    * ç”Ÿæˆç¼–码的服务
    */
   @Resource
   private MdmProductCodeService productCodeService;
   /**
    * å­—典的服务
    */
   @Resource
   IDictBizClient iDictBizClient;
   /**
    * å…¬å¼çš„æœåŠ¡
    */
   @Autowired
   private FormulaServiceImpl formulaService;
   /**
    * ç›¸ä¼¼é¡¹æŸ¥è¯¢è§„则
    */
   @Autowired
   private ICodeResembleRuleService resembleRuleService;
   /**
    * å¯¹è±¡çš„æ“ä½œ
    */
   @Autowired
   private RevisionModelUtil revisionModelUtil;
   /**
    * é˜¶æ®µçš„æœåŠ¡
    */
   @Autowired
   private ICodePhaseAttrService phaseAttrService;
//
   /**
    * é€šç”¨æŸ¥è¯¢
    */
   @Resource
   CommonsMapper commonsMapper;
   @Resource
   CodeWupinMapper codeWupinMapper;
   /**
    * ç¼–码规则的服务
    */
   @Autowired
   private ICodeRuleService ruleService;
   /**
    * ç¼–码规则的服务
    */
   @Autowired
   private ICodeAllCodeService codeAllCodeService;
   /**
    * åˆ†ç±»ç å€¼çš„æœåŠ¡
    */
   @Autowired
   private ICodeClassifyValueService classifyValueService;
   /**
    * åˆ†ç±»çš„æœåŠ¡
    */
   @Resource
   private ICodeClassifyService classifyService;
   /**
    * æ¨¡æ¿æŒ‰é’®æœåŠ¡
    */
   @Autowired
   private ICodeClassifyTemplateButtonService templateButtonService;
//   /**
//    * ç”¨æˆ·æŸ¥è¯¢çš„æœåŠ¡,需要问一下是否需要重写,使用查询此平台的用户表
//    */
//   @Autowired
//   private SmUserQueryServiceI userQueryService;
   /**
    * å…³é”®å±žæ€§çš„配置
    */
   @Autowired
   private ICodeKeyAttrRepeatService keyRuleService;
   /**
    * æ—¥å¿—
    */
   private Logger logger = LoggerFactory.getLogger(getClass());
   /**
    * ç©ºæ ¼
    */
   public static final String SPACE = " ";
   /**
    * å¯†çº§çš„字段
    */
   public static final String SECRET_FILED = "secretgrade";
   /**
    * ç”¨æˆ·æ–°å¢žæ•°æ®çš„æ—¶å€™å¯ä»¥æŸ¥çœ‹çš„密级
    */
   public static final String MY_DATA_SECRET = "myDataSecret";
   /**
    * æ‹·è´çš„版本
    */
   public static final String COPY_FROM_VERSION = "copyfromversion";
   /**
    * åªæ˜¯sql
    */
   public static final String ONLY = "${vcionly}";
   /**
    * é»˜è®¤çš„æ—¶é—´æ ¼å¼
    */
   private static final String DATETIME_FORMAT = "yyyy-mm-dd hh24:mi:ss";
   /**
    * æ—¥æœŸæ ¼å¼
    */
   private static final String DATE_FORMAT = "yyyy-mm-dd";
   /**
    * å¿…输
    */
   public static final String REQUIRED_CHAR = "*";
   /**
    * æ›¿æ¢å­—符
    */
   public static final String SPECIAL_CHAR  = "VCI";
//   @Autowired
//   private CodeOsbtmtypeMapper codeOsbtmtypeMapper;----
   /**
    * ä½¿ç”¨åˆ†ç±»çš„主键获取可以使用的模板对象
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @return æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    */
   @Override
   public CodeClassifyTemplateVO getUsedTemplateByClassifyOid(String codeClassifyOid) {
      return getUsedTemplateByClassifyOid(codeClassifyOid, true);
   }
   /**
    * ä½¿ç”¨åˆ†ç±»çš„主键获取可以使用的模板对象
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @param hasAttr         åŒ…含属性
    * @return æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    */
   @Override
   public CodeClassifyTemplateVO getUsedTemplateByClassifyOid(String codeClassifyOid, boolean hasAttr) {
      List<CodeClassifyTemplateVO> templateVOs = templateService.listReleaseTemplateByClassifyOid(codeClassifyOid, hasAttr);
      return templateVOs.get(templateVOs.size() - 1);
   }
   /**
    * èŽ·å–æžšä¸¾çš„ä¸‹æ‹‰é€‰é¡¹
    *
    * @param attrVO æ¨¡æ¿å±žæ€§çš„对象
    * @return ä¸‹æ‹‰é€‰é¡¹
    */
   @Override
   public List<KeyValue> listComboboxItems(CodeClassifyTemplateAttrVO attrVO) {
      List<KeyValue> comboboxKVs = null;
      if (StringUtils.isNotBlank(attrVO.getEnumString())) {
         comboboxKVs = JSONObject.parseArray(attrVO.getEnumString(), KeyValue.class);
      } else {
//         comboboxKVs = enumService.getEnum(attrVO.getEnumid());
//          Dict dict = new Dict();
//         dict.setParentId(Long.valueOf(attrVO.getEnumid()));
         R<List<DictBiz>> list = iDictBizClient.getList(attrVO.getEnumId());
         if(list.isSuccess()){
            for (DictBiz datum : list.getData()) {
               KeyValue keyValue = new KeyValue();
               keyValue.setKey(datum.getDictKey());
               keyValue.setValue(datum.getDictValue());
               comboboxKVs.add(keyValue);
            }
         }
      }
      return comboboxKVs;
   }
   /**
    * ä¿®æ”¹çŠ¶æ€
    *
    * @param baseModelDTO æ•°æ®ä¼ è¾“对象
    */
   @Override
   public void changeStatus(BaseModelDTO baseModelDTO) {
      VciBaseUtil.alertNotNull(baseModelDTO, "数据信息", baseModelDTO.getOid(), "主键", baseModelDTO.getBtmname(), "业务类型", baseModelDTO.getLcStatus(), "目标状态");
      List<String> oids = VciBaseUtil.str2List(baseModelDTO.getOid());
//      List<ClientBusinessObject> cboList = boService.selectCBOByOidCollection(oids, baseModelDTO.getBtmname());
      //插个点 ä¸šåŠ¡ç±»åž‹å®ŒæˆåŽéœ€è¦ä¿®æ”¹
      QueryWrapper<CodeOsbtmtypeEntity> wrapper = new QueryWrapper<>();
      wrapper.eq("BTMNAME",baseModelDTO.getBtmname());
      wrapper.in("OID",oids);
      List<CodeOsbtmtypeEntity> cboList = codeOsbtmtypeMapper.selectList(wrapper);
      //还需要修改allCode的生命周期
//      Map<String, String> conditionMap = new HashMap<>();
      QueryWrapper<CodeAllCode> allCodeWrapper = new QueryWrapper<>();
      allCodeWrapper.eq("createcodebtm",baseModelDTO.getBtmname());
      allCodeWrapper.in("createcodeoid",oids);
//      conditionMap.put("createcodeoid", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(oids.toArray(new String[0])) + ")");
//      conditionMap.put("createcodebtm", baseModelDTO.getBtmname());
      List<CodeAllCode> codeCbos = codeAllCodeService.selectByWrapper(allCodeWrapper);
//      List<ClientBusinessObject> codeCbos = boService.queryCBO(MdmBtmTypeConstant.CODE_ALL_CODE, conditionMap);
      // å›žæ”¶éœ€è¦ä¸šåŠ¡æ•°æ®åˆ é™¤
      if (CodeDefaultLC.TASK_BACK.getValue().equals(baseModelDTO.getLcStatus())) {
//         BatchCBO batchCBO = new BatchCBO();
//         batchCBO.getDeleteCbos().addAll(cboList);
         codeOsbtmtypeMapper.deleteBatchIds(cboList);
//         boService.persistenceBatch(batchCBO);
      } else {
//         lifeCycleService.transCboStatus(cboList, baseModelDTO.getLcStatus());
      }
//      lifeCycleService.transCboStatus(codeCbos, baseModelDTO.getLcStatus());
   }
   /**
    * ç”³è¯·å•一编码
    *
    * @param orderDTO ç”³è¯·çš„信息,需要包含属性的内容和码段相关的内容
    * @return è¿”回编码的内容
    */
   @Override
   public String addSaveCode(CodeOrderDTO orderDTO) {
      VciBaseUtil.alertNotNull(orderDTO, "编码申请相关的属性和码段的内容都为空", orderDTO.getCodeClassifyOid(), "主题库分类的主键",
         orderDTO.getTemplateOid(), "模板的主键", orderDTO.getCodeRuleOid(), "编码规则的主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
      CodeRuleVO ruleVO = ruleService.getObjectHasSecByOid(orderDTO.getCodeRuleOid());
      //1.判断规则中除了流水码段,是否有其他码段
      checkSecValueOnOrder(ruleVO, orderDTO);
      //2.判断必输项
      checkRequiredAttrOnOrder(templateVO, orderDTO);
      //3.先注入,再组合,最后校验
      switchClassifyLevelOnOrder(templateVO, classifyFullInfo, orderDTO);
      //4.处理组合规则。组合规则不能使用编码的属性,因为编码的生成可能是需要属性的
      switchComponentAttrOnOrder(templateVO, orderDTO);
      //5.校验规则
      checkVerifyOnOrder(templateVO, orderDTO);
      //6.关键属性
      checkKeyAttrOnOrder(classifyFullInfo, templateVO, orderDTO);
      //7.枚举转换
      checkEnumOnOrder(templateVO, orderDTO);
      //8.处理时间格式,在数据库里面不论是字符串还是日期格式,都使用相同的格式存储
      switchDateAttrOnOrder(templateVO, orderDTO);
      //9.生成编码的信息
//      ClientBusinessObject cbo = boService.createCBOByBtmName(classifyFullInfo.getTopClassifyVO().getBtmtypeid());
      CodeWupinEntity cbo = createCBOByBtmName(classifyFullInfo.getTopClassifyVO().getBtmtypeid());
//      //默认的属性都不用从前端拷贝
//      //设置编码需要的默认属性的内容
      copyValueToCBO(classifyFullInfo, cbo, orderDTO, templateVO, false);
//      //TODO:因为默认的属性都不拷贝,目前集团码叫name,并没有从DTO拷贝到cbo里。增加一个单独处理,以后再看要不要调整
      cbo.setName(orderDTO.getName() == null ? "" : orderDTO.getName());
//      //end -- modify by lihang @20220407
      List<CodeWupinEntity> cboList = new ArrayList<>();
      //备注
      cbo.setDescription(orderDTO.getDescription());
      cboList.add(cbo);
//
//      cboList.add(cbo);
      List<String> codeList = productCodeService.productCodeAndSaveData(classifyFullInfo, templateVO, ruleVO, orderDTO.getSecDTOList(),cboList);
      List<String> charList = new ArrayList<>();
      for (CodeWupinEntity wupinEntity : cboList) {
         charList.add(wupinEntity.getId());
      }
      batchSaveSelectChar(templateVO, charList);
      return codeList.size() > 0 ? codeList.get(0) : "";
//      return null;
   }
   /**
    * å¤„理分类注入的信息
    *
    * @param templateVO         æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡ï¼Œå¿…须要后模板的属性
    * @param classifyFullInfoBO åˆ†ç±»çš„全路径
    * @param orderDTO           ç¼–码申请的信息
    */
   private void switchClassifyLevelOnOrder(CodeClassifyTemplateVO templateVO, CodeClassifyFullInfoBO classifyFullInfoBO, CodeOrderDTO orderDTO) {
      Map<String,CodeClassifyTemplateAttrVO> classifyAttrVOMap = templateVO.getAttributes().stream().filter(
         s -> StringUtils.isNotBlank(s.getClassifyInvokeAttr()) && StringUtils.isNotBlank(s.getClassifyInvokeLevel())
      ).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (classifyFullInfoBO.getTopClassifyVO() == null) {
         //需要重新查询一下,因为这个是指定的分类进来的
      }
      if (!CollectionUtils.isEmpty(classifyAttrVOMap)) {
         classifyAttrVOMap.forEach((attrId, attrVO) -> {
            //分类注入的编号或者名称,
            //层级包含指定层和最小层
            CodeClassifyVO classifyVO = null;
            if (!CodeLevelTypeEnum.MIN.getValue().equalsIgnoreCase(attrVO.getClassifyInvokeLevel()) && !"min".equalsIgnoreCase(attrVO.getClassifyInvokeLevel())) {
               //指定了层级的
               //注意,因为查询上级分类出来的层级是倒序的,即顶层节点是最大的值
               List<CodeClassifyVO> classifyVOS = classifyFullInfoBO.getParentClassifyVOs().stream().sorted(((o1, o2) -> o2.getDataLevel().compareTo(o1.getDataLevel()))).collect(Collectors.toList());
               int level = VciBaseUtil.getInt(attrVO.getClassifyInvokeLevel());
               if (classifyVOS.size() >= level && level > 0) {
                  classifyVO = classifyVOS.get(level - 1);
               }
            } else {
               //当前的分类
               classifyVO = classifyFullInfoBO.getCurrentClassifyVO();
            }
            if (classifyVO == null) {
               //说明层级有误
               orderDTO.getData().put(attrId, "分类树上没有层级[" + attrVO.getClassifyInvokeLevel() + "]");
               // classifyVO = classifyFullInfoBO.getCurrentClassifyVO();
            } else {
               Map<String, String> classifyDataMap = VciBaseUtil.objectToMapString(classifyVO);
               String value = classifyDataMap.getOrDefault(attrVO.getClassifyInvokeAttr(), "");
               orderDTO.getData().put(attrId, value);
            }
         });
      }
   }
   /**
    * åˆ¤æ–­ç¼–码的码段是否输入或者选择了码值
    *
    * @param ruleVO   è§„则的显示对象
    * @param orderDTO ç¼–码申请的内容
    */
   @Override
   public void checkSecValueOnOrder(CodeRuleVO ruleVO, CodeOrderDTO orderDTO) {
      List<String> unSerialSecOidList = ruleVO.getSecVOList().stream().filter(
         s -> !(CodeSecTypeEnum.CODE_SERIAL_SEC.getValue().equalsIgnoreCase(s.getSecType())
            || CodeSecTypeEnum.CODE_ATTR_SEC.getValue().equalsIgnoreCase(s.getSecType())
            || CodeSecTypeEnum.CODE_DATE_SEC.getValue().equalsIgnoreCase(s.getSecType())
            || CodeSecTypeEnum.CODE_LEVEL_SEC.getValue().equalsIgnoreCase(s.getSecType())
            || VciBaseUtil.getBoolean(s.getNullableFlag()))
      ).map(CodeBasicSecVO::getOid).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(unSerialSecOidList)) {
         if (CollectionUtils.isEmpty(orderDTO.getSecDTOList())) {
            throw new VciBaseException("非流水码段(或者必输码段)必须要输入(或选择)码值");
         }
         if (orderDTO.getSecDTOList().stream().anyMatch(s -> !unSerialSecOidList.contains(s.getSecOid())
            && StringUtils.isBlank(s.getSecValue()))) {
            throw new VciBaseException("非流水码段(或者必输码段)必须要输入(或选择)码值");
         }
      }
   }
   /**
    * æ ¡éªŒå±žæ€§æ˜¯å¦ä¸ºå¿…输
    *
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡ï¼Œéœ€è¦åŒ…含模板属性
    * @param orderDTO   ç¼–码申请的信息
    */
   private void checkRequiredAttrOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      Map<String, CodeClassifyTemplateAttrVO> requiredAttrMap = templateVO.getAttributes().stream().filter(
            s -> VciBaseUtil.getBoolean(s.getRequireFlag()) && StringUtils.isBlank(s.getComponentRule())
               && StringUtils.isBlank(s.getClassifyInvokeAttr()))
         .collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(requiredAttrMap)) {
         requiredAttrMap.forEach((attrId, attrVO) -> {
            //只有企业编码,状态,备注,模板主键,分类主键这几个是固定的,其余都是自行配置的
            if (StringUtils.isBlank(getValueFromOrderDTO(orderDTO, attrId))) {
               throw new VciBaseException("属性【{0}】必须要输入(选择)内容", new String[]{attrVO.getName()});
            }
         });
      }
   }
   /**
    * ä»Žç¼–码申请信息对象上获取某个属性的值
    *
    * @param orderDTO ç¼–码申请对象
    * @param attrId   å±žæ€§çš„编号
    * @return å€¼
    */
   private String getValueFromOrderDTO(CodeOrderDTO orderDTO, String attrId) {
      attrId = attrId.toLowerCase(Locale.ROOT);
      String value = null;
      if (VciQueryWrapperForDO.BASIC_FIELD_MAP.containsKey(attrId)) {
         value = WebUtil.getStringValueFromObject(WebUtil.getValueFromField(WebUtil.getFieldForObject(attrId, orderDTO.getClass()).getName(), orderDTO));
      } else {
         //说明是自行配置的
         //前端必须要传递小写的属性
         value = orderDTO.getData().getOrDefault(attrId, "");
      }
      return value;
   }
   /**
    * è½¬æ¢ç»„合规则的值
    *
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡ï¼Œéœ€è¦åŒ…含模板属性
    * @param orderDTO   ç¼–码申请的信息
    */
   private void switchComponentAttrOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      Map<String, CodeClassifyTemplateAttrVO> compAttrVOMap = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getComponentRule())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(compAttrVOMap)) {
         Map<String, String> dataMap = WebUtil.objectToMapString(orderDTO);
         Map<String, String> dataLowMap = new HashMap<>();
         if (!CollectionUtils.isEmpty(dataMap)) {
            dataMap.forEach((key, value) -> {
               dataLowMap.put(key.toLowerCase(Locale.ROOT), value);
            });
         }
         dataLowMap.putAll(orderDTO.getData());
         compAttrVOMap.forEach((attrId, attrVO) -> {
            dataLowMap.put(attrId, formulaService.getValueByFormula(dataLowMap, attrVO.getComponentRule()));
         });
         dataLowMap.forEach((key, value) -> {
            setValueToOrderDTO(orderDTO, key, value);
         });
      }
   }
   /**
    * è®¾ç½®æ–°çš„值到申请对象上
    *
    * @param orderDTO ç¼–码申请对象
    * @param attrId   å±žæ€§çš„编号
    * @param value    å€¼
    */
   private void setValueToOrderDTO(CodeOrderDTO orderDTO, String attrId, String value) {
      attrId = attrId.toLowerCase(Locale.ROOT);
      if (VciQueryWrapperForDO.BASIC_FIELD_MAP.containsKey(attrId)) {
         WebUtil.setValueToField(WebUtil.getFieldForObject(attrId, orderDTO.getClass()).getName(), orderDTO, value);
      } else {
         orderDTO.getData().put(attrId, value);
      }
   }
   /**
    * æ ¡éªŒæ­£åˆ™è¡¨è¾¾å¼æ˜¯å¦æ­£ç¡®
    *
    * @param templateVO æ¨¡æ¿çš„信息,必须包含属性的内容
    * @param orderDTO   ç¼–码申请的相关的信息
    */
   private void checkVerifyOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      Map<String, CodeClassifyTemplateAttrVO> verifyAttrVOMap = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getVerifyRule())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(verifyAttrVOMap)) {
         verifyAttrVOMap.forEach((attrId, attrVO) -> {
            String value = getValueFromOrderDTO(orderDTO, attrId);
            if (StringUtils.isNotBlank(value) && !value.matches(attrVO.getVerifyRule())) {
               //校验正则表达式
               throw new VciBaseException("属性[{0}]的值不符合校验规则的要求", new String[]{attrVO.getName()});
            }
         });
      }
   }
   /**
    * æ ¡éªŒå…³é”®å±žæ€§
    *
    * @param classifyFullInfo åˆ†ç±»çš„全部信息
    * @param templateVO       æ¨¡æ¿çš„内容,必须包含模板属性
    * @param orderDTO         ç¼–码申请的相关的信息
    */
   private void checkKeyAttrOnOrder(CodeClassifyFullInfoBO classifyFullInfo, CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      //先获取关键属性的规则,也利用继承的方式
      CodeKeyAttrRepeatVO keyRuleVO = keyRuleService.getRuleByClassifyFullInfo(classifyFullInfo);
      //注意的是keyRuleVO可能为空,表示不使用规则控制
      //获取所有的关键属性
      Map<String, CodeClassifyTemplateAttrVO> ketAttrMap = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getKeyAttrFlag())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      Map<String, String> conditionMap = new HashMap<>();
      boolean trimAll = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnoreallspaceflag());
      //全部去空的优先级大于去空
      boolean trim = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorespaceflag());
      boolean ignoreCase = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorecaseflag());
      boolean ignoreWidth = keyRuleVO == null ? false : VciBaseUtil.getBoolean(keyRuleVO.getIgnorewidthflag());
      ketAttrMap.forEach((attrId, attrVO) -> {
         String value = getValueFromOrderDTO(orderDTO, attrId);
         if (value == null) {
            value = "";
         }
         wrapperKeyAttrConditionMap(value, keyRuleVO, attrId, trim, ignoreCase, ignoreWidth, trimAll, conditionMap);
      });
      //没有限制分类,但是一个模板只可能在一个业务类型里面,所以直接查询这个业务类型即可
      if (!CollectionUtils.isEmpty(conditionMap)) {
         final String[] sql = {"select count(*) from " + VciBaseUtil.getTableName(classifyFullInfo.getTopClassifyVO().getBtmtypeid()) + " t where 1 = 1 "};
         conditionMap.forEach((key, value) -> {
            sql[0] += " and " + key + " = " + value;
         });
         if (StringUtils.isNotBlank(orderDTO.getOid())) {
            //修改的时候,需要排除自己
            sql[0] += " and oid != '" + orderDTO.getOid() + "'";
         } else if (StringUtils.isNotBlank(orderDTO.getCopyFromVersion())) {
            sql[0] += " and oid != '" + orderDTO.getCopyFromVersion() + "'";
         }
         sql[0] += " and islastR = '1' and islastV = '1' ";
//         if (boService.queryCountBySql(sql[0], new HashMap<>()) > 0) {
         if (Integer.parseInt(commonsMapper.selectById(sql[0]).get(0)) > 0) {
            String ruleInfoMsg = keyRuleVO == null ? "" : "查询规则:去除空格--{0},忽略大小写--{1},忽略全半角--{2},忽略全部空格--{3}";
            String[] objs = new String[]{trim ? "是" : "否", ignoreCase ? "是" : "否", ignoreWidth ? "是" : "否", trimAll ? "是" : "否"};
            throw new VciBaseException("根据您填写的关键属性的内容,结合关键属性查询规则,发现这个数据已经在系统中存在了。请修正!。" + ruleInfoMsg, objs);
         }
      }
   }
   /**
    * å°è£…关键属性的查询语句
    *
    * @param value        å½“前的值
    * @param keyRuleVO    å…³é”®å±žæ€§çš„æŽ§åˆ¶è§„则,可以为空
    * @param attrId       å±žæ€§çš„编号
    * @param trim         æ˜¯å¦åŽ»é™¤ç©ºæ ¼
    * @param ignoreCase   æ˜¯å¦ä¸åŒºåˆ†å¤§å°å†™
    * @param ignoreWidth  æ˜¯å¦å¿½ç•¥å…¨åŠè§’
    * @param trimAll      æ˜¯å¦å¿½ç•¥å…¨éƒ¨ç©ºæ ¼
    * @param conditionMap æŸ¥è¯¢æ¡ä»¶
    */
   @Override
   public void wrapperKeyAttrConditionMap(String value, CodeKeyAttrRepeatVO keyRuleVO, String attrId,
                                 boolean trim, boolean ignoreCase, boolean ignoreWidth,
                                 boolean trimAll, Map<String, String> conditionMap) {
      boolean ignoreSpace = trim || trimAll;
      if (StringUtils.isBlank(value)) {
         //为空的时候,不能用QueryOperation.ISNULL,平台不知道啥时候不处理这种了
         conditionMap.put("t."+attrId, "null");
      } else {
         if (keyRuleVO != null) {
            String queryKey = "";
            String queryValue = "";
            String temp = "";
            if (ignoreCase && ignoreSpace && ignoreWidth) {
               //忽略大小写,且去空,忽略全半角
               temp = (trimAll ? "REPLACE" : "TRIM") + "(UPPER(to_single_byte(%s)) " + (trimAll ? ",' ','')" : ")");
            } else if (ignoreCase && ignoreSpace && !ignoreWidth) {
               //忽略大小写、去空、不忽略全半角
               temp = (trimAll ? "REPLACE" : "TRIM") + "(UPPER(%s) " + (trimAll ? ",' ','')" : ")");
            } else if (ignoreCase && !ignoreSpace && ignoreWidth) {
               //忽略大小写、不去空、忽略全半角
               temp = "UPPER(to_single_byte(%s))";
            } else if (!ignoreCase && ignoreSpace && ignoreWidth) {
               //不忽略大小写、去空、忽略全半角
               temp = (trimAll ? "REPLACE" : "TRIM") + "(to_single_byte(%s) " + (trimAll ? ",' ','')" : ")");
            } else if (ignoreCase && !ignoreSpace && !ignoreWidth) {
               //忽略大小写、不去空、不忽略全半角
               temp = "UPPER(%s)";
            } else if (!ignoreCase && !ignoreCase && ignoreWidth) {
               //不忽略大小写、不去空、忽略全半角
               temp = "to_single_byte(%s)";
            } else if (!ignoreCase && ignoreSpace && !ignoreWidth) {
               //不忽略大小写、去空、不忽略全半角
               temp = (trimAll ? "REPLACE" : "TRIM") + "(%s " + (trimAll ? ",' ','')" : ")");
            } else if (!ignoreCase && !ignoreSpace && !ignoreWidth) {
               //不忽略大小写、不去空、不忽略全半角
               temp = "%s";
            }
            queryKey = String.format(temp, "t."+attrId);
            queryValue = String.format(temp, "'" + (trim ? value.trim() : value) + "'");
            conditionMap.put(queryKey, queryValue);
         } else {
            //为空的时候不代表不校验,只是不去除相关的信息
            conditionMap.put("t."+attrId, value);
         }
      }
   }
   /**
    * æ ¡éªŒæžšä¸¾çš„内容
    *
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡ï¼Œéœ€è¦åŒ…含属性
    * @param orderDTO   ç¼–码申请的信息
    */
   private void checkEnumOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      //如果枚举可以修改,则不需要校验是否符合枚举的选项
      Map<String, CodeClassifyTemplateAttrVO> enumAttrVOMap = templateVO.getAttributes().stream().filter(s -> (StringUtils.isNotBlank(s.getEnumString()) || StringUtils.isNotBlank(s.getEnumId())) && !VciBaseUtil.getBoolean(s.getEnumEditFlag())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(enumAttrVOMap)) {
         enumAttrVOMap.forEach((attrId, attrVO) -> {
            String value = getValueFromOrderDTO(orderDTO, attrId);
            if (StringUtils.isNotBlank(value)) {
               //有值才能校验
               List<KeyValue> comboboxKVs = listComboboxItems(attrVO);
               if (!comboboxKVs.stream().anyMatch(s -> value.equalsIgnoreCase(s.getKey()))) {
                  throw new VciBaseException("属性【{0}】的值不符合枚举的要求", new String[]{attrVO.getName()});
               }
            }
         });
      }
   }
   /**
    * è½¬æ¢æ—¶é—´çš„æ ¼å¼
    *
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡ï¼Œéœ€è¦åŒ…含属性
    * @param orderDTO   ç¼–码申请的信息
    */
   private void switchDateAttrOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
      Map<String, CodeClassifyTemplateAttrVO> dateAttrVOMap = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getCodeDateFormat())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      if (!CollectionUtils.isEmpty(dateAttrVOMap)) {
         dateAttrVOMap.forEach((attrId, attrVO) -> {
            String value = getValueFromOrderDTO(orderDTO, attrId);
            if (StringUtils.isNotBlank(value)) {
               DateConverter dateConverter = new DateConverter();
               dateConverter.setAsText(value);
               value = VciDateUtil.date2Str(dateConverter.getValue(), VciDateUtil.DateTimeMillFormat);
               setValueToOrderDTO(orderDTO, attrId, value);
            }
         });
      }
   }
   /**
    * æ‹·è´æ•°æ®åˆ°cbo对象上
    *
    * @param classifyFullInfo åˆ†ç±»çš„全部信息
    * @param cbo              ä¸šåŠ¡æ•°æ®
    * @param orderDTO         ç¼–码申请的信息
    * @param templateVO       æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    * @param edit             æ˜¯å¦ä¸ºä¿®æ”¹
    */
   private void copyValueToCBO(CodeClassifyFullInfoBO classifyFullInfo, CodeWupinEntity cbo,
                        CodeOrderDTO orderDTO, CodeClassifyTemplateVO templateVO,
                        boolean edit) {
      String fullPath = "";
      if (!CollectionUtils.isEmpty(classifyFullInfo.getParentClassifyVOs())) {
         fullPath = classifyFullInfo.getParentClassifyVOs().stream().sorted(((o1, o2) -> o2.getDataLevel().compareTo(o1.getDataLevel())))
            .map(CodeClassifyVO::getOid).collect(Collectors.joining("##"));
      } else {
         fullPath = classifyFullInfo.getCurrentClassifyVO().getOid();
      }
//      BeanUtils.
      BeanUtils.copyProperties(orderDTO.getData(),cbo);
      cbo.setMaterialtype(Short.valueOf("1001"));
//      orderDTO.getData().forEach((key, value) -> {
//         if (!edit || (!checkUnAttrUnEdit(key) &&
//            !VciQueryWrapperForDO.LC_STATUS_FIELD.equalsIgnoreCase(key))) {
//            try {
//               cbo.setAttributeValue(key, value);
//            } catch (Exception e) {
//               logger.error("设置属性的值错误", e);
//            }
//         }
//      });
      try {
         cbo.setCodeclsfid(classifyFullInfo.getCurrentClassifyVO().getOid());
         cbo.setCodetemplateoid(templateVO.getOid());
         cbo.setCodeclsfpath(fullPath);
//         cbo.setMaterialclassify("model_type");
//         cbo.setMaterialname(orderDTO.getData().get("materialname"));
//         cbo.setShifoupihaoguanli("true");
//         cbo.setKucunwl("true");
//         cbo.setXiaoshouwl("false");
         if (!edit && StringUtils.isBlank(orderDTO.getLcStatus())) {
            //找生命周期的起始状态,插个点,看生命周期是否需要创建
            if (StringUtils.isNotBlank(cbo.getLctid())) {
//               OsLifeCycleVO lifeCycleVO = lifeCycleService.getLifeCycleById(cbo.getLctid());
//               if (lifeCycleVO != null) {
//                  cbo.setLcStatus("Editing");
////                  cbo.setLcStatus(lifeCycleVO.getStartStatus());
//               } else {
                  cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
//               }
            } else {
               cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
            }
         }
         int secret = VciBaseUtil.getInt(cbo.getSecretGrade().toString());
         //插个点,后续看密级服务是否可用
//         if (secret == 0 || !secretService.checkDataSecret(secret)) {
         if (secret == 0 ) {
            Integer userSecret = VciBaseUtil.getCurrentUserSecret();
//            cbo.setAttributeValue(SECRET_FIELD, String.valueOf((userSecret == null || userSecret == 0) ? UserSecretEnum.NONE.getValue() : userSecret));
            cbo.setSecretGrade(userSecret == null || userSecret == 0 ? UserSecretEnum.NONE.getValue() : userSecret);
         }
      } catch (Throwable e) {
         logger.error("设置默认的属性的值错误", e);
      }
   }
   /**
    * åˆå§‹åŒ–业务类型
    * --创建人默认为当前用户,如果需要修改,可以在获取后自行处理
    * @param btmName ä¸šåŠ¡ç±»åž‹çš„åç§°ï¼Œä¼šè‡ªåŠ¨å˜æˆå°å†™
    * @return CodeWupinEntity
    * @throws VciBaseException åˆå§‹åŒ–出错的是会抛出异常
    */
   @Override
   public CodeWupinEntity createCBOByBtmName(String btmName)
      throws VciBaseException {
      if(btmName!=null){
         btmName = btmName.trim().toLowerCase();
      }
      String userid = AuthUtil.getUser().getUserName();
//      if(!hasCreatedCbos.containsKey(btmName)){
//         if(StringUtils.isEmpty(userid)){
//            throw new VciBaseException(msgCodePrefix +"noHasUserid");
//         }
//         try {
//            hasCreatedCbos.put(btmName, createBusinessObject(btmName));
//         } catch (Exception e) {
//            logger.error("创建业务类型对象",e);
//            throw new VciBaseException(msgCodePrefix + "initBoError",new String[]{btmName});
//         }
//      }
//      ClientBusinessObject cbo = cloneClientBusinessObject(hasCreatedCbos.get(btmName));
      QueryWrapper<CodeOsbtmtypeEntity> btmWrapper = new QueryWrapper<>();
      btmWrapper.eq("ID",btmName);
      CodeOsbtmtypeEntity btmTypeVO = codeOsbtmtypeMapper.selectOne(btmWrapper);
//      OsBtmTypeVO btmTypeVO = btmService.getBtmById(boName);
      String userName = AuthUtil.getUser().getUserName();
      CodeWupinEntity wupinEntity = new CodeWupinEntity();
      wupinEntity.setOid(null);
//      bo.setRevisionid((new ObjectUtility()).getNewObjectID36());
//      bo.setNameoid((new ObjectUtility()).getNewObjectID36());
      wupinEntity.setBtmname(btmName);
      wupinEntity.setLastR(String.valueOf(1));
      wupinEntity.setFirstR(String.valueOf(1));
      wupinEntity.setFirstV(String.valueOf(1));
      wupinEntity.setLastV(String.valueOf(1));
      wupinEntity.setCreator(userName);
      wupinEntity.setCreateTime(new Date());
      wupinEntity.setLastModifier(userName);
      wupinEntity.setLastModifyTime(new Date());
      wupinEntity.setRevisionRule(btmTypeVO.getRevisionruleid());
      wupinEntity.setVersionRule(String.valueOf(btmTypeVO.getVersionRule()));
      if(StringUtils.isNotBlank(btmTypeVO.getRevisionruleid())){
         //插个点,需要问勇哥版本问题,展示默认为1
//         OsRevisionRuleVO revisionRuleVO = revisionRuleService.getRevisionRuleById(btmTypeVO.getRevisionruleid());
         wupinEntity.setRevisionValue("1");
      }
      wupinEntity.setRevisionSeq(1);
      wupinEntity.setVersionSeq(1);
      //插个点,需要问勇哥版本问题,展示默认为1
      wupinEntity.setVersionValue("1");
      wupinEntity.setLctid("wupinLC");
      wupinEntity.setLcStatus("Editing");
      wupinEntity.setId("");
      wupinEntity.setName("");
      wupinEntity.setDescription("");
      wupinEntity.setOwner(userName);
      wupinEntity.setCheckinby(userName);
      wupinEntity.setCopyFromVersion("");
      wupinEntity.setMaterialtype((short) 1001);
      wupinEntity.setCaigouwl("true");
      wupinEntity.setShifoupihaoguanli("true");
      wupinEntity.setKucunwl("true");
      wupinEntity.setXiaoshouwl("false");
      wupinEntity.setPassing("true");
//      this.initTypeAttributeValue(wupinEntity,btmTypeVO);
      return wupinEntity;
//      return cbo;
   }
   /**
    * æ˜¯å¦ä¸ºä¿®æ”¹å¿½ç•¥çš„属性
    * @param attrName å±žæ€§çš„名字
    * @return true è¡¨ç¤ºåº”该忽略
    */
   boolean checkUnAttrUnEdit(String attrName){
      return  (VciQueryWrapperForDO.OID_FIELD.equalsIgnoreCase(attrName)
         ||"ts".equalsIgnoreCase(attrName)
         || "lastmodifier".equalsIgnoreCase(attrName)
         || "lastmodifytime".equalsIgnoreCase(attrName)
         || "createtime".equalsIgnoreCase(attrName)
         || "checkintime".equalsIgnoreCase(attrName)
         ||"checkouttime".equalsIgnoreCase(attrName));
   }
   /**
    * ä¿å­˜å¯è¾“可选的信息
    *
    * @param templateVO æ¨¡æ¿çš„对象
    * @param cboList    æ•°æ®çš„内容
    */
   @Override
   public void batchSaveSelectChar(CodeClassifyTemplateVO templateVO, /*List<ClientBusinessObject> cboList*/
                           List<String> cboList) {
      if (templateVO != null && !CollectionUtils.isEmpty(cboList)) {
         //是异步的,所以直接循环
         List<CodeClassifyTemplateAttrVO> selectAttrVOs = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getLibraryIdentification())).collect(Collectors.toList());
         if (!CollectionUtils.isEmpty(selectAttrVOs)) {
//            SessionInfo sessionInfo = VciBaseUtil.getCurrentUserSessionInfo();
            selectAttrVOs.parallelStream().forEach(attrVO -> {
               List<String> valuesList = cboList;
//               cboList.parallelStream().forEach(cbo -> {
//                  String value = cbo.get.getAttributeValue(attrVO.getId());
//                  if (StringUtils.isNotBlank(value)) {
//                     valuesList.add(value);
//                  }
//               });
               if (!CollectionUtils.isEmpty(valuesList)) {
                  for (String s : valuesList) {
                     DictBiz dictBiz = new DictBiz();
                     dictBiz.setCode(templateVO.getBtmTypeId());
                     dictBiz.setDictKey(s);
                     dictBiz.setDictValue(s);
                     //从原来的charService(可输可选)更改为调用omd中的接口来实现
                     iDictBizClient.getCheck(dictBiz);
                  }
//                  charService.saveBySameNamespaceAndFlag(templateVO.getBtmTypeId(), attrVO.getLibraryIdentification(), valuesList, sessionInfo);
               }
            });
         }
      }
   }
    @Override
    public MdmUIInfoVO getFormDefineByTemplateOid(String templateOid, String codeClassifyOid) {
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(templateOid);
      MdmUIInfoVO uiInfoVO = new MdmUIInfoVO();
      uiInfoVO.setTemplateVO(templateVO);
      uiInfoVO.setFormDefineVO(wrapperFormDefineByTemplate(templateVO, codeClassifyOid));
      wrapperResemble(templateVO, uiInfoVO);
      return uiInfoVO;
    }
   /**
    * æ¨¡æ¿å±žæ€§è½¬æ¢ä¸ºè¡¨å•定义的信息
    *
    * @param templateVO      æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    * @param codeClassifyOid åˆ†ç±»çš„主键,为空的时候,获取模板所属的分类主键.用于产生分类注入
    * @return è¡¨æ ¼çš„信息
    */
   private UIFormDefineVO wrapperFormDefineByTemplate(CodeClassifyTemplateVO templateVO, String codeClassifyOid) {
      UIFormDefineVO formDefineVO = new UIFormDefineVO();
      formDefineVO.setOid(templateVO.getOid());
      formDefineVO.setBtmType(templateVO.getBtmTypeId());
      if (StringUtils.isBlank(codeClassifyOid)) {
         codeClassifyOid = templateVO.getCodeclassifyoid();
      }
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      List<UIFormItemVO> itemVOS = new ArrayList<>();
      Map<String, List<CodeClassifyTemplateAttrVO>> attrGroupMap = templateVO.getAttributes().stream().
         filter(s -> StringUtils.isNotBlank(s.getAttributeGroup())).collect(Collectors.groupingBy(s -> s.getAttributeGroup()));
      templateVO.getAttributes().forEach(attrVO -> {
         UIFormItemVO formItemVO = templateAttr2FormField(attrVO, templateVO.getBtmTypeId());
         itemVOS.add(formItemVO);
      });
      //处理属性分组
      if (!CollectionUtils.isEmpty(attrGroupMap)) {
         //按照分组的属性排列,找到每一个分组的第一个属性
         for (String key : attrGroupMap.keySet()) {
            List<CodeClassifyTemplateAttrVO> value = attrGroupMap.get(key);
            //找到这个分组的属性的第一个
            CodeClassifyTemplateAttrVO attrVO = value.stream().sorted(((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()))).findFirst().get();
            //我们找到这个属性在最终的itemVOs里的位置
            UIFormItemVO lineVO = new UIFormItemVO();
            lineVO.setField(attrVO.getId() + "_line");
            lineVO.setType("line");
            lineVO.setText(key);
            //找位置
            for (int i = 0; i < itemVOS.size(); i++) {
               UIFormItemVO record = itemVOS.get(i);
               if (record.getField().equalsIgnoreCase(attrVO.getId())) {
                  itemVOS.add(i, lineVO);
                  break;
               }
            }
         }
      }
      CodeOrderDTO orderDTO = new CodeOrderDTO();
      switchClassifyLevelOnOrder(templateVO, classifyFullInfo, orderDTO);
      if (!CollectionUtils.isEmpty(orderDTO.getData())) {
         orderDTO.getData().forEach((key, value) -> {
            for (int i = 0; i < itemVOS.size(); i++) {
               UIFormItemVO itemVO = itemVOS.get(i);
               if (itemVO.getField().equalsIgnoreCase(key)) {
                  itemVO.setDefaultValue(value);
                  break;
               }
            }
         });
      }
      formDefineVO.setItems(itemVOS);
      //查询是否有分类注入的
      return formDefineVO;
   }
   /**
    * å±žæ€§ç±»åž‹ä¸Žjs中的字段类型的映射
    */
   private static Map<String, String> vciFieldTypeMap = new HashMap<String, String>() {{
      put(VciFieldTypeEnum.VTString.name(), "text");
      put(VciFieldTypeEnum.VTInteger.name(), "text");
      put(VciFieldTypeEnum.VTLong.name(), "text");
      put(VciFieldTypeEnum.VTDouble.name(), "text");
      put(VciFieldTypeEnum.VTClob.name(), "text");
      put(VciFieldTypeEnum.VTBoolean.name(), "truefalse");
      put(VciFieldTypeEnum.VTDateTime.name(), "datetime");
      put(VciFieldTypeEnum.VTDate.name(), "datetime");
      put(VciFieldTypeEnum.VTTime.name(), "datetime");
      put(VciFieldTypeEnum.VTFilePath.name(), "file");
   }};
   /**
    * æ¨¡æ¿å±žæ€§è½¬æ¢ä¸ºè¡¨å•的字段
    *
    * @param attrVO  æ¨¡æ¿å±žæ€§
    * @param btmType ä¸šåŠ¡ç±»åž‹
    * @return è¡¨å•的字段
    */
   @Override
   public UIFormItemVO templateAttr2FormField(CodeClassifyTemplateAttrVO attrVO, String btmType) {
      UIFormItemVO itemVO = new UIFormItemVO();
      if (SECRET_FILED.equalsIgnoreCase(attrVO.getId())) {
//         attrVO.setEnumid(OsEnumServiceImpl.MY_DATA_SECRET);
         attrVO.setEnumId(MY_DATA_SECRET);
      }
      itemVO.setField(attrVO.getId());
      itemVO.setText(attrVO.getName());
      itemVO.setType(vciFieldTypeMap.getOrDefault(attrVO.getAttributeDataType(), "text"));
      if (VciBaseUtil.getBoolean(attrVO.getTextAreaFlag())) {
         itemVO.setType("textarea");
      }
      if (VciFieldTypeEnum.VTLong.name().equalsIgnoreCase(attrVO.getAttributeDataType())
         || VciFieldTypeEnum.VTInteger.name().equalsIgnoreCase(attrVO.getAttributeDataType())
         || VciFieldTypeEnum.VTDouble.name().equalsIgnoreCase(attrVO.getAttributeDataType())) {
         itemVO.setVerify("number");
      }
      itemVO.setReadOnly(VciBaseUtil.getBoolean(attrVO.getReadOnlyFlag()));
      itemVO.setKeyAttr(VciBaseUtil.getBoolean(attrVO.getKeyAttrFlag()));
      itemVO.setRequired(VciBaseUtil.getBoolean(attrVO.getRequireFlag()));
      itemVO.setDefaultValue(attrVO.getDefaultValue());
      itemVO.setDateFormate(attrVO.getCodeDateFormat());
      itemVO.setHidden(!VciBaseUtil.getBoolean(attrVO.getFormDisplayFlag()));
      itemVO.setVerify(attrVO.getVerifyRule());
      itemVO.setPrefix(attrVO.getPrefixValue());
      itemVO.setSuffix(attrVO.getSuffixValue());
      itemVO.setTooltips(attrVO.getExplain());
      itemVO.setSelectLibFlag(attrVO.getLibraryIdentification());
      //看看是否有枚举
      if ((StringUtils.isNotBlank(attrVO.getEnumString())
         && !"[]".equalsIgnoreCase(attrVO.getEnumString())) ||
         StringUtils.isNotBlank(attrVO.getEnumId())) {
         itemVO.setType("combox");
         itemVO.setComboxKey(attrVO.getEnumId());
         if (StringUtils.isNotBlank(attrVO.getEnumString())) {
            //指定的下拉框内容
            itemVO.setData(JSONObject.parseArray(attrVO.getEnumString(), KeyValue.class));
            if (StringUtils.isBlank(attrVO.getEnumId())) {
               itemVO.setComboxKey(itemVO.getField() + "_data");
            }
         }
      }
      //看是否有参照
      if (StringUtils.isNotBlank(attrVO.getReferBtmId()) || StringUtils.isNotBlank(attrVO.getReferConfig())) {
         itemVO.setType("refer");
         itemVO.setShowField(itemVO.getField() + "name");
         if (StringUtils.isNotBlank(attrVO.getReferConfig())) {
            //配置的内容
            itemVO.setReferConfig(JSONObject.parseObject(attrVO.getReferConfig(), UIFormReferVO.class));
         } else {
            UIFormReferVO formReferVO = new UIFormReferVO();
            formReferVO.setType("default");
            formReferVO.setReferType(attrVO.getReferBtmId());
            itemVO.setReferConfig(formReferVO);
         }
      }
      //如果是组合规则,分类注入的,显示为只读
      if (StringUtils.isNotBlank(attrVO.getComponentRule())) {
         itemVO.setReadOnly(true);
         itemVO.setTooltips("本属性为组合规则");
         itemVO.setRequired(false);
      }
      if (StringUtils.isNotBlank(attrVO.getClassifyInvokeAttr())) {
         itemVO.setReadOnly(!VciBaseUtil.getBoolean(attrVO.getClassifyInvokeEditFlag()));
         itemVO.setTooltips("本属性是分类注入");
         itemVO.setRequired(false);
      }
      if (VciQueryWrapperForDO.LC_STATUS_FIELD.equalsIgnoreCase(itemVO.getField())) {
         //是生命周期状态
         itemVO.setType("combox");
         itemVO.setComboxKey(btmType + LC_STATUS_SUBFIX);
      }
      return itemVO;
   }
   /**
    * å°è£…相似项查询的列表
    *
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    * @param uiInfoVO   é¡µé¢çš„信息
    */
   private void wrapperResemble(CodeClassifyTemplateVO templateVO, MdmUIInfoVO uiInfoVO) {
      List<CodeClassifyTemplateAttrVO> resembleAttrList = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getSameRepeatAttrFlag())
         || VciQueryWrapperForDO.ID_FIELD.equalsIgnoreCase(s.getId())).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(resembleAttrList) && resembleAttrList.size() > 1) {
         UITableDefineVO resembleTable = new UITableDefineVO();
         resembleTable.setOid(templateVO.getOid());
         resembleTable.setBtmType(templateVO.getBtmTypeId());
         resembleTable.setDisplayQueryArea(false);
         resembleTable.setPageVO(new UITablePageVO());
         //处理所有的列,这个模板没有合并的表头的情况
         List<UITableFieldVO> fieldVOList = new ArrayList<>();
         resembleAttrList.forEach(attrVO -> {
            UITableFieldVO tableFieldVO = templateAttr2TableField(attrVO,false);
            tableFieldVO.setHidden(false);
            fieldVOList.add(tableFieldVO);
         });
         List<List<UITableFieldVO>> cols = new ArrayList<>();
         cols.add(fieldVOList);
         resembleTable.setCols(cols);
         uiInfoVO.setResembleTableVO(resembleTable);
      }
   }
   /**
    * æ¨¡æ¿å±žæ€§è½¬æ¢ä¸ºè¡¨æ ¼æ˜¾ç¤ºçš„配置
    *
    * @param attrVO æ¨¡æ¿å±žæ€§
    * @param forEdit æ˜¯å¦æ˜¯ç¼–辑所需
    * @return è¡¨æ ¼çš„字段
    */
   @Override
   public UITableFieldVO templateAttr2TableField(CodeClassifyTemplateAttrVO attrVO,boolean forEdit) {
      UITableFieldVO fieldVO = new UITableFieldVO();
      if (SECRET_FILED.equalsIgnoreCase(attrVO.getId())) {
         attrVO.setEnumId(MY_DATA_SECRET);
      }
      fieldVO.setField(attrVO.getId());
      fieldVO.setTitle(attrVO.getName());
      fieldVO.setFieldType(vciFieldTypeMap.getOrDefault(attrVO.getAttributeDataType(), "text"));
      fieldVO.setSort(true);
      fieldVO.setSortField(fieldVO.getField());
      fieldVO.setQueryField(fieldVO.getField());
      if (forEdit){
         fieldVO.setHidden(!VciBaseUtil.getBoolean(attrVO.getFormDisplayFlag()));
      }else {
         fieldVO.setHidden(!VciBaseUtil.getBoolean(attrVO.getTableDisplayFlag()));
      }
      if (attrVO.getAttrTableWidth() != null && attrVO.getAttrTableWidth() > 0) {
         fieldVO.setMinWidth(Integer.valueOf(attrVO.getAttrTableWidth()));
         fieldVO.setWidth(Integer.valueOf(attrVO.getAttrTableWidth()));
      }
      //看看是否有枚举
      if ((StringUtils.isNotBlank(attrVO.getEnumString())
         && !"[]".equalsIgnoreCase(attrVO.getEnumString())) ||
         StringUtils.isNotBlank(attrVO.getEnumId())) {
         fieldVO.setFieldType("combox");
         fieldVO.setField(fieldVO.getField() + "Text");
         fieldVO.setComboxKey(attrVO.getEnumId());
         if (StringUtils.isNotBlank(attrVO.getEnumString())) {
            //指定的下拉框内容
            fieldVO.setData(JSONObject.parseArray(attrVO.getEnumString(), KeyValue.class));
            if (StringUtils.isBlank(attrVO.getEnumId())) {
               fieldVO.setComboxKey(fieldVO.getField() + "_data");
            }
         }else {
//            List<KeyValue> osEnumItemVOList= enumService.getEnum(attrVO.getEnumId());
//            fieldVO.setData(osEnumItemVOList);
         }
      }
      //看是否有参照
      if (StringUtils.isNotBlank(attrVO.getReferBtmId()) || StringUtils.isNotBlank(attrVO.getReferConfig())) {
         fieldVO.setFieldType("refer");
         fieldVO.setQueryField(fieldVO.getField());
         fieldVO.setField(fieldVO.getField() + "name");
         fieldVO.setShowField(fieldVO.getField());
         if (StringUtils.isNotBlank(attrVO.getReferConfig())) {
            //配置的内容
            fieldVO.setReferConfig(JSONObject.parseObject(attrVO.getReferConfig(), UIFormReferVO.class));
         } else {
            UIFormReferVO formReferVO = new UIFormReferVO();
            formReferVO.setType("default");
            formReferVO.setReferType(attrVO.getReferBtmId());
            fieldVO.setReferConfig(formReferVO);
         }
      }
      if (VciQueryWrapperForDO.LC_STATUS_FIELD.equalsIgnoreCase(fieldVO.getSortField())) {
         fieldVO.setField("lcstatus_text");
      }
      Map<String, String> eventJsMap = new HashMap<>();
      //超链接与模板是互斥
      if (StringUtils.isNotBlank(attrVO.getTableHref())) {
         String event = fieldVO.getSortField() + "_href";
         eventJsMap.put(event, attrVO.getTableHref());
         fieldVO.setTemplet("function(d){ return '<a class=\"layui-btn layui-btn-intable \" lay-event=\"" + event + "\">d." + fieldVO.getField() + "</a>';}");
      }
      if (StringUtils.isNotBlank(attrVO.getTableDisplayJs())) {
         //直接写function(d){ return xxxxx;}
         fieldVO.setTemplet(attrVO.getTableDisplayJs());
      }
      if (StringUtils.isBlank(fieldVO.getTemplet()) && VciFieldTypeEnum.VTBoolean.name().equalsIgnoreCase(attrVO.getAttributeDataType())) {
         fieldVO.setTemplet("function(d){return $webUtil.formateBoolean(d." + fieldVO.getField() + ");}");
      }
      fieldVO.setOptionJsMap(eventJsMap);
      fieldVO.setStyle(attrVO.getTableDisplayStyle());
      //列表里不允许直接编辑
      fieldVO.setDateFormate(attrVO.getCodeDateFormat());
      return fieldVO;
   }
   /**
    * ç›¸ä¼¼é¡¹æŸ¥è¯¢
    *
    * @param orderDTO ç¼–码的相关信息
    * @return æ•°æ®åˆ—表
    */
   @Override
   public DataGrid<Map<String, String>> resembleQuery(CodeOrderDTO orderDTO) {
      VciBaseUtil.alertNotNull(orderDTO, "申请的信息", orderDTO.getCodeClassifyOid(), "分类主键", orderDTO.getTemplateOid(), "模板主键");
      CodeClassifyFullInfoBO fullInfoBO = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
      switchClassifyLevelOnOrder(templateVO, fullInfoBO, orderDTO);
      switchDateAttrOnOrder(templateVO, orderDTO);
      switchComponentAttrOnOrder(templateVO, orderDTO);
      //需要获取是否有相似查询属性
      Map<String, CodeClassifyTemplateAttrVO> attrVOs = templateVO.getAttributes().stream().filter(s -> VciBaseUtil.getBoolean(s.getSameRepeatAttrFlag())).collect(Collectors.toMap(s -> s.getId(), t -> t));
      if (CollectionUtils.isEmpty(attrVOs)) {
         //都没有属性,肯定不能查询了
         return new DataGrid<>();
      }
      Map<String, String> conditionMap = new HashMap<>();
      //我们首先获取有没有查询规则
      CodeResembleRuleVO resembleRuleVO = Optional.ofNullable(getUseResembleRule(fullInfoBO, fullInfoBO.getCurrentClassifyVO())).orElseGet(() -> new CodeResembleRuleVO());
      attrVOs.forEach((attrId, attrVO) -> {
         String value = getValueFromOrderDTO(orderDTO, attrId);
         if (value == null) {
            value = "";
         }
         wrapperResembleConditionMap(value, resembleRuleVO, attrId, conditionMap);
      });
      //没有限制分类,但是一个模板只可能在一个业务类型里面,所以直接查询这个业务类型即可
      if (!CollectionUtils.isEmpty(conditionMap)) {
         Map<String, String> andConditionMap = new HashMap<>();
         andConditionMap.put("islastr", "1");
         andConditionMap.put("islastv", "1");
         if (StringUtils.isNotBlank(orderDTO.getOid())) {
            andConditionMap.put("oid", QueryOptionConstant.NOTEQUAL + orderDTO.getOid());
         }
         conditionMap.putAll(andConditionMap);
         PageHelper pageHelper = new PageHelper(-1);
         pageHelper.addDefaultDesc("id");
         return queryGrid(fullInfoBO.getTopClassifyVO().getBtmtypeid(), templateVO, conditionMap, pageHelper);
      }
      return new DataGrid<>();
   }
   /**
    * èŽ·å–ä½¿ç”¨çš„ç›¸ä¼¼æŸ¥è¯¢è§„åˆ™
    *
    * @param fullInfoBO        ç±»å…¨éƒ¨ä¿¡æ¯
    * @param currentClassifyVO å½“前的分类
    * @return è§„则,如果不存在会返回Null
    */
   @Override
   public CodeResembleRuleVO getUseResembleRule(CodeClassifyFullInfoBO fullInfoBO, CodeClassifyVO currentClassifyVO) {
      if (currentClassifyVO == null) {
         return null;
      }
      if (currentClassifyVO != null && StringUtils.isNotBlank(currentClassifyVO.getCodeResembleRuleOid())) {
         //说明已经存在
         return resembleRuleService.getObjectByOid(currentClassifyVO.getCodeResembleRuleOid());
      }
      if (StringUtils.isBlank(currentClassifyVO.getParentcodeclassifyoid())) {
         return null;
      }
      Map<String, CodeClassifyVO> classifyVOMap = fullInfoBO.getParentClassifyVOs().stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
      return getUseResembleRule(fullInfoBO, classifyVOMap.getOrDefault(currentClassifyVO.getParentcodeclassifyoid(), null));
   }
   /**
    * å°è£…相似项查询的查询条件的映射
    *
    * @param value          å€¼
    * @param resembleRuleVO ç›¸ä¼¼é¡¹è§„则
    * @param attrId         å±žæ€§çš„编号
    * @param conditionMap   æŸ¥è¯¢æ¡ä»¶
    */
   @Override
   public void wrapperResembleConditionMap(String value, CodeResembleRuleVO resembleRuleVO, String attrId, Map<String, String> conditionMap) {
      boolean ignoreSpace = VciBaseUtil.getBoolean(resembleRuleVO.getIgnorespaceflag()) || VciBaseUtil.getBoolean(resembleRuleVO.getIgnoreallspaceflag());
      if (StringUtils.isBlank(value)) {
         //为空的时候就不查询它就是
      } else {
         String queryKey = "";
         String queryValue = "";
         boolean ignoreCase = VciBaseUtil.getBoolean(resembleRuleVO.getIgnorecaseflag());
         boolean ignoreWidth = VciBaseUtil.getBoolean(resembleRuleVO.getIgnorewidthflag());
         boolean trimAll = VciBaseUtil.getBoolean(resembleRuleVO.getIgnoreallspaceflag());
         boolean trim = VciBaseUtil.getBoolean(resembleRuleVO.getIgnoreallspaceflag());
         String temp = "";
         if (ignoreCase && ignoreSpace && ignoreWidth) {
            //忽略大小写,且去空,忽略全半角
            temp = (trimAll ? "REPLACE" : "TRIM") + "(UPPER(to_single_byte('%s')) " + (trimAll ? ",' ','')" : ")");
         } else if (ignoreCase && ignoreSpace && !ignoreWidth) {
            //忽略大小写、去空、不忽略全半角
            temp = (trimAll ? "REPLACE" : "TRIM") + "(UPPER(%s) " + (trimAll ? ",' ','')" : ")");
         } else if (ignoreCase && !ignoreSpace && ignoreWidth) {
            //忽略大小写、不去空、忽略全半角
            temp = "UPPER(to_single_byte('%s'))";
         } else if (!ignoreCase && ignoreSpace && ignoreWidth) {
            //不忽略大小写、去空、忽略全半角
            temp = (trimAll ? "REPLACE" : "TRIM") + "(to_single_byte('%s') " + (trimAll ? ",' ','')" : ")");
         } else if (ignoreCase && !ignoreSpace && !ignoreWidth) {
            //忽略大小写、不去空、不忽略全半角
            temp = "UPPER(%s)";
         } else if (!ignoreCase && !ignoreCase && ignoreWidth) {
            //不忽略大小写、不去空、忽略全半角
            temp = "to_single_byte('%s')";
         } else if (!ignoreCase && ignoreSpace && !ignoreWidth) {
            //不忽略大小写、去空、不忽略全半角
            temp = (trimAll ? "REPLACE" : "TRIM") + "(%s " + (trimAll ? ",' ','')" : ")");
         } else if (!ignoreCase && !ignoreSpace && !ignoreWidth) {
            //不忽略大小写、不去空、不忽略全半角
            temp = "%s";
         }
         if (StringUtils.isNotBlank(resembleRuleVO.getLinkCharacter())) {
            List<String> chars = VciBaseUtil.str2List(resembleRuleVO.getLinkCharacter());
            for (int i = 0; i < chars.size(); i++) {
               String s = chars.get(i);
               temp = "replace(" + temp + ",'" + s + "','')";
            }
         }
         queryValue = String.format(temp, (trim ? value.trim() : value));
         temp = temp.replace("to_single_byte('%s')","to_single_byte(%s)");
         queryKey = String.format(temp, "t."+attrId);
         conditionMap.put(queryKey, QueryOptionConstant.OR + queryValue);
      }
   }
   /**
    * æŸ¥è¯¢ç¼–码数据的列表
    *
    * @param btmType      ä¸šåŠ¡ç±»åž‹
    * @param templateVO   æ¨¡æ¿çš„对象,需要包含模板的属性
    * @param conditionMap æŸ¥è¯¢æ¡ä»¶
    * @param pageHelper   åˆ†é¡µå¯¹è±¡
    * @return æ•°æ®åˆ—表
    */
   @Override
   public DataGrid<Map<String, String>> queryGrid(String btmType, CodeClassifyTemplateVO templateVO, Map<String, String> conditionMap, PageHelper pageHelper) {
      CodeTemplateAttrSqlBO sqlBO = getSqlByTemplateVO(btmType, templateVO, conditionMap, pageHelper);
//      List<Map> maps = boService.queryByOnlySqlForMap(sqlBO.getSqlHasPage());
      List<Map> maps = commonsMapper.selectBySql(sqlBO.getSqlHasPage());
      DataGrid<Map<String, String>> dataGrid = new DataGrid<>();
      List<Map<String, String>> dataList = new ArrayList<>();
      if (!CollectionUtils.isEmpty(maps)) {
         maps.stream().forEach(map -> {
            Map<String, String> data = new HashMap<>();
            map.forEach((key, value) -> {
               data.put(((String) key).toLowerCase(Locale.ROOT), (String) value);
            });
            dataList.add(data);
         });
      }
      dataGrid.setData(dataList);
      if (!CollectionUtils.isEmpty(dataList)) {
         wrapperData(dataGrid.getData(), templateVO, sqlBO.getSelectFieldList(), false);
         dataGrid.setTotal(Long.parseLong(commonsMapper.selectBySql(sqlBO.getSqlCount()).get(0).values().toArray()[0].toString()));
      }
      return dataGrid;
   }
   /**
    * å°è£…查询出来的数据
    *
    * @param dataMap              æ•°æ®çš„æ˜ å°„
    * @param templateVO           æ¨¡æ¿çš„属性
    * @param onlySelectAttrIdList ä»…仅查询的属性字段
    * @param form è¡¨å•里使用
    */
   @Override
   public void wrapperData(List<Map<String, String>> dataMap, CodeClassifyTemplateVO templateVO,
                     Collection<String> onlySelectAttrIdList, boolean form) {
      if (onlySelectAttrIdList == null) {
         onlySelectAttrIdList = new ArrayList<>();
      }
      //先转换一下时间格式
      List<String> finalOnlySelectAttrIdList = onlySelectAttrIdList.stream().collect(Collectors.toList());
      List<CodeClassifyTemplateAttrVO> dateFormatAttrVOs = templateVO.getAttributes().stream().filter(
         s -> StringUtils.isNotBlank(s.getCodeDateFormat()) &&
            (finalOnlySelectAttrIdList.size() == 0 || finalOnlySelectAttrIdList.contains(s.getId().toLowerCase(Locale.ROOT)))
      ).collect(Collectors.toList());
      //枚举的内容
      List<CodeClassifyTemplateAttrVO> enumAttrVOs = templateVO.getAttributes().stream().filter(
         s -> (StringUtils.isNotBlank(s.getEnumId()) || StringUtils.isNotBlank(s.getEnumString()))
            &&
            (finalOnlySelectAttrIdList.size() == 0 || finalOnlySelectAttrIdList.contains(s.getId().toLowerCase(Locale.ROOT)))
      ).collect(Collectors.toList());
      List<String> userIds = new ArrayList<>();
      dataMap.stream().forEach(data -> {
         //处理时间
         if (!form) {
            //表单的时候只能用统一的时间格式
            wrapperDateFormat(dateFormatAttrVOs, data);
         }
         //处理枚举
         wrapperEnum(enumAttrVOs, data);
         String lcstatus = data.get(VciQueryWrapperForDO.LC_STATUS_FIELD);
         String copyFromVersion = data.getOrDefault(COPY_FROM_VERSION,"");
         if ((CodeDefaultLC.EDITING.getValue().equalsIgnoreCase(lcstatus) || CodeDefaultLC.AUDITING.getValue().equalsIgnoreCase(lcstatus))
            && StringUtils.isBlank(copyFromVersion)
         ) {
            data.put(VciQueryWrapperForDO.ID_FIELD, "******");
         }
         data.put(VciQueryWrapperForDO.LC_STATUS_FIELD_TEXT.toLowerCase(Locale.ROOT), CodeDefaultLC.getTextByValue(lcstatus));
         if(CodeDefaultLC.EDITING.getValue().equalsIgnoreCase(lcstatus)
            && StringUtils.isNotBlank(copyFromVersion)){
            data.put(VciQueryWrapperForDO.LC_STATUS_FIELD_TEXT.toLowerCase(Locale.ROOT), "修改中");
         }
         if (data.containsKey("creator")) {
            userIds.add(data.get("creator"));
         }
         if (data.containsKey("lastmodifier")) {
            userIds.add(data.get("lastmodifier"));
         }
      });
      if (!CollectionUtils.isEmpty(userIds)) {
//         Map<String, SmUserVO> userVOMap = Optional.ofNullable(userQueryService.listUserByUserIds(userIds)).orElseGet(() -> new ArrayList<>()).stream().collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
//         dataMap.stream().forEach(data -> {
//            String creator = data.getOrDefault("creator", null);
//            if (StringUtils.isNotBlank(creator) && userVOMap.containsKey(creator.toLowerCase(Locale.ROOT))) {
//               data.put("creator", creator + "(" + userVOMap.get(creator.toLowerCase(Locale.ROOT)).getName() + ")");
//            }
//            String lastmodifier = data.getOrDefault("lastmodifier", null);
//            if (StringUtils.isNotBlank(lastmodifier) && userVOMap.containsKey(lastmodifier.toLowerCase(Locale.ROOT))) {
//               data.put("lastmodifier", lastmodifier + "(" + userVOMap.get(lastmodifier.toLowerCase(Locale.ROOT)).getName() + ")");
//            }
//         });
      }
   }
   /**
    * å¤„理时间格式
    *
    * @param dateFormatAttrVOs æ—¶é—´æ ¼å¼çš„属性
    * @param data              å½“前行数据
    */
   private void wrapperDateFormat(Collection<CodeClassifyTemplateAttrVO> dateFormatAttrVOs, Map<String, String> data) {
      if (!CollectionUtils.isEmpty(dateFormatAttrVOs)) {
         dateFormatAttrVOs.stream().forEach(dateFormatAttrVO -> {
            String attrId = dateFormatAttrVO.getId().toLowerCase(Locale.ROOT);
            String oldValue = data.getOrDefault(attrId, null);
            if (StringUtils.isNotBlank(oldValue)) {
               DateConverter dateConverter = new DateConverter();
               try {
                  dateConverter.setAsText(oldValue);
                  Date value = dateConverter.getValue();
                  if (value != null) {
                     data.put(attrId, VciDateUtil.date2Str(value, dateFormatAttrVO.getCodeDateFormat()));
                  }
               } catch (Throwable e) {
                  //转换可能有问题,这就使用原本存储的值
               }
            }
         });
      }
   }
   /**
    * å¤„理枚举的内容,如果不在枚举中,会返回原本的值
    *
    * @param enumAttrVOs æžšä¸¾å±žæ€§
    * @param data        å½“前行数据
    */
   private void wrapperEnum(Collection<CodeClassifyTemplateAttrVO> enumAttrVOs, Map<String, String> data) {
      //处理枚举的内容,为了兼容以前的数据,如果数据不能使用枚举转换的话,那还是显示以前的值
      if (!CollectionUtils.isEmpty(enumAttrVOs)) {
         enumAttrVOs.stream().forEach(enumAttrVO -> {
            String attrId = enumAttrVO.getId().toLowerCase(Locale.ROOT);
            String oldValue = data.getOrDefault(attrId, null);
            if (StringUtils.isNotBlank(oldValue)) {
               List<KeyValue> comboxKVs = listComboboxItems(enumAttrVO);
               String newValue = oldValue;
               KeyValue keyValue = Optional.ofNullable(comboxKVs).orElseGet(() -> new ArrayList<>()).stream().filter(s -> s.getKey().equalsIgnoreCase(oldValue)).findFirst().orElseGet(() -> null);
               if (keyValue != null) {
                  newValue = keyValue.getValue();
               }
               data.put(attrId + "Text", newValue);
            }
         });
      }
   }
   /**
    * æ ¹æ®æ¨¡æ¿å±žæ€§ç”Ÿæˆç›¸åº”çš„sql信息
    *
    * @param btmType      ä¸šåŠ¡ç±»åž‹
    * @param templateVO   æ¨¡æ¿æ˜¾ç¤ºå¯¹è±¡ï¼Œå¿…须包含属性
    * @param conditionMap æŸ¥è¯¢æ¡ä»¶
    * @param pageHelper   åˆ†é¡µå’ŒæŽ’序对象
    * @return sql的相关信息
    */
   @Override
   public CodeTemplateAttrSqlBO getSqlByTemplateVO(String btmType, CodeClassifyTemplateVO templateVO, Map<String, String> conditionMap, PageHelper pageHelper) {
      //因为参照不一定是在平台的属性池里面设置,所以我们得需要自行处理
      //参考VciQueryWrapper来处理
      //1. æ‰¾åˆ°æ‰€æœ‰çš„字段,
      Map<String, CodeClassifyTemplateAttrVO> attrVOMap = templateVO.getAttributes().stream().collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
      List<String> selectFieldList = attrVOMap.keySet().stream().collect(Collectors.toList());
      //所有的参照的字段
      Map<String/**属性字段**/, String> joinTableList = new ConcurrentHashMap<>();
      List<CodeClassifyTemplateAttrVO> referAttrVOs = templateVO.getAttributes().stream().filter(
         s -> StringUtils.isNotBlank(s.getReferBtmId()) || StringUtils.isNotBlank(s.getReferConfig())
      ).collect(Collectors.toList());
      Map<String/**参照的属性**/, String/**实际的字段**/> referFieldMap = new HashMap<>();
      if (!CollectionUtils.isEmpty(referAttrVOs)) {
         referAttrVOs.parallelStream().forEach(attrVO -> {
            UIFormReferVO referVO = null;
            if (StringUtils.isNotBlank(attrVO.getReferConfig())) {
               referVO = JSONObject.parseObject(attrVO.getReferConfig(), UIFormReferVO.class);
            } else {
               referVO = new UIFormReferVO();
               referVO.setReferType(attrVO.getReferBtmId());
               referVO.setValueField(VciQueryWrapperForDO.OID_FIELD);
               referVO.setTextField("name");
            }
            String referTable = VciBaseUtil.getTableName(referVO.getReferType());
            String referTableNick = attrVO.getId() + "0";
            String left = " left join " + referTable + " " + referTableNick + " on " + referTableNick + "." + referVO.getValueField() + " =  t." + attrVO.getId();
            joinTableList.put(attrVO.getId(), left);
            String referShowField = attrVO.getId() + "Name";
            List<String> textFields = VciBaseUtil.str2List(referVO.getTextField());
            String showFieldInSource = "";
            if (textFields.contains("name")) {
               showFieldInSource = "name";
            } else {
               showFieldInSource = textFields.get(0);
            }
            referFieldMap.put(attrVO.getId(), referTableNick + "." + showFieldInSource);
            selectFieldList.add(referTableNick + "." + showFieldInSource + " as " + referShowField);
         });
      }
      Optional.ofNullable(attributeService.getDefaultAttributeVOMap()).orElseGet(() -> new HashMap<>()).keySet().stream().forEach(attrId -> {
         if (!selectFieldList.contains(attrId) && !"secretgrade".equalsIgnoreCase(attrId)) {
            selectFieldList.add(attrId);
         }
      });
      if (!selectFieldList.contains(CODE_FIELD)) {
         selectFieldList.add(CODE_FIELD);
      }
      if (!selectFieldList.contains(CODE_CLASSIFY_OID_FIELD)) {
         selectFieldList.add(CODE_CLASSIFY_OID_FIELD);
      }
      if (!selectFieldList.contains(CODE_TEMPLATE_OID_FIELD)) {
         selectFieldList.add(CODE_TEMPLATE_OID_FIELD);
      }
      if (!selectFieldList.contains(CODE_FULL_PATH_FILED)) {
         selectFieldList.add(CODE_FULL_PATH_FILED);
      }
      //处理查询条件
      //TODO éªŒè¯sql注入
      List<String> andSql = new ArrayList<>();
      List<String> orSql = new ArrayList<>();
      if (!CollectionUtils.isEmpty(conditionMap)) {
         Map<String, String> orConditionMap = new HashMap<>();
         Map<String, String> andCondtionMap = new HashMap<>();
         //先分离or的查询条件,另外当查询条件是空的时候也不查询
         conditionMap.forEach((k, v) -> {
            if (StringUtils.isNotBlank(v)) {
               if (v.startsWith(QueryOptionConstant.OR)) {
                  orConditionMap.put(k, v.substring(QueryOptionConstant.OR.length()));
               } else {
                  andCondtionMap.put(k, v);
               }
            }
         });
         andCondtionMap.forEach((k, v) -> {
            andSql.add(getConditionSql(k.toLowerCase(), v, referFieldMap, attrVOMap));
         });
         orConditionMap.forEach((k, v) -> {
            orSql.add(getConditionSql(k.toLowerCase(), v, referFieldMap, attrVOMap));
         });
      }
      //组合起来
      StringBuilder andSb = new StringBuilder();
      andSql.stream().forEach(s -> {
         andSb.append(s).append(SPACE).append(QueryOptionConstant.AND).append(SPACE);
      });
      String andString = andSb.toString().trim();
      String endWithSql = QueryOptionConstant.AND;
      if (andString.endsWith(endWithSql)) {
         andString = andString.substring(0, andString.length() - endWithSql.length());
      }
      String orString = orSql.stream().collect(Collectors.joining(" or "));
      String whereSql = "";
      if (StringUtils.isNotBlank(orString)) {
         if (StringUtils.isBlank(andString)) {
            andString = " 1 = 1 ";
         }
         whereSql = SPACE + "(" + SPACE + andString + SPACE + ") and (" + SPACE + orString + SPACE + ")" + SPACE;
      } else {
         whereSql = andString + SPACE;
      }
      if (attrVOMap.keySet().contains("secretgrade")) {
         Integer userSecret = VciBaseUtil.getCurrentUserSecret();
         if (userSecret == null || userSecret == 0) {
//            userSecret = secretService.getMinUserSecret();
         }
         whereSql += " and ( t.secretGrade <= " + userSecret + ") ";
      }
      String tableName = VciBaseUtil.getTableName(btmType);
      String sql = "select " + selectFieldList.stream().map(s -> (s.contains(".") ? s : ("t." + s))).collect(Collectors.joining(","))
         + " from " + tableName + SPACE + "t" + SPACE
         + joinTableList.values().stream().collect(Collectors.joining(SPACE))
         + (StringUtils.isBlank(whereSql) ? "" : " where ") + whereSql;
      if (pageHelper == null) {
         pageHelper = new PageHelper(-1);
      }
      //看看排序
      String orderSql = pageHelper.getOrderSql("t");
      sql += (orderSql == null ? "" : orderSql);
      String whereSubfixForPage = " ) A where rownum < " + (pageHelper.getLimit() * pageHelper.getPage() + 1) + ") where RN >= "
         + (pageHelper.getLimit() * (pageHelper.getPage() - 1) + 1);
      String sqlHasPage = pageHelper.getLimit() > 0 ? ("select * from (select A.*,rownum RN from (" + sql + whereSubfixForPage) : sql;
      String sqlCount = "select count(1) from " + tableName + SPACE + "t" + SPACE + joinTableList.values().stream().collect(Collectors.joining(SPACE))
         + (StringUtils.isBlank(whereSql) ? "" : " where ") + whereSql;
      CodeTemplateAttrSqlBO sqlBO = new CodeTemplateAttrSqlBO();
      sqlBO.setTableName(tableName);
      sqlBO.setJoinTable(joinTableList);
      sqlBO.setNickName("t");
//      sqlBO.setPageHelper(pageHelper);
      sqlBO.setSqlHasPage(sqlHasPage);
      sqlBO.setSqlCount(sqlCount);
      sqlBO.setSqlUnPage(sql);
      return sqlBO;
   }
   /**
    * ç»„合查询条件的sql
    *
    * @param key           å­—段
    * @param value         åå­—
    * @param referFieldMap å‚照的字段
    * @param attrVOMap     å±žæ€§çš„æ˜ å°„
    * @return Sql语句
    */
   private String getConditionSql(String key, String value, Map<String/**参照的属性**/, String/**实际的属性**/> referFieldMap, Map<String, CodeClassifyTemplateAttrVO> attrVOMap) {
      if (key.endsWith("_begin")) {
         //说明是>=的。我们需要先获取一下
         String field = (key.substring(0, key.length() - 6).toLowerCase().trim());
         if (referFieldMap.containsKey(field)) {
            //说明还是参照里面的,我们默认这种情况下都是字符串吧,因为参照的属性不一定用的平台的属性池里的,所以大部分情况下,显示的属性都是字符串吧
            return referFieldMap.get(field) + SPACE + " >= '" + value + "'" + SPACE;
         } else {
            return (field.contains(".") ? "" : "t.") + field + SPACE + " >= " + getStringValueInWhere(value, field, attrVOMap);
         }
      } else if (key.endsWith("_end")) {
         //说明是<=的。我们需要先获取一下
         String field = (key.substring(0, key.length() - 6).toLowerCase().trim());
         if (referFieldMap.containsKey(field)) {
            //说明还是参照里面的,我们默认这种情况下都是字符串吧,因为参照的属性不一定用的平台的属性池里的,所以大部分情况下,显示的属性都是字符串吧
            return referFieldMap.get(field) + SPACE + " <= '" + value + "'" + SPACE;
         } else {
            return (field.contains(".") ? "" : "t.") + field + SPACE + " <= " + getStringValueInWhere(field, value, attrVOMap);
         }
      } else {
         if (referFieldMap.containsKey(key)) {
            //说明是参照的,我们参照的查询都认为是字符串,如果是时间格式的查询肯定有问题,
            String selectKey = referFieldMap.get(key);
            return getSqlByValue(selectKey, value, null);
         } else {
            return getSqlByValue(key, value, attrVOMap);
         }
      }
   }
   /**
    * èŽ·å–æŸ¥è¯¢æ¡ä»¶ä¸­çš„å€¼çš„ï¼Œå¤„ç†ä¸åŒçš„ç±»åž‹
    *
    * @param value å€¼
    * @param field å­—段名称
    * @return æ—¥æœŸæˆ–者时间格式会包括to_date,字符串会加'
    */
   private String getStringValueInWhere(String field, String value, Map<String, CodeClassifyTemplateAttrVO> attrVOMap) {
      if ((field.contains(".") && !field.toLowerCase(Locale.ROOT).startsWith("t.")) || attrVOMap == null
         || !field.replace("t.", "").matches(RegExpConstant.LETTER) || value.startsWith(ONLY)) {
         //说明可能是指定的某个条件,直接返回
         if (value.startsWith(ONLY)) {
            value = value.replace(ONLY, "");
         }
         if ((value.startsWith("(") && value.endsWith(")")) || (value.startsWith("'") && value.endsWith("'"))) {
            return value;
         }
         if (field.contains(".") && attrVOMap != null && attrVOMap.containsKey(field.split("\\.")[0].toLowerCase(Locale.ROOT))) {
            //是参照
            return "'" + value + "'";
         } else {
            return value;
         }
      } else {
         //看看是不是这个对象里的属性
         if (attrVOMap.containsKey(field)) {
            VciFieldTypeEnum fieldTypeEnum = VciFieldTypeEnum.valueOf(attrVOMap.get(field).getAttributeDataType());
            if ("ts".equalsIgnoreCase(field)) {
               return "to_timestamp('" + value + "', '" + DATETIME_FORMAT + ".ff')";
            }
            DateConverter dateConverter = new DateConverter();
            if (VciFieldTypeEnum.VTDateTime.equals(fieldTypeEnum)) {
               //实际上,数据库都是timestamp的类型.
               dateConverter.setAsText(value);
               return "to_date('" + dateConverter.getAsText(VciDateUtil.DateTimeFormat) + "','" + DATETIME_FORMAT + "')";
            } else if (VciFieldTypeEnum.VTDate.equals(fieldTypeEnum)) {
               dateConverter.setAsText(value);
               return "to_date('" + dateConverter.getAsText(VciDateUtil.DateFormat) + "','" + DATE_FORMAT + "')";
            } else if (VciFieldTypeEnum.VTDouble.equals(fieldTypeEnum)
               || VciFieldTypeEnum.VTLong.equals(fieldTypeEnum)
               || VciFieldTypeEnum.VTInteger.equals(fieldTypeEnum)) {
               return value;
            } else {
               return "'" + value + "'";
            }
         } else {
            if ((value.startsWith("(") && value.endsWith(")")) || (value.startsWith("'") && value.endsWith("'"))) {
               return value;
            }
            return "'" + value + "'";
         }
      }
   }
   /**
    * å°è£…最终的sql语句中的值部分
    *
    * @param selectKey æŸ¥è¯¢çš„字段
    * @param value     å€¼
    * @param attrVOMap å±žæ€§çš„æ˜¾ç¤ºå¯¹è±¡æ˜ å°„
    * @return sql里的值
    */
   private String getSqlByValue(String selectKey, String value, Map<String, CodeClassifyTemplateAttrVO> attrVOMap) {
      StringBuilder sql = new StringBuilder();
      if (!selectKey.contains(".") && (attrVOMap.containsKey(selectKey.toLowerCase(Locale.ROOT)) || attributeService.isDefaultAttr(selectKey) || selectKey.matches(RegExpConstant.LETTER))) {
         sql.append("t.");
      }
      if (value.startsWith(QueryOptionConstant.IN)) {
         sql.append(selectKey)
            .append(SPACE)
            .append("in")
            .append(SPACE)
            .append("(")
            .append(value.replace(QueryOptionConstant.IN, ""))
            .append(")");
      } else if (value.startsWith(QueryOptionConstant.NOTIN)) {
         sql.append(selectKey)
            .append(SPACE)
            .append("not in")
            .append(SPACE)
            .append("(")
            .append(value.replace(QueryOptionConstant.NOTIN, ""))
            .append(")");
      } else if (value.startsWith(QueryOptionConstant.NOTEQUAL)) {
         value = value.replace(QueryOptionConstant.NOTEQUAL, "");
         value = getStringValueInWhere(selectKey, value, attrVOMap);
         sql.append(selectKey)
            .append(SPACE)
            .append(QueryOptionConstant.NOTEQUAL)
            .append(SPACE)
            .append(value);
      } else if (value.startsWith(QueryOptionConstant.MORETHAN)) {
         value = value.replace(QueryOptionConstant.MORETHAN, "");
         value = getStringValueInWhere(selectKey, value, attrVOMap);
         sql.append(selectKey)
            .append(SPACE)
            .append(QueryOptionConstant.MORETHAN)
            .append(SPACE)
            .append(value);
      } else if (value.startsWith(QueryOptionConstant.MORE)) {
         value = value.replace(QueryOptionConstant.MORE, "");
         value = getStringValueInWhere(selectKey, value, attrVOMap);
         sql.append(selectKey)
            .append(SPACE)
            .append(QueryOptionConstant.MORE)
            .append(SPACE)
            .append(value);
      } else if (value.startsWith(QueryOptionConstant.LESSTHAN)) {
         value = value.replace(QueryOptionConstant.LESSTHAN, "");
         value = getStringValueInWhere(selectKey, value, attrVOMap);
         sql.append(selectKey)
            .append(SPACE)
            .append(QueryOptionConstant.LESSTHAN)
            .append(SPACE)
            .append(value);
      } else if (value.startsWith(QueryOptionConstant.LESS)) {
         value = value.replace(QueryOptionConstant.LESS, "");
         value = getStringValueInWhere(selectKey, value, attrVOMap);
         sql.append(selectKey)
            .append(SPACE)
            .append(QueryOptionConstant.LESS)
            .append(SPACE)
            .append(value);
      } else if (value.startsWith(QueryOptionConstant.ISNOTNULL)) {
         sql.append(selectKey)
            .append(SPACE)
            .append(" is not null");
      } else if (value.startsWith(QueryOptionConstant.ISNULL)) {
         sql.append(selectKey)
            .append(SPACE)
            .append(" is null");
      } else if (value.contains("*")) {
         //说明是like,或者lefe like ,right like
         value = getStringValueInWhere(selectKey, value, attrVOMap);
         sql.append(selectKey)
            .append(SPACE)
            .append("like")
            .append(SPACE)
            //   .append("'")
            .append(value.replace("*", "%"))
            //  .append("'")
            .append(SPACE);
      } else {
         value= value.replace(SPECIAL_CHAR,REQUIRED_CHAR);
         value = getStringValueInWhere(selectKey, value, attrVOMap);
         sql.append(selectKey)
            .append(SPACE)
            .append(QueryOptionConstant.EQUAL)
            .append(SPACE)
            .append(value);
      }
      sql.append(SPACE);
      return sql.toString();
   }
   /**
    * ä¿®æ”¹ä¸»é¢˜åº“数据
    *
    * @param orderDTO æ•°æ®çš„内容,不用包含码段的内容了
    */
   @Override
   public void editSaveCode(CodeOrderDTO orderDTO) {
      VciBaseUtil.alertNotNull(orderDTO, "编码申请相关的属性的内容都为空", orderDTO.getOid(), "数据主键",
         orderDTO.getCodeClassifyOid(), "主题库分类的主键");
//      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
      //找业务类型,然后使用主键去获取数据库里的数据
//      List<ClientBusinessObject> cbos = boService.queryCBO(classifyFullInfo.getTopClassifyVO().getBtmtypeid(), WebUtil.getOidQuery(orderDTO.getOid()));
      QueryWrapper<CodeWupinEntity> btmWrapper = new QueryWrapper<>();
      btmWrapper.eq("OID",orderDTO.getOid());
      CodeWupinEntity cbo = codeWupinMapper.selectOne(btmWrapper);
//      CodeClstemplateVO templateVO = templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
//      CodeRuleVO ruleVO = ruleService.getObjectHasSecByOid(orderDTO.getCodeRuleOid());
      if (cbo != null) {
         throw new VciBaseException(DATA_OID_NOT_EXIST);
      }
//      ClientBusinessObject cbo = cbos.get(0);
      if (!cbo.getTs().toString().contains(VciDateUtil.date2Str(orderDTO.getTs(), VciDateUtil.DateTimeFormat))) {
         throw new VciBaseException("数据不是最新的,可能他人已经修改,请刷新后再试");
      }
      if (!CodeDefaultLC.EDITING.getValue().equalsIgnoreCase(cbo.getLcStatus()) && !orderDTO.isEditInProcess()) {
         throw new VciBaseException("数据不是{0}的状态,不允许修改", new String[]{CodeDefaultLC.EDITING.getText()});
      }
      //注意模板不能使用数据存储的时候的模板,因为可能会变化
      //1. åˆ¤æ–­å¿…输项
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
      checkRequiredAttrOnOrder(templateVO, orderDTO);
      //2.先注入,再组合,最后校验
      switchClassifyLevelOnOrder(templateVO, classifyFullInfo, orderDTO);
      //3.处理组合规则。组合规则不能使用编码的属性,因为编码的生成可能是需要属性的
      switchComponentAttrOnOrder(templateVO, orderDTO);
      //4.校验规则
      checkVerifyOnOrder(templateVO, orderDTO);
      //5.判断关键属性
      checkKeyAttrOnOrder(classifyFullInfo, templateVO, orderDTO);
      //6.校验枚举的内容是否正确
      checkEnumOnOrder(templateVO, orderDTO);
      //7.处理时间格式,在数据库里面不论是字符串还是日期格式,都使用相同的格式存储
      switchDateAttrOnOrder(templateVO, orderDTO);
      //默认的内容不能变,所以只需要拷贝自定义的相关属性即可
      copyValueToCBO(classifyFullInfo, cbo, orderDTO, templateVO, true);
      //企业码和集团码的不修改
      cbo.setDescription(orderDTO.getDescription());
      cbo.setName(orderDTO.getName());
      try {
         cbo.setDescription(orderDTO.getDescription());
         cbo.setName(orderDTO.getName());
////         cbo.setAttributeValueWithNoCheck("description", orderDTO.getDescription());
//         cbo.setAttributeValue("name", orderDTO.getName());
      } catch (Exception e) {
         e.printStackTrace();
      }
      cbo.setLastModifyTime(new Date());
      cbo.setLastModifier(AuthUtil.getUser().getUserName());
      codeWupinMapper.updateById(cbo);
//
//      List<CodeWupinEntity> cboList = new ArrayList<>();
//
//      //备注
//      cbo.setDescription(orderDTO.getDescription());
//      cboList.add(cbo);
////
////      cboList.add(cbo);
//      List<String> codeList = productCodeService.productCodeAndSaveData(classifyFullInfo, templateVO, ruleVO, orderDTO.getSecDTOList(),cboList);
//
//
//      List<String> charList = new ArrayList<>();
//      for (CodeWupinEntity wupinEntity : cboList) {
//         charList.add(wupinEntity.getId());
//      }
//      batchSaveSelectChar(templateVO, charList);
//      return codeList.size() > 0 ? codeList.get(0) : "";
      //修改的时候,编码是不变的
//      BatchCBO batchCBO = new BatchCBO();
//      batchCBO.getUpdateCbos().add(cbo);
//      List<ClientBusinessObject> cboList = new ArrayList<>();
//      cboList.add(cbo);
//      boService.persistenceBatch(batchCBO);
      batchSaveSelectChar(templateVO, Arrays.asList(cbo.getId()));
   }
   /**
    * åˆ é™¤ä¸»é¢˜åº“数据
    *
    * @param deleteBatchDTO æ•°æ®çš„内容,必须要有主键和分类主键
    */
   @Override
   public void deleteCode(CodeDeleteBatchDTO deleteBatchDTO) {
      VciBaseUtil.alertNotNull(deleteBatchDTO, "编码申请相关的属性和码段的内容都为空", deleteBatchDTO.getOidList(), "数据主键",
         deleteBatchDTO.getCodeClassifyOid(), "主题库分类的主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(deleteBatchDTO.getCodeClassifyOid());
      //找业务类型,然后使用主键去获取数据库里的数据
      Collection<String> oidCollection = null;
      for (Collection<String> strings : VciBaseUtil.switchCollectionForOracleIn(deleteBatchDTO.getOidList())) {
         oidCollection.addAll(strings);
      }
      List<CodeWupinEntity> cboList = codeWupinMapper.selectBatchIds(oidCollection);
      //      List<ClientBusinessObject> cboList = new ArrayList<>();
//      oidCollection.stream().forEach(oids -> {
//         Map<String, String> conditionMap = new HashMap<>();
//         conditionMap.put("oid", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(oids.toArray(new String[0])) + ")");
//         List<ClientBusinessObject> cbos = boService.queryCBO(classifyFullInfo.getTopClassifyVO().getBtmtypeid(), conditionMap);
//         cboList.addAll(cbos);
//      });
      if (CollectionUtils.isEmpty(cboList)) {
         throw new VciBaseException("数据全部在系统中不存在");
      }
      List<CodeWupinEntity> editCBOs = cboList.stream().filter(s -> !CodeDefaultLC.EDITING.getValue().equalsIgnoreCase(s.getLcStatus())).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(editCBOs)) {
         CodeWupinEntity cbo = editCBOs.get(0);
         throw new VciBaseException("编码为{0}等共{1}条数据的状态不是[{2}],不允许删除", new String[]{cbo.getId(), String.valueOf(editCBOs.size()), CodeDefaultLC.EDITING.getText()});
      }
      //只能删除自己创建的数据
      String userId = AuthUtil.getUser().getUserName();
      for (CodeWupinEntity clientBusinessObject:cboList){
         String creator = clientBusinessObject.getCreator();
         if(!userId.equalsIgnoreCase(creator)){
            throw new VciBaseException("编码为"+clientBusinessObject.getId()+"的数据不是当前用户创建,不能删除!");
         }
      }
//      BatchCBO batchCBO = new BatchCBO();
//      batchCBO.getDeleteCbos().addAll(cboList);
//      WebUtil.setPersistence(false);
//      batchCBO.copyFromOther(
      productCodeService.recycleCode(classifyFullInfo.getCurrentClassifyVO().getBtmtypeid(), deleteBatchDTO.getOidList());
      baseMapper.deleteBatchIds(cboList);
      //      );
//      WebUtil.setPersistence(true);
//      boService.persistenceBatch(batchCBO);
   }
   /**
    * ä½¿ç”¨åˆ†ç±»å’Œé˜¶æ®µçš„编号,获取包含的属性
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @param phase           é˜¶æ®µçš„名称
    * @return å±žæ€§çš„英文名称
    */
   @Override
   public List<String> listPhaseAttrByClassifyOid(String codeClassifyOid, String phase) {
      CodeClassifyTemplateVO templateVO = getUsedTemplateByClassifyOid(codeClassifyOid, false);
      //找阶段
      return phaseAttrService.listAttrByTemplateOidAndPhaseId(templateVO.getOid(), phase);
   }
   /**
    * è·¯å¾„上包含当前分类的所有分类信息
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @return åˆ†ç±»æ ‘
    */
   @Override
   public List<Tree> hasSelfClassifyTree(String codeClassifyOid) {
      if (StringUtils.isBlank(codeClassifyOid)) {
         return new ArrayList<>();
      }
      CodeClassifyFullInfoBO fullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      //查询子
      List<CodeClassifyVO> childrenClassifys = classifyService.listChildrenClassify(codeClassifyOid, true, "id", true);
      Map<String, CodeClassifyVO> classifyVOMap = new HashMap<>();
      classifyVOMap.putAll(Optional.ofNullable(fullInfo.getParentClassifyVOs()).orElseGet(() -> new ArrayList<>()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t)));
      classifyVOMap.putAll(Optional.ofNullable(childrenClassifys).orElseGet(() -> new ArrayList<>()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t)));
      TreeWrapperOptions treeWrapperOptions = new TreeWrapperOptions(CodeClassifyServiceImpl.PARENT_FIELD_NAME.toLowerCase(Locale.ROOT));
      return revisionModelUtil.doList2Trees(classifyVOMap.values().stream().collect(Collectors.toList()), treeWrapperOptions, (CodeClassifyVO s) -> {
         return s.getId() + " " + s.getName() + (FrameworkDataLCStatus.DISABLED.getValue().equalsIgnoreCase(s
            .getLcStatus()) ? (" ã€åœç”¨ã€‘ ") : "");
      });
   }
   /**
    * ä½¿ç”¨åˆ†ç±»èŽ·å–å¯¹åº”çš„æ•°æ®
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @param templateOid     æ¨¡æ¿çš„主键
    * @param conditionMap    æŸ¥è¯¢æ¡ä»¶
    * @param pageHelper      åˆ†é¡µçš„对象
    * @return æ•°æ®ï¼ˆåŒ…含下级分类)
    */
   @Override
   public DataGrid<Map<String, String>> gridTableDataByClassifyOid(String codeClassifyOid, String templateOid, Map<String, String> conditionMap, PageHelper pageHelper) {
      //1. ä½¿ç”¨åˆ†ç±»èŽ·å–æ‰€æœ‰çš„ä¸‹çº§åˆ†ç±»ï¼Œç„¶åŽæ ¹æ®åˆ†ç±»æŸ¥è¯¢å¯¹åº”çš„æ•°æ®
      //2. å…¨éƒ¨ä½¿ç”¨å½“前分类的当前模板来展示内容
      //3. å¦‚果模板上有枚举注入,组合规则,和参照的,需要执行转换
      //4. æŸ¥è¯¢çš„æ—¶å€™ï¼Œç›´æŽ¥ä½¿ç”¨codeclsfpath来查询
      CodeClassifyVO topClassifyVO = classifyService.getTopClassifyVO(codeClassifyOid);
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(templateOid);
      if (topClassifyVO == null || StringUtils.isBlank(topClassifyVO.getBtmtypeid())) {
         throw new VciBaseException("当前主题库分类没有顶层分类,或者顶层分类没有设置业务类型");
      }
      String btmTypeId = topClassifyVO.getBtmtypeid();
      if (StringUtils.isBlank(btmTypeId)) {
         return new DataGrid<>("这个分类所属顶层分类没有添加业务类型");
      }
      if (conditionMap == null) {
         conditionMap = new HashMap<>();
      }
      //pageHelper.addDefaultDesc("createTime");
      pageHelper.addDefaultDesc("id");
      if (!classifyService.checkHasChild(codeClassifyOid)) {
         conditionMap.put(CODE_CLASSIFY_OID_FIELD, codeClassifyOid);
      } else {
         conditionMap.put(CODE_CLASSIFY_OID_FIELD, QueryOptionConstant.IN + "(select oid from " + VciBaseUtil.getTableName(MdmBtmTypeConstant.CODE_CLASSIFY)
            + " where lcstatus='" + FrameWorkDefaultValueConstant.FRAMEWORK_DATA_ENABLED +
            "' start with parentCodeClassifyOid = '" + codeClassifyOid + "' CONNECT BY PRIOR OID = parentCodeClassifyOid )");
      }
      conditionMap.put("islastr", "1");
      conditionMap.put("islastv", "1");
      return queryGrid(btmTypeId, templateVO, conditionMap, pageHelper);
//        List<String> selectFieldList = templateVO.getAttributes().stream().map(CodeClassifyTemplateAttrVO::getId).collect(Collectors.toList());
//        //参照让平台直接查询就行
//        List<String> finalSelectFieldList = selectFieldList;
//        List<CodeClassifyTemplateAttrVO> referAttrVOs = templateVO.getAttributes().stream().filter(
//                s -> StringUtils.isNotBlank(s.getReferbtmid())
//                        &&
//                        (finalSelectFieldList.size() ==0 || finalSelectFieldList.contains(s.getId().toLowerCase(Locale.ROOT)))
//        ).collect(Collectors.toList());
//        if(!CollectionUtils.isEmpty(referAttrVOs)){
//            for (int i = 0; i < referAttrVOs.size(); i++) {
//                selectFieldList.add(referAttrVOs.get(i).getId() + ".name");
//            }
//        }
//        //我们使用和业务类型的来查询
//        DataGrid<Map<String,String>> dataGrid = boService.queryGridByBo(btmTypeId, conditionMap, pageHelper, selectFieldList);
//        //我们需要使用模板来转换
//        if(!CollectionUtils.isEmpty(dataGrid.getData())){
//            wrapperData(dataGrid.getData(),templateVO,finalSelectFieldList,false);
//        }
//        return dataGrid;
   }
   /**
    * æ‰¹é‡ä¿å­˜æµç¨‹æ‰§è¡Œé¡µé¢ä¿®æ”¹çš„内容
    *
    * @param orderDTOList ç¼–码相关的信息,不需要码段的信息
    * @return æ‰§è¡Œç»“æžœ
    */
   @Override
   public R batchUpdateCode(List<CodeOrderDTO> orderDTOList) {
//      VciBaseUtil.alertNotNull(orderDTOList,"编码申请相关的属性内容");
//      orderDTOList.forEach(orderDTO -> {
//         VciBaseUtil.alertNotNull(orderDTO, "编码申请相关的属性的内容都为空", orderDTO.getOid(), "数据主键",
//            orderDTO.getCodeClassifyOid(), "主题库分类的主键");
//      });
//      Map<String, CodeOrderDTO> orderDTOMap = orderDTOList.stream().filter(orderDTO -> orderDTO != null && StringUtils.isNotBlank(orderDTO.getOid())).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
//      List<ClientBusinessObject> updateList = new ArrayList<>();
//      // åº”该都是一个分类下的业务数据,找第一条的就行
//      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTOList.get(0).getCodeClassifyOid());
//      Map<String,String> cboOidMap = new HashMap<>();
//      if (CollectionUtils.isEmpty(orderDTOMap.keySet())){
//         throw new VciBaseException(DATA_OID_NOT_EXIST);
//      }
//      cboOidMap.put("oid",QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(orderDTOMap.keySet().toArray(new String[0])) + ")");
//      List<ClientBusinessObject> cboList = boService.queryCBO(classifyFullInfo.getTopClassifyVO().getBtmtypeid(), cboOidMap);
//      if (CollectionUtils.isEmpty(cboList)){
//         throw new VciBaseException(DATA_OID_NOT_EXIST);
//      }
//      BatchCBO batchCBO = new BatchCBO();
//      CodeClassifyTemplateVO firstTemplateVO = templateService.getObjectHasAttrByOid(orderDTOMap.values().stream().findFirst().get().getTemplateOid());
//      Map<String, ClientBusinessObject> cboMap = cboList.stream().filter(cbo -> cbo != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(s -> s.getOid(), t -> t));
//      orderDTOMap.keySet().stream().forEach(oid -> {
//         CodeOrderDTO orderDTO = orderDTOMap.get(oid);
//         ClientBusinessObject cbo = cboMap.get(oid);
//         if (!cbo.getTs().contains(VciDateUtil.date2Str(orderDTO.getTs(), VciDateUtil.DateTimeFormat))) {
//            throw new VciBaseException("数据不是最新的,可能他人已经修改,请刷新后再试");
//         }
//         if (!CodeDefaultLC.EDITING.getValue().equalsIgnoreCase(cbo.getLcStatus()) && !orderDTO.isEditInProcess()) {
//            throw new VciBaseException("数据不是{0}的状态,不允许修改", new String[]{CodeDefaultLC.EDITING.getText()});
//         }
//         //1. åˆ¤æ–­å¿…输项
//         CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
//         checkRequiredAttrOnOrder(templateVO, orderDTO);
//         //2.先注入,再组合,最后校验
//         switchClassifyLevelOnOrder(templateVO, classifyFullInfo, orderDTO);
//         //3.处理组合规则。组合规则不能使用编码的属性,因为编码的生成可能是需要属性的
//         switchComponentAttrOnOrder(templateVO, orderDTO);
//         //4.校验规则
//         checkVerifyOnOrder(templateVO, orderDTO);
//         //5.判断关键属性
//         checkKeyAttrOnOrder(classifyFullInfo, templateVO, orderDTO);
//         //6.校验枚举的内容是否正确
//         checkEnumOnOrder(templateVO, orderDTO);
//         //7.处理时间格式,在数据库里面不论是字符串还是日期格式,都使用相同的格式存储
//         switchDateAttrOnOrder(templateVO, orderDTO);
//         //默认的内容不能变,所以只需要拷贝自定义的相关属性即可
//         copyValueToCBO(classifyFullInfo, cbo, orderDTO, templateVO, true);
//         //企业码和集团码的不修改
//         cbo.setDescription(orderDTO.getDescription());
//         cbo.setName(orderDTO.getName());
//         try {
//            cbo.setAttributeValueWithNoCheck("description", orderDTO.getDescription());
//            cbo.setAttributeValue("name", orderDTO.getName());
//         } catch (VCIError e) {
//            e.printStackTrace();
//         }
//         batchCBO.getUpdateCbos().add(cbo);
//         updateList.add(cbo);
//      });
//      boService.persistenceBatch(batchCBO);
//      batchSaveSelectChar(firstTemplateVO, cboList);
      return R.success("操作成功!");
   }
   /**
    * æ ‡è®°æµç¨‹ä¸­ä¸šåŠ¡æ•°æ®æ˜¯å¦é€šè¿‡
    *
    * @param oid     ä¸šåŠ¡æ•°æ®ä¸»é”®
    * @param btmName ä¸šåŠ¡ç±»åž‹
    * @param pass    æ˜¯å¦é€šè¿‡
    * @return æ‰§è¡Œç»“æžœ
    */
   @Override
   public R markDataPassing(String oid, String btmName, Boolean pass) {
      VciBaseUtil.alertNotNull(oid, "业务数据主键", btmName, "业务类型", pass, "标记类型");
      boolean flag = false;
//      try {
//         ClientBusinessObjectOperation operation = new ClientBusinessObjectOperation();
//         ClientBusinessObject data = operation.readBusinessObjectById(oid, btmName);
//         if (data == null || StringUtils.isBlank(data.getOid())) {
//            return BaseResult.fail(DATA_OID_NOT_EXIST);
//         }
//         data.setAttributeValue("passing", String.valueOf(pass));
//         flag = operation.updateBuinessObject(data);
//      } catch (VCIError e) {
//         e.printStackTrace();
//      }
      if (flag) {
         return R.success("标记成功!");
      } else {
         return R.fail("标记失败!");
      }
   }
   /**
    * é¢„览组合规则
    *
    * @param orderDTO é¢„览的信息,包含模板的主键
    * @return key是组合规则的属性。value是组合后的值,。如果缺少某个属性的值,会作为value返回
    */
   @Override
   public Map<String, String> previewCompRule(CodeOrderDTO orderDTO) {
      VciBaseUtil.alertNotNull(orderDTO, "编码申请相关信息", orderDTO.getTemplateOid(), "模板的主键");
      //查询分类的信息,查询模板的信息
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
      switchComponentAttrOnOrder(templateVO, orderDTO);
      return orderDTO.getData();
   }
   /**
    * åˆ†ç±»æ³¨å…¥çš„内容预览
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @param codeTemplateOid æ¨¡æ¿çš„主键
    * @return key是分类注入的属性,value是注入后的值
    */
   @Override
   public Map<String, String> previewClassify(String codeClassifyOid, String codeTemplateOid) {
      if (StringUtils.isBlank(codeClassifyOid) || StringUtils.isBlank(codeTemplateOid)) {
         return new HashMap<>();
      }
      //查询分类的信息,查询模板的信息
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(codeTemplateOid);
      //
      CodeOrderDTO orderDTO = new CodeOrderDTO();
      orderDTO.setData(new HashMap<>());
      switchClassifyLevelOnOrder(templateVO, classifyFullInfo, orderDTO);
      return orderDTO.getData();
   }
   /**
    * å‡ç‰ˆçš„主题库数据
    *
    * @param orderDTO æ•°æ®çš„内容,不需要包含码段的内容
    */
   @Override
   public void upSaveCode(CodeOrderDTO orderDTO) {
      VciBaseUtil.alertNotNull(orderDTO, "编码申请相关的属性的内容为空", orderDTO.getCopyFromVersion(), "原始数据的主键",
         orderDTO.getCodeClassifyOid(), "主题库分类的主键");
      CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
      //找业务类型,然后使用主键去获取数据库里的数据
//      List<ClientBusinessObject> cbos = boService.queryCBO(classifyFullInfo.getTopClassifyVO().getBtmtypeid(), WebUtil.getOidQuery(orderDTO.getCopyFromVersion()));
//      if (CollectionUtils.isEmpty(cbos)) {
//         throw new VciBaseException(DATA_OID_NOT_EXIST);
//      }
//      ClientBusinessObject oldCbo = cbos.get(0);
//      if (!CodeDefaultLC.RELEASED.getValue().equalsIgnoreCase(oldCbo.getLcStatus())) {
//         throw new VciBaseException("数据不是{0}的状态,不允许数据更改", new String[]{CodeDefaultLC.RELEASED.getText()});
//      }
//      //需要升版
//      ClientBusinessObjectOperation cboOperation = new ClientBusinessObjectOperation();
//      ClientBusinessObject cbo = null;
//      try {
//         //cbo = cboOperation.createBusinessObjectVersion(oldCbo,VciBaseUtil.getCurrentUserId());
//         cbo = cboOperation.reviseBusinessObject(oldCbo, "");
//      } catch (VCIError e) {
//         throw new VciBaseException("初始化相关的内容出现了错误", new String[0], e);
//      }
//      //1. åˆ¤æ–­å¿…输项
//      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(orderDTO.getTemplateOid());
//      checkRequiredAttrOnOrder(templateVO, orderDTO);
//      //2.先注入,再组合,最后校验
//      switchClassifyLevelOnOrder(templateVO, classifyFullInfo, orderDTO);
//      //3.处理组合规则。组合规则不能使用编码的属性,因为编码的生成可能是需要属性的
//      switchComponentAttrOnOrder(templateVO, orderDTO);
//      //4.校验规则
//      checkVerifyOnOrder(templateVO, orderDTO);
//      //5.判断关键属性
//      checkKeyAttrOnOrder(classifyFullInfo, templateVO, orderDTO);
//      //6.校验枚举的内容是否正确
//      checkEnumOnOrder(templateVO, orderDTO);
//      //7.处理时间格式,在数据库里面不论是字符串还是日期格式,都使用相同的格式存储
//      switchDateAttrOnOrder(templateVO, orderDTO);
//      //默认的内容不能变,所以只需要拷贝自定义的相关属性即可
//      copyValueToCBO(classifyFullInfo, cbo, orderDTO, templateVO, true);
//      //企业码和集团码的不修改
//      cbo.setDescription(orderDTO.getDescription());
//      cbo.setName(orderDTO.getName());
//      try {
//         cbo.setAttributeValueWithNoCheck("description", orderDTO.getDescription());
//         cbo.setAttributeValue("name", orderDTO.getName());
//      } catch (VCIError e) {
//         e.printStackTrace();
//      }
//      //数据的时候,编码是不变的
//      cbo.setCreateTime(DateUtils.convert2String(new Date(Long.parseLong(cbo.getCreateTime())), "yyyy-MM-dd HH:mm:ss"));
//      cbo.setLastModifyTime(DateUtils.convert2String(new Date(Long.parseLong(cbo.getLastModifyTime())), "yyyy-MM-dd HH:mm:ss"));
//      List<ClientBusinessObject> cboList = new ArrayList<>();
//      cboList.add(cbo);
//      try {
//         cboOperation.saveRevisionBuinessObject(cbo);
//      } catch (VCIError vciError) {
//         throw new VciBaseException("数据更改保存出错了", new String[0], vciError);
//      }
//      batchSaveSelectChar(templateVO, cboList);
   }
   /**
    * ä½¿ç”¨ç æ®µçš„主键获取分类的码值内容
    *
    * @param classifySecOid         ç æ®µçš„主键
    * @param parentClassifyValueOid ä¸Šçº§åˆ†ç±»çš„主键
    * @return åˆ†ç±»ç å€¼çš„内容
    */
   @Override
   public List<CodeClassifyValueVO> listCodeClassifyValueBySecOid(String classifySecOid, String parentClassifyValueOid) {
      return classifyValueService.listCodeClassifyValueBySecOid(classifySecOid, parentClassifyValueOid);
   }
   /**
    * ä½¿ç”¨ä¸»é¢˜åº“分类获取编码规则
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @return ç¼–码规则的内容
    */
   @Override
   public CodeRuleVO getCodeRuleByClassifyOid(String codeClassifyOid) {
      VciBaseUtil.alertNotNull(codeClassifyOid, "分类的主键");
      CodeClassifyVO classifyVO = classifyService.getObjectByOid(codeClassifyOid);
      String codeRuleOid = classifyVO.getCoderuleoid();
      if (StringUtils.isBlank(codeRuleOid)) {
         //往上找
         CodeClassifyFullInfoBO fullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
         return getCodeRuleByClassifyFullInfo(fullInfo);
      }
      //我们查询编码规则
      return ruleService.getObjectHasSecByOid(codeRuleOid);
   }
   /**
    * ä½¿ç”¨åˆ†ç±»çš„全部信息获取编码规则
    *
    * @param fullInfoBO åˆ†ç±»çš„全部信息
    * @return è§„则的内容
    */
   @Override
   public CodeRuleVO getCodeRuleByClassifyFullInfo(CodeClassifyFullInfoBO fullInfoBO) {
      //往上找
      String codeRuleOid = "";
      if (StringUtils.isNotBlank(fullInfoBO.getCurrentClassifyVO().getCoderuleoid())) {
         codeRuleOid = fullInfoBO.getCurrentClassifyVO().getCoderuleoid();
      } else {
         if (CollectionUtils.isEmpty(fullInfoBO.getParentClassifyVOs())) {
            //说明已经是最高层级,
            throw new VciBaseException("当前主题库分类,以及它的所有的上级分类都没有设置编码规则");
         }
         List<CodeClassifyVO> parentClassifyVOList = fullInfoBO.getParentClassifyVOs().stream().sorted((o1, o2) -> o1.getDataLevel().compareTo(o2.getDataLevel())).collect(Collectors.toList());
         //从最高的level开始获取
         for (int i = 0; i < parentClassifyVOList.size(); i++) {
            CodeClassifyVO record = parentClassifyVOList.get(i);
            if (StringUtils.isNotBlank(record.getCoderuleoid())) {
               codeRuleOid = record.getCoderuleoid();
               break;
            }
         }
         if (StringUtils.isBlank(codeRuleOid)) {
            throw new VciBaseException("当前主题库分类,以及它的所有的上级分类都没有设置编码规则");
         }
      }
      return ruleService.getObjectHasSecByOid(codeRuleOid);
   }
   /**
    * ä½¿ç”¨æ•°æ®ä¸»é”®èŽ·å–æ•°æ®çš„å…¨éƒ¨ä¿¡æ¯
    *
    * @param oid         ä¸»é”®
    * @param templateOid æ¨¡æ¿çš„主键
    * @return æ•°æ®çš„内容
    */
   @Override
   public R<List<Map<String, String>>> getDataByOid(String oid, String templateOid) {
      CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(templateOid);
      //为了防止模板上的业务类型与分类上不对应
      CodeClassifyVO topClassifyVO = classifyService.getTopClassifyVO(templateVO.getCodeclassifyoid());
      String btmId = topClassifyVO.getBtmtypeid();
      //查询数据
      Map<String, String> conditionMap = WebUtil.getOidQuery(oid);
      CodeTemplateAttrSqlBO sqlBO = getSqlByTemplateVO(btmId, templateVO, conditionMap, new PageHelper(-1));
      //我们使用和业务类型的来查询
      List<Map> cbos = commonsMapper.selectBySql(sqlBO.getSqlUnPage());
//      List<ClientBusinessObject> cbos = boService.queryByOnlySql(sqlBO.getSqlUnPage());
      if (CollectionUtils.isEmpty(cbos)) {
         throw new VciBaseException("数据在系统中不存在,是否因为修改过业务类型?");
      }
//      Map<String, String> data = new HashMap<>();
      Map<String,String> cbo = cbos.get(0);
//      WebUtil.copyValueToMapFromCbos(cbo, data);
      List<Map<String, String>> dataList = new ArrayList<>();
      dataList.add(cbo);
      wrapperData(dataList, templateVO, sqlBO.getSelectFieldList(), true);
      R<List<Map<String, String>>> result = R.data(Collections.singletonList(cbo));
      //我们要看是否不是升版的,升版的话,需要对比不相等的属性
      String copy = String.valueOf(cbo.get("COPYFROMVERSION"));
//      if (StringUtils.isBlank(copy)) {
//         copy = cbo.getAttributeValue("copyfromversion");
//      }
      if (StringUtils.isNotBlank(copy)) {
         //说明有变更的内容
         CodeTemplateAttrSqlBO oldSqlBO = getSqlByTemplateVO(btmId, templateVO, WebUtil.getOidQuery(copy), new PageHelper(-1));
         //我们使用和业务类型的来查询
//         List<Map> cbos = commonsMapper.selectBySql(sqlBO.getSqlUnPage());
         List<Map> oldCbos = commonsMapper.selectBySql(oldSqlBO.getSqlUnPage());
         if (!CollectionUtils.isEmpty(oldCbos)) {
//            Map<String, String> newData = new HashMap<>();
//            WebUtil.copyValueToMapFromCbos(cbo, newData);
            Map<String, String> oldData = new HashMap<>();
            oldData = oldCbos.get(0);
            Map<String, String> difFieldMap = new HashMap<>();
            Map<String, String> finalOldData = oldData;
            cbo.forEach((key, value) -> {
               String oldValue = finalOldData.getOrDefault(key, "");
               if (value == null) {
                  value = "";
               }
               if (oldValue == null) {
                  oldValue = "";
               }
               if (!value.equalsIgnoreCase(oldValue)) {
                  difFieldMap.put(key, oldValue);
               }
            });
            List<Map<String, String>> difFieldList = new ArrayList<>();
            difFieldList.add(difFieldMap);
            result.setData(difFieldList);
         }
      }
      return result;
   }
   /**
    * ä½¿ç”¨æ¨¡æ¿çš„主键获取表单的信息
    *
    * @param templateOid æ¨¡æ¿çš„主键
    * @param executionId æµç¨‹æ‰§è¡Œid
    * @param processUse  æµç¨‹æ¨¡æ¿çš„用途
    * @return ui相关的内容
    */
   @Override
   public List<String> getFieldByProcessTemplate(String templateOid, String executionId, String processUse) {
      VciBaseUtil.alertNotNull(templateOid, "模板主键", executionId, "流程的执行Id", processUse, "流程模板用途");
      while (StringUtils.countMatches(executionId, ".") > 1) {
         executionId = executionId.substring(0, executionId.lastIndexOf("."));
      }
      String sql = "select wm_concat(distinct (t.codetempattrOidArr)) codetempattroidarr\n" +
         "from " + VciBaseUtil.getTableName(MdmBtmTypeConstant.CODE_CLASSIFY_PROCESS_TEMPLATE) + " t\n" +
         "join PLFLOWINSTANCE plfi on t.ID = plfi.PLTEMPLATEPUID\n" +
         "where plfi.PLEXECUTIONID = '" + executionId + "' and t.CLASSIFYTEMPLATEOID = '" + templateOid + "' and t.CODEPROCESSUSE = '" + processUse + "'";
//      List<ClientBusinessObject> tempAttrOidArr = boService.queryByOnlySql(sql);
      List<Map> tempAttrOidArr = commonsMapper.selectBySql(sql);
      if (CollectionUtils.isEmpty(tempAttrOidArr) || StringUtils.isBlank((CharSequence) tempAttrOidArr.get(0).get("codetempattroidarr"))) {
         return new ArrayList<>();
      }
      return VciBaseUtil.str2List(tempAttrOidArr.get(0).get("codetempattroidarr").toString());
   }
   /**
    * ä½¿ç”¨åˆ†ç±»çš„主键获取业务数据
    *
    * @param btmType     ä¸šåŠ¡ç±»åž‹
    * @param queryObject æŸ¥è¯¢å¯¹è±¡
    * @return è¡¨æ ¼çš„æ˜¾ç¤ºå¯¹è±¡å€¼
    */
   @Override
   public DataGrid<Map<String, String>> getTableDataByExecutionId(String btmType, BaseQueryObject queryObject) {
      VciBaseUtil.alertNotNull(btmType, "业务类型");
      if (queryObject == null) {
         queryObject = new BaseQueryObject();
      }
      if (queryObject.getConditionMap() == null) {
         queryObject.setConditionMap(new HashMap<>());
      }
      Map<String, String> conditionMap = queryObject.getConditionMap();
      PageHelper pageHelper = queryObject.getPageHelper();
      if (!conditionMap.containsKey("oid")) {
         throw new VciBaseException("业务数据主键不能为空");
      }
      List<String> oidList = VciBaseUtil.str2List(conditionMap.get("oid"));
      Map<String, String> oidMap = new HashMap<>();
      if (conditionMap.get("oid").contains(",")) {
         oidMap.put("oid", QueryOptionConstant.IN +"("+ VciBaseUtil.toInSql(oidList.toArray(new String[0])) + ")");
      } else {
         oidMap.put("oid", conditionMap.get("oid"));
      }
      if (CollectionUtils.isEmpty(oidMap)) {
         throw new VciBaseException("业务数据主键不能为空");
      }
//      List<ClientBusinessObject> cbos = boService.queryCBO(btmType, oidMap);
//      if (CollectionUtils.isEmpty(cbos)) {
//         throw new VciBaseException("未找到业务数据");
//      }
//      ClientBusinessObject cbo = cbos.get(0);
//      String templateOid = cbo.getAttributeValue("CODETEMPLATEOID");
//      Map<String, String> templateOidMap = new HashMap<>();
//      templateOidMap.put("oid", templateOid);
//      List<CodeClassifyTemplate> templateDOList = boService.queryObject(CodeClassifyTemplate.class, templateOidMap);
//      templateOidMap.clear();
//      templateOidMap.put("CLASSIFYTEMPLATEOID",templateOid);
//      List<CodeClassifyTemplateAttr> attrDOList = boService.queryObject(CodeClassifyTemplateAttr.class, templateOidMap);
//      if (CollectionUtils.isEmpty(templateDOList)) {
//         logger.error("找不到业务数据关联的模板,模板主键:" + templateOid);
//         throw new VciBaseException("找不到业务数据关联的模板");
//      }
//      CodeClassifyTemplateVO templateVO = templateService.codeClassifyTemplateDO2VO(templateDOList.get(0));
//      templateVO.setAttributes(templateAttrService.codeClassifyTemplateAttrDO2VOs(attrDOList));
//      try {
//         if (oidList.size() > 1){
//            DataGrid<Map<String,String>> allDataGrid = new DataGrid<>();
//            List<Map<String,String>> allData = new ArrayList<>();
//            oidList.forEach(oid -> {
//               Map<String,String> condition = new HashMap<>();
//               condition.put("oid",oid);
//               DataGrid<Map<String, String>> dataGrid = queryGrid(btmType, templateVO, condition, pageHelper);
//               allData.addAll(dataGrid.getData());
//            });
//            allDataGrid.setData(allData);
//            return allDataGrid;
//         }else {
//            return queryGrid(btmType, templateVO, conditionMap, pageHelper);
//         }
//      } catch (Exception e) {
//         System.out.println(e.getMessage());
         return null;
//      }
   }
   /**
    * ä½¿ç”¨åˆ†ç±»çš„主键获取表格的定义
    *
    * @param codeClassifyOid åˆ†ç±»ä¸»é”®
    * @param phase           é˜¶æ®µçš„名称
    * @return UI相关的信息(仅包含表单)
    */
   @Override
   public MdmUIInfoVO getTableDefineByClassifyOid_v2(String codeClassifyOid, String phase) {
      MdmUIInfoVO uiInfoVO = new MdmUIInfoVO();
      CodeClassifyTemplateVO templateVO = getUsedTemplateByClassifyOid(codeClassifyOid);
      uiInfoVO.setTemplateVO(templateVO);
      UITableDefineVO uiTableDefineVO = wrapperTableDefineByTemplate(templateVO,true);
      List<String> phaseAttrIdList = listPhaseAttrByClassifyOid(codeClassifyOid, phase);
      uiTableDefineVO.getCols().stream().forEach(list -> {
         List<UITableFieldVO> visiableTableField=new ArrayList<>();
         if(StringUtils.isNotBlank(phase)) {
            visiableTableField = list.stream().filter(col ->
               phaseAttrIdList.stream().anyMatch(s -> StringUtils.equalsIgnoreCase(col.getField(), s) ||
                  (StringUtils.equalsIgnoreCase(col.getFieldType(), "combox") && StringUtils.equalsIgnoreCase(col.getSortField(), s))
                  || (StringUtils.equalsIgnoreCase(col.getFieldType(), "refer") && StringUtils.equalsIgnoreCase(col.getQueryField(), s))
               )).collect(Collectors.toList());
         }else{
            visiableTableField=  list.stream().filter(col ->
               templateVO.getAttributes().stream().anyMatch(s ->
                  (!s.getReadOnlyFlag().equalsIgnoreCase("true")&& StringUtils.equalsIgnoreCase(col.getField(), s.getId())) ||
                     (StringUtils.equalsIgnoreCase(col.getFieldType(), "combox") && StringUtils.equalsIgnoreCase(col.getSortField(), s.getId()))
                     || (StringUtils.equalsIgnoreCase(col.getFieldType(), "refer") && StringUtils.equalsIgnoreCase(col.getQueryField(), s.getId()))
               )).collect(Collectors.toList());
         }
         visiableTableField.stream().forEach(vo -> {
            uiTableDefineVO.setHasEditor(true);
            if ("refer".equalsIgnoreCase(vo.getFieldType())) {
               setReferConfig2EditConfig(vo);
            } else if ("combox".equalsIgnoreCase(vo.getFieldType())) {
               setComboxConfig2EditConfig(vo);
            } else if (StringUtils.isNotBlank(vo.getDateFormate())){
               vo.setEdit("date");
            }else {
               vo.setEdit(vo.getFieldType());
            }
         });
      });
      uiInfoVO.setTableDefineVO(uiTableDefineVO);
      wrapperResemble(templateVO, uiInfoVO);
      return uiInfoVO;
   }
   /**
    * æ¨¡æ¿å±žæ€§è½¬æ¢ä¸ºè¡¨æ ¼å®šä¹‰çš„信息
    *
    * @param templateVO æ¨¡æ¿çš„æ˜¾ç¤ºå¯¹è±¡
    * @param forEdit æ˜¯å¦æ˜¯ç¼–辑所需
    * @return è¡¨æ ¼çš„信息
    */
   private UITableDefineVO wrapperTableDefineByTemplate(CodeClassifyTemplateVO templateVO,boolean forEdit) {
      //封装信息
      UITableDefineVO tableDefineVO = new UITableDefineVO();
      tableDefineVO.setOid(templateVO.getOid());
      tableDefineVO.setBtmType(templateVO.getBtmTypeId());
      tableDefineVO.setDisplayQueryArea(true);
      //前端会默认分页的信息
      //处理所有的列,这个模板没有合并的表头的情况
      List<UITableFieldVO> fieldVOList = new ArrayList<>();
      Map<String, String> comboxOrReferFieldMap = new HashMap<>();
      templateVO.getAttributes().forEach(attrVO -> {
         UITableFieldVO tableFieldVO = templateAttr2TableField(attrVO,forEdit);
         if ("combox".equalsIgnoreCase(tableFieldVO.getFieldType())) {
            comboxOrReferFieldMap.put(tableFieldVO.getSortField(), tableFieldVO.getField());
         }
         if ("refer".equalsIgnoreCase(tableFieldVO.getFieldType())) {
            comboxOrReferFieldMap.put(tableFieldVO.getSortField(), tableFieldVO.getField());
         }
         if(StringUtils.isNotBlank(tableFieldVO.getEdit())){
            tableDefineVO.setHasEditor(true);
         }
         fieldVOList.add(tableFieldVO);
      });
      List<List<UITableFieldVO>> cols = new ArrayList<>();
      cols.add(fieldVOList);
      tableDefineVO.setCols(cols);
      Map<String, UITableFieldVO> fieldVOMap = fieldVOList.stream().collect(Collectors.toMap(s -> s.getField().toLowerCase(Locale.ROOT), t -> t));
      //查询属性
      List<CodeClassifyTemplateAttrVO> queryAttrVOs = templateVO.getAttributes().stream().filter(s -> BooleanEnum.TRUE.getValue().equalsIgnoreCase(s.getQueryAttrFlag())).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(queryAttrVOs)) {
         List<UITableFieldVO> queryFieldVOs = new ArrayList<>();
         queryAttrVOs.stream().forEach(attrVO -> {
            String attrId = attrVO.getId().toLowerCase(Locale.ROOT);
            attrId = comboxOrReferFieldMap.getOrDefault(attrId, attrVO.getId()).toLowerCase(Locale.ROOT);
            if (fieldVOMap.containsKey(attrId)) {
               queryFieldVOs.add(fieldVOMap.get(attrId));
            }
         });
         tableDefineVO.setQueryColumns(queryFieldVOs);
      }
      //高级属性
      List<CodeClassifyTemplateAttrVO> seniorQueryAttrVOs = templateVO.getAttributes().stream().filter(s -> BooleanEnum.TRUE.getValue().equalsIgnoreCase(s.getSeniorQueryAttrFlag())).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(seniorQueryAttrVOs)) {
         List<UITableFieldVO> queryFieldVOs = new ArrayList<>();
         seniorQueryAttrVOs.stream().forEach(attrVO -> {
            String attrId = attrVO.getId().toLowerCase(Locale.ROOT);
            attrId = comboxOrReferFieldMap.getOrDefault(attrId, attrId).toLowerCase(Locale.ROOT);
            if (fieldVOMap.containsKey(attrId)) {
               queryFieldVOs.add(fieldVOMap.get(attrId));
            }
         });
         tableDefineVO.setSeniorQueryColumns(queryFieldVOs);
      }
      return tableDefineVO;
   }
   /**
    * åŠ è½½æˆå‚ç…§çš„ä¿®æ”¹é…ç½®
    * @param vo è¡¨æ ¼å­—段显示对象
    */
   private void setReferConfig2EditConfig(UITableFieldVO vo) {
      if (!CollectionUtils.isEmpty(vo.getReferConfig().getWhere())){
         vo.getReferConfig().getWhere().keySet().forEach(key -> {
            vo.getReferConfig().getWhere().put(key, "'" + vo.getReferConfig().getWhere().get(key) + "'");
         });
      }
      if (StringUtils.isNotBlank(vo.getReferConfig().getParentValue())){
         String parentValue = vo.getReferConfig().getParentValue();
         parentValue ="\\" +  parentValue.replaceAll("'","{vci-quote}").replaceAll("=","{vci-equals}");
         vo.getReferConfig().setParentValue(parentValue);
      }
      String referConfig = vo.getReferConfig().toString()
         .replaceAll("=",":")
         .replaceAll("UITableCustomDefineVO","")
         .replaceAll("UIFieldSortVO","")
         .replaceAll("UITablePageVO","")
         .replaceAll("UITableFieldVO","")
         .replaceAll("UIFormReferVO","")
         .replaceAll("\\{vci-equals}","=")
         .replaceAll("\\{vci-quote}","\\\\'")
         .replaceAll("'null'","null");
      referConfig = referConfig + ",fieldMap:{" + vo.getQueryField() + ":'" + vo.getReferConfig().getValueField() + "'}";
      vo.setEditConfig("{referConfig:" + referConfig + "}");
      vo.setEdit(vo.getFieldType());
   }
   /**
    * åŠ è½½æˆä¸‹æ‹‰æ¡†çš„ä¿®æ”¹é…ç½®
    * @param vo è¡¨æ ¼å­—段显示对象
    */
   private void setComboxConfig2EditConfig(UITableFieldVO vo) {
      vo.setEditConfig("{editable:true,comboxKey:'" + vo.getComboxKey() + "'");
      if (!CollectionUtils.isEmpty(vo.getData())){
         vo.setEditConfig(vo.getEditConfig()+", comboxConfig:");
         for (int i = 0; i < vo.getData().size(); i++) {
            KeyValue data = vo.getData().get(i);
            if (i == vo.getData().size() -1){
               vo.setEditConfig(vo.getEditConfig() + "{attributes:"+data.getAttributes()+",key:'"+data.getKey()+"',value:'"+data.getValue()+"'}]}");
            }else if (i == 0){
               vo.setEditConfig(vo.getEditConfig() + "{data:[{attributes:"+data.getAttributes()+",key:'"+data.getKey()+"',value:'"+data.getValue()+"'},");
            }else{
               vo.setEditConfig(vo.getEditConfig() + "{attributes:"+data.getAttributes()+",key:'"+data.getKey()+"',value:'"+data.getValue()+"'},");
            }
         }
         vo.setEditConfig(vo.getEditConfig() + ",valueField:'" + vo.getQueryField() + "'");
      }
      vo.setEditConfig(vo.getEditConfig() + "}");
      vo.setEdit(vo.getFieldType());
   }
   /**
    * ä½¿ç”¨åˆ†ç±»çš„编号路径,获取表单的相关定义
    *
    * @param idPath ç¼–号的路径,必须从顶层节点开始,xx/yyy/zz
    * @return UI相关的信息(仅包含表单)
    */
   @Override
   public MdmUIInfoVO getFormDefineByClassifyIdPath(String idPath) {
      CodeClassifyVO classifyVO = classifyService.getObjectByIdPath(idPath);
      if(classifyVO !=null){
         return getFormDefineByClassifyOid(classifyVO.getOid());
      }
      return null;
   }
   /**
    * ä½¿ç”¨ä¸»é¢˜åº“分类的主键获取表单的信息
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @return ui相关的内容
    */
   @Override
   public MdmUIInfoVO getFormDefineByClassifyOid(String codeClassifyOid) {
      MdmUIInfoVO uiInfoVO = new MdmUIInfoVO();
      CodeClassifyTemplateVO templateVO = getUsedTemplateByClassifyOid(codeClassifyOid);
      uiInfoVO.setTemplateVO(templateVO);
      uiInfoVO.setFormDefineVO(wrapperFormDefineByTemplate(templateVO, codeClassifyOid));
      wrapperResemble(templateVO, uiInfoVO);
      return uiInfoVO;
   }
   /**
    * ä½¿ç”¨æ¨¡æ¿ä¸»é”®èŽ·å–ui相关的内容
    *
    * @param templateOid æ¨¡æ¿çš„主键
    * @return ui相关的内容
    */
   @Override
   public MdmUIInfoVO getTableDefineByTemplateOid(String templateOid) {
      return getTableDefineByTemplateVO(templateService.getObjectHasAttrByOid(templateOid));
   }
   /**
    * ä½¿ç”¨æ¨¡æ¿æ˜¾ç¤ºå¯¹è±¡è½¬æ¢ä¸ºè¡¨æ ¼çš„信息(包含扩展的按钮)
    *
    * @param templateVO æ¨¡æ¿çš„信息
    * @return UI相关的内容(仅包含表格信息)
    */
   private MdmUIInfoVO getTableDefineByTemplateVO(CodeClassifyTemplateVO templateVO) {
      //先看这个分类本身是否有模板
      MdmUIInfoVO uiInfoVO = new MdmUIInfoVO();
      uiInfoVO.setTemplateVO(templateVO);
      //我们需要将模板转换为表格相关的显示信息
      uiInfoVO.setTableDefineVO(wrapperTableDefineByTemplate(uiInfoVO.getTemplateVO(),false));
      //需要去看扩展的按钮,只有列表里面本身才添加进去,工具栏上的单独获取
      List<CodeClassifyTemplateButtonVO> buttonVOS = templateButtonService.listButtonByTemplateOid(templateVO.getOid(), true);
      if (!CollectionUtils.isEmpty(buttonVOS)) {
         //我们要分开为按钮,还是在操作列里面
         List<CodeClassifyTemplateButtonVO> tableButtonVOs = buttonVOS.stream().filter(s -> CodeUseButtonPositionTypeEnum.TABLE.getValue().equalsIgnoreCase(s.getButtonUse())).collect(Collectors.toList());
         if (!CollectionUtils.isEmpty(tableButtonVOs)) {
            UITableFieldVO optionFieldVO = new UITableFieldVO();
            optionFieldVO.setField("options");
            optionFieldVO.setTitle("操作");
            optionFieldVO.setFieldType("text");
            optionFieldVO.setOptionField(true);
            List<KeyValue> buttons = new ArrayList<>();
            Map<String, String> optionJsMap = new HashMap<>();
            tableButtonVOs.stream().forEach(buttonVO -> {
               KeyValue kv = new KeyValue();
               kv.setKey(buttonVO.getId());
               kv.setValue(buttonVO.getClassifyButtonOidName());
               kv.setAttributes(VciBaseUtil.objectToMap(buttonVO));
               buttons.add(kv);
               optionJsMap.put(buttonVO.getId(), buttonVO.getButtonVO().getExecutejs());
            });
            optionFieldVO.setOptionJsMap(optionJsMap);
            uiInfoVO.getTableDefineVO().getCols().get(0).add(optionFieldVO);
         }
      }
      return uiInfoVO;
   }
   /**
    * ä½¿ç”¨åˆ†ç±»çš„编号路径,获取表格的相关定义
    *
    * @param codeClassifyIdPath åˆ†ç±»çš„编号路径,必须是从顶层节点开始,xxx/yy/zz这样的格式
    * @param functionId         åŠŸèƒ½çš„ç¼–å·
    * @return UI相关的信息(仅包含表格)
    */
   @Override
   public MdmUIInfoVO getUIInfoByClassifyIdPath(String codeClassifyIdPath, String functionId) {
      CodeClassifyVO classifyVO = classifyService.getObjectByIdPath(codeClassifyIdPath);
      if(classifyVO !=null){
         return getUIInfoByClassifyOid(classifyVO.getOid(),functionId);
      }
      return null;
   }
   /**
    * ä½¿ç”¨åˆ†ç±»ä¸»é”®èŽ·å–é¡µé¢çš„å†…å®¹ï¼ŒåŒ…å«æŒ‰é’®
    *
    * @param codeClassifyOid ä¸»é¢˜åº“分类主键
    * @param functionId      åŠŸèƒ½çš„ç¼–å·
    * @return UI相关的内容
    */
   @Override
   public MdmUIInfoVO getUIInfoByClassifyOid(String codeClassifyOid, String functionId) {
      VciBaseUtil.alertNotNull(codeClassifyOid, "主题库分类主键");
      MdmUIInfoVO uiInfoVO = getTableDefineByTemplateVO(getUsedTemplateByClassifyOid(codeClassifyOid));
      uiInfoVO.setLeaf(classifyService.countChildrenByClassifyOid(codeClassifyOid) == 0);
      if (StringUtils.isNotBlank(functionId) && !"~".equalsIgnoreCase(functionId)) {
         //功能按钮服务还未实现,等实现了,在进行调用
         //List<SmOperationVO> operationVOS = operationService.listButtonByFunctionId(functionId);
//         if (operationVOS == null) {
//            operationVOS = new ArrayList<>();
//         }
         //查询扩展按钮
//         List<CodeButtonVO> buttonVOS = listButtonInToolbarByClassifyOid(codeClassifyOid);
//         if (!CollectionUtils.isEmpty(buttonVOS)) {
//            for (int i = 0; i < buttonVOS.size(); i++) {
//               CodeButtonVO buttonVO = buttonVOS.get(i);
//               SmOperationVO operationVO = new SmOperationVO();
//               operationVO.setModuleNo(functionId);
//               operationVO.setUniqueFlag(buttonVO.getId());
//               operationVO.setName(buttonVO.getName());
//               operationVO.setAlias(operationVO.getName());
//               operationVO.setExecuteJs(buttonVO.getExecutejs());
//               operationVO.setIconCls(buttonVO.getIconcls());
//               operationVOS.add(operationVO);
//            }
//         }
//         uiInfoVO.setButtons(operationVOS);
      }
      return uiInfoVO;
   }
   /**
    * ä½¿ç”¨åˆ†ç±»ä¸»é”®èŽ·å–å·¥å…·æ ä¸­çš„æŒ‰é’®ä¿¡æ¯
    *
    * @param codeClassifyOid åˆ†ç±»çš„主键
    * @return æŒ‰é’®çš„信息,会按照排序号进行排序
    */
   @Override
   public List<CodeButtonVO> listButtonInToolbarByClassifyOid(String codeClassifyOid) {
      CodeClassifyTemplateVO templateVO = getUsedTemplateByClassifyOid(codeClassifyOid);
      return listButtonInToolbarByTemplateOid(templateVO.getOid());
   }
   /**
    * ä½¿ç”¨æ¨¡æ¿ä¸»é”®èŽ·å–å·¥å…·æ ä¸­çš„æŒ‰é’®ä¿¡æ¯
    *
    * @param templateOid æ¨¡æ¿çš„主键
    * @return æŒ‰é’®çš„信息,会按照排序号进行排序
    */
   @Override
   public List<CodeButtonVO> listButtonInToolbarByTemplateOid(String templateOid) {
      List<CodeClassifyTemplateButtonVO> buttonVOS = templateButtonService.listButtonByTemplateOid(templateOid, true);
      if (CollectionUtils.isEmpty(buttonVOS)) {
         return new ArrayList<>();
      }
      List<CodeClassifyTemplateButtonVO> toolbarButtons = buttonVOS.stream().filter(s -> CodeUseButtonPositionTypeEnum.TOOLBAR.getValue().equalsIgnoreCase(s.getButtonUse())).collect(Collectors.toList());
      if (CollectionUtils.isEmpty(toolbarButtons)) {
         return new ArrayList<>();
      }
      List<CodeButtonVO> buttonVOList = new ArrayList<>();
      for (int i = 0; i < toolbarButtons.size(); i++) {
         buttonVOList.add(toolbarButtons.get(i).getButtonVO());
      }
      return buttonVOList;
   }
}