Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/OsAttributeServiceImpl.java
@@ -4,33 +4,36 @@
import com.vci.client.common.datatype.VTInteger;
import com.vci.client.common.datatype.VTLong;
import com.vci.client.common.datatype.VTString;
import com.vci.client.mw.ClientSessionUtility;
import com.vci.common.utility.ObjectUtility;
import com.vci.corba.common.PLException;
import com.vci.corba.omd.atm.AttributeDef;
import com.vci.dto.OsAttributeDTO;
import com.vci.enumpck.UI.ItemTypeEnum;
import com.vci.model.OsAttributeDO;
import com.vci.omd.dataType.VTDataType;
import com.vci.pagemodel.OsEnumItemVO;
import com.vci.omd.objects.OtherInfo;
import com.vci.pagemodel.OsAttributeVO;
import com.vci.pagemodel.OsEnumVO;
import com.vci.pagemodel.OsUsedAttributeVO;
import com.vci.po.OsAttributePO;
import com.vci.starter.poi.bo.ReadExcelOption;
import com.vci.starter.poi.bo.WriteExcelData;
import com.vci.starter.poi.bo.WriteExcelOption;
import com.vci.starter.poi.constant.ExcelLangCodeConstant;
import com.vci.starter.poi.util.ExcelUtil;
import com.vci.starter.web.annotation.log.VciUnLog;
import com.vci.starter.web.enumpck.VciFieldTypeEnum;
import com.vci.starter.web.exception.VciBaseException;
import com.vci.starter.web.pagemodel.BaseQueryObject;
import com.vci.starter.web.pagemodel.DataGrid;
import com.vci.starter.web.pagemodel.*;
import com.vci.starter.web.util.*;
import com.vci.model.OsAttributeDO;
import com.vci.pagemodel.OsAttributeVO;
import com.vci.web.properties.UsedNames;
import com.vci.web.enumpck.PortalVITypeFlag;
import com.vci.web.service.OsAttributeServiceI;
import com.vci.web.service.OsBaseServiceI;
import com.vci.web.service.OsEnumServiceI;
import com.vci.web.service.OsLinkTypeServiceI;
import com.vci.web.util.Func;
import com.vci.starter.web.util.Lcm.Func;
import com.vci.web.util.PlatformClientUtil;
import com.vci.web.util.WebUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -38,14 +41,11 @@
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
//import static com.vci.client.omd.attribpool.ui.VTDataTypePanel.*;
import static com.vci.omd.constants.AttributeConstants.*;
/**
@@ -80,14 +80,22 @@
   private Integer NAME_MAX_LENGTH = 28;
   /**
    * 系统中变量配置文件中配置的key
    * 数据库中的一些关键字
    */
   private final String SYSUSEDNAMES = "sysUsedNames";
   /**
    * 数据库中关键字配置文件中配置的key
    */
   private final String DATABASEUSEDNAMES = "dataBaseUsedNames";
   private final List<String> DATABASEUSEDNAMELIST = Arrays.asList(
         "ACCESS", "ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC", "AUDIT", "BETWEEN",
         "BY", "CHAR", "CHECK", "CLUSTER", "COLUMN", "COMMENT", "COMPRESS", "CONNECT",
         "CREATE", "CURRENT", "DATE", "DECIMAL", "DEFAULT", "DELETE", "DESC", "DISTINCT",
         "DROP", "ELSE", "EXCLUSIVE", "EXISTS", "FILE", "FLOAT", "FOR", "FROM", "GRANT", "GROUP",
         "HAVING", "IDENTIFIED", "IMMEDIATE", "IN", "INCREMENT", "INDEX", "INITIAL",
         "INSERT", "INTEGER", "INTERSECT", "INTO", "IS", "LEVEL", "LIKE", "LOCK", "LONG",
         "MAXEXTENTS", "MINUS", "MLSLABEL", "MODE", "MODIFY", "NOAUDIT", "NOCOMPRESS",
         "NOT", "NOWAIT", "NULL", "NUMBER", "OF", "OFFLINE", "ON", "ONLINE", "OPTION", "OR", "ORDER",
         "P", "CTFREE", "PRIOR", "PRIVILEGES", "PUBLIC", "RAW", "RENAME", "RESOURCE", "REVOKE",
         "ROW", "ROWID", "ROWNUM", "ROWS", "SELECT", "SESSION", "SET", "SHARE", "SIZE", "SMALLINT",
         "START", "SUCCESSFUL", "SYNONYM", "SYSDATE", "TABLE", "THEN", "TO", "TRIGGER", "UID", "UNION",
         "UNIQUE", "UPDATE", "USER", "VALIDATE", "VALUES", "VARCHAR", "VARCHAR2", "VIEW",
         "WHENEVER", "WHERE", "WITH");
   /**
    * 链接类型服务
@@ -104,6 +112,18 @@
   private OsBtmServiceImpl osBtmService;
   /**
    * 枚举的服务
    */
   @Autowired
   @Lazy
   private OsEnumServiceI  enumService;
   /**
    *  必填列
    */
   private List<Integer> ColumnNameisRed = new ArrayList<Integer>();
   /**
    * 默认的属性
    */
   private static List<OsAttributeVO> defaultAttributeVOs = new ArrayList<>();
