From 83bfd0bf23c932d97877e895e67ad854fbd7c53b Mon Sep 17 00:00:00 2001
From: wangting <675591594@qq.com>
Date: 星期五, 27 九月 2024 10:03:34 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisConfig.java                           |    2 
 Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisService.java                          |   38 +
 Source/plt-web/plt-web-ui/src/views/modelingMenu/ui/uiDefine/rightRegion/bottomTable/index.vue                                | 1152 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/constant/VConstant.java                          |    5 
 Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmSessionForLoginImpl.java       |    2 
 Source/plt-web/plt-web-parent/plt-web/pom.xml                                                                                 |   17 
 Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciSecurityInterceptor.java          |   16 
 Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/LoginServiceImpl.java                            |   16 
 Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmHMSysModConfigServiceImpl.java |   12 
 Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciLogAfterInterceptor.java          |    2 
 Source/plt-web/plt-web-parent/plt-web-base/pom.xml                                                                            |   17 
 Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/FastJson2JsonRedisSerializer.java          |    2 
 Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIManagerServiceImpl.java                        |    2 
 Source/plt-web/plt-web-parent/plt-web-api/src/main/java/com/vci/pagemodel/PLTabButtonVO.java                                  |    4 
 14 files changed, 1,226 insertions(+), 61 deletions(-)

diff --git a/Source/plt-web/plt-web-parent/plt-web-api/src/main/java/com/vci/pagemodel/PLTabButtonVO.java b/Source/plt-web/plt-web-parent/plt-web-api/src/main/java/com/vci/pagemodel/PLTabButtonVO.java
index 8480dbe..9e69eaa 100644
--- a/Source/plt-web/plt-web-parent/plt-web-api/src/main/java/com/vci/pagemodel/PLTabButtonVO.java
+++ b/Source/plt-web/plt-web-parent/plt-web-api/src/main/java/com/vci/pagemodel/PLTabButtonVO.java
@@ -76,7 +76,7 @@
     private List<PLTabButtonVO> children;
 
     /**
-     * 鏄惁鏄剧ず
+     * 鏄剧ず鏂瑰紡
      */
     private String displayMode;
 
@@ -91,7 +91,7 @@
     private String authorization;
 
     /**
-     * 鏄剧ず鏂瑰紡
+     * 鏄惁鏄剧ず
      */
     private String show;
 
diff --git a/Source/plt-web/plt-web-parent/plt-web-base/pom.xml b/Source/plt-web/plt-web-parent/plt-web-base/pom.xml
index f07c7fa..880a7ba 100644
--- a/Source/plt-web/plt-web-parent/plt-web-base/pom.xml
+++ b/Source/plt-web/plt-web-parent/plt-web-base/pom.xml
@@ -73,6 +73,23 @@
             <artifactId>icegridgui</artifactId>
             <version>1.0.RELEASE</version>
         </dependency>
+        <!--redis start-->
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-redis</artifactId>
+            <version>2.1.5.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>2.9.0</version>
+        </dependency>
+        <!--redis end-->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.13.3</version>
+        </dependency>
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/constant/VConstant.java b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/constant/VConstant.java
index e9c2ddd..5dff82d 100644
--- a/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/constant/VConstant.java
+++ b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/constant/VConstant.java
@@ -82,6 +82,11 @@
     public static final String SYS_ENUM_KEY = "sys_enum:";
 
     /**
+     * 褰撳墠鐧诲綍鐨勭敤鎴锋�绘暟cache key
+     */
+    public static final String CURRENT_LOGGED_USERS_KEY = "current_logged_users";
+
+    /**
      * 璧勬簮鏄犲皠璺緞 鍓嶇紑
      */
     public static final String RESOURCE_PREFIX = "/profile";
diff --git a/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciLogAfterInterceptor.java b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciLogAfterInterceptor.java
index 334d0a2..cbde7da 100644
--- a/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciLogAfterInterceptor.java
+++ b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciLogAfterInterceptor.java
@@ -1,8 +1,6 @@
 package com.vci.starter.web.interceptor;
 
 import com.vci.starter.web.constant.TokenKeyConstant;
-import com.vci.starter.web.util.VciBaseUtil;
-import com.vci.starter.web.util.WebThreadLocalUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.MDC;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciSecurityInterceptor.java b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciSecurityInterceptor.java
index 9679f27..68ef18a 100644
--- a/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciSecurityInterceptor.java
+++ b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciSecurityInterceptor.java
@@ -4,9 +4,11 @@
 import com.vci.starter.web.annotation.controller.VciUnCheckRight;
 import com.vci.starter.web.autoconfigure.SpringMVCConfig;
 import com.vci.starter.web.constant.TokenKeyConstant;
+import com.vci.starter.web.constant.VConstant;
 import com.vci.starter.web.enumpck.ResultCodeEnum;
 import com.vci.starter.web.pagemodel.BaseResult;
 import com.vci.starter.web.pagemodel.SessionInfo;
+import com.vci.starter.web.redis.RedisService;
 import com.vci.starter.web.util.ApplicationContextProvider;
 import com.vci.starter.web.util.LangBaseUtil;
 import com.vci.starter.web.util.VciBaseUtil;
@@ -15,15 +17,11 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.stereotype.Component;
-import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.servlet.HandlerInterceptor;
 
-import javax.annotation.Resource;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -56,6 +54,9 @@
     @Autowired
     private VciSessionForLoginI vciSessionForLoginI;
 
+    @Autowired
+    private RedisService redisService;
+
     /**
      * 鎵ц鎷︽埅
      * @param request 璇锋眰瀵硅薄
@@ -76,7 +77,7 @@
         if(StringUtils.isBlank(userToken)){
             userToken = request.getParameter(TokenKeyConstant.USER_TOKEN_KEY);
         }
-        if(!(handler instanceof  HandlerMethod)){
+        if(!(handler instanceof HandlerMethod)){
             return true;
         }
 
@@ -127,6 +128,11 @@
                 if(logger.isErrorEnabled()) {
                     logger.error("token鍊奸潪娉曪紝鎴栬繃鏈燂紝鎴栬�呯敤鎴峰凡缁忚韪笅绾�," + userToken);
                 }
+                //鍒犻櫎缂撳瓨涓粺璁$殑鐢ㄦ埛淇℃伅
+                if(redisService == null){
+                    redisService = ApplicationContextProvider.getBean(RedisService.class);
+                }
+                redisService.decreOnlineUser(VConstant.CURRENT_LOGGED_USERS_KEY);
                 sendErrorMsg(response,"token鍊奸潪娉曪紝鎴栬繃鏈燂紝鎴栬�呯敤鎴峰凡缁忚韪笅绾�," + userToken,1);
                 return false;
             }else{
diff --git a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/FastJson2JsonRedisSerializer.java b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/FastJson2JsonRedisSerializer.java
similarity index 97%
rename from Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/FastJson2JsonRedisSerializer.java
rename to Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/FastJson2JsonRedisSerializer.java
index 2112c43..e48ac8a 100644
--- a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/FastJson2JsonRedisSerializer.java
+++ b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/FastJson2JsonRedisSerializer.java
@@ -1,4 +1,4 @@
-package com.vci.web.redis;
+package com.vci.starter.web.redis;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.serializer.SerializerFeature;
diff --git a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/RedisConfig.java b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisConfig.java
similarity index 98%
rename from Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/RedisConfig.java
rename to Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisConfig.java
index 7e64afc..d2375b7 100644
--- a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/RedisConfig.java
+++ b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisConfig.java
@@ -1,4 +1,4 @@
-package com.vci.web.redis;
+package com.vci.starter.web.redis;
 
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.cache.annotation.CachingConfigurerSupport;
diff --git a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/RedisService.java b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisService.java
similarity index 91%
rename from Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/RedisService.java
rename to Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisService.java
index 7172e62..b795342 100644
--- a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/RedisService.java
+++ b/Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/redis/RedisService.java
@@ -1,4 +1,4 @@
-package com.vci.web.redis;
+package com.vci.starter.web.redis;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -11,6 +11,7 @@
 import org.springframework.data.redis.serializer.RedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
 
 import java.io.IOException;
 import java.util.*;
@@ -21,10 +22,9 @@
  * @author dangsn
  **/
 @SuppressWarnings(value = { "unchecked", "rawtypes" })
