ludc
2023-05-18 6cdce28d612c56bc5b8524268c78064c0818e46f
Source/UBCS/ubcs-service/ubcs-code/src/main/java/com/vci/ubcs/code/service/impl/MdmEngineServiceImpl.java
@@ -1,63 +1,24 @@
package com.vci.ubcs.code.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.vci.ubcs.code.constant.MdmBtmTypeConstant;
import com.vci.ubcs.code.constant.MdmEngineConstant;
import com.vci.ubcs.code.enumpack.CodeLevelTypeEnum;
import com.vci.ubcs.code.enumpack.CodeSecTypeEnum;
import com.vci.ubcs.code.enumpack.CodeUseButtonPositionTypeEnum;
import com.vci.ubcs.code.lifecycle.CodeDefaultLC;
import com.vci.ubcs.code.entity.CodeClassifyTemplateAttrDO;
import com.vci.ubcs.code.entity.CodeClassifyTemplateDO;
import com.vci.ubcs.code.utils.DateUtils;
import com.vci.corba.common.VCIError;
import com.vci.frameworkcore.compatibility.SmUserQueryServiceI;
import com.vci.frameworkcore.constant.FrameWorkDefaultValueConstant;
import com.vci.frameworkcore.lcstatuspck.FrameworkDataLCStatus;
import com.vci.frameworkcore.pagemodel.SmUserVO;
import com.vci.starter.revision.bo.TreeWrapperOptions;
import com.vci.starter.revision.service.RevisionModelUtil;
import com.vci.starter.web.constant.QueryOptionConstant;
import com.vci.starter.web.constant.RegExpConstant;
import com.vci.starter.web.enumpck.BooleanEnum;
import com.vci.starter.web.enumpck.UserSecretEnum;
import com.vci.starter.web.enumpck.VciFieldTypeEnum;
import com.vci.starter.web.exception.VciBaseException;
import com.vci.starter.web.pagemodel.*;
import com.vci.starter.web.toolmodel.DateConverter;
import com.vci.starter.web.util.VciBaseUtil;
import com.vci.starter.web.util.VciDateUtil;
import com.vci.starter.web.wrapper.VciQueryWrapperForDO;
import com.vci.ubcs.code.service.*;
import com.vci.ubcs.code.vo.pagemodel.*;
import com.vci.web.dto.BaseModelDTO;
import com.vci.web.pageModel.KeyValue;
import com.vci.web.pageModel.*;
import com.vci.web.service.*;
import com.vci.web.service.impl.FormulaServiceImpl;
import com.vci.web.service.impl.OsEnumServiceImpl;
import com.vci.web.util.WebUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.cloud.commons.lang.StringUtils;
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.dto.CodeDeleteBatchDTO;
import com.vci.ubcs.code.dto.CodeOrderDTO;
import com.vci.ubcs.code.entity.CodeAllCode;
import com.vci.ubcs.code.mapper.CodeAllCodeMapper;
import com.vci.ubcs.code.service.*;
import com.vci.ubcs.code.vo.pagemodel.CodeClassifyTemplateVO;
import com.vci.ubcs.code.vo.pagemodel.CodeClassifyVO;
import com.vci.ubcs.code.vo.pagemodel.CodeRuleVO;
import com.vci.ubcs.starter.exception.VciBaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import plm.bs.bom.clientobject.ClientBusinessObject;
import plm.bs.bom.clientobject.ClientBusinessObjectOperation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
//
import static com.vci.frameworkcore.constant.FrameWorkBusLangCodeConstant.DATA_OID_NOT_EXIST;
import static com.vci.web.constant.EnumIdConstant.LC_STATUS_SUBFIX;
/**
 * 主数据引擎服务
@@ -65,2691 +26,1795 @@
 * @author weidy
 * @date 2022-2-22
 */