@@ -112,6 +132,100 @@
    * 默认属性的映射,key是小写
    */
   private static Map<String,OsAttributeVO> defaultAttributeVOMap = new HashMap<>();
   @Override
   public List<Tree> getTreeAttributesByBtmName(TreeQueryObject treeQueryObject) {
      List<Tree> rootTreeList=new ArrayList<>();
      Map<String, String> conditionMap = treeQueryObject.getConditionMap();
      if (conditionMap == null) {
         conditionMap = new HashMap<>();
      }
      String typeName = StringUtils.isBlank(conditionMap.get("typeName")) ? "" : conditionMap.get("typeName");
      if (StringUtils.isBlank(typeName)) {
         VciBaseUtil.alertNotNull(typeName,"业务类型名称");
      }
      try {
         String typeFlag=StringUtils.isBlank(conditionMap.get("typeFlag"))?"":conditionMap.get("typeFlag");
         PortalVITypeFlag portalVITypeFlag= PortalVITypeFlag.getByName(typeFlag);
         Short viTypeFlag=-1;
         if(portalVITypeFlag!=null){
            viTypeFlag=portalVITypeFlag.getIntVal();
         }
         boolean isDefault =Boolean.parseBoolean(conditionMap.get("isDefault"));
         Tree tree = new Tree("root", "【" + typeName + "】属性信息", "root");
         tree.setLevel(0);
         rootTreeList.add(tree);
         getChildTree(rootTreeList,typeName, viTypeFlag,isDefault);
      }catch (Throwable e){
       e.printStackTrace();
      }
      return rootTreeList;
   }
   /**
    * 构造属性树节点
    * @param parentTreeList
    * @param refTypeName
    * @param refFlag
    * @param isDefault
    * @throws Exception
    */
   private void getChildTree(List<Tree> parentTreeList,String refTypeName,int refFlag,boolean isDefault) throws Exception {
      for (Tree pTree : parentTreeList) {
         if (pTree.getLevel()>= 3) {
            continue;
         }
         Object o= pTree.getData();
         String pName=pTree.getText();
         boolean isOsAttributeVO=false;
         if(o instanceof OsAttributeVO){
            isOsAttributeVO=true;
            OsAttributeVO osAttributeVO=(OsAttributeVO)o;
            String other = osAttributeVO.getOther();
            OtherInfo otherInfo = OtherInfo.getOtherInfoByText(other);
            refFlag = otherInfo.getRefFlag();
            refTypeName = otherInfo.getRefTypeName();
         }
         List<OsAttributeVO> childOsAttributeVOList=new ArrayList<>();
         if (refFlag != -1) {
            // pName: 为参照属性名加上路径
            childOsAttributeVOList=getOsAttributeVOSByBtName(refTypeName,refFlag,isDefault);
            if(!CollectionUtils.isEmpty(childOsAttributeVOList)) {
               List<Tree> childTreeList= new ArrayList<>();
               boolean finalIsOsAttributeVO = isOsAttributeVO;
               childOsAttributeVOList.stream().forEach(childOsAttributeVO->{
                  Tree childTree = new Tree(childOsAttributeVO.getOid(), childOsAttributeVO.getId(), childOsAttributeVO);
                  childTree.setOid(childOsAttributeVO.getOid());
                  childTree.setParentName(pTree.getText());
                  childTree.setParentId(pTree.getOid());
                  childTree.setLevel(pTree.getLevel()+1);
                  childTree.setLeaf(true);
                  if(finalIsOsAttributeVO) {
                     childTree.setText(pName + "." + childOsAttributeVO.getId());
                  }else{
                     childTree.setText(childOsAttributeVO.getId());
                  }
                  if (childTree.getLevel()>= 3) {
                     childTree.setLeaf(true);
                  }
                  childTreeList.add(childTree);
               });
               if(childTreeList.size()>0){
                  pTree.setChildren(childTreeList);
                  pTree.setExpanded(false);
                  getChildTree(childTreeList,refTypeName,refFlag,isDefault);
               }else{
                  pTree.setLeaf(true);
                  pTree.setExpanded(true);
               }
            }
         }else{
            pTree.setExpanded(true);
         }
      }
   }
   /**
    * 获取默认的属性
@@ -184,14 +298,10 @@
   public List<OsAttributeVO> getByAttributeNames(String[] attrNames) throws PLException {
      VciBaseUtil.alertNotNull(attrNames,"属性名");
      List<OsAttributeVO> osAttributeVOS = new ArrayList<>();
      for (int i = 0; i < attrNames.length; i++) {
         AttributeDef[] attributeDefs = platformClientUtil.getAttributeService().getAttributeDefs(attrNames[i],1,1);
         if(Func.isNotEmpty(attributeDefs)){
            Arrays.stream(attributeDefs).forEach(attributeDef -> {
               osAttributeVOS.add(attributeDO2VO(attributeDef));
            });
         }
      }
      AttributeDef[] attributeDefs = platformClientUtil.getAttributeService().getAttributeDefsByNames(attrNames);
      Arrays.stream(attributeDefs).forEach(attr->{
         osAttributeVOS.add(attributeDO2VO(attr));
      });
      return osAttributeVOS;
   }
@@ -224,19 +334,30 @@
         attributeVO.setId(attribItem.name);
         attributeVO.setCreator(attribItem.creator);
         try {
            attributeVO.setCreateTime(VciDateUtil.str2Date(String.valueOf(attribItem.createTime),VciDateUtil.DateTimeFormat));
            attributeVO.setLastModifyTime(VciDateUtil.str2Date(String.valueOf(attribItem.modifyTime),VciDateUtil.DateTimeFormat));
            attributeVO.setCreateTime(new Date(attribItem.createTime));
            attributeVO.setLastModifyTime(new Date(attribItem.modifyTime));
            attributeVO.setTs(VciDateUtil.str2Date(attribItem.ts,VciDateUtil.DateTimeMillFormat));
         }catch (Throwable e){
            e.printStackTrace();
            String errorLog = "属性DO转VO时出错,原因:"+VciBaseUtil.getExceptionMessage(e);
            logger.error(errorLog);
            throw new VciBaseException(errorLog);
         }
         attributeVO.setLastModifier(attribItem.modifier);
         attributeVO.setName(attribItem.label);
         attributeVO.setDescription(attribItem.description);
         attributeVO.setAttributeDataType(attribItem.vtDataType);
         attributeVO.setAttributeDataTypeText(VciFieldTypeEnum.getTextByValue(attribItem.vtDataType));
         //获取UI属性类型
         attributeVO.setAttributeUIType(ItemTypeEnum.convertAttributeTypeTOUITypeTextByValue(attribItem.vtDataType,false));
         //获取UI属性类型文本
         attributeVO.setAttributeUITypeText(ItemTypeEnum.convertAttributeTypeTOUITypeTextByValue(attribItem.vtDataType,true));
         attributeVO.setDefaultValue(attribItem.defValue);
         attributeVO.setRange(attribItem.rage);
         if(Func.isNotBlank(attribItem.rage)){
            attributeVO.setRange(attribItem.rage.replace("&lt;","<"));
         }else{
            attributeVO.setRange(attribItem.rage);
         }
         attributeVO.setOther(attribItem.other);
         //处理参照相关属性
         if(StringUtils.isNotBlank(attribItem.other)) {
@@ -248,6 +369,12 @@
                     attributeVO.setBtmTypeId(s.split("=")[1].trim());
                  }
                  //链接类型不支持
                  if (s.toLowerCase().contains("link") && s.split("=").length > 1) {//必须要判断长度,因为枚举的时候也是包含这个btm的
                     attributeVO.setLinkTypeName(s.split("=")[1].trim());
                  }
                  if (s.toLowerCase().contains("version") && s.split("=").length > 1) {//必须要判断长度,因为枚举的时候也是包含这个btm的
                     attributeVO.setVersion(WebUtil.getInt(s.split("=")[1].trim()));
                  }
               }
            }
            //必输和长度
@@ -390,6 +517,32 @@
   }
   /**
    * 使用属性编号获取对象--批量
    *
    * @param attrCodes 属性的英文名称
    * @param attributeVOMap 属性对象
    * @return 属性的显示对象
    */
   @Override
   public List<OsAttributeVO> listAttrByIds(Collection<String> attrCodes,Map<String, OsAttributeVO> attributeVOMap) {
      if(CollectionUtils.isEmpty(attrCodes)){
         return null;
      }
      if(attributeVOMap == null){
         attributeVOMap = self.selectAllAttributeMap();
      }
      List<OsAttributeVO> attributeVOS = new ArrayList<>();
      Map<String, OsAttributeVO> finalAttributeVOMap = attributeVOMap;
      attrCodes.stream().forEach(attrCode->{
         OsAttributeVO attributeVO = finalAttributeVOMap.getOrDefault(attrCode.toLowerCase(),null);
         if(attributeVO!=null){
            attributeVOS.add(attributeVO);
         }
      });
      return attributeVOS;
   }
   /**
    * 批量添加属性
    *
    * @param attribItemList 属性的列表
@@ -450,9 +603,13 @@
      );
      //属性英文名称校验(判空、系统中判重、是否关键字、是否合规等)
      checkName(osAttributeDTO.getId());
      //检查属性名是否已存在与系统中
      if(platformClientUtil.getAttributeService().checkRowIsExists(osAttributeDTO.getId())){
         throw new PLException("500",new String[]{"属性名称【" + osAttributeDTO.getId() + "】在系统中已存在!"});
      }
      //检查默认值与属性类型是否匹配
      checkDefValue(osAttributeDTO);
      //dto对象转换为存储所需对象
      //osAttributeDTO.setOid(VciBaseUtil.getPk().toUpperCase(Locale.ROOT));
      AttributeDef attributeDef = this.osAttributeDTO2AttributeDef(osAttributeDTO);
      return platformClientUtil.getAttributeService().addAttributeDef(attributeDef);
   }
@@ -481,9 +638,10 @@
      //检查默认值与属性类型是否匹配
      checkDefValue(osAttributeDTO);
      boolean compatible = isCompatible(osAttributeVO,osAttributeDTO);
      boolean hasInstance = hasInstance(osAttributeDTO.getName());
      //产生数据, 并且不兼容
      if(hasInstance && !compatible){
      //boolean hasInstance = hasInstance(osAttributeDTO.getId()); //不判断是否产生数据只要被引用就需要进一步判断类型是否兼容
      boolean checkAttrIsUse = this.checkAttrIsUse(osAttributeDTO.getId());
      //TODO:按照以前操作配置文档中的逻辑应该是:不论是否产生数据只要被引用就需要要判断类型是否兼容(如VTString不能转为VTIntger或VTLong)
      if(checkAttrIsUse/*hasInstance*/ && !compatible){
         throw new PLException("500",new String[]{"无效变更, 不兼容已产生的数据!"});
      }
      String userId = WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId();