-@Component
+@Service
 @Slf4j
-public class RedisService
-{
+public class RedisService {
     @Autowired(required = false)
     public RedisTemplate redisTemplate;
 
@@ -393,19 +393,33 @@
     /**
      * 鐢ㄦ埛鐧诲綍
      * @param currentLoggedUserKey
-     * @param username
      */
-    public void userLogin(String currentLoggedUserKey,String username) {
-        redisTemplate.opsForSet().add(currentLoggedUserKey, username);
+    public void increOnlineUser(String currentLoggedUserKey) {
+        // 妫�鏌ラ敭鏄惁瀛樺湪
+        if (!redisTemplate.hasKey(currentLoggedUserKey)) {
+            // 濡傛灉閿笉瀛樺湪锛屽垵濮嬪寲涓�0
+            redisTemplate.opsForValue().set(currentLoggedUserKey, 0);
+        }
+        // 鑷鍦ㄧ嚎鐢ㄦ埛鏁�
+        redisTemplate.opsForValue().increment(currentLoggedUserKey);
     }
 
     /**
      * 鐢ㄦ埛鐧诲嚭
      * @param currentLoggedUserKey
-     * @param username
      */
-    public void userLogout(String currentLoggedUserKey,String username) {
-        redisTemplate.opsForSet().remove(currentLoggedUserKey, username);
+    public void decreOnlineUser(String currentLoggedUserKey) {
+        // 妫�鏌ュ綋鍓嶅湪绾跨敤鎴锋暟
+        String currentLoggedUser = (String)redisTemplate.opsForValue().get(currentLoggedUserKey);
+
+        if (currentLoggedUser != null) {
+            Long currentCount = Long.parseLong((String)redisTemplate.opsForValue().get(currentLoggedUserKey));
+            if(currentCount > 0){
+
+            }
+            // 鑷噺鍦ㄧ嚎鐢ㄦ埛鏁�
+            redisTemplate.opsForValue().decrement(currentLoggedUserKey);
+        }
     }
 
     /**
@@ -413,8 +427,8 @@
      * @param currentLoggedUserKey
      * @return
      */
-    public long getCurrentLoggedUserCount(String currentLoggedUserKey) {
-        return redisTemplate.opsForSet().size(currentLoggedUserKey);
+    public long getCurrentOnlineUserCount(String currentLoggedUserKey) {
+        return Long.parseLong(redisTemplate.opsForValue().get(currentLoggedUserKey).toString());
     }
 
     /**
diff --git a/Source/plt-web/plt-web-parent/plt-web/pom.xml b/Source/plt-web/plt-web-parent/plt-web/pom.xml
index 039b4d9..a35b80a 100644
--- a/Source/plt-web/plt-web-parent/plt-web/pom.xml
+++ b/Source/plt-web/plt-web-parent/plt-web/pom.xml
@@ -106,23 +106,6 @@
             <version>0.9.11</version>
         </dependency>
 
-        <!--redis start-->
-        <dependency>
-            <groupId>org.springframework.data</groupId>
-            <artifactId>spring-data-redis</artifactId>
-            <version>2.1.5.RELEASE</version>
-        </dependency>
-        <dependency>
-            <groupId>redis.clients</groupId>
-            <artifactId>jedis</artifactId>
-            <version>2.9.0</version>
-        </dependency>
-        <!--redis end-->
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-core</artifactId>
-            <version>2.13.3</version>
-        </dependency>
     </dependencies>
 
     <build>
diff --git a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmHMSysModConfigServiceImpl.java b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmHMSysModConfigServiceImpl.java
index 54c8d31..897ed4a 100644
--- a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmHMSysModConfigServiceImpl.java
+++ b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmHMSysModConfigServiceImpl.java
@@ -12,13 +12,14 @@
 import com.vci.starter.poi.bo.WriteExcelData;
 import com.vci.starter.poi.bo.WriteExcelOption;
 import com.vci.starter.poi.util.ExcelUtil;
+import com.vci.starter.web.constant.VConstant;
 import com.vci.starter.web.exception.VciBaseException;
 import com.vci.starter.web.pagemodel.BaseResult;
 import com.vci.starter.web.pagemodel.SessionInfo;
 import com.vci.starter.web.util.LocalFileUtil;
 import com.vci.starter.web.util.VciBaseUtil;
 import com.vci.starter.web.util.WebThreadLocalUtil;
-import com.vci.web.redis.RedisService;
+import com.vci.starter.web.redis.RedisService;
 import com.vci.web.util.Func;
 import com.vci.web.util.PlatformClientUtil;
 import org.slf4j.Logger;
@@ -62,11 +63,6 @@
 
     @Autowired
     private RedisService redisService;
-
-    /**
-     * 褰撳墠鐧诲綍鐨勭敤鎴锋�绘暟key
-     */
-    private static final String CURRENT_LOGGED_USERS_KEY = "current_logged_users";
 
     /**
      * 鏃ュ織
@@ -609,8 +605,6 @@
         return res;
     }
 
-
-
     /**
      * 妫�鏌ユ槸鍚﹀瓨鍦ㄥ紩鐢ㄥ叧绯�
      * @param ids
@@ -795,7 +789,7 @@
      */
     @Override
     public long getOnlineUsersNum() {
-        long currentLoggedUserCount = redisService.getCurrentLoggedUserCount(CURRENT_LOGGED_USERS_KEY);
+        long currentLoggedUserCount = redisService.getCurrentOnlineUserCount(VConstant.CURRENT_LOGGED_USERS_KEY);
         return currentLoggedUserCount;
     }
 
diff --git a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmSessionForLoginImpl.java b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmSessionForLoginImpl.java
index 8896f69..34f1d9a 100644
--- a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmSessionForLoginImpl.java
+++ b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/frameworkcore/compatibility/impl/SmSessionForLoginImpl.java
@@ -13,7 +13,7 @@
 import com.vci.starter.web.util.*;
 import com.vci.constant.CacheNameConstant;
 import com.vci.web.properties.WebProperties;
-import com.vci.web.redis.RedisService;
+import com.vci.starter.web.redis.RedisService;
 import com.vci.web.service.WebBoServiceI;
 import com.vci.web.util.PlatformClientUtil;
 import com.vci.web.util.WebUtil;
diff --git a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/LoginServiceImpl.java b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/LoginServiceImpl.java
index eb454b7..bb4ab4f 100644
--- a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/LoginServiceImpl.java
+++ b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/LoginServiceImpl.java
@@ -19,6 +19,7 @@
 import com.vci.starter.web.annotation.bus.VciLoginAfter;
 import com.vci.starter.web.annotation.bus.VciLogoutBefore;
 import com.vci.starter.web.annotation.bus.VciLogoutPlugin;
+import com.vci.starter.web.constant.VConstant;
 import com.vci.starter.web.exception.VciBaseException;
 import com.vci.starter.web.interceptor.VciSessionForLoginI;
 import com.vci.starter.web.pagemodel.RequestClientInfo;
@@ -30,7 +31,7 @@
 import com.vci.constant.CacheNameConstant;
 import com.vci.dto.LoginUserDTO;
 import com.vci.web.properties.WebProperties;
-import com.vci.web.redis.RedisService;
+import com.vci.starter.web.redis.RedisService;
 import com.vci.web.service.LoginServiceI;
 import com.vci.web.util.Func;
 import com.vci.web.util.PlatformClientUtil;
@@ -128,11 +129,6 @@
     private PlatformClientUtil platformClientUtil;
 
     /**
-     * 褰撳墠鐧诲綍鐨勭敤鎴锋�绘暟key
-     */
-    private static final String CURRENT_LOGGED_USERS_KEY = "current_logged_users";
-
-    /**
      * 鎵ц鐧诲綍
      * @param userDTO 鐧诲綍淇℃伅
      * @param clientInfo 璇锋眰鐨勫鎴风鐨勪俊鎭�
@@ -151,7 +147,7 @@
      * @return 鎵ц缁撴灉
      * @throws VciBaseException 鍙傛暟閿欒锛岀敤鎴蜂笉鑳界櫥褰曠瓑浼氭姏鍑哄紓甯�
      */
-    private LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo, boolean checkPassword/*鍗曠偣鐧诲綍涓嶉渶瑕佹牎楠屽瘑鐮�*/) throws VciBaseException, PLException {
+    private LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo, boolean checkPassword/*鍗曠偣鐧诲綍涓嶉渶瑕佹牎楠屽瘑鐮�*/) throws VciBaseException {
         LoginResultBO loginResult = new LoginResultBO();
         loginResult.setSuccess(false);
 
@@ -172,7 +168,7 @@
             String tokenKey = redisService.getCacheObject(userIdTokenKey);
             redisService.deleteObject(tokenKey);
             redisService.deleteObject(userIdTokenKey);
-            redisService.userLogout(CURRENT_LOGGED_USERS_KEY,userDTO.getUserId());
+            redisService.decreOnlineUser(VConstant.CURRENT_LOGGED_USERS_KEY);
         }
 
         //3.鑾峰彇鐢ㄦ埛鐨勫璞★紙瀵硅薄涓寘鍚鑹查儴闂ㄨ繕鏈夊瘑鐮佺瓥鐣ヤ俊鎭�(褰撳墠鐢ㄦ埛娌¤缃瘑鐮佺瓥鐣ュ氨鏄彇鐨勯粯璁ゅ瘑鐮佺瓥鐣�)锛�
@@ -249,7 +245,7 @@
         //鍒濆鍖栧钩鍙扮殑token
         sessionForLogin.initInvocationInfo(sessionInfo);
         //璁板綍褰撳墠鐧诲綍浜烘暟鐨勬�绘暟
-        redisService.userLogin(CURRENT_LOGGED_USERS_KEY,userDTO.getUserId());
+        redisService.increOnlineUser(VConstant.CURRENT_LOGGED_USERS_KEY);
         //鎷疯礉鐢ㄦ埛鍒版柊鐨剆ession浼氳瘽涓�
         copyUser2SessionInfo(user, sessionInfo, userDTO.getLangCode());
         //鎷疯礉璇锋眰淇℃伅鍒皊ession浼氳瘽涓�
@@ -567,7 +563,7 @@
             });
         }
         //娓呴櫎瀛樺綋鍓嶇櫥褰曠殑鐢ㄦ埛锛堟�绘暟-1锛�
-        redisService.userLogout(CURRENT_LOGGED_USERS_KEY,WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId());
+        redisService.decreOnlineUser(VConstant.CURRENT_LOGGED_USERS_KEY);
         sessionForLogin.logout(userToken);
         if(!CollectionUtils.isEmpty(logoutpluginBeanMap)){
             logoutpluginBeanMap.forEach((k,v) -> {
diff --git a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIManagerServiceImpl.java b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIManagerServiceImpl.java
index 40346aa..da050fc 100644
--- a/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIManagerServiceImpl.java
+++ b/Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIManagerServiceImpl.java
@@ -21,7 +21,7 @@
 import com.vci.starter.web.pagemodel.DataGrid;
 import com.vci.starter.web.pagemodel.SessionInfo;
 import com.vci.starter.web.util.*;
-import com.vci.web.redis.RedisService;
+import com.vci.starter.web.redis.RedisService;
 import com.vci.web.service.OsBtmServiceI;
 import com.vci.web.service.UIManagerServiceI;
 import com.vci.web.util.*;
diff --git a/Source/plt-web/plt-web-ui/src/views/modelingMenu/ui/uiDefine/rightRegion/bottomTable/index.vue b/Source/plt-web/plt-web-ui/src/views/modelingMenu/ui/uiDefine/rightRegion/bottomTable/index.vue
new file mode 100644
index 0000000..097644e
--- /dev/null
+++ b/Source/plt-web/plt-web-ui/src/views/modelingMenu/ui/uiDefine/rightRegion/bottomTable/index.vue
@@ -0,0 +1,1152 @@
+<template>
+  <basic-container>
+    <avue-crud
+      ref="crud"
+      v-model="form"
+      :data="data"
+      :option="option"
+      :table-loading="tableLoading"
+      @row-del="rowDelHandler"
+      @row-save="rowSaveHandler"
+      @row-update="rowUpdateHandler"
+      @refresh-change="handleRefresh"
+      @selection-change="selectChangeHandler"
+      @row-click="rowClickHandler">
+      <template slot="menuLeft" slot-scope="scope">
+        <el-button icon="el-icon-plus" plain size="small" type="primary"
+                   @click="addClickHandler">澧炲姞
+        </el-button>
+        <el-button icon="el-icon-edit-outline" plain size="small" type="primary"
+                   @click="btnDesignClickHandler">鎸夐挳璁捐
+        </el-button>
+      </template>
+
+      <!-- eventKey鎿嶄綔鎸夐挳 -->
+      <template slot="eventButtonForm" slot-scope="scope">
+        <div style="width: 100%;display: flex;justify-content: center">
+          <el-button plain size="mini" type="primary" @click="formDataAddClickHandler">鍒涘缓</el-button>
+          <el-button plain size="mini" type="danger" @click="formDataDelClickHandler">鍒犻櫎</el-button>
+          <el-button plain size="mini" type="primary" @click="moveUp">涓婄Щ</el-button>
+          <el-button plain size="mini" type="primary" @click="moveDown">涓嬬Щ</el-button>
+        </div>
+      </template>
+      <!-- eventKey浠ュ強eventValue鏄剧ず鍖哄煙 -->
+      <template slot="bottomValueForm" slot-scope="scope">
+        <div style="height: 200px; width: 95%; border: 1px solid #bdbbbb;overflow-y: auto">
+          <!-- 鍐呭 -->
+          <el-table
+            :data="FormData"
+            :highlight-current-row="true"
+            style="width: 100%"
+            @row-click="formDataRowClick">
+            <el-table-column
+              align="center"
+              label="EventKey"
+              prop="eventKey">
+            </el-table-column>
+            <el-table-column
+              align="center"
+              label="EventValue"
+              prop="eventValue">
+            </el-table-column>
+          </el-table>
+        </div>
+      </template>
+
+      <!-- 鍒囨崲鎼滅储绫诲瀷 婧愬璞� 鐩爣瀵硅薄鏄剧ずlabel鍒囨崲 -->
+      <template slot="showTypeLabel" slot-scope="{}">
+        <span v-if="form.templateType === '3'">椤剁骇鑺傜偣</span>
+        <span v-else-if="form.templateType === '5'">涓氬姟绫诲瀷</span>
+        <span v-else-if="form.templateType === '6'">瀵硅薄绫诲瀷</span>
+        <span v-else-if="form.searchTarger === '1'">婧愬璞�</span>
+        <span v-else-if="form.searchTarger === '2'">鐩爣瀵硅薄</span>
+      </template>
+    </avue-crud>
+    <el-dialog
+      v-dialogDrag
+      :visible.sync="btnDesignVisible"
+      append-to-body="true"
+      class="avue-dialog"
+      title="閰嶇疆鎸夐挳"
+      width="70%"
+      @close="dialogClose">
+      <el-container>
+        <el-header style="height: 40px !important;">
+          <div style="display: flex">
+            <el-button :disabled="!disabledBtn" plain size="mini" type="primary" @click="addClickBtnHandler">娣诲姞
+            </el-button>
+            <el-button :disabled="!disabledBtn" plain size="mini" type="primary" @click="editClickBtnHandler">淇敼
+            </el-button>
+            <el-button :disabled="!disabledBtn" plain size="mini" type="danger" @click="delClickBtnHandler">鍒犻櫎
+            </el-button>
+            <el-button :disabled="disabledBtn" plain size="mini" type="primary" @click="saveClickBtnHandler">淇濆瓨
+            </el-button>
+            <el-button :disabled="disabledBtn" plain size="mini" type="primary" @click="escClickBtnHandler">鍙栨秷
+            </el-button>
+            <el-button plain size="mini" type="primary">璋冩暣涓轰笅绾ф寜閽�</el-button>
+            <el-button plain size="mini" type="primary">璋冩暣涓轰笂绾ф寜閽�</el-button>
+            <el-button plain size="mini" type="primary">澶嶅埗鍒板叾浠栫粍浠�</el-button>
+          </div>
+        </el-header>
+        <el-container>
+          <el-aside width="20%">
+            <basic-container>
+              <div style="height:650px;">
+                <avue-tree
+                  ref="Tree"
+                  :data="treeData"
+                  :loading="treeLoading"
+                  :option="treeOption"
+                  node-key="value"
+                  @node-click="nodeTreeClick">
+                  <span slot-scope="{ node, data }" class="el-tree-node__label">
+                    <span style="font-size: 14px">
+                    <i class="el-icon-s-promotion"></i>
+                      {{ (node || {}).label }}
+                    </span>
+                  </span>
+                </avue-tree>
+              </div>
+            </basic-container>
+          </el-aside>
+
+          <el-main>
+            <basic-container>
+              <el-divider content-position="left">鍩虹淇℃伅</el-divider>
+              <el-form ref="form" :model="basicForm" :rules="rules" label-width="90px" size="small"
+                       style="margin-top: 20px">
+                <el-row>
+                  <el-form-item :inline-message='true' label="缂栧彿锛�" prop="seq">
+                    <el-input-number v-model="basicForm.seq" :disabled="disabledBtn" :max="9999" :min="1"
+                                     controls-position="right"></el-input-number>
+                  </el-form-item>
+
+                  <el-form-item :inline-message='true' label="鍚嶇О锛�" prop="label">
+                    <el-col :span="14">
+                      <el-input v-model="basicForm.label" :readonly="disabledBtn"></el-input>
+                    </el-col>
+                  </el-form-item>
+
+                  <el-form-item label="Action锛�" prop="Action">
+                    <el-col :span="14">
+                      <el-input v-model="basicForm.actionOId" :readonly="disabledBtn"></el-input>
+                    </el-col>
+                  </el-form-item>
+
+                  <el-col :span="12">
+                    <el-form-item label="鏄惁鎺堟潈锛�" prop="resource">
+                      <el-radio v-model="basicForm.authorization" :disabled="disabledBtn" label="0">鏄�</el-radio>
+                      <el-radio v-model="basicForm.authorization" :disabled="disabledBtn" label="1">鍚�</el-radio>
+                    </el-form-item>
+                  </el-col>
+
+                  <el-col :span="12">
+                    <el-form-item label="鏄惁鏄剧ず锛�" prop="show">
+                      <el-radio v-model="basicForm.show" :disabled="disabledBtn" label="0">鏄�</el-radio>
+                      <el-radio v-model="basicForm.show" :disabled="disabledBtn" label="1">鍚�</el-radio>
+                    </el-form-item>
+                  </el-col>
+
+                  <el-col :span="12">
+                    <el-form-item label="鏄剧ず鏂瑰紡锛�" prop="showType">
+                      <el-radio v-model="basicForm.displayMode" :disabled="disabledBtn" label="text">鏂囧瓧</el-radio>
+                      <el-radio v-model="basicForm.displayMode" :disabled="disabledBtn" label="image">鍥炬爣</el-radio>
+                      <el-radio v-model="basicForm.displayMode" :disabled="disabledBtn" label="textandimage">鏂囧瓧鍜屽浘鏍�
+                      </el-radio>
+                    </el-form-item>
+                  </el-col>
+
+                  <el-col :span="12">
+                    <el-form-item label="鎻愮ず淇℃伅锛�" prop="desc">
+                      <el-input v-model="basicForm.desc" :readonly="disabledBtn" type="textarea"></el-input>
+                    </el-form-item>
+                  </el-col>
+
+                </el-row>
+              </el-form>
+
+              <el-divider content-position="left">鍙傛暟淇℃伅</el-divider>
+              <avue-crud
+                ref="paramsCrud"
+                :data="paramsData"
+                :option="paramsOption"
+                style="margin-top: 20px"
+                @row-save="paramsRowSave">
+                <template slot="menuLeft" slot-scope="scope">
+                  <el-button :disabled="disabledBtn" icon="el-icon-plus" plain size="small" type="primary"
+                             @click="paramsRowAddClickHandler">鍒涘缓
+                  </el-button>
+                </template>
+
+                <template slot="menu" slot-scope="scope">
+                  <el-button :disabled="disabledBtn" icon="el-icon-delete" size="small" type="text"
+                             @click="paramsRowDeleteHandler(scope.row)">鍒犻櫎
+                  </el-button>
+                </template>
+
+              </avue-crud>
+            </basic-container>
+          </el-main>
+        </el-container>
+      </el-container>
+    </el-dialog>
+  </basic-container>
+</template>
+
+<script>
+import basicOption from "@/util/basic-option";
+import func from "@/util/func";
+import {
+  getBtmDatasByPage,
+  getPortalVIDatasByPage,
+  getQTInfoDatasByPage,
+  getTabButtons,
+  addTapButton,
+  updateTapButton
+} from "@/api/UI/uiDefine/api";
+
+export default {
+  props: {
+    sourceData: {
+      type: Array,
+      default: () => [
+        {
+          "controlPath": "",
+          "description": "",
+          "eventKey": "",
+          "eventMap": null,
+          "eventValue": "",
+          "expandCols": "",
+          "expandMode": "",
+          "extAttr": "",
+          "id": "ABAE25CE-867E-9C73-AC1A-B316FD91C65B",
+          "isShowImage": "",
+          "linkType": "parttodocument",
+          "name": "鎶�鏈枃浠�",
+          "navigatorType": "",
+          "orderField": "",
+          "orderMode": "",
+          "orientation": "",
+          "qryType": null,
+          "queryTemplateName": "QueryPartEngineeringTechnology",
+          "refTreeSet": "",
+          "returnRows": "",
+          "rootContent": "",
+          "searchTarger": "2",
+          "separator": "",
+          "seq": "1",
+          "showAbs": "",
+          "showContent": "",
+          "showContentRelation": "",
+          "showContentTable": "",
+          "showContentType": "",
+          "showExpression": "",
+          "showExpressionRoot": "",
+          "showLinkAbs": "",
+          "showType": "document",
+          "subUILayout": "",
+          "subUIObjType": "",
+          "tabPageOId": "98F9082F-BAF4-FB81-3230-32590B34A329",
+          "templateId": "PartEngineeringTechnology_list",
+          "templateType": "1",
+          "type": 3,
+          "uiLayout": null,
+          "uiParser": "",
+          "validity": ""
+        }
+      ]
+    },
+    height: {
+      type: String,
+      default: () => "auto"
+    }
+  },
+  name: "index",
+  data() {
+    return {
+      saveType: '',
+      disabledBtn: true,
+      paramsData: [],
+      nodeTreeRow: {},
+      paramsOption: {
+        ...basicOption,
+        height: 260,
+        addBtn: false,
+        tip: false,
+        editBtn: false,
+        delBtn: false,
+        refreshBtn: false,
+        column: [
+          {
+            label: '鍚嶇О',
+            prop: 'name'
+          },
+          {
+            label: '鍊�',
+            prop: 'value'
+          }
+        ]
+      },
+      rules: {
+        seq: [
+          {required: true, message: '璇疯緭鍏ョ紪鍙�', type: 'number', trigger: 'blur'},
+        ],
+        label: [
+          {required: true, message: '璇疯緭鍏ュ悕绉�', trigger: 'blur'},
+        ],
+      },
+      // 鎸夐挳璁捐 鍩虹淇℃伅
+      basicForm: {
+        seq: 1
+      },
+      treeData: [
+        {
+          label: this.sourceData[0].name,
+          oId: 'parentNode',
+          children: []
+        }
+      ],
+      treeOption: {
+        menu: false,
+        addBtn: false,
+        defaultExpandedKeys: ['parentNode'],
+        props: {
+          label: 'label',
+          value: 'oId',
+          children: 'children',
+        },
+      },
+      treeLoading: false,
+      btnDesignVisible: false,
+      FormData: [],
+      form: {},
+      data: this.sourceData,
+      option: {
+        ...basicOption,
+        height: this.height,
+        addBtn: false,
+        index: true,
+        calcHeight: -30,
+        column: [
+          {
+            label: '鍚嶇О',
+            prop: 'name',
+            rules: [
+              {
+                required: true,
+                message: '璇疯緭鍏ュ悕绉�',
+                trigger: 'blur'
+              }
+            ]
+          },
+          {
+            label: '缂栧彿',
+            prop: 'seq',
+            hide: false,
+            rules: [
+              {
+                required: true,
+                message: '璇疯緭鍏ョ紪鍙�',
+                trigger: 'blur'
+              }
+            ],
+          },
+          {
+            label: 'UI瑙f瀽绫诲瀷',
+            prop: 'uiParser',
+            hide: true,
+          },
+          {
+            label: '鎵╁睍灞炴��',
+            prop: 'extAttr',
+            hide: true,
+          },
+          {
+            label: '妯℃澘绫诲瀷',
+            prop: 'templateType',
+            type: 'radio',
+            span: 24,
+            value: '1',
+            dicData: [
+              {
+                label: 'Table(琛ㄦ牸)',
+                value: '1'
+              },
+              {
+                label: 'Custom锛堣嚜瀹氫箟妯℃澘锛�',
+                value: '2'
+              },
+              {
+                label: 'TreeTable(鏍戣〃)',
+                value: '3',
+              },
+              {
+                label: 'Form(琛ㄥ崟)',
+                value: '4',
+              },
+              {
+                label: 'Tree(鏍�)',
+                value: '5',
+              },
+              {
+                label: 'UILayout(UI瀹氫箟)',
+                value: '6',
+              }
+            ],
+            formatter: (row) => {
+              const val = this.templateTypeValueHandler(row.templateType);
+              return val;
+            },
+            change: (val) => {
+              console.log(val);
+              const searchTarger = this.option.column.find(item => item.prop === 'searchTarger');  // 鑾峰彇鎼滅储绫诲瀷閰嶇疆椤�
+              searchTarger.display = true; // 鍒囨崲榛樿灞曠ず鎼滅储绫诲瀷
+              // 妯℃澘绫诲瀷涓鸿〃鏍�
+              this.templateTypeTable(val.value === '1');
+              // 妯℃澘绫诲瀷涓鸿嚜瀹氫箟妯℃澘
+              this.templateTypeCustom(val.value === '2');
+              // 妯℃澘绫诲瀷涓烘爲琛�
+              this.templateTypeTreeTable(val.value === '3');
+              // 妯℃澘绫诲瀷涓鸿〃鍗�
+              this.templateTypeForm(val.value === '4');
+              // 妯℃澘绫诲瀷涓烘爲
+              this.templateTypeTree(val.value === '5');
+              // 妯℃澘绫诲瀷涓篣I瀹氫箟
+              this.templateTypeUI(val.value === '6');
+            }
+          },
+          {
+            label: '鏄剧ず绫诲瀷',
+            prop: 'navigatorType',
+            type: 'radio',
+            span: 24,
+            value: '1',
+            hide: true,
+            dicData: [
+              {
+                label: '涓嶆樉绀�',
+                value: '1'
+              },
+              {
+                label: '鏄剧ず瑙掕壊',
+                value: '2'
+              },
+              {
+                label: '鏄剧ずFolder',
+                value: '3',
+              },
+            ],
+          },
+          {
+            label: '鎼滅储绫诲瀷',
+            prop: 'searchTarger',
+            display: true,
+            type: 'radio',
+            value: '1',
+            span: 24,
+            dicData: [
+              {
+                label: '鏈璞″睘鎬�',
+                value: '1'
+              },
+              {
+                label: '鍏宠仈瀵硅薄灞炴��',
+                value: '2'
+              },
+            ],
+            formatter: (row) => {
+              return row.searchTarger === '1' ? '鏈璞″睘鎬�' : '鍏宠仈瀵硅薄灞炴��';
+            },
+            change: (val) => {
+              // 濡傛灉妯℃澘绫诲瀷鏄〃鏍笺�� 鏍戣〃 銆� 琛ㄥ崟 鍒囨崲瀵硅薄灞炴�х殑鏃跺�欙紝濡傛灉鏄湰瀵硅薄灞炴�т笉灞曠ず閾炬帴绫诲瀷锛屽惁鍒欏睍绀洪摼鎺ョ被鍨�
+              if (['1', '3', '4'].includes(this.form.templateType)) {
+                const obj = this.option.group[0].column.find(item => item.prop === 'linkType');
+                obj.display = val.value !== '1';
+              }
+            }
+          },
+          {
+            label: '鎻忚堪',
+            prop: 'description',
+            display: false
+          },
+        ],
+        group: [
+          {
+            icon: 'el-icon-folder-opened',
+            label: '',
+            arrow: false,
+            prop: 'group1',
+            column: [
+              {
+                label: '婧愬璞�',
+                prop: 'showType',
+                type: 'table',
+                display: false,
+                placeholder: "璇疯緭鍏ュ唴瀹�",
+                props: {
+                  label: 'name',
+                  value: 'name'
+                },
+                children: {
+                  border: true,
+                  column: [{
+                    label: '鍚嶇О',
+                    search: true,
+                    searchSpan: 24,
+                    prop: 'name'
+                  }, {
+                    label: '鏍囩',
+                    prop: 'label'
+                  }],
+                },
+                onLoad: ({page, value, data}, callback) => {
+                  //page鍒嗛〉
+                  // 涓嶇鏄悳绱� 杩樻槸棣栨鍔犺浇閮戒細瑙﹀彂page 鎵�浠ュ彧闇�瑕佹嬁page瀛樺湪涓庡惁杩涜璇锋眰灏卞彲浠� 濡傛灉鍐嶅幓鍒ゆ柇data鎼滅储 鎴栬�卾alue鍒濇鍔犺浇灏变細閲嶅璇锋眰
+                  if (page) {
+                    const params = {
+                      "conditionMap[filterInputValue]": value ? value.name : ''
+                    };
+                    getBtmDatasByPage(page.currentPage, page.pageSize, params).then(res => {
+                      callback({
+                        total: res.data.total,
+                        data: res.data.data
+                      })
+                    })
+                  }
+                },
+              },
+              {
+                label: '閾炬帴绫诲瀷',
+                prop: 'linkType',
+                type: 'table',
+                display: false,
+                props: {
+                  label: 'viName',
+                  value: 'viName'
+                },
+                children: {
+                  border: true,
+                  column: [{
+                    label: '鍚嶇О',
+                    search: true,
+                    searchSpan: 24,
+                    prop: 'viName'
+                  }, {
+                    label: '绫诲瀷',
+                    prop: 'viType'
+                  }],
+                },
+                onLoad: ({page, value, data}, callback) => {
+                  if (page) {
+                    const params = {
+                      "conditionMap[selectBtmType]": this.form.showType,
+                      "conditionMap[filterInputValue]": data ? data.viName : '',
+                    };
+                    getPortalVIDatasByPage(page.currentPage, page.pageSize, params).then(res => {
+                      console.log(res);
+                      callback({
+                        total: res.data.total,
+                        data: res.data.data
+                      })
+                    })
+                  }
+                },
+              },
+              {
+                label: '閫夋嫨妯℃澘',
+                prop: 'showTypea',
+                display: false,
+                type: 'table',
+                props: {
+                  label: 'viName',
+                  value: 'viName'
+                },
+                children: {
+                  border: true,
+                  column: [{
+                    label: '鍚嶇О',
+                    search: true,
+                    searchSpan: 24,
+                    prop: 'viName'
+                  }, {
+                    label: '绫诲瀷',
+                    prop: 'viType'
+                  }],
+                },
+                onLoad: ({page, value, data}, callback) => {
+                  if (page) {
+                    const params = {
+                      "conditionMap[selectBtmType]": this.form.showType,
+                      "conditionMap[filterInputValue]": data ? data.viName : '',
+                    };
+                    getPortalVIDatasByPage(page.currentPage, page.pageSize, params).then(res => {
+                      console.log(res);
+                      callback({
+                        total: res.data.total,
+                        data: res.data.data
+                      })
+                    })
+                  }
+                },
+              },
+              {
+                label: 'UI瀹氫箟',
+                prop: 'UI',
+                type: 'table',
+                display: false,
+                props: {
+                  label: 'qtName',
+                  value: 'qtName'
+                },
+                children: {
+                  border: true,
+                  column: [{
+                    label: '鍚嶇О',
+                    search: true,
+                    searchSpan: 24,
+                    prop: 'qtName'
+                  }, {
+                    label: '绫诲瀷',
+                    prop: 'btmName'
+                  }],
+                },
+                onLoad: ({page, value, data}, callback) => {
+                  if (page) {
+                    const params = {
+                      "conditionMap[selectBtmType]": this.form.showType,
+                      "conditionMap[filterInputValue]": data ? data.qtName : '',
+                    };
+                    getQTInfoDatasByPage(page.currentPage, page.pageSize, params).then(res => {
+                      callback({
+                        total: res.data.total,
+                        data: res.data.data
+                      })
+                    })
+                  }
+                },
+              },
+              {
+                label: '鏌ヨ绫诲瀷',
+                prop: 'searchType',
+                display: false,
+                type: 'radio',
+                span: 24,
+                dicData: [
+                  {
+                    label: '涓氬姟绫诲瀷',
+                    value: '1'
+                  },
+                  {
+                    label: '閾炬帴绫诲瀷',
+                    value: '2'
+                  }
+                ]
+              },
+              {
+                label: '鏌ヨ瀵硅薄绫诲瀷',
+                prop: 'searchObjType',
+                type: 'table',
+                display: false,
+                labelWidth: 100,
+                props: {
+                  label: 'qtName',
+                  value: 'qtName'
+                },
+                children: {
+                  border: true,
+                  column: [{
+                    label: '鍚嶇О',
+                    search: true,
+                    searchSpan: 24,
+                    prop: 'qtName'
+                  }, {
+                    label: '绫诲瀷',
+                    prop: 'btmName'
+                  }],
+                },
+                onLoad: ({page, value, data}, callback) => {
+                  if (page) {
+                    const params = {
+                      "conditionMap[selectBtmType]": this.form.showType,
+                      "conditionMap[filterInputValue]": data ? data.qtName : '',
+                    };
+                    getQTInfoDatasByPage(page.currentPage, page.pageSize, params).then(res => {
+                      callback({
+                        total: res.data.total,
+                        data: res.data.data
+                      })
+                    })
+                  }
+                },
+              },
+              {
+                label: '鏌ヨ妯℃澘',
+                prop: 'showTypes',
+                type: 'table',
+                display: false,
+                props: {
+                  label: 'qtName',
+                  value: 'qtName'
+                },
+                children: {
+                  border: true,
+                  column: [{
+                    label: '鍚嶇О',
+                    search: true,
+                    searchSpan: 24,
+                    prop: 'qtName'
+                  }, {
+                    label: '绫诲瀷',
+                    prop: 'btmName'
+                  }],
+                },
+                onLoad: ({page, value, data}, callback) => {
+                  if (page) {
+                    const params = {
+                      "conditionMap[selectBtmType]": this.form.showType,
+                      "conditionMap[filterInputValue]": data ? data.qtName : '',
+                    };
+                    getQTInfoDatasByPage(page.currentPage, page.pageSize, params).then(res => {
+                      callback({
+                        total: res.data.total,
+                        data: res.data.data
+                      })
+                    })
+                  }
+                },
+              },
+              {
+                label: '鎺у埗璺緞',
+                prop: 'kzlj',
+                display: false,
+                type: 'textarea',
+                rows: 3
+              },
+              {
+                label: '鏍硅妭鐐规樉绀鸿〃杈惧紡',
+                prop: 'genjiedian',
+                display: false,
+                labelWidth: 135,
+                span: 24
+              },
+              {
+                label: '鏍戣妭鐐规樉绀鸿〃杈惧紡',
+                prop: 'shujiedian',
+                display: false,
+                labelWidth: 135,
+                span: 24
+              },
+              {
+                label: '鍙傜収鏍戣缃�',
+                prop: 'canzhaoshu',
+                display: false,
+              },
+              {
+                label: '鍒嗛殧绗�',
+                prop: 'fgf',
+                display: false,
+              },
+              {
+                label: '灞曞紑鏂瑰紡',
+                prop: 'zkfs',
+                display: false,
+                type: 'radio',
+                dicData: [
+                  {
+                    label: '閫愮骇灞曞紑',
+                    value: '1'
+                  },
+                  {
+                    label: '鍏ㄩ儴灞曞紑',
+                    value: '2'
+                  }
+                ]
+              },
+            ]
+          },
+          {
+            icon: 'el-icon-folder-opened',
+            label: '',
+            arrow: false,
+            prop: 'group2',
+            column: [
+              {
+                label: 'EventKey',
+                prop: 'eventKey',
+                type: 'select',
+                value: 'SelectionEvent',
+                dicData: [
+                  {
+                    label: 'SelectionEvent',
+                    value: 'SelectionEvent'
+                  },
+                  {
+                    label: 'DBClickEvent',
+                    value: 'DBClickEvent'
+                  },
+                  {
+                    label: 'ClickEvent',
+                    value: 'ClickEvent'
+                  }
+                ],
+              },
+              {
+                label: 'EventValue',
+                prop: 'eventValue',
+                labelWidth: 100
+              },
+              {
+                label: '',
+                prop: 'eventButton',
+                span: 24
+              },
+              {
+                label: '',
+                prop: 'bottomValue',
+                span: 24
+              },
+            ]
+          }
+        ],
+      },
+      tableLoading: false,
+      lastIndex: null,
+      selectList: [],
+      formDataRow: {},
+    }
+  },
+  computed: {},
+  methods: {
+    // 鏍规嵁涓嶅悓鍊煎尯鍒嗙被鍨�
+    templateTypeValueHandler(val) {
+      const componentMap = {
+        '1': '琛ㄦ牸',
+        '2': '鑷畾涔夋ā鏉�',
+        '3': '鏍戣〃',
+        '4': '琛ㄥ崟',
+        '5': '鏍�',
+        '6': 'UI瀹氫箟',
+      };
+
+      return componentMap[val] || ""; // 濡傛灉涓虹┖ 杩斿洖绌�
+    },
+
+    // 琛ㄦ牸澶氶��
+    selectChangeHandler(row) {
+      this.selectList = row;
+    },
+
+    // 琛岀偣鍑�
+    rowClickHandler(row) {
+      func.rowClickHandler(
+        row,
+        this.$refs.crud,
+        this.lastIndex,
+        (newIndex) => {
+          this.lastIndex = newIndex;
+        },
+        () => {
+          this.selectList = [];
+        }
+      );
+    },
+
+    // 澧炲姞
+    addClickHandler() {
+      this.$refs.crud.rowAdd();
+    },
+
+    // 瀵硅瘽妗嗚〃鏍艰鐐瑰嚮
+    formDataRowClick(row) {
+      this.formDataRow = row;
+    },
+
+    // 瀵硅瘽妗嗚〃鏍兼坊鍔�
+    formDataAddClickHandler() {
+      if (!this.form.eventKey) {
+        this.$message.error('璇烽�夋嫨EventKey');
+        return;
+      }
+
+      if (!this.form.eventValue) {
+        this.$message.error('璇疯緭鍏ventValue');
+        return;
+      }
+
+      if (this.FormData.length >= 1) {
+        const eventValueStatus = this.FormData.some(item => item.eventValue === this.form.eventValue);
+
+        if (eventValueStatus) {
+          this.$message.error('宸插瓨鍦ㄧ浉鍚岀殑 EventValue锛屼笉鑳介噸澶嶆坊鍔�');
+          return;
+        }
+      }
+      const obj = {
+        index: this.FormData.length,
+        eventKey: this.form.eventKey,
+        eventValue: this.form.eventValue
+      }
+
+      this.FormData.push(obj);
+    },
+
+    // 瀵硅瘽妗嗚〃鏍煎垹闄�
+    formDataDelClickHandler() {
+      if (func.isEmptyObject(this.formDataRow)) {
+        this.$message.error('璇烽�夋嫨涓�鏉℃暟鎹�');
+        return;
+      }
+
+      this.FormData = this.FormData.filter(item => item.index !== this.formDataRow.index);
+    },
+
+    // 妯℃澘绫诲瀷鏄剧ず闅愯棌鏂规硶
+    updateDisplay(val, showTpeMap) {
+      const groupList = this.option.group[0].column; // 鑾峰彇绗竴灞俫roup鎵�鏈夋暟鎹�
+      groupList.forEach(item => {
+        item.display = showTpeMap.includes(item.prop) ? val : !val; // 鏇存柊display
+      });
+    },
+
+    // 妯℃澘绫诲瀷涓鸿〃鏍�
+    templateTypeTable(val) {
+      if (!val) return;
+      this.updateDisplay(val, ['showType', 'showTypea', 'showTypes']);
+    },
+
+    // 妯℃澘绫诲瀷涓鸿嚜瀹氫箟妯℃澘
+    templateTypeCustom(val) {
+      if (!val) return;
+      const searchTarger = this.option.column.find(item => item.prop === 'searchTarger');  // 鑾峰彇鎼滅储绫诲瀷閰嶇疆椤�
+      searchTarger.display = false; // 涓嶅睍绀烘悳绱㈢被鍨�
+      this.updateDisplay(val, ['kzlj']);
+    },
+
+    // 妯℃澘绫诲瀷涓烘爲琛�
+    templateTypeTreeTable(val) {
+      if (!val) return;
+      this.updateDisplay(val, ['showType', 'showTypea', 'showTypes', 'zkl', 'zkfs']);
+    },
+
+    // 妯℃澘绫诲瀷涓鸿〃鍗�
+    templateTypeForm(val) {
+      if (!val) return;
+      this.updateDisplay(val, ['showType', 'showTypea', 'showTypes']);
+    },
+
+    // 妯℃澘绫诲瀷涓烘爲
+    templateTypeTree(val) {
+      if (!val) return;
+      const searchTarger = this.option.column.find(item => item.prop === 'searchTarger');  // 鑾峰彇鎼滅储绫诲瀷閰嶇疆椤�
+      searchTarger.display = false; // 涓嶅睍绀烘悳绱㈢被鍨�
+      this.updateDisplay(val, ['showType', 'showTypes', 'genjiedian', 'shujiedian', 'canzhaoshu', 'fgf', 'zkfs', 'linkType']);
+    },
+
+    // 妯℃澘绫诲瀷涓篣I瀹氫箟
+    templateTypeUI(val) {
+      if (!val) return;
+      const searchTarger = this.option.column.find(item => item.prop === 'searchTarger');  // 鑾峰彇鎼滅储绫诲瀷閰嶇疆椤�
+      searchTarger.display = false; // 涓嶅睍绀烘悳绱㈢被鍨�
+      this.updateDisplay(val, ['showType', 'UI', 'searchType', 'searchObjType', 'showTypes']);
+    },
+
+    // 鏌ユ壘鏁扮粍涓璞$储寮�
+    findIndexByEventValue(array, eventValue) {
+      return array.findIndex(item => item.eventValue === eventValue);
+    },
+
+    // 涓婄Щ
+    moveUp() {
+      const index = this.findIndexByEventValue(this.FormData, this.formDataRow.eventValue);
+      if (index > 0) {
+        // 浣跨敤 splice 鏂规硶鏉ユā鎷熶氦鎹�
+        const temp = this.FormData.splice(index - 1, 1, this.FormData[index])[0]; // 绉婚櫎 index-1 鐨勫厓绱狅紝骞跺湪鐩稿悓浣嶇疆鎻掑叆 index 鐨勫厓绱狅紝杩斿洖琚Щ闄ょ殑鍏冪礌
+        this.FormData.splice(index, 1, temp); // 鍦� index 浣嶇疆鎻掑叆涔嬪墠琚Щ闄ょ殑鍏冪礌
+      }
+    },
+
+    // 涓嬬Щ
+    moveDown() {
+      const index = this.findIndexByEventValue(this.FormData, this.formDataRow.eventValue);
+      const length = this.FormData.length;
+      if (index < length - 1) {
+        const temp = this.FormData[index];
+        this.FormData.splice(index, 1, this.FormData.splice(index + 1, 1, temp)[0]);
+      }
+    },
+
+    // 鎸夐挳璁捐鍏抽棴瀵硅瘽妗�
+    dialogClose() {
+
+    },
+
+    // 鎸夐挳璁捐
+    btnDesignClickHandler() {
+      if (this.selectList.length <= 0) {
+        this.$message.error('璇疯嚦灏戦�夋嫨涓�鏉℃暟鎹�');
+        return;
+      }
+      if (this.selectList.length > 1) {
+        this.$message.error('鏈�澶氶�夋嫨涓�鏉℃暟鎹�');
+        return;
+      }
+      this.btnDesignVisible = true;
+      this.getTabBtnTree();
+    },
+
+    // 宸︿晶鏍戣姹�
+    getTabBtnTree() {
+      const params = {
+        pageDefinationOid: this.selectList[0].id
+      }
+      this.treeLoading = true;
+      getTabButtons(params).then(res => {
+        if (res.data.code === 200) {
+          const data = res.data.data;
+          this.treeData[0].children = data;
+          this.treeLoading = false;
+        } else {
+          this.$message.error('璇锋鏌ユ帶鍒跺彴閿欒');
+        }
+      })
+    },
+
+    // 鎸夐挳璁捐琛岀偣鍑�
+    nodeTreeClick(row) {
+      this.nodeTreeRow = row;
+      this.basicForm = {...row};
+      this.paramsData = row.buttonParams ? Object.entries(row.buttonParams).map(([key, value]) => ({
+        name: key,
+        value: value
+      })) : [];
+      this.disabledBtn = true;
+    },
+
+    // 鎸夐挳璁捐鍙傛暟淇℃伅鍒犻櫎
+    paramsRowDeleteHandler(row) {
+      this.paramsData.splice(row.$index, 1)
+    },
+
+    // 鎸夐挳璁捐鍙傛暟淇℃伅娣诲姞鎸夐挳
+    paramsRowAddClickHandler() {
+      this.$refs.paramsCrud.rowAdd();
+    },
+
+    // 鎸夐挳璁捐鍙傛暟淇℃伅淇濆瓨
+    paramsRowSave(row, done, loading) {
+      if (!row.name) {
+        this.$message.error('鍚嶇О涓嶈兘涓虹┖');
+        return loading();
+      }
+
+      if (!row.value) {
+        this.$message.error('鍊间笉鑳戒负绌�');
+        return loading();
+      }
+
+      this.paramsData.push(row);
+      done();
+    },
+
+    // 鎸夐挳璁捐娣诲姞
+    addClickBtnHandler() {
+      if (func.isEmptyObject(this.nodeTreeRow)) {
+        this.$message.error('璇烽�夋嫨鑺傜偣杩涜娣诲姞');
+        return;
+      }
+      this.disabledBtn = false;
+      this.basicForm = {};
+      this.paramsData = [];
+      this.saveType = 'add';
+    },
+
+    // 鎸夐挳璁捐淇敼
+    editClickBtnHandler() {
+      if (func.isEmptyObject(this.nodeTreeRow)) {
+        this.$message.error('璇烽�夋嫨鑺傜偣杩涜娣诲姞');
+        return;
+      }
+
+      if (this.nodeTreeRow.oId === "parentNode") {
+        this.$message.error('椤跺眰鑺傜偣涓嶅厑璁镐慨鏀�');
+        return;
+      }
+
+      this.disabledBtn = false;
+      this.saveType = 'edit';
+    },
+
+    // 鎸夐挳璁捐鍙栨秷
+    escClickBtnHandler() {
+      this.disabledBtn = true;
+      if (this.saveType === 'add') {
+        this.$refs.Tree.setCurrentKey(null);
+      }
+    },
+
+    // 鎸夐挳璁捐淇濆瓨
+    saveClickBtnHandler() {
+      const saveFunction = this.saveType === 'add' ? addTapButton : updateTapButton;
+      const bottomParams = {};
+      if (this.paramsData.length > 0) {
+        this.paramsData.forEach(item => {
+          bottomParams[item.name] = item.value
+        })
+      }
+      ;
+
+      const params = this.saveType === 'add' ? {
+        ...this.basicForm,
+        parentId: this.nodeTreeRow.oId === 'parentNode' ? '' : this.nodeTreeRow.parentId,
+        buttonParams: bottomParams
+      } : {
+        ...this.basicForm,
+        buttonParams: bottomParams
+      }
+
+      saveFunction(params).then(res => {
+        if (res.data.code === 200) {
+          this.$message.success(res.data.obj);
+          this.disabledBtn = true;
+          this.getTabBtnTree();
+          this.basicForm = {};
+          this.paramsData = [];
+        }
+      })
+    },
+
+    // 鎸夐挳璁捐鍒犻櫎
+    delClickBtnHandler() {
+      if (func.isEmptyObject(this.nodeTreeRow)) {
+        this.$message.error('璇烽�夋嫨鑺傜偣杩涜鍒犻櫎');
+        return;
+      }
+
+      if (this.nodeTreeRow.oId === "parentNode") {
+        this.$message.error('椤跺眰鑺傜偣涓嶅厑璁稿垹闄�');
+        return;
+      }
+
+      this.$confirm('鎮ㄧ‘瀹氳鍒犻櫎鎵�閫夋嫨鐨勬暟鎹悧锛�', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(() => {
+
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '宸插彇娑堝垹闄�'
+        });
+      });
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.el-divider__text, .el-link {
+  font-size: 16px !important;
+}
+</style>

--
Gitblit v1.9.3