@Slf4j
@Service
public class MdmEngineServiceImpl implements MdmEngineServiceI {
public class MdmEngineServiceImpl extends ServiceImpl<CodeAllCodeMapper, CodeAllCode> implements MdmEngineService {
//
//
//   /**
//    * 分类的服务
//    */
//   @Resource
//   private ICodeClassifyService classifyService;
//
//   /**
//    * 关键属性的配置
//    */
//   @Autowired
//   private ICodeKeyattrrepeatService keyRuleService;
//   /**
//    * 日志
//    */
//   private Logger logger = LoggerFactory.getLogger(getClass());
//
//   //   @Autowired
//   //   private CodeOsbtmtypeMapper codeOsbtmtypeMapper;
//
   /**
    * 模板的服务
    */
   @Autowired(required = false)
   private ICodeClassifyTemplateAttrService codeClassifyTemplateAttrService;
    /**
     * 必输
     */
    public static final String REQUIRED_CHAR = "*";
    /**
     * 替换字符
     */
    public static final String SPECIAL_CHAR  = "VCI";
    /**
     * 模板的服务
     */
    @Autowired
    private CodeClassifyTemplateServiceI templateService;
   /***
    * 编码规则服务
    */
   @Autowired(required = false)
   private ICodeRuleService codeRuleService;
   /***
    * 分类模板服务
    */
   @Autowired(required = false)
   private  ICodeClstemplateService plCodeClstemplateService;
    /**
     * 模板按钮服务
     */
    @Autowired
    private CodeClassifyTemplateButtonServiceI templateButtonService;
   /**
    * 使用分类的主键获取可以使用的模板对象
    *
    * @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) {
      CodeClassifyTemplateVO templateVO=new CodeClassifyTemplateVO();
      List<CodeClassifyTemplateVO>templateVOs=plCodeClstemplateService.listReleaseTemplateByClassifyOid(codeClassifyOid,hasAttr);
      if(templateVOs.size()>0){
         templateVO=   templateVOs.get(templateVOs.size() - 1);
      }
      return templateVO;
   }
    /**
     * 分类的服务
     */
    @Autowired
    private CodeClassifyServiceI classifyService;
    /**
     * 业务数据的服务
     */
    @Autowired
    @Lazy
   private WebBoServiceI boService;
    /**
     * 公式的服务
     */
    @Autowired
    private FormulaServiceImpl formulaService;
    /**
     * 枚举的服务
     */
    @Autowired
    private OsEnumServiceI enumService;
    /**
     * 生命周期的服务
     */
    @Autowired
    private OsLifeCycleServiceI lifeCycleService;
    /**
     * 编码规则的服务
     */
    @Autowired
    private CodeRuleServiceI ruleService;
    /**
     * 分类码值的服务
     */
    @Autowired
    private CodeClassifyValueServiceI classifyValueService;
    /**
     * 关键属性的配置
     */
    @Autowired
    private CodeKeyAttrRepeatRuleServiceI keyRuleService;
    /**
     * 功能按钮的服务
     */
    @Autowired
    private SmOperationServiceI operationService;
    /**
     * 生成编码的服务
     */
    @Autowired
    private MdmProductCodeServiceI productCodeService;
    /**
     * 阶段的服务
     */
    @Autowired
    private CodePhaseAttrServiceI phaseAttrService;
    /**
     * 日志
     */
    private Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 密级的服务
     */
    @Autowired
    private WebSecretServiceI secretService;
    /**
     * 可输可选
     */
    @Autowired
    private BdSelectInputCharServiceI charService;
    /**
     * 对象的操作
     */
    @Autowired
    private RevisionModelUtil revisionModelUtil;
    /**
     * 相似项查询规则
     */
    @Autowired
    private CodeResembleRuleServiceI resembleRuleService;
    /**
     * 属性的服务
     */
    @Autowired
    private OsAttributeServiceI attributeService;
    /**
     * 用户查询的服务
     */
    @Autowired(required = false)
    private SmUserQueryServiceI userQueryService;
    /**
     * 模板属性的服务
     */
    @Autowired
    private CodeClassifyTemplateAttrServiceI templateAttrService;
    /**
     * 拷贝的版本
     */
    public static final String COPY_FROM_VERSION = "copyfromversion";
    /**
     * 使用分类主键获取页面的内容,包含按钮
     *
     * @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;
    }
    /**
     * 使用主题库分类获取ui相关的内容(不包含按钮)
     *
     * @param codeClassifyOid 主题库的分类的主键
     * @return UI相关的内容
     */
    @Override
    public MdmUIInfoVO getTableDefineByClassifyOid(String codeClassifyOid) {
        VciBaseUtil.alertNotNull(codeClassifyOid, "主题库分类主键");
        return getTableDefineByTemplateVO(getUsedTemplateByClassifyOid(codeClassifyOid));
    }
    /**
     * 使用模板显示对象转换为表格的信息(包含扩展的按钮)
     *
     * @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 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 codeClassifyTemplateOid 模板的主键
     * @return ui相关的内容
     */
    @Override
    public MdmUIInfoVO getFormDefineByTemplateOid(String codeClassifyTemplateOid) {
        return getFormDefineByTemplateOid(codeClassifyTemplateOid, null);
    }
    /**
     * 使用模板的主键获取表单的信息
     *
     * @param codeClassifyTemplateOid 模板的主键
     * @param codeClassifyOid         使用模板的分类主键
     * @return ui相关的内容
     */
    @Override
    public MdmUIInfoVO getFormDefineByTemplateOid(String codeClassifyTemplateOid, String codeClassifyOid) {
        CodeClassifyTemplateVO templateVO = templateService.getObjectHasAttrByOid(codeClassifyTemplateOid);
        MdmUIInfoVO uiInfoVO = new MdmUIInfoVO();
        uiInfoVO.setTemplateVO(templateVO);
        uiInfoVO.setFormDefineVO(wrapperFormDefineByTemplate(templateVO, codeClassifyOid));
        wrapperResemble(templateVO, uiInfoVO);
        return uiInfoVO;
    }
    /**
     * 封装相似项查询的列表
     *
     * @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 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 distinct (t.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);
        if (CollectionUtils.isEmpty(tempAttrOidArr) || StringUtils.isBlank(tempAttrOidArr.get(0).getAttributeValue("codetempattroidarr"))) {
            return new ArrayList<>();
        }
        return VciBaseUtil.str2List(tempAttrOidArr.get(0).getAttributeValue("codetempattroidarr"));
    }
    /**
     * 使用主题库分类的主键获取表单的信息
     *
     * @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;
    }
    /**
     * 使用分类的主键获取表格的定义
     *
     * @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 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());
    }
    /**
     * 使用模板主键获取ui相关的内容
     *
     * @param templateOid 模板的主键
     * @return ui相关的内容
     */
    @Override
    public MdmUIInfoVO getTableDefineByTemplateOid(String templateOid) {
        return getTableDefineByTemplateVO(templateService.getObjectHasAttrByOid(templateOid));
    }
    /**
     * 使用分类主键获取工具栏中的按钮信息
     *
     * @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;
    }
    /**
     * 使用分类获取对应的数据
     *
     * @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(MdmEngineConstant.CODE_CLASSIFY_OID_FIELD, codeClassifyOid);
        } else {
            conditionMap.put(MdmEngineConstant.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 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());
        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(boService.queryCountBySql(sqlBO.getSqlCount(), new HashMap<>()));
        }
        return dataGrid;
    }
    /**
     * 根据模板属性生成相应的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(MdmEngineConstant.CODE_FIELD)) {
            selectFieldList.add(MdmEngineConstant.CODE_FIELD);
        }
        if (!selectFieldList.contains(MdmEngineConstant.CODE_CLASSIFY_OID_FIELD)) {
            selectFieldList.add(MdmEngineConstant.CODE_CLASSIFY_OID_FIELD);
        }
        if (!selectFieldList.contains(MdmEngineConstant.CODE_TEMPLATE_OID_FIELD)) {
            selectFieldList.add(MdmEngineConstant.CODE_TEMPLATE_OID_FIELD);
        }
        if (!selectFieldList.contains(MdmEngineConstant.CODE_FULL_PATH_FILED)) {
            selectFieldList.add(MdmEngineConstant.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;
    }
    /**
     * 空格
     */
    public static final String SPACE = " ";
    /**
     * 组合查询条件的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);
            }
        }
    }
    /**
     * 封装最终的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();
    }
    /**
     * 默认的时间格式
     */
    private static final String DATETIME_FORMAT = "yyyy-mm-dd hh24:mi:ss";
    /**
     * 日期格式
     */
    private static final String DATE_FORMAT = "yyyy-mm-dd";
    /**
     * 只是sql
     */
    public static final String ONLY = "${vcionly}";
    /**
     * 获取查询条件中的值的,处理不同的类型
     *
     * @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 + "'";
            }
        }
    }
    /**
     * 封装开关的内容,常用于导出
     * @param dataMap 数据的内容
     * @param templateVO 模板的显示
     */
    @Override
    public void wrapperBoolean(List<Map<String, String>> dataMap, CodeClassifyTemplateVO templateVO){
        List<String> booleanAttributes = templateVO.getAttributes().stream().filter(s -> VciFieldTypeEnum.VTBoolean.name().equalsIgnoreCase(s.getAttributedatatype())).map(s -> s.getId().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(booleanAttributes)){
            dataMap.stream().forEach(data -> {
                booleanAttributes.stream().forEach(attrId->{
                    if(data.containsKey(attrId)){
                        String value = data.get(attrId);
                        data.put(attrId, BooleanEnum.TRUE.getValue().equalsIgnoreCase(value)?"是":"否");
                    }
                });
            });
        }
    }
    /**
     * 封装查询出来的数据
     *
     * @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);
                }
            });
        }
    }
    /**
     * 获取枚举的下拉选项
     *
     * @param attrVO 模板属性的对象
     * @return 下拉选项
     */
    @Override
    public List<KeyValue> listComboboxItems(CodeClassifyTemplateAttrVO attrVO) {
        List<KeyValue> comboboxKVs;
        if (StringUtils.isNotBlank(attrVO.getEnumString())) {
            comboboxKVs = JSONObject.parseArray(attrVO.getEnumString(), KeyValue.class);
        } else {
            comboboxKVs = enumService.getEnum(attrVO.getEnumid());
        }
        return comboboxKVs;
    }
    /**
     * 处理组合规则的内容,如果不在枚举中,会返回原本的值
     *
     * @param compAttrVOs 组合规则属性
     * @param data        当前行数据
     */
    private void wrapperComponentRule(Collection<CodeClassifyTemplateAttrVO> compAttrVOs, Map<String, String> data) {
        if (!CollectionUtils.isEmpty(compAttrVOs)) {
            compAttrVOs.stream().forEach(attrVO -> {
                String attrId = attrVO.getId().toLowerCase(Locale.ROOT);
                //用公式去计算
                //先用当前数据替换一下
                String calculatedValue = formulaService.getValueByFormula(data, attrVO.getComponentrule());
                data.put(attrId, calculatedValue);
            });
        }
    }
    /**
     * 使用数据主键获取数据的全部信息
     *
     * @param oid         主键
     * @param templateOid 模板的主键
     * @return 数据的内容
     */
    @Override
    public BaseResult<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<ClientBusinessObject> cbos = boService.queryByOnlySql(sqlBO.getSqlUnPage());
        if (CollectionUtils.isEmpty(cbos)) {
            throw new VciBaseException("数据在系统中不存在,是否因为修改过业务类型?");
        }
        Map<String, String> data = new HashMap<>();
        ClientBusinessObject cbo = cbos.get(0);
        WebUtil.copyValueToMapFromCbos(cbo, data);
        List<Map<String, String>> dataList = new ArrayList<>();
        dataList.add(data);
        wrapperData(dataList, templateVO, sqlBO.getSelectFieldList(), true);
        BaseResult<Map<String, String>> result = BaseResult.success(data);
        //我们要看是否不是升版的,升版的话,需要对比不相等的属性
        String copy = cbo.getCopyFromVersion();
        if (StringUtils.isBlank(copy)) {
            copy = cbo.getAttributeValue("copyfromversion");
        }
        if (StringUtils.isNotBlank(copy)) {
            //说明有变更的内容
            CodeTemplateAttrSqlBO oldSqlBO = getSqlByTemplateVO(btmId, templateVO, WebUtil.getOidQuery(copy), new PageHelper(-1));
            //我们使用和业务类型的来查询
            List<ClientBusinessObject> oldCbos = boService.queryByOnlySql(oldSqlBO.getSqlUnPage());
            if (!CollectionUtils.isEmpty(oldCbos)) {
                Map<String, String> newData = new HashMap<>();
                WebUtil.copyValueToMapFromCbos(cbo, newData);
                Map<String, String> oldData = new HashMap<>();
                WebUtil.copyValueToMapFromCbos(oldCbos.get(0), oldData);
                Map<String, String> difFieldMap = new HashMap<>();
                newData.forEach((key, value) -> {
                    String oldValue = oldData.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 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 classifySecOid         码段的主键
     * @param parentClassifyValueOid 上级分类的主键
     * @return 分类码值的内容
     */
    @Override
    public List<CodeClassifyValueVO> listCodeClassifyValueBySecOid(String classifySecOid, String parentClassifyValueOid) {
        return classifyValueService.listCodeClassifyValueBySecOid(classifySecOid, parentClassifyValueOid);
    }
    /**
     * 申请单一编码
     *
     * @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());
        //默认的属性都不用从前端拷贝
        //设置编码需要的默认属性的内容
        copyValueToCBO(classifyFullInfo, cbo, orderDTO, templateVO, false);
        //TODO:因为默认的属性都不拷贝,目前集团码叫name,并没有从DTO拷贝到cbo里。增加一个单独处理,以后再看要不要调整
        cbo.setName(orderDTO.getName() == null ? "" : orderDTO.getName());
        //end -- modify by lihang @20220407
        List<ClientBusinessObject> cboList = new ArrayList<>();
        //备注
        cbo.setDescription(orderDTO.getDescription()==null?"":orderDTO.getDescription());
        cboList.add(cbo);
        List<String> codeList = productCodeService.productCodeAndSaveData(classifyFullInfo, templateVO, ruleVO, orderDTO.getSecDTOList(), cboList);
        batchSaveSelectChar(templateVO, cboList);
        return codeList.size() > 0 ? codeList.get(0) : "";
    }
    /**
     * 修改主题库数据
     *
     * @param orderDTO 数据的内容,不用包含码段的内容了
     */
    @Override
    public void editSaveCode(CodeOrderDTO orderDTO) {
        VciBaseUtil.alertNotNull(orderDTO, "编码申请相关的属性的内容都为空", orderDTO.getOid(), "数据主键",
                orderDTO.getCodeClassifyOid(), "主题库分类的主键");
        CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(orderDTO.getCodeClassifyOid());
        //找业务类型,然后使用主键去获取数据库里的数据
        List<ClientBusinessObject> cbos = boService.queryCBO(classifyFullInfo.getTopClassifyVO().getBtmtypeid(), WebUtil.getOidQuery(orderDTO.getOid()));
        if (CollectionUtils.isEmpty(cbos)) {
            throw new VciBaseException(DATA_OID_NOT_EXIST);
        }
        ClientBusinessObject cbo = cbos.get(0);
        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()==null?"":orderDTO.getDescription());
        cbo.setName(orderDTO.getName()==null?"":orderDTO.getName());
        try {
            cbo.setAttributeValueWithNoCheck("description", orderDTO.getDescription());
            cbo.setAttributeValue("name", orderDTO.getName());
        } catch (VCIError e) {
            e.printStackTrace();
        }
        //修改的时候,编码是不变的
        BatchCBO batchCBO = new BatchCBO();
        batchCBO.getUpdateCbos().add(cbo);
        List<ClientBusinessObject> cboList = new ArrayList<>();
        cboList.add(cbo);
        boService.persistenceBatch(batchCBO);
        batchSaveSelectChar(templateVO, cboList);
    }
    /**
     * 升版的主题库数据
     *
     * @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());
        cbo.setDescription(orderDTO.getDescription()==null?"":orderDTO.getDescription());
        cbo.setName(orderDTO.getName()==null?"":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 templateVO 模板的对象
     * @param cboList    数据的内容
     */
    @Override
    public void batchSaveSelectChar(CodeClassifyTemplateVO templateVO, List<ClientBusinessObject> 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 = new CopyOnWriteArrayList<>();
                    cboList.parallelStream().forEach(cbo -> {
                        String value = cbo.getAttributeValue(attrVO.getId());
                        if (StringUtils.isNotBlank(value)) {
                            valuesList.add(value);
                        }
                    });
                    if (!CollectionUtils.isEmpty(valuesList)) {
                        charService.saveBySameNamespaceAndFlag(templateVO.getBtmTypeId(), attrVO.getLibraryIdentification(), valuesList, sessionInfo);
                    }
                });
            }
        }
    }
    /**
     * 删除主题库数据
     *
     * @param deleteBatchDTO 数据的内容,必须要有主键和分类主键
     */
    @Override
    public void deleteCode(CodeDeleteBatchDTO deleteBatchDTO) {
        VciBaseUtil.alertNotNull(deleteBatchDTO, "编码申请相关的属性和码段的内容都为空", deleteBatchDTO.getOidList(), "数据主键",
                deleteBatchDTO.getCodeClassifyOid(), "主题库分类的主键");
        CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(deleteBatchDTO.getCodeClassifyOid());
        //找业务类型,然后使用主键去获取数据库里的数据
        Collection<Collection<String>> oidCollection = VciBaseUtil.switchCollectionForOracleIn(deleteBatchDTO.getOidList());
        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<ClientBusinessObject> editCBOs = cboList.stream().filter(s -> !CodeDefaultLC.EDITING.getValue().equalsIgnoreCase(s.getLcStatus())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(editCBOs)) {
            ClientBusinessObject cbo = editCBOs.get(0);
            throw new VciBaseException("编码为{0}等共{1}条数据的状态不是[{2}],不允许删除", new String[]{cbo.getId(), String.valueOf(editCBOs.size()), CodeDefaultLC.EDITING.getText()});
        }
        //只能删除自己创建的数据
        String userId = WebUtil.getCurrentUserId();
        for (ClientBusinessObject 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()));
        WebUtil.setPersistence(true);
        boService.persistenceBatch(batchCBO);
    }
    /**
     * 拷贝数据到cbo对象上
     *
     * @param classifyFullInfo 分类的全部信息
     * @param cbo              业务数据
     * @param orderDTO         编码申请的信息
     * @param templateVO       模板的显示对象
     * @param edit             是否为修改
     */
    private void copyValueToCBO(CodeClassifyFullInfoBO classifyFullInfo, ClientBusinessObject 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();
        }
        orderDTO.getData().forEach((key, value) -> {
            if (!edit || (!boService.checkUnAttrUnEdit(key) &&
                    !VciQueryWrapperForDO.LC_STATUS_FIELD.equalsIgnoreCase(key))) {
                try {
                    cbo.setAttributeValue(key, value);
                } catch (VCIError e) {
                    logger.error("设置属性的值错误", e);
                }
            }
        });
        try {
            cbo.setAttributeValue(MdmEngineConstant.CODE_CLASSIFY_OID_FIELD, classifyFullInfo.getCurrentClassifyVO().getOid());
            cbo.setAttributeValue(MdmEngineConstant.CODE_TEMPLATE_OID_FIELD, templateVO.getOid());
            cbo.setAttributeValue(MdmEngineConstant.CODE_FULL_PATH_FILED, fullPath);
            if (!edit && StringUtils.isBlank(orderDTO.getLcStatus())) {
                //找生命周期的起始状态,
                if (StringUtils.isNotBlank(cbo.getLctId())) {
                    OsLifeCycleVO lifeCycleVO = lifeCycleService.getLifeCycleById(cbo.getLctId());
                    if (lifeCycleVO != null) {
                        cbo.setLcStatus(lifeCycleVO.getStartStatus());
                    } else {
                        cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
                    }
                } else {
                    cbo.setLcStatus(CodeDefaultLC.EDITING.getValue());
                }
            }
            int secret = VciBaseUtil.getInt(cbo.getAttributeValue(MdmEngineConstant.SECRET_FIELD));
            if (secret == 0 || !secretService.checkDataSecret(secret)) {
                Integer userSecret = VciBaseUtil.getCurrentUserSecret();
                cbo.setAttributeValue(MdmEngineConstant.SECRET_FIELD, String.valueOf((userSecret == null || userSecret == 0) ? UserSecretEnum.NONE.getValue() : userSecret));
            }
        } catch (Throwable e) {
            logger.error("设置默认的属性的值错误", e);
        }
    }
    /**
     * 转换组合规则的值
     *
     * @param templateVO 模板的显示对象,需要包含模板属性
     * @param orderDTO   编码申请的信息
     */
    private void switchComponentAttrOnOrder(CodeClassifyTemplateVO templateVO, CodeOrderDTO orderDTO) {
        Map<String, CodeClassifyTemplateAttrVO> compAttrVOMap = templateVO.getAttributes().stream().filter(s -> StringUtils.isNotBlank(s.getComponentrule())).collect(Collectors.toMap(s -> s.getId().toLowerCase(Locale.ROOT), t -> t));
        if (!CollectionUtils.isEmpty(compAttrVOMap)) {
            Map<String, String> dataMap = WebUtil.objectToMapString(orderDTO);
            Map<String, String> dataLowMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(dataMap)) {
                dataMap.forEach((key, value) -> {
                    dataLowMap.put(key.toLowerCase(Locale.ROOT), value);
                });
            }
            dataLowMap.putAll(orderDTO.getData());
            compAttrVOMap.forEach((attrId, attrVO) -> {
                dataLowMap.put(attrId, formulaService.getValueByFormula(dataLowMap, attrVO.getComponentrule()));
            });
            dataLowMap.forEach((key, value) -> {
                setValueToOrderDTO(orderDTO, key, value);
            });
        }
    }
    /**
     * 处理分类注入的信息
     *
     * @param templateVO         模板的显示对象,必须要后模板的属性
     * @param 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 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);
                }
            });
        }
    }
    /**
     * 校验枚举的内容
     *
     * @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 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) {
        //先获取关键属性的规则,也利用继承的方式
        CodeKeyAttrRepeatRuleVO 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) {
                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, CodeKeyAttrRepeatRuleVO 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 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)
                || VciQueryWrapperForDO.SECRET_MANAGE_FIELD_MAP.containsKey(attrId)
                || VciQueryWrapperForDO.REVISION_MANAGE_FIELD_MAP.containsKey(attrId)
                || VciQueryWrapperForDO.LIFECYCLE_MANAGE_FIELD_MAP.containsKey(attrId)
                || VciQueryWrapperForDO.BASE_MODEL_COMPATIBILITY_MAP.containsValue(attrId)
        ) {
            value = WebUtil.getStringValueFromObject(WebUtil.getValueFromField(WebUtil.getFieldForObject(attrId, orderDTO.getClass()).getName(), orderDTO));
        } else {
            //说明是自行配置的
            //前端必须要传递小写的属性
            value = orderDTO.getData().getOrDefault(attrId, "");
        }
        return 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 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 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 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 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 预览的信息,包含模板的主键
     * @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 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());
        //还需要修改allCode的生命周期
        Map<String, String> conditionMap = new HashMap<>();
        conditionMap.put("createcodeoid", QueryOptionConstant.IN + "(" + VciBaseUtil.toInSql(oids.toArray(new String[0])) + ")");
        conditionMap.put("createcodebtm", baseModelDTO.getBtmname());
        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);
            boService.persistenceBatch(batchCBO);
        } else {
            lifeCycleService.transCboStatus(cboList, baseModelDTO.getLcStatus());
        }
        lifeCycleService.transCboStatus(codeCbos, baseModelDTO.getLcStatus());
    }
    /**
     * 相似项查询
     *
     * @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 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 codeClassifyOid 分类主键
     * @return 规则,如果不存在会返回null
     */
    @Override
    public CodeResembleRuleVO getUseResembleRuleByClassifyOid(String codeClassifyOid) {
        CodeClassifyFullInfoBO classifyFullInfo = classifyService.getClassifyFullInfo(codeClassifyOid);
        return getUseResembleRule(classifyFullInfo, classifyFullInfo.getCurrentClassifyVO());
    }
    /**
     * 获取使用的相似查询规则
     *
     * @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 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;
    }
    /**
     * 模板属性转换为表格定义的信息
     *
     * @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 attrVO 模板属性
     * @param forEdit 是否是编辑所需
     * @return 表格的字段
     */
    @Override
    public UITableFieldVO templateAttr2TableField(CodeClassifyTemplateAttrVO attrVO,boolean forEdit) {
        UITableFieldVO fieldVO = new UITableFieldVO();
        if (SECRET_FILED.equalsIgnoreCase(attrVO.getId())) {
            attrVO.setEnumid(OsEnumServiceImpl.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(attrVO.getAttrTableWidth());
            fieldVO.setWidth(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;
    }
    /**
     * 密级的字段
     */
    public static final String SECRET_FILED = "secretgrade";
    /**
     * 模板属性转换为表单的字段
     *
     * @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);
        }
        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;
    }
    /**
     * 属性类型与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 oid     业务数据主键
     * @param btmName 业务类型
     * @param pass    是否通过
     * @return 执行结果
     */
    @Override
    public BaseResult 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 BaseResult.success();
        } else {
            return BaseResult.fail("标记失败");
        }
    }
    /**
     * 使用分类的主键获取业务数据
     *
     * @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<CodeClassifyTemplateDO> templateDOList = boService.queryObject(CodeClassifyTemplateDO.class, templateOidMap);
        templateOidMap.clear();
        templateOidMap.put("CLASSIFYTEMPLATEOID",templateOid);
        List<CodeClassifyTemplateAttrDO> attrDOList = boService.queryObject(CodeClassifyTemplateAttrDO.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 orderDTOList 编码相关的信息,不需要码段的信息
     * @return 执行结果
     */
    @Override
    public BaseResult 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 BaseResult.success();
    }
    /**
     * 使用分类的编号路径,获取表格的相关定义
     *
     * @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 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 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 codeRuleService.getObjectHasSecByOid(codeRuleOid);
   }
//
//   /**
//    * 获取枚举的下拉选项
//    *
//    * @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 = baseMapper.selectList(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());
//      CodeClstemplateVO 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);
////      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(CodeClstemplateVO templateVO, CodeClassifyFullInfoBO classifyFullInfoBO, CodeOrderDTO orderDTO) {
////      Map<String,CodeClstempattrVO> 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(CodeClstemplateVO templateVO, CodeOrderDTO orderDTO) {
////      Map<String, CodeClstempattrVO> 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(CodeClstemplateVO templateVO, CodeOrderDTO orderDTO) {
////      Map<String, CodeClstempattrVO> 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(CodeClstemplateVO templateVO, CodeOrderDTO orderDTO) {
////      Map<String, CodeClstempattrVO> 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, CodeClstemplateVO templateVO, CodeOrderDTO orderDTO) {
////      //先获取关键属性的规则,也利用继承的方式
////      CodeKeyattrrepeatVO keyRuleVO = keyRuleService.getRuleByClassifyFullInfo(classifyFullInfo);
////      //注意的是keyRuleVO可能为空,表示不使用规则控制
////      //获取所有的关键属性
////      Map<String, CodeClstempattrVO> 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(CodeClstemplateVO templateVO, CodeOrderDTO orderDTO) {
////      //如果枚举可以修改,则不需要校验是否符合枚举的选项
////
////      Map<String, CodeClstempattrVO> 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)) {
////               CodeClassifyTemplateAttrVO codeClassifyTemplateAttrVO = new CodeClassifyTemplateAttrVO();
////               BeanUtils.copyProperties(attrVO,codeClassifyTemplateAttrVO);
////               //有值才能校验
////               List<KeyValue> comboboxKVs = listComboboxItems(codeClassifyTemplateAttrVO);
////               if (!comboboxKVs.stream().anyMatch(s -> value.equalsIgnoreCase(s.getKey()))) {
////                  throw new VciBaseException("属性【{0}】的值不符合枚举的要求", new String[]{attrVO.getName()});
////               }
////            }
////         });
////      }
////   }
////
////   /**
////    * 转换时间的格式
////    *
////    * @param templateVO 模板的显示对象,需要包含属性
////    * @param orderDTO   编码申请的信息
////    */
////   private void switchDateAttrOnOrder(CodeClstemplateVO templateVO, CodeOrderDTO orderDTO) {
////      Map<String, CodeClstempattrVO> 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, CodeClstemplateVO 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(CodeClstemplateVO templateVO, /*List<ClientBusinessObject> cboList*/
////                           List<String> cboList) {
////      if (templateVO != null && !CollectionUtils.isEmpty(cboList)) {
////         //是异步的,所以直接循环
////         List<CodeClstempattrVO> 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) {
////      CodeClstemplateVO 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(CodeClstemplateVO 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<CodeClstempattrVO>> 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<CodeClstempattrVO> value = attrGroupMap.get(key);
////            //找到这个分组的属性的第一个
////            CodeClstempattrVO 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(CodeClstempattrVO 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(CodeClstemplateVO templateVO, MdmUIInfoVO uiInfoVO) {
////      List<CodeClstempattrVO> 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(CodeClstempattrVO 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<CodeOsbtmtypeEntity> btmWrapper = new QueryWrapper<>();
////      btmWrapper.eq("OID",orderDTO.getOid());
////      CodeWupinEntity cbo = codeOsbtmtypeMapper.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();
////      }
////
////
////      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, cboList);
////   }
//
}