@@ -519,14 +677,20 @@
    */
   private AttributeDef osAttributeDTO2AttributeDef(OsAttributeDTO osAttributeDTO) {
      AttributeDef attributeDef = new AttributeDef();
      attributeDef.oid = osAttributeDTO.getOid();
      attributeDef.name = osAttributeDTO.getId().toLowerCase().replaceAll(" ", "");
      attributeDef.label = osAttributeDTO.getName();
      attributeDef.description = osAttributeDTO.getDescription();
      attributeDef.vtDataType = (String)osAttributeDTO.getAttributeDataType();
      attributeDef.defValue = Func.isBlank(osAttributeDTO.getDefaultValue()) ? "" : osAttributeDTO.getDefaultValue();
      attributeDef.rage = Func.isBlank(osAttributeDTO.getRange()) ? "" : osAttributeDTO.getRange();
      attributeDef.creator = Func.isBlank(osAttributeDTO.getCreator()) ? WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId():osAttributeDTO.getCreator();
      if(Func.isBlank(osAttributeDTO.getRange())){
         attributeDef.rage = "";
      }else{
         //特殊字符处理,直接存储<会报错
         attributeDef.rage = osAttributeDTO.getRange().replace("<","&lt;");
      }
      attributeDef.ts = Func.format((Func.isNotEmpty(osAttributeDTO.getTs()) ? osAttributeDTO.getTs():new Date()),VciDateUtil.DateTimeMillFormat);
      attributeDef.creator = Func.isBlank(osAttributeDTO.getCreator()) ? WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId():osAttributeDTO.getCreator();
      attributeDef.createTime = Func.isEmpty(osAttributeDTO.getCreateTime()) ? System.currentTimeMillis():osAttributeDTO.getCreateTime().getTime();
      attributeDef.modifier = Func.isBlank(osAttributeDTO.getLastModifier()) ? WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId():osAttributeDTO.getLastModifier();
      attributeDef.modifyTime = System.currentTimeMillis();
@@ -563,9 +727,13 @@
            break;
         case VTString:
            if (StringUtils.isNotBlank(osAttributeDTO.getBtmTypeId())) {
               //参照
               //参照业务类型
               sb.append(BTM).append(" = ").append(osAttributeDTO.getBtmTypeId()).append(";");
               //链接类型暂时不支持
            }
            if(StringUtils.isNotBlank(osAttributeDTO.getLinkTypeName())){
               //参照链接类型
               sb.append(LINKTYPENAME).append(" = ").append(osAttributeDTO.getLinkTypeName()).append(";");
               sb.append(VERSION).append(" = ").append(osAttributeDTO.getVersion()).append(";");
            }
            sb.append(LENGTH).append(" = ").append(length > osAttributeDTO.getAttrLength()?length:osAttributeDTO.getAttrLength()).append(";");
            if (StringUtils.isNotBlank(osAttributeDTO.getEnumId())) {
@@ -626,6 +794,26 @@
   }
   /**
    * 查看属性是否被引用
    * @param abName
    * @return false未被引用 true被引用
    */
   private boolean checkAttrIsUse(String abName) throws PLException {
      if(Func.isBlank(abName)){
         return false;
      }
      String[] btNames = platformClientUtil.getBtmService().getBTNamesByAPName(abName);
      if(Func.isNotEmpty(btNames)){
         return true;
      }
      String[] ltNames = platformClientUtil.getLinkTypeService().getLTNamesByAPName(abName);
      if(Func.isNotEmpty(ltNames)){
         return true;
      }
      return false;
   }
   /**
    * 检查属性名称是否符合规范
    * @param attributeName
    * @return 没有返回值,存在问题直接抛出错误
@@ -636,12 +824,12 @@
      }
      if(!attributeName.matches("[a-z A-Z]*")){
         throw new PLException("500",new String[]{"注意:属性名只能为英文字母!"+ NAME_MAX_LENGTH});
         throw new PLException("500",new String[]{"注意:属性名只能为英文字母!"});
      }
      int length = attributeName.length();
      if(length > NAME_MAX_LENGTH){
         throw new PLException("500",new String[]{"属性名过长,属性名长度不能超过!"+ NAME_MAX_LENGTH});
         throw new PLException("500",new String[]{"属性名过长,属性名长度不能超过"+ NAME_MAX_LENGTH});
      }
      String abName = attributeName.toLowerCase();
@@ -654,9 +842,9 @@
         throw new PLException("500",new String[]{"属性名无效,原因:属性名是数据库关键字!"});
      }
      //检查属性名是否已存在与系统中
      if(platformClientUtil.getAttributeService().checkRowIsExists(abName)){
         throw new PLException("500",new String[]{"属性名称在系统中已存在!"});
      }
      /*if(platformClientUtil.getAttributeService().checkRowIsExists(abName)){
         throw new PLException("500",new String[]{"属性名称【" + abName + "】在系统中已存在!"});
      }*/
   }
   /**
@@ -692,7 +880,6 @@
            if(rages == null || rages.equals("")){
               return;
            }
            VTInteger obj = new VTInteger(Integer.valueOf(defValue));
            boolean flag = obj.checkRageValueByRage(rages);
            if(!flag){
@@ -707,7 +894,6 @@
            if(rages == null || rages.equals("")){
               return;
            }
            VTLong obj = new VTLong(Long.valueOf(defValue));
            boolean flag = obj.checkRageValueByRage(rages);
            if(!flag){
@@ -727,7 +913,6 @@
            if(!flag){
               throw new PLException("500",new String[]{"默认值与值域冲突!"});
            }
         }
      }
   }
@@ -737,10 +922,14 @@
    * @param abName
    * @return
    */
   private boolean usedBySystem(String abName) {
   private boolean usedBySystem(String abName) throws PLException {
      boolean flag = false;
      String[] names = UsedNames.getProperty(SYSUSEDNAMES).toUpperCase().split(",");
      List<String> nameList = Arrays.asList(names);
      AttributeDef[] sysAttributeDefs = platformClientUtil.getBtmService().getSysAttributeDefs();
      List<String> nameList = null;
      if(Func.isNotEmpty(sysAttributeDefs)){
         nameList = Arrays.stream(sysAttributeDefs)
               .map(item -> item.name.toUpperCase(Locale.ROOT)).collect(Collectors.toList());
      }
      if(nameList.contains(abName.toUpperCase())){
         flag = true;
      }
@@ -754,9 +943,7 @@
    */
   private boolean usedByDataBase(String abName){
      boolean flag = false;
      String[] names = UsedNames.getProperty(DATABASEUSEDNAMES).toUpperCase().split(",");
      List<String> nameList = Arrays.asList(names);
      if(nameList.contains(abName.toUpperCase())){
      if(DATABASEUSEDNAMELIST.contains(abName.toUpperCase())){
         flag = true;
      }
      return flag;
@@ -781,7 +968,7 @@
         if(Func.isBlank(oid) || Func.isBlank(name) || Func.isEmpty(ts)){
            throw new PLException("500",new String[]{"待删除的属性列表中主键【oid】、调整时间【ts】、属性名【name】不能为空!"});
         }
         //判断枚举是否有被引用
         //判断属性是否有被引用
         List<Map<String, String>> usedAttrList = this.getUsedAttributeList(name);
         if(Func.isNotEmpty(usedAttrList)){
            throw new PLException("500",new String[]{"删除的属性中,属性名称为:【" + name + "】,已被引用!"});
@@ -809,11 +996,14 @@
         throw new PLException("500",new String[]{"请选择要查询应用范围的属性!"});
      }
      String[] btNames = platformClientUtil.getBtmService().getBTNamesByAPName(attributeName);
      if(Func.isEmpty(btNames)){
      String[] ltNames = platformClientUtil.getLinkTypeService().getLTNamesByAPName(attributeName);
      String[] mergedArray = Stream.concat(Stream.of(btNames), Stream.of(ltNames)).toArray(String[]::new);
      if(Func.isEmpty(mergedArray)){
         return new ArrayList<>();
      }
      List<Map<String,String>> btmNameMapList = new ArrayList<>();
      Arrays.stream(btNames).forEach(btName->{
      Arrays.stream(mergedArray).forEach(btName->{
         Map<String, String> itemMap = new HashMap<>();
         itemMap.put("attributeName",attributeName);
         itemMap.put("source",btName);
@@ -826,22 +1016,18 @@
    * 导出选中的属性
    * @param exportFileName 导出的文件名
    * @param attrNames 需要导出的属性名称
    * @param flag 控制导出的列名是否和导入模板一致
    * @return
    */
   @Override
   public String exportAttributes(String exportFileName, String attrNames) throws PLException {
   public String exportAttributes(String exportFileName, String attrNames,boolean flag/*控制导出的列名是否和导入模板一致*/) throws PLException {
      if(Func.isBlank(attrNames)){
         throw new PLException("500",new String[]{"请勾选要导出的属性!"});
      }
      //界面没传名称,使用默认导出名称
      exportFileName = Func.isBlank(exportFileName) ?  "属性池中属性导出_" + Func.format(new Date(),"yyyy-MM-dd HHmmss.sss"):exportFileName;
      //设置列名
      List<String> columns = new ArrayList<>(
            Arrays.asList("属性名", "标签", "描述",
                  "属性类型", "允许为空", "默认值", "使用的枚举英文名称(枚举名)",
                  "使用的枚举中文名称(标签)", "参照的业务类型编号", "参照的业务类型名称",
                  "属性长度", "小数精度位数","小数刻度位数","取值范围","创建时间")
      );
      List<String> columns = this.getCloumns(flag);
      //写excel
      String excelPath = LocalFileUtil.getDefaultTempFolder() + File.separator + exportFileName +  ".xls";
@@ -857,8 +1043,8 @@
         excelDataList.add(new WriteExcelData(0,index, columns.get(index)));
      }
      //按照属性名查询属性,然后处理属性导出
      List<String> enumNameList = Func.toStrList(attrNames);
      List<OsAttributeVO> osAttributeVOS = this.listAttrByIds(enumNameList);
      List<String> attrameList = Func.toStrList(attrNames);
      List<OsAttributeVO> osAttributeVOS = this.listAttrByIds(attrameList);
      if(Func.isEmpty(osAttributeVOS)){
         excelDataList.add(new WriteExcelData(1,1, "根据属性名称未查询到属性信息,请刷新后尝试重新导出!"));
      }else{
@@ -869,23 +1055,220 @@
            excelDataList.add(new WriteExcelData(i+1,0, osAttributeVO.getId()));
            excelDataList.add(new WriteExcelData(i+1,1, osAttributeVO.getName()));
            excelDataList.add(new WriteExcelData(i+1,2, osAttributeVO.getDescription()));
            excelDataList.add(new WriteExcelData(i+1,3, osAttributeVO.getAttributeDataTypeText()+(osAttributeVO.getAttributeDataType())));
            if(flag){
               excelDataList.add(new WriteExcelData(i+1,3, osAttributeVO.getAttributeDataType()));
            }else{
               excelDataList.add(new WriteExcelData(i+1,3, osAttributeVO.getAttributeDataType()+"("+osAttributeVO.getAttributeDataTypeText()+")"));
            }
            excelDataList.add(new WriteExcelData(i+1,4, osAttributeVO.isNullableFlag()));
            excelDataList.add(new WriteExcelData(i+1,5, osAttributeVO.getDefaultValue()));
            excelDataList.add(new WriteExcelData(i+1,6, osAttributeVO.getEnumId()));
            excelDataList.add(new WriteExcelData(i+1,7, osAttributeVO.getEnumName()));
            excelDataList.add(new WriteExcelData(i+1,8, osAttributeVO.getBtmTypeId()));
            excelDataList.add(new WriteExcelData(i+1,9, osAttributeVO.getBtmTypeName()));
            excelDataList.add(new WriteExcelData(i+1,10, osAttributeVO.getAttrLength()));
            //excelDataList.add(new WriteExcelData(i+1,7, osAttributeVO.getEnumName()));
            excelDataList.add(new WriteExcelData(i+1,7, osAttributeVO.getBtmTypeId()));
            //excelDataList.add(new WriteExcelData(i+1,9, osAttributeVO.getBtmTypeName()));
            excelDataList.add(new WriteExcelData(i+1,8, osAttributeVO.getAttrLength()));
            excelDataList.add(new WriteExcelData(i+1,9, osAttributeVO.getLinkTypeName()));
            excelDataList.add(new WriteExcelData(i+1,10, osAttributeVO.getVersion()));
            excelDataList.add(new WriteExcelData(i+1,11, osAttributeVO.getPrecisionLength()));
            excelDataList.add(new WriteExcelData(i+1,12, osAttributeVO.getScaleLength()));
            excelDataList.add(new WriteExcelData(i+1,13, osAttributeVO.getRange()));
            excelDataList.add(new WriteExcelData(i+1,14, osAttributeVO.getCreateTime()));
            if(!flag){
               excelDataList.add(new WriteExcelData(i+1,14, Func.format(osAttributeVO.getCreateTime(),"yyyy年MM月dd日 hh:mm:ss")));
            }
         }
      }
      WriteExcelOption excelOption = new WriteExcelOption(excelDataList);
      ExcelUtil.writeDataToFile(excelPath, excelOption);
      return excelPath;
   }
   /**
    * 获取导出或导入模板的列名
    * @param flag 是否获取导入模板列名
    * @return
    */
   private List<String> getCloumns(boolean flag){
      if(flag){
         return new ArrayList<>(
               Arrays.asList("属性名", "标签", "描述",
                     "属性类型(参照新增界面的属性类型如VTString)", "允许为空(是/否)", "默认值", "使用的枚举英文名称"
                     , "参照的业务类型编号","参照的链接类型编号","版本版次","属性长度", "小数精度位数","小数刻度位数"
                     ,"取值范围"
               )
         );
      }
      return new ArrayList<>(
            Arrays.asList("属性名", "标签", "描述",
                  "属性类型", "允许为空", "默认值", "使用的枚举英文名称(枚举名)",
                  "参照的业务类型编号", "参照的链接类型编号","版本版次","属性长度",
                  "小数精度位数","小数刻度位数","取值范围","创建时间")
      );
   }
   /**
    * 下载属性导入模板
    * @param exportFileName
    * @return
    * @throws PLException
    */
   @Override
   public String downloadAttributeTemplate(String exportFileName) throws Exception {
      //界面没传名称,使用默认导出名称
      exportFileName = Func.isBlank(exportFileName) ?  "属性池导入模板_" + Func.format(new Date(),"yyyy-MM-dd HHmmss.sss"):exportFileName;
      //设置列名
      List<String> columns = this.getCloumns(true);
      //设置必填列
      ColumnNameisRed.clear();
      ColumnNameisRed.add(0);
      ColumnNameisRed.add(3);
      ColumnNameisRed.add(10);
      //写excel
      String excelPath = LocalFileUtil.getDefaultTempFolder() + File.separator + exportFileName +  ".xls";
      try {
         new File(excelPath).createNewFile();
      } catch (Throwable e) {
         throw new VciBaseException(LangBaseUtil.getErrorMsg(e), new String[]{excelPath}, e);
      }
      //设置列
      List<WriteExcelData> excelDataList = new ArrayList<>();
      //设置列头
      for (int index = 0; index < columns.size(); index++) {
         //判断是否为必填列,给必填列设置颜色
         if(ColumnNameisRed.contains(index)){
            WriteExcelData excelData = new WriteExcelData(0, index, columns.get(index));
            excelData.setFontColor(String.valueOf(HSSFColor.HSSFColorPredefined.RED.getIndex()));
            excelDataList.add(excelData);
         }else{
            excelDataList.add(new WriteExcelData(0,index, columns.get(index)));
         }
      }
      WriteExcelOption excelOption = new WriteExcelOption(excelDataList);
      ExcelUtil.writeDataToFile(excelPath, excelOption);
      return excelPath;
   }
   /**
    * 导入属性
    * @param file
    * @param isContinue 系统中出现重复是否跳过报错继续执行
    * @return
    * @throws Exception
    */
   @Override
   public BaseResult importAttributes(File file, boolean isContinue) throws Exception{
      VciBaseUtil.alertNotNull(file,"excel文件");
      if(!file.exists()){
         throw new VciBaseException("导入的excel文件不存在,{0}",new String[]{file.getPath()});
      }
      try{
         //1、读取excel中的数据,组成对象
         ReadExcelOption excelOption = new ReadExcelOption();
         List<OsAttributePO> poList = ExcelUtil.readDataObjectFromExcel(file, OsAttributePO.class,excelOption,(value, po, fieldName)->{});
         //去除都是空的情况
         if(CollectionUtils.isEmpty(poList)){
            return BaseResult.fail(ExcelLangCodeConstant.IMPORT_CONTENT_NULL,new String[]{});
         }
         //excel判重,数据校验,dto对象转换,存储对象转换,执行保存
         List<OsAttributeDTO> dtoList = new ArrayList<>();
         //当前excel中是否重复用的判重Map:(key:判重属性,value:行号)
         Map<String, String> excelReapeat = new HashMap<>();
         for (int i = 0; i < poList.size(); i++) {
            OsAttributePO osAttributePO = poList.get(i);
            if(Func.isBlank(osAttributePO.getId())){//属性名判空
               throw new VciBaseException("第【"+osAttributePO.getRowIndex()+"】行,attrnameerror");
            }else if(Func.isBlank(osAttributePO.getAttributeDataType())){
               throw new VciBaseException("第【"+osAttributePO.getRowIndex()+"】行,typeerror");
            }else if(excelReapeat.containsKey(osAttributePO.getId())){//属性名表格中判重
               throw new VciBaseException("第【"+excelReapeat.get(osAttributePO.getId())+"】行和第【"+osAttributePO.getRowIndex()+"】行数据,属性名重复");
            }else {
               try {
                  if(platformClientUtil.getAttributeService().checkRowIsExists(osAttributePO.getId())){
                     throw new PLException("500",new String[]{"属性名称【" + osAttributePO.getId() + "】在系统中已存在!"});
                  }
               } catch (PLException e) {
                  e.printStackTrace();
                  String errorMsg = "与系统中属性名查重时出现错误,原因:" + VciBaseUtil.getExceptionMessage(e);
                  logger.error(errorMsg);
                  //是否跳过当期重复数据
                  if(isContinue){
                     continue;
                  }
                  throw new VciBaseException(errorMsg);
               }
            }
            //属性名校验
            try {
               checkName(osAttributePO.getId());
            } catch (PLException e) {
               e.printStackTrace();
               throw new VciBaseException(VciBaseUtil.getExceptionMessage(e));
            }
            //属性名excel中判重处理
            excelReapeat.put(osAttributePO.getId(),osAttributePO.getRowIndex());
            OsAttributeDTO osAttributeDTO = new OsAttributeDTO();
            //查询属性是否存在,填写了枚举但没填写取值范围,这时候直接使用枚举项值作为默认的range
            if(Func.isNotBlank(osAttributePO.getEnumId()) && Func.isBlank(osAttributePO.getRange())){
               try {
                  OsEnumVO enumVO = enumService.getEnumTypeById(osAttributePO.getEnumId());
                  if(Func.isEmpty(enumVO)){
                     throw new VciBaseException("第【" + osAttributePO.getRowIndex() + "】行数据,通过枚举名称【" + osAttributePO.getEnumId()
                           + "】未获取到枚举信息!");
                  }
                  String itemValues = enumVO.getItemMaps().values().stream().collect(Collectors.joining(";"));
                  osAttributeDTO.setRange(itemValues);
               } catch (PLException e) {
                  e.printStackTrace();
                  throw new VciBaseException("枚举查询失败,原因:"+e.getMessage());
               }
               osAttributeDTO.setBtmTypeId(osAttributePO.getEnumId());
            }
            osAttributeDTO.setOid(ObjectUtility.getNewObjectID36());
            osAttributeDTO.setId(osAttributePO.getId());
            osAttributeDTO.setName(osAttributePO.getName());
            osAttributeDTO.setDescription(osAttributePO.getDescription());
            osAttributeDTO.setDefaultValue(osAttributePO.getDefaultValue());
            osAttributeDTO.setAttrLength(osAttributePO.getAttrLength());
            osAttributeDTO.setAttributeDataType(osAttributePO.getAttributeDataType());
            osAttributeDTO.setBtmTypeId(osAttributePO.getBtmTypeId());
            //osAttributeDTO.setBtmTypeName(osAttributePO.getBtmname());
            osAttributeDTO.setLinkTypeName(osAttributePO.getLinkTypeName());
            osAttributeDTO.setVersion(osAttributePO.getVersion());
            osAttributeDTO.setEnumId(osAttributePO.getEnumId());
            //osAttributeDTO.setEnumName(osAttributePO.getEnumId());
            osAttributeDTO.setPrecisionLength(osAttributePO.getPrecisionLength());
            osAttributeDTO.setScaleLength(osAttributePO.getScaleLength());
            osAttributeDTO.setRange(osAttributePO.getRange());
            osAttributeDTO.setNullableFlag("是".equals(osAttributePO.getNullableFlag()) ? true:false);
            try {
               //检查默认值与属性类型是否匹配
               checkDefValue(osAttributeDTO);
            } catch (PLException e) {
               e.printStackTrace();
               throw new VciBaseException(VciBaseUtil.getExceptionMessage(e));
            }
            dtoList.add(osAttributeDTO);
         }
         //执行保存操作
         dtoList.stream().forEach(dto->{
            try {
               boolean b = platformClientUtil.getAttributeService().addAttributeDef(osAttributeDTO2AttributeDef(dto));
               if(!b){
                  throw new VciBaseException("save and return false");
               }
            } catch (PLException e) {
               e.printStackTrace();
               throw new VciBaseException("执行保存时出现错误,错误属性对象名为:【" + dto.getId() + "】,原因:"+VciBaseUtil.getExceptionMessage(e));
            }
         });
      }catch (Exception e){
         if(logger.isErrorEnabled()){
            logger.error("读取excel内容时或保存属性时出现了错误,具体原因:",VciBaseUtil.getExceptionMessage(e));
         }
         e.printStackTrace();
         return BaseResult.fail(VciBaseUtil.getExceptionMessage(e),new String[]{},e);
      }
      return BaseResult.success("属性导入成功!");
   }
   /**
@@ -903,17 +1286,61 @@
   }
   /**
    * 根据业务类型获取属性信息
    * @param btName 业务类型/链接类型
    * @param typeFlag 0:业务类型,1:链接类型
    * @return
    */
   @Override
   public List<OsAttributeVO> getOsAttributeVOSByBtName(String btName, int typeFlag,boolean isDefault) throws Exception{
      VciBaseUtil.alertNotNull(btName,"参数不允许为空",typeFlag,"参数不允许为空");
      List<OsAttributeVO> attributeVOS=new ArrayList<>();
      try {
         List<AttributeDef> attributeDefList=new ArrayList<>();
         if(typeFlag==0){
            AttributeDef [] attributeDefs=   platformClientUtil.getBtmService().getAttributeDefs(btName);
            if(attributeDefs!=null){
               attributeDefList.addAll(Arrays.stream(attributeDefs).collect(Collectors.toList()));
            }
            if(isDefault){
               AttributeDef [] sysAttributeDefs=platformClientUtil.getBtmService().getSysAttributeDefs();
               if(sysAttributeDefs!=null){
                  attributeDefList.addAll(Arrays.stream(sysAttributeDefs).collect(Collectors.toList()));
               }
            }
         }else{
            AttributeDef []   attributeDefs=platformClientUtil.getLinkTypeService().getAttributes(btName);
            if(attributeDefs!=null){
               attributeDefList.addAll(Arrays.stream(attributeDefs).collect(Collectors.toList()));
            }
            if(isDefault){
               AttributeDef[] sysAbItems = platformClientUtil.getLinkTypeService().getSysAttributeDefs();
               if(sysAbItems!=null){
                  attributeDefList.addAll(Arrays.stream(sysAbItems).collect(Collectors.toList()));
               }
            }
         }
         attributeVOS=attributeDO2VOs(attributeDefList);
      }catch (PLException e){
         throw new Exception("根据业务类型获取属性异常"+e.getMessage());
      }
      return attributeVOS;
   }
   /**
    * 是否为参照属性
    * @param other 配置的其他
    * @return true 是参照
    */
   private boolean isReferAttr(String other){
      if(StringUtils.isNotBlank(other)
            && (other.toLowerCase().contains("btm") || other.toLowerCase().contains("ltm"))){
            && (other.toLowerCase().contains("btm") || other.toLowerCase().contains("link"))){
         //还不能确定,因为枚举的时候也会设置btm
         String[] temp = other.split(";");
         for(String s : temp){
            if((s.contains("btm") || s.contains("ltm")) && s.split("=").length>1){
            if((s.contains("btm") || s.contains("link")) && s.split("=").length>1){
               return true;
            }
         }