This is an automated email from the ASF dual-hosted git repository.

benjobs pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git


The following commit(s) were added to refs/heads/dev by this push:
     new 60fcbc788 [Feature] add depend apps page and fix alert setting style 
(#1921)
60fcbc788 is described below

commit 60fcbc7886e9c54928e25a197bae88e17d23d565
Author: Sizhu Wang <[email protected]>
AuthorDate: Fri Oct 28 23:21:39 2022 +0800

    [Feature] add depend apps page and fix alert setting style (#1921)
---
 .../src/api/flink/setting/types/alert.type.ts      |   1 +
 .../src/api/system/variable.ts                     |  11 +
 .../src/components/CardList/src/CardList.vue       |   4 +-
 .../src/design/public.less                         |  22 +-
 .../src/layouts/default/footer/index.vue           |   6 +-
 .../src/router/constant.ts                         |   3 +
 .../src/router/guard/permissionGuard.ts            |   1 -
 .../src/settings/projectSetting.ts                 |   2 +-
 .../src/store/modules/permission.ts                |   6 +-
 .../src/store/modules/user.ts                      |  12 +-
 .../src/utils/auth/index.ts                        |  29 ++-
 .../src/utils/cache/persistent.ts                  |  11 -
 .../src/views/base/login/Login.vue                 | 222 +++++++++++----------
 .../src/views/base/login/LoginForm.vue             |   7 +-
 .../src/views/flink/app/EditStreamPark.vue         |  40 +++-
 .../src/views/flink/app/data/index.ts              |   2 +-
 .../src/views/flink/setting/View.less              |   2 +-
 .../src/views/flink/setting/View.vue               |   6 +-
 .../views/flink/setting/components/AlertModal.vue  | 208 ++++++-------------
 .../flink/setting/components/AlertSetting.vue      | 203 ++++++++++++-------
 .../flink/setting/components/AlertTypeInfo.vue     | 119 +++++++++++
 .../views/flink/setting/components/SettingList.vue |   1 +
 .../flink/setting/components/SystemSetting.vue     |  17 +-
 .../views/flink/setting/components/alert.data.ts   |  79 ++++++--
 .../views/flink/setting/hooks/useClusterSetting.ts |   8 +-
 .../src/views/system/variable/DependApps.vue       |  70 +++++++
 .../src/views/system/variable/View.vue             |  27 ++-
 .../variable/{ => components}/VariableDrawer.vue   |   1 -
 .../variable/{ => components}/VariableInfo.vue     |   0
 29 files changed, 701 insertions(+), 419 deletions(-)

diff --git 
a/streampark-console/streampark-console-newui/src/api/flink/setting/types/alert.type.ts
 
b/streampark-console/streampark-console-newui/src/api/flink/setting/types/alert.type.ts
index 6af8c3e22..9606523c0 100644
--- 
a/streampark-console/streampark-console-newui/src/api/flink/setting/types/alert.type.ts
+++ 
b/streampark-console/streampark-console-newui/src/api/flink/setting/types/alert.type.ts
@@ -26,6 +26,7 @@ export interface AlertSetting {
   larkParams: string;
   createTime: string;
   modifyTime: string;
+  alertTypeTags?: string[];
 }
 
 // Create an alert
diff --git 
a/streampark-console/streampark-console-newui/src/api/system/variable.ts 
b/streampark-console/streampark-console-newui/src/api/system/variable.ts
index 7ba3b1a61..25e247f4e 100644
--- a/streampark-console/streampark-console-newui/src/api/system/variable.ts
+++ b/streampark-console/streampark-console-newui/src/api/system/variable.ts
@@ -22,6 +22,7 @@ import { VariableDeleteParam, VariableListRecord, 
VariableParam } from './model/
 
 enum VARIABLE_API {
   LIST = '/variable/list',
+  DEPEND = '/variable/dependApps',
   UPDATE = '/variable/update',
   POST = '/variable/post',
   DELETE = '/variable/delete',
@@ -62,6 +63,7 @@ export function fetchUpdateVariable(data: VariableParam): 
Promise<boolean | unde
 export function fetchVariableDelete(data: VariableDeleteParam): 
Promise<AxiosResponse<Result>> {
   return defHttp.delete({ url: VARIABLE_API.DELETE, data }, { 
isReturnNativeResponse: true });
 }
+
 /**
  * Code check
  * @param {Object} data
@@ -72,3 +74,12 @@ export function fetchCheckVariableCode(data: {
 }): Promise<AxiosResponse<Result>> {
   return defHttp.post({ url: VARIABLE_API.CHECK_CODE, data }, { 
isReturnNativeResponse: true });
 }
+
+/**
+ * Code check
+ * @param {Object} data
+ * @returns {Promise<AxiosResponse<Result>>}
+ */
+export function fetchDependApps(data: Recordable): Promise<any> {
+  return defHttp.post({ url: VARIABLE_API.DEPEND, data });
+}
diff --git 
a/streampark-console/streampark-console-newui/src/components/CardList/src/CardList.vue
 
b/streampark-console/streampark-console-newui/src/components/CardList/src/CardList.vue
index ca8571442..a11104d9b 100644
--- 
a/streampark-console/streampark-console-newui/src/components/CardList/src/CardList.vue
+++ 
b/streampark-console/streampark-console-newui/src/components/CardList/src/CardList.vue
@@ -26,8 +26,8 @@
         :pagination="paginationProp"
       >
         <template #header>
-          <div class="flex justify-end space-x-2"
-            ><slot name="header"></slot>
+          <div class="flex justify-end space-x-2">
+            <slot name="header"></slot>
             <Tooltip>
               <template #title>
                 <div class="w-50">Display quantity per line</div
diff --git a/streampark-console/streampark-console-newui/src/design/public.less 
b/streampark-console/streampark-console-newui/src/design/public.less
index bbaa20016..6268fac5b 100644
--- a/streampark-console/streampark-console-newui/src/design/public.less
+++ b/streampark-console/streampark-console-newui/src/design/public.less
@@ -24,8 +24,8 @@
 // =================================
 
 ::-webkit-scrollbar {
-  width: 14px;
-  height: 12px;
+  width: 7px;
+  height: 8px;
 }
 
 // ::-webkit-scrollbar-track {
@@ -33,21 +33,21 @@
 // }
 
 ::-webkit-scrollbar-track {
-  // background-color: rgb(0 0 0 / 5%);
-  background-color: unset;
+  background-color: rgb(0 0 0 / 5%);
 }
 
-::-webkit-scrollbar-thumb:hover,
 ::-webkit-scrollbar-thumb {
-  background-color: #e6f7ff;
+  // background: rgba(0, 0, 0, 0.6);
+  background-color: rgb(144 147 153 / 30%);
+  // background-color: rgba(144, 147, 153, 0.3);
+  border-radius: 2px;
+  box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
 }
 
-[data-theme="dark"] {
-  ::-webkit-scrollbar-thumb:hover,
-  ::-webkit-scrollbar-thumb {
-    background-color: #2a2a2a;
-  }
+::-webkit-scrollbar-thumb:hover {
+  background-color: @border-color-dark;
 }
+
 // =================================
 // ==============nprogress==========
 // =================================
diff --git 
a/streampark-console/streampark-console-newui/src/layouts/default/footer/index.vue
 
b/streampark-console/streampark-console-newui/src/layouts/default/footer/index.vue
index c1e556543..726f92b1a 100644
--- 
a/streampark-console/streampark-console-newui/src/layouts/default/footer/index.vue
+++ 
b/streampark-console/streampark-console-newui/src/layouts/default/footer/index.vue
@@ -24,7 +24,8 @@
       <!-- <a @click="openWindow(DOC_URL)">{{ 
t('layout.footer.onlineDocument') }}</a> -->
     </div>
     <div :class="`${prefixCls}__copyright`">
-      Copyright &copy;2019~{{ new Date().getFullYear() }} {{ title }}
+      Copyright &copy;{{ new Date().getFullYear() }} The Apache Software 
Foundation. Apache
+      StreamPark, StreamPark, and its feather logo are trademarks of The 
Apache Software Foundation
     </div>
   </Footer>
 </template>
@@ -43,7 +44,6 @@
   import { useRouter } from 'vue-router';
   import { useDesign } from '/@/hooks/web/useDesign';
   import { useLayoutHeight } from '../content/useContentViewHeight';
-  import { useGlobSetting } from '/@/hooks/setting';
 
   export default defineComponent({
     name: 'LayoutFooter',
@@ -53,7 +53,6 @@
       const { getShowFooter } = useRootSetting();
       const { currentRoute } = useRouter();
       const { prefixCls } = useDesign('layout-footer');
-      const { title } = useGlobSetting();
       const footerRef = ref<ComponentRef>(null);
       const { setFooterHeight } = useLayoutHeight();
 
@@ -76,7 +75,6 @@
         SITE_URL,
         openWindow,
         footerRef,
-        title,
       };
     },
   });
diff --git a/streampark-console/streampark-console-newui/src/router/constant.ts 
b/streampark-console/streampark-console-newui/src/router/constant.ts
index b92c90f8a..c3448b591 100644
--- a/streampark-console/streampark-console-newui/src/router/constant.ts
+++ b/streampark-console/streampark-console-newui/src/router/constant.ts
@@ -40,6 +40,8 @@ export const getParentLayout = (_name?: string) => {
 };
 const projectPath = '/flink/project';
 const settingPath = '/flink/setting';
+const variablePath = '/system/variable';
+
 const applicationPath = '/flink/app';
 export const menuMap = {
   [`${projectPath}/add`]: projectPath,
@@ -51,4 +53,5 @@ export const menuMap = {
   [`${applicationPath}/edit_streampark`]: applicationPath,
   [`${settingPath}/add_cluster`]: settingPath,
   [`${settingPath}/edit_cluster`]: settingPath,
+  [`${variablePath}/depend_apps`]: variablePath,
 };
diff --git 
a/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts
 
b/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts
index 3dcbd321d..4a931a342 100644
--- 
a/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts
+++ 
b/streampark-console/streampark-console-newui/src/router/guard/permissionGuard.ts
@@ -46,7 +46,6 @@ export function createPermissionGuard(router: Router) {
     }
 
     const token = userStore.getToken;
-
     // Whitelist can be directly entered
     if (whitePathList.includes(to.path as PageEnum)) {
       if (to.path === LOGIN_PATH && token) {
diff --git 
a/streampark-console/streampark-console-newui/src/settings/projectSetting.ts 
b/streampark-console/streampark-console-newui/src/settings/projectSetting.ts
index f63a14cd2..7dd2a2936 100644
--- a/streampark-console/streampark-console-newui/src/settings/projectSetting.ts
+++ b/streampark-console/streampark-console-newui/src/settings/projectSetting.ts
@@ -43,7 +43,7 @@ const setting: ProjectConfig = {
   permissionMode: PermissionModeEnum.BACK,
 
   // Permission-related cache is stored in sessionStorage or localStorage
-  permissionCacheType: CacheTypeEnum.LOCAL,
+  permissionCacheType: CacheTypeEnum.SESSION,
 
   // Session timeout processing
   sessionTimeoutProcessing: SessionTimeoutProcessingEnum.ROUTE_JUMP,
diff --git 
a/streampark-console/streampark-console-newui/src/store/modules/permission.ts 
b/streampark-console/streampark-console-newui/src/store/modules/permission.ts
index da57124a8..19c7ddbd3 100644
--- 
a/streampark-console/streampark-console-newui/src/store/modules/permission.ts
+++ 
b/streampark-console/streampark-console-newui/src/store/modules/permission.ts
@@ -40,9 +40,10 @@ import { getPermCode } from '/@/api/system/user';
 import { useMessage } from '/@/hooks/web/useMessage';
 import { PageEnum } from '/@/enums/pageEnum';
 import { fetchUserTeam } from '/@/api/system/member';
-import { Persistent } from '/@/utils/cache/persistent';
+// import { Persistent } from '/@/utils/cache/persistent';
 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
 import { UserInfo } from '/#/store';
+import { getAuthCache } from '/@/utils/auth';
 
 interface PermissionState {
   // Permission code list
@@ -126,7 +127,7 @@ export const usePermissionStore = defineStore({
       const userStore = useUserStore();
       const appStore = useAppStoreWithOut();
       // get teamList
-      const { userId } = Persistent.getLocal(USER_INFO_KEY) as UserInfo;
+      const { userId } = getAuthCache(USER_INFO_KEY) as UserInfo;
       if (userStore.teamList.length == 0 && userId) {
         const teamList = await fetchUserTeam({ userId });
         userStore.setTeamList(teamList.map((i) => ({ label: i.teamName, value: 
i.id })));
@@ -239,6 +240,7 @@ export const usePermissionStore = defineStore({
                 title: t('sys.api.errorTip'),
                 content: 'No permission, please contact the administrator',
               });
+              userStore.logout();
               return Promise.reject(new Error('routeList is empty'));
             }
             routeList = (routeList[0].children as AppRouteRecordRaw[]).map((v) 
=> {
diff --git 
a/streampark-console/streampark-console-newui/src/store/modules/user.ts 
b/streampark-console/streampark-console-newui/src/store/modules/user.ts
index a99b307ac..cdb1dab57 100644
--- a/streampark-console/streampark-console-newui/src/store/modules/user.ts
+++ b/streampark-console/streampark-console-newui/src/store/modules/user.ts
@@ -38,8 +38,6 @@ import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
 import { h } from 'vue';
 import { getUserTeamId } from '/@/utils';
 import { usePermission } from '/@/hooks/web/usePermission';
-import { AesEncryption } from '/@/utils/cipher';
-import { cacheCipher } from '/@/settings/encryptionSetting';
 
 interface TeamListType {
   label: string;
@@ -112,13 +110,6 @@ export const useUserStore = defineStore({
     setToken(info: string | undefined) {
       this.token = info ? info : ''; // for null or undefined value
       setAuthCache(TOKEN_KEY, info);
-      let cacheToken = this.token;
-      // production encrypted
-      if (import.meta.env.PROD && cacheToken) {
-        const encryption = new AesEncryption({ key: cacheCipher.key, iv: 
cacheCipher.iv });
-        cacheToken = encryption.encryptByAES(cacheToken);
-      }
-      localStorage.setItem(TOKEN_KEY, cacheToken);
     },
     setExpire(info: string | undefined) {
       this.expire = info || '';
@@ -149,12 +140,11 @@ export const useUserStore = defineStore({
     setData(data: Recordable) {
       const { token, expire, user, permissions, roles = [] } = data;
 
+      this.setToken(token);
       this.setExpire(expire);
       this.setUserInfo(user);
       this.setRoleList(roles);
       this.setPermissions(permissions);
-      // set token must be placed at the end, need to listen to this value
-      this.setToken(token);
     },
     // set team
     async setTeamId(data: { teamId: string; userId?: string }): 
Promise<boolean> {
diff --git 
a/streampark-console/streampark-console-newui/src/utils/auth/index.ts 
b/streampark-console/streampark-console-newui/src/utils/auth/index.ts
index ecd313c46..81bc699b0 100644
--- a/streampark-console/streampark-console-newui/src/utils/auth/index.ts
+++ b/streampark-console/streampark-console-newui/src/utils/auth/index.ts
@@ -27,16 +27,33 @@ export function getToken() {
 }
 
 export function getAuthCache<T>(key: BasicKeys) {
-  const fn = isLocal ? Persistent.getLocal : Persistent.getSession;
-  return fn(key) as T;
+  if (isLocal) {
+    return Persistent.getLocal(key) as T;
+  } else {
+    const sessionCacheValue = Persistent.getSession(key) as T;
+    const localCacheValue = Persistent.getLocal(key) as T;
+    if (!sessionCacheValue && localCacheValue) {
+      Persistent.setSession(key, localCacheValue, true);
+      return localCacheValue;
+    }
+    return sessionCacheValue;
+  }
 }
 
 export function setAuthCache(key: BasicKeys, value) {
-  const fn = isLocal ? Persistent.setLocal : Persistent.setSession;
-  return fn(key, value, true);
+  if (isLocal) {
+    return Persistent.setLocal(key, value, true);
+  } else {
+    Persistent.setLocal(key, value, true);
+    return Persistent.setSession(key, value, true);
+  }
 }
 
 export function clearAuthCache(immediate = true) {
-  const fn = isLocal ? Persistent.clearLocal : Persistent.clearSession;
-  return fn(immediate);
+  if (isLocal) {
+    return Persistent.clearLocal(immediate);
+  } else {
+    Persistent.clearLocal(immediate);
+    return Persistent.clearSession(immediate);
+  }
 }
diff --git 
a/streampark-console/streampark-console-newui/src/utils/cache/persistent.ts 
b/streampark-console/streampark-console-newui/src/utils/cache/persistent.ts
index 4488d17e3..0cb495c5d 100644
--- a/streampark-console/streampark-console-newui/src/utils/cache/persistent.ts
+++ b/streampark-console/streampark-console-newui/src/utils/cache/persistent.ts
@@ -135,17 +135,6 @@ function storageChange(e: any) {
     Persistent.clearAll();
     return;
   }
-  // token change reload
-  if (key === TOKEN_KEY && oldValue !== newValue) {
-    const { [TOKEN_KEY]: tokenCache } = pick(ls.get(APP_LOCAL_CACHE_KEY), 
TOKEN_KEY);
-    // no token or token value is invalid
-    if (tokenCache?.value !== newValue) {
-      Persistent.clearLocal();
-      return;
-    }
-    window.location.reload();
-    return;
-  }
   if (!!newValue && !!oldValue) {
     if (APP_LOCAL_CACHE_KEY === key) {
       Persistent.clearLocal();
diff --git 
a/streampark-console/streampark-console-newui/src/views/base/login/Login.vue 
b/streampark-console/streampark-console-newui/src/views/base/login/Login.vue
index dfcde4316..9295de01c 100644
--- a/streampark-console/streampark-console-newui/src/views/base/login/Login.vue
+++ b/streampark-console/streampark-console-newui/src/views/base/login/Login.vue
@@ -21,8 +21,9 @@
         <div class="flex w-full h-full py-5 xl:h-auto xl:py-0 xl:my-0">
           <div
             :class="`${prefixCls}-form`"
-            class="relative w-auto px-12 bg-[rgba(0,0,0,0.4)] py-5 mx-auto 
my-auto shadow-md enter-y">
-            <LoginForm/>
+            class="relative w-auto px-12 bg-[rgba(0,0,0,0.4)] py-5 mx-auto 
my-auto shadow-md enter-y"
+          >
+            <LoginForm />
           </div>
         </div>
       </div>
@@ -30,137 +31,144 @@
   </div>
 </template>
 <script lang="ts" setup>
-import LoginForm from './LoginForm.vue';
-import ForgetPasswordForm from './ForgetPasswordForm.vue';
-import {useDesign} from '/@/hooks/web/useDesign';
-
-defineProps({
-  sessionTimeout: {
-    type: Boolean,
-  },
-});
-
-// const globSetting = useGlobSetting();
-const {prefixCls} = useDesign('login');
-// const title = computed(() => globSetting?.title ?? '');
+  import LoginForm from './LoginForm.vue';
+  import { useDesign } from '/@/hooks/web/useDesign';
+
+  defineProps({
+    sessionTimeout: {
+      type: Boolean,
+    },
+  });
+
+  // const globSetting = useGlobSetting();
+  const { prefixCls } = useDesign('login');
+  // const title = computed(() => globSetting?.title ?? '');
 </script>
 <style lang="less">
-@prefix-cls: ~'@{namespace}-login';
-@logo-prefix-cls: ~'@{namespace}-app-logo';
-@countdown-prefix-cls: ~'@{namespace}-countdown-input';
-@active-color: 255, 255, 255;
-
-input.fix-auto-fill, .fix-auto-fill input {
-  box-shadow: inherit !important;
-}
-
-.@{prefix-cls} {
-  min-height: 100%;
-  overflow: hidden;
-  background: url('/@/assets/images/sign-bg.jpg') no-repeat 50%;
-  background-size: cover;
-
-  .ant-input-affix-wrapper {
-    border: 1px solid rgba(@active-color, 0.55);
-    border-radius: 1px;
-    color: rgba(@active-color, 0.65);
-    margin-top: 10px;
-    background-color: rgba(@active-color, 0.05) !important;
+  @prefix-cls: ~'@{namespace}-login';
+  @logo-prefix-cls: ~'@{namespace}-app-logo';
+  @countdown-prefix-cls: ~'@{namespace}-countdown-input';
+  @active-color: 255, 255, 255;
+
+  input.fix-auto-fill,
+  .fix-auto-fill input {
+    box-shadow: inherit !important;
   }
 
-  .signin-title {
-    padding-top: 20px;
-    font-size: 16px;
-    color: rgba(255, 255, 255, 0.65);
-    margin-top: 12px;
-    margin-bottom: 20px;
-  }
+  .@{prefix-cls} {
+    min-height: 100%;
+    overflow: hidden;
+    background: url('/@/assets/images/sign-bg.jpg') no-repeat 50%;
+    background-size: cover;
+
+    .ant-input-affix-wrapper {
+      border: 1px solid rgba(@active-color, 0.55);
+      border-radius: 1px;
+      color: rgba(@active-color, 0.65);
+      margin-top: 10px;
+      background-color: rgba(@active-color, 0.05) !important;
+    }
 
-  .logo {
-    padding-top: 20px;
-    height: 130px;
-    margin: auto;
-  }
+    .signin-title {
+      padding-top: 20px;
+      font-size: 16px;
+      color: rgba(255, 255, 255, 0.65);
+      margin-top: 12px;
+      margin-bottom: 20px;
+    }
 
-  .signin-form {
-    .ant-input {
-      padding-top: 3px;
-      padding-bottom: 3px;
+    .logo {
+      padding-top: 20px;
+      height: 130px;
+      margin: auto;
+    }
 
-      .ant-input-affix-wrapper:hover, .ant-input:not(.ant-input-disabled) {
-        border-color: rgba(@active-color, .95);
+    .signin-form {
+      .ant-form-item-has-error 
:not(.ant-input-disabled):not(.ant-input-borderless).ant-input {
+        background-color: transparent !important;
       }
-    }
 
-    .signin-btn {
-      .ant-btn {
-        margin-top: 30px;
-        height: 40px;
-        background: rgba(@active-color, .40);
-        border: unset;
+      .ant-input {
+        padding-top: 3px;
+        padding-bottom: 3px;
+        color: @white;
+
+        .ant-input-affix-wrapper:hover,
+        .ant-input:not(.ant-input-disabled) {
+          border-color: rgba(@active-color, 0.95);
+        }
+      }
+      .ant-input-password-icon {
+        color: @content-bg !important;
+      }
+      .signin-btn {
+        .ant-btn {
+          margin-top: 30px;
+          height: 40px;
+          background: rgba(@active-color, 0.4);
+          border: unset;
+        }
       }
-    }
 
-    .text-left {
-      .ant-btn {
-        padding: 0px;
+      .text-left {
+        .ant-btn {
+          padding: 0px;
+        }
       }
     }
 
-  }
+    &::after {
+      content: '';
+      width: 100%;
+      position: absolute;
+      left: 0;
+      top: 0;
+      bottom: -20px;
+      background: inherit;
+      z-index: 2;
+      filter: blur(1px);
+    }
 
-  &::after {
-    content: '';
-    width: 100%;
-    position: absolute;
-    left: 0;
-    top: 0;
-    bottom: -20px;
-    background: inherit;
-    z-index: 2;
-    filter: blur(1px);
-  }
+    &-sign-in-way {
+      .anticon {
+        font-size: 22px;
+        color: #888;
+        cursor: pointer;
 
+        &:hover {
+          color: @primary-color;
+        }
+      }
+    }
 
-  &-sign-in-way {
-    .anticon {
-      font-size: 22px;
-      color: #888;
-      cursor: pointer;
+    input {
+      min-width: 300px;
+      background: transparent;
 
-      &:hover {
-        color: @primary-color;
+      @media (max-width: @screen-xl) {
+        min-width: 260px;
       }
-    }
-  }
 
-  input {
-    min-width: 300px;
+      @media (max-width: @screen-lg) {
+        min-width: 200px;
+      }
 
-    @media (max-width: @screen-xl) {
-      min-width: 260px;
-    }
+      @media (max-width: @screen-md) {
+        min-width: 180px;
+      }
 
-    @media (max-width: @screen-lg) {
-      min-width: 200px;
+      @media (max-width: @screen-sm) {
+        min-width: 100px;
+      }
     }
 
-    @media (max-width: @screen-md) {
-      min-width: 180px;
+    .@{countdown-prefix-cls} input {
+      min-width: unset;
     }
 
-    @media (max-width: @screen-sm) {
-      min-width: 100px;
+    .ant-divider-inner-text {
+      font-size: 12px;
+      color: @text-color-secondary;
     }
   }
-
-  .@{countdown-prefix-cls} input {
-    min-width: unset;
-  }
-
-  .ant-divider-inner-text {
-    font-size: 12px;
-    color: @text-color-secondary;
-  }
-}
 </style>
diff --git 
a/streampark-console/streampark-console-newui/src/views/base/login/LoginForm.vue
 
b/streampark-console/streampark-console-newui/src/views/base/login/LoginForm.vue
index 98f36c91c..f86fc1d70 100644
--- 
a/streampark-console/streampark-console-newui/src/views/base/login/LoginForm.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/base/login/LoginForm.vue
@@ -23,12 +23,14 @@
     ref="formRef"
     v-show="getShow"
     @keypress.enter="handleLogin"
+    autocomplete="off"
   >
     <FormItem name="account" class="enter-x">
       <Input
         v-model:value="formData.account"
         :placeholder="t('sys.login.userName')"
-        class="fix-auto-fill">
+        class="fix-auto-fill"
+      >
         <template #prefix>
           <user-outlined type="user" />
         </template>
@@ -38,7 +40,8 @@
       <InputPassword
         visibilityToggle
         v-model:value="formData.password"
-        :placeholder="t('sys.login.password')">
+        :placeholder="t('sys.login.password')"
+      >
         <template #prefix>
           <lock-outlined type="user" />
         </template>
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue
 
b/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue
index b6ad353f8..75d93984d 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/app/EditStreamPark.vue
@@ -69,7 +69,7 @@
     tmPodTemplate: '',
   });
   const { handleResetApplication, defaultOptions } = useEdit();
-  const { getEditStreamParkFormSchema, registerDifferentDrawer, alerts, 
flinkEnvs } =
+  const { getEditStreamParkFormSchema, registerDifferentDrawer, alerts, 
flinkEnvs, flinkClusters } =
     useEditStreamParkSchema(configVersions, flinkSqlHistory, dependencyRef);
 
   const [registerForm, { setFieldsValue, getFieldsValue, submit }] = useForm({
@@ -169,7 +169,15 @@
       if (values.uploadJars != null && values.uploadJars.length > 0) {
         Object.assign(dependency, { jar: values.dependency });
       }
-
+      if (values.yarnSessionClusterId) {
+        const cluster =
+          flinkClusters.value.filter(
+            (c) => c.clusterId === values.yarnSessionClusterId && 
c.clusterState === 1,
+          )[0] || null;
+        values.clusterId = cluster.id;
+        values.flinkClusterId = cluster.id;
+        values.yarnSessionClusterId = cluster.clusterId;
+      }
       let config = values.configOverride;
       if (config != null && config.trim() !== '') {
         config = decodeByBase64(config);
@@ -204,6 +212,15 @@
       } else {
         config = null;
       }
+      if (values.yarnSessionClusterId) {
+        const cluster =
+          flinkClusters.value.filter(
+            (c) => c.clusterId === values.yarnSessionClusterId && 
c.clusterState === 1,
+          )[0] || null;
+        values.clusterId = cluster.id;
+        values.flinkClusterId = cluster.id;
+        values.yarnSessionClusterId = cluster.clusterId;
+      }
       const configId = values.strategy === 1 ? app.configId : null;
       const params = {
         id: app.id,
@@ -238,13 +255,15 @@
     const appId = route.query.appId;
     const res = await fetchGet({ id: appId as string });
     let configId = '';
-    const confVersion = await fetchConfHistory({ id: route.query.appId });
-    confVersion.forEach((value) => {
-      if (value.effective) {
-        configId = value.id;
-      }
+    fetchConfHistory({ id: route.query.appId }).then((confVersion) => {
+      confVersion.forEach((value) => {
+        if (value.effective) {
+          configId = value.id;
+        }
+      });
+      configVersions.value = confVersion;
     });
-    configVersions.value = confVersion;
+
     Object.assign(app, res);
     Object.assign(defaultOptions, JSON.parse(app.options || '{}'));
     setFieldsValue({
@@ -261,8 +280,9 @@
       unref(flinkSql)?.setContent(decodeByBase64(res.flinkSql));
     });
     if (app.jobType === 2) {
-      const res = await fetchFlinkHistory({ id: appId });
-      flinkSqlHistory.value = res;
+      fetchFlinkHistory({ id: appId }).then((res) => {
+        flinkSqlHistory.value = res;
+      });
     }
     if (app.alertId) {
       selectAlertId.value = unref(alerts).filter((t) => t.id == 
app.alertId)[0]?.id;
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts 
b/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts
index 17196c0ee..c1a6eaa07 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/app/data/index.ts
@@ -63,7 +63,7 @@ export const getAppColumns = (): BasicColumn[] => [
       { text: 'ADDED', value: '0' },
       { text: 'STARTING', value: '3' },
       { text: 'RUNNING', value: '5' },
-      { text: 'FAILED', value: '6' },
+      { text: 'FAILED', value: '7' },
       { text: 'CANCELED', value: '9' },
       { text: 'FINISHED', value: '10' },
       { text: 'LOST', value: '13' },
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/View.less 
b/streampark-console/streampark-console-newui/src/views/flink/setting/View.less
index 66bcca94c..9d0ffb837 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/View.less
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/View.less
@@ -22,7 +22,7 @@
   .system-setting {
 
     .ant-card-body {
-      padding: 0 24px !important;
+      padding: 0 24px;
     }
 
     .collapse {
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/View.vue 
b/streampark-console/streampark-console-newui/src/views/flink/setting/View.vue
index 2c158b34c..016aa178e 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/View.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/View.vue
@@ -24,7 +24,11 @@
           </Card>
         </TabPane>
         <TabPane tab="Alert Setting" key="alert">
-          <Card :bordered="false" class="system-setting">
+          <Card
+            :bordered="false"
+            class="system-setting !bg-transparent"
+            :body-style="{ padding: 0 }"
+          >
             <AlertSetting />
           </Card>
         </TabPane>
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue
 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue
index fa405f5bd..014e802e8 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertModal.vue
@@ -15,19 +15,17 @@
   limitations under the License.
 -->
 <script lang="ts">
-  import { defineComponent } from 'vue';
-  import { omit } from 'lodash-es';
-  import { alertFormSchema } from './alert.data';
-
   export default defineComponent({
     name: 'AlertModal',
   });
 </script>
 <script setup lang="ts" name="AlertModal">
-  import { ref } from 'vue';
+  import { ref, defineComponent, h } from 'vue';
+  import { omit } from 'lodash-es';
+  import { alertFormSchema, alertTypes } from './alert.data';
   import { BasicModal, useModalInner } from '/@/components/Modal';
   import { BasicForm, useForm } from '/@/components/Form';
-  import { Form, Select, Input, Divider, Tooltip, Switch } from 
'ant-design-vue';
+  import { Form, Select, Input, Divider } from 'ant-design-vue';
   import { SvgIcon } from '/@/components/Icon';
   import { fetchAlertAdd, fetchAlertUpdate, fetchExistsAlert } from 
'/@/api/flink/setting/alert';
   import { useUserStore } from '/@/store/modules/user';
@@ -39,16 +37,7 @@
 
   const emit = defineEmits(['reload', 'register']);
   const alertId = ref<string | null>(null);
-  const alertTypes = ref([
-    { name: 'E-mail', value: 1, disabled: false, icon: 'mail' },
-    { name: 'Ding Talk', value: 2, disabled: false, icon: 'dingtalk' },
-    { name: 'Wechat', value: 4, disabled: false, icon: 'wecom' },
-    { name: 'SMS', value: 8, disabled: true, icon: 'message' },
-    { name: 'Lark', value: 16, disabled: false, icon: 'lark' },
-  ]);
-  const alertType = ref<number[]>([]);
-  const dingtalkSecretEnable = ref(false);
-  const larkSecretEnable = ref(false);
+  const alertType = ref<string[]>([]);
 
   const { Swal } = useMessage();
   const userStore = useUserStore();
@@ -65,9 +54,11 @@
         label: 'Alert Name',
         component: 'Input',
         componentProps: { allowClear: true, placeholder: 'Please enter alert 
name' },
-        colProps: {
-          style: { marginBottom: '20px' },
-        },
+        itemExtra: h(
+          'span',
+          { class: 'conf-switch' },
+          'the alert name, e.g: StreamPark team alert',
+        ),
         dynamicRules: () => {
           return [
             {
@@ -117,6 +108,7 @@
     try {
       changeOkLoading(true);
       const formValue = await validateFields();
+      console.log('formValue', formValue);
       const param = {
         id: alertId.value,
         alertName: formValue.alertName,
@@ -212,170 +204,88 @@
           placeholder="Alert Type"
           allowClear
           mode="multiple"
-          @change="(value:number[])=>alertType=value"
+          @change="(value:string[])=>alertType=value"
         >
           <SelectOption
-            v-for="(o, index) in alertTypes"
-            :key="`alertType_${index}`"
-            :disabled="o.disabled"
-            :value="o.value"
+            v-for="(v, k) in alertTypes"
+            :key="`alertType_${k}`"
+            :disabled="v.disabled"
+            :value="k"
           >
-            <SvgIcon :name="o.icon" />
-            {{ o.name }}
+            <SvgIcon :name="v.icon" />
+            {{ v.name }}
           </SelectOption>
         </Select>
       </template>
-
+      {{ alertType }}
       <template #alertEmail="{ model, field }">
         <!-- Alert Email -->
-        <Divider v-if="alertType.indexOf(1) > -1">
-          <SvgIcon name="mail" size="20" />
-          E-mail
-        </Divider>
-        <FormItem
-          v-if="alertType.indexOf(1) > -1"
-          label="Alert Email"
-          :rules="[{ required: true, message: 'email address is required', 
trigger: 'blur' }]"
-          name="alertEmail"
-        >
-          <Input
-            v-model:value="model[field]"
-            placeholder="Please enter email,separate multiple emails with 
comma(,)"
-          />
-        </FormItem>
+        <template v-if="(alertType || []).includes('1')">
+          <Divider>
+            <SvgIcon name="mail" size="20" />
+            E-mail
+          </Divider>
+          <FormItem
+            label="Alert Email"
+            :rules="[
+              { required: true, message: 'email address is required', trigger: 
'blur' },
+              { type: 'email', message: 'Incorrect format', trigger: 'blur' },
+            ]"
+            name="alertEmail"
+          >
+            <Input
+              v-model:value="model[field]"
+              placeholder="Please enter email,separate multiple emails with 
comma(,)"
+            />
+          </FormItem>
+        </template>
       </template>
 
-      <template #alertDingURL="{ model, field }" v-if="alertType.indexOf(2) > 
-1">
-        <Divider v-if="alertType.indexOf(2) > -1">
+      <template #alertDingURL="{ model, field }" v-if="(alertType || 
[]).includes('2')">
+        <Divider>
           <SvgIcon name="dingtalk" size="20" />
           Ding Talk
         </Divider>
         <FormItem
           label="DingTalk Url"
-          defaultValue="https://oapi.dingtalk.com/robot/send";
-          name="alertEmail"
+          name="alertDingURL"
+          :rules="[
+            {
+              pattern:
+                
/^((https?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/,
+              message: 'Incorrect format',
+              trigger: 'blur',
+            },
+          ]"
         >
           <Input v-model:value="model[field]" placeholder="Please enter 
DingTask Url" allowClear />
         </FormItem>
       </template>
 
-      <template #dingtalkToken="{ model, field }" v-if="alertType.indexOf(2) > 
-1">
-        <FormItem
-          label="Access Token"
-          name="dingtalkToken"
-          :rules="[{ required: true, message: 'Access token is required' }]"
-        >
-          <Input
-            v-model:value="model[field]"
-            placeholder="Please enter the access token of DingTalk"
-            allowClear
-          />
-        </FormItem>
-      </template>
-
-      <template #dingtalkSecretEnable="{ model, field }" 
v-if="alertType.indexOf(2) > -1">
-        <FormItem label="Secret Enable" name="dingtalkSecretEnable">
-          <Tooltip title="DingTalk ecretToken is enable">
-            <Switch
-              v-model:checked="model[field]"
-              checked-children="ON"
-              un-checked-children="OFF"
-              allowClear
-              @change="(checked:boolean) => (dingtalkSecretEnable = checked)"
-            />
-          </Tooltip>
-        </FormItem>
-      </template>
-      <!-- Secret Token -->
-      <template
-        #dingtalkSecretToken="{ model, field }"
-        v-if="alertType.indexOf(2) > -1 && dingtalkSecretEnable"
-      >
-        <FormItem
-          label="Secret Token"
-          name="dingtalkSecretToken"
-          :rules="[{ required: true, message: 'DingTalk SecretToken is 
required' }]"
-        >
-          <Input
-            v-model:value="model[field]"
-            placeholder="Please enter DingTalk SecretToken"
-            allowClear
-          />
-        </FormItem>
-      </template>
-
-      <!-- DingTalk User -->
-      <template #alertDingUser="{ model, field }" v-if="alertType.indexOf(2) > 
-1">
-        <FormItem label="DingTalk User" name="alertDingUser">
-          <Input
-            v-model:value="model[field]"
-            placeholder="Please enter DingTalk receive user"
-            allowClear
-          />
-        </FormItem>
-      </template>
-
-      <!-- At All User -->
-      <template #dingtalkIsAtAll="{ model, field }" v-if="alertType.indexOf(2) 
> -1">
-        <FormItem label="At All User">
-          <Tooltip title="Whether Notify All">
-            <Switch
-              v-model:checked="model[field]"
-              checked-children="ON"
-              un-checked-children="OFF"
-            />
-          </Tooltip>
-        </FormItem>
-      </template>
-
       <!-- WeChat -->
-      <template #weToken="{ model, field, schema }" v-if="alertType.indexOf(4) 
> -1">
+      <template #weToken="{ model, field, schema }" v-if="(alertType || 
[]).includes('4')">
         <Divider><SvgIcon name="wecom" size="20" /> WeChat </Divider>
         <FormItem :label="schema.label" :name="field" :rules="schema.rules">
-          <Input v-model:value="model[field]" v-bind="schema.componentProps" />
+          <InputTextArea v-model:value="model[field]" 
v-bind="schema.componentProps" />
         </FormItem>
       </template>
 
-      <template #alertSms="{ model, field, schema }" 
v-if="alertType.indexOf(8) > -1">
+      <template #alertSms="{ model, field, schema }" v-if="(alertType || 
[]).includes('8')">
         <Divider><SvgIcon name="message" size="20" /> SMS </Divider>
         <FormItem :label="schema.label" :name="field" :rules="schema.rules">
           <Input v-model:value="model[field]" v-bind="schema.componentProps" />
         </FormItem>
       </template>
 
-      <template #alertSmsTemplate="{ model, field, schema }" 
v-if="alertType.indexOf(8) > -1">
-        <FormItem :label="schema.label" :name="field" :rules="schema.rules">
-          <InputTextArea v-model:value="model[field]" 
v-bind="schema.componentProps" />
-        </FormItem>
-      </template>
-
-      <template #larkToken="{ model, field, schema }" 
v-if="alertType.indexOf(16) > -1">
+      <!-- lark -->
+      <template #larkToken="{ model, field, schema }" v-if="(alertType || 
[]).includes('16')">
         <Divider><SvgIcon name="lark" size="20" /> Lark </Divider>
         <FormItem :label="schema.label" :name="field" :rules="schema.rules">
-          <Input v-model:value="model[field]" v-bind="schema.componentProps" />
-        </FormItem>
-      </template>
-
-      <template #larkIsAtAll="{ model, field, schema }" 
v-if="alertType.indexOf(16) > -1">
-        <FormItem :label="schema.label" :name="field" :rules="schema.rules">
-          <Tooltip title="Whether Notify All">
-            <Switch
-              checked-children="ON"
-              un-checked-children="OFF"
-              allowClear
-              v-model:checked="model[field]"
-              @change="(checked:boolean) => (larkSecretEnable = checked)"
-            />
-          </Tooltip>
-        </FormItem>
-      </template>
-
-      <template
-        #larkSecretToken="{ model, field, schema }"
-        v-if="alertType.indexOf(16) > -1 && larkSecretEnable"
-      >
-        <FormItem :label="schema.label" :name="field" :rules="schema.rules">
-          <Input v-bind="schema.componentProps" v-model:checked="model[field]" 
/>
+          <Input
+            v-model:value="model[field]"
+            placeholder="Please enter the access token of LarkTalk"
+            allow-clear
+          />
         </FormItem>
       </template>
     </BasicForm>
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue
 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue
index f6b401900..5b5c9decd 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertSetting.vue
@@ -24,7 +24,7 @@
 </script>
 <script setup lang="ts" name="AlertSetting">
   import { onMounted, ref } from 'vue';
-  import { List, Popconfirm, Tooltip } from 'ant-design-vue';
+  import { List, Popconfirm, Tooltip, Card, Tag } from 'ant-design-vue';
   import {
     ThunderboltOutlined,
     EditOutlined,
@@ -32,35 +32,42 @@
     PlusOutlined,
   } from '@ant-design/icons-vue';
   import { useModal } from '/@/components/Modal';
-  import { SvgIcon } from '/@/components/Icon';
   import AlertModal from './AlertModal.vue';
   import { fetchAlertSetting, fetchSendAlert, fetchAlertDelete } from 
'/@/api/flink/setting/alert';
   import { AlertSetting } from '/@/api/flink/setting/types/alert.type';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import AlertTypeInfo from './AlertTypeInfo.vue';
 
   const ListItem = List.Item;
-  const ListItemMeta = ListItem.Meta;
 
   const { t } = useI18n();
   const { Swal, createMessage } = useMessage();
   const [registerAlertModal, { openModal: openAlertModal }] = useModal();
   const alerts = ref<AlertSetting[]>([]);
-  const alertType = ref<number[]>([]);
+
   /* Get alert configuration */
   async function getAlertSetting() {
     const res = await fetchAlertSetting();
+    res.map((a) => (a.alertTypeTags = computeAlertType(a.alertType)));
     alerts.value = res;
   }
+  const alertTypeMap = {
+    1: 'mail',
+    2: 'dingtalk',
+    4: 'wecom',
+    8: 'message',
+    16: 'lark',
+  };
   /* compute type */
   function computeAlertType(level: number) {
     if (level === null) {
       level = 0;
     }
-    const result: number[] = [];
+    const result: string[] = [];
     while (level != 0) {
       // Get the lowest 1
       const code = level & -level;
-      result.push(code);
+      result.push(String(code));
       // Set the lowest position to 0
       level ^= code;
     }
@@ -86,24 +93,22 @@
   }
   /* Click the edit button */
   function handleEditAlertConf(item: AlertSetting) {
-    alertType.value = computeAlertType(item.alertType);
-
     let emailParams: Recordable<any> = {};
     let dingTalkParams: Recordable<any> = {};
     let weComParams: Recordable<any> = {};
     let larkParams: Recordable<any> = {};
-    if (alertType.value.indexOf(1) > -1) {
+    if (item.alertTypeTags?.includes('1')) {
       emailParams = JSON.parse(item.emailParams);
     }
-    if (alertType.value.indexOf(2) > -1) {
+    if (item.alertTypeTags?.includes('2')) {
       dingTalkParams = JSON.parse(item.dingTalkParams);
       // dingtalkIsAtAll = dingTalkParams.isAtAll;
       // dingtalkSecretEnable = dingTalkParams.secretEnable;
     }
-    if (alertType.value.indexOf(4) > -1) {
+    if (item.alertTypeTags?.includes('4')) {
       weComParams = JSON.parse(item.weComParams) as Recordable;
     }
-    if (alertType.value.indexOf(16) > -1) {
+    if (item.alertTypeTags?.includes('16')) {
       larkParams = JSON.parse(item.larkParams) as Recordable;
       // larkIsAtAll = larkParams.isAtAll;
       // larkSecretEnable = larkParams.secretEnable;
@@ -113,7 +118,7 @@
     openAlertModal(true, {
       alertId: item.id,
       alertName: item.alertName,
-      alertType: alertType.value,
+      alertType: item.alertTypeTags,
       alertEmail: emailParams.contacts,
       alertDingURL: dingTalkParams.alertDingURL,
       dingtalkToken: dingTalkParams.token,
@@ -153,75 +158,133 @@
       console.error(error);
     }
   }
+
+  function getAlertTypeName(type: number) {
+    return alertTypeMap[type] || '';
+  }
+
   onMounted(() => {
     getAlertSetting();
   });
 </script>
 
 <template>
-  <div v-auth="'project:create'">
+  <div v-auth="'project:create'" class="bg-white p-10px">
     <a-button type="dashed" style="width: 100%; margin-top: 20px" 
@click="openAlertModal(true, {})">
       <PlusOutlined />
       {{ t('common.add') }}
     </a-button>
   </div>
-  <List>
-    <ListItem v-for="(item, index) in alerts" :key="index">
-      <ListItemMeta style="width: 40%">
-        <template #title>{{ item.alertName }}</template>
-        <template #avatar>
-          <div class="avatar">
-            <SvgIcon name="flink" />
-          </div>
-        </template>
-      </ListItemMeta>
-      <div class="list-content" style="width: 40%">
-        <div text-align center>Alert Type</div>
-        <SvgIcon name="mail" size="25" 
v-if="computeAlertType(item.alertType).indexOf(1) > -1" />
-        <SvgIcon
-          name="dingtalk"
-          size="25"
-          v-if="computeAlertType(item.alertType).indexOf(2) > -1"
-        />
-        <SvgIcon name="wecom" size="25" 
v-if="computeAlertType(item.alertType).indexOf(4) > -1" />
-        <SvgIcon name="message" size="25" 
v-if="computeAlertType(item.alertType).indexOf(8) > -1" />
-        <SvgIcon name="lark" size="25" 
v-if="computeAlertType(item.alertType).indexOf(16) > -1" />
-      </div>
-      <template #actions>
-        <Tooltip title="Alert Test">
-          <a-button
-            @click="handleTestAlarm(item)"
-            type="link"
-            size="large"
-            style="margin-left: 3px"
-            class="control-button ctl-btn-color"
-          >
-            <ThunderboltOutlined />
-          </a-button>
-        </Tooltip>
-        <Tooltip title="Edit Alert Config">
-          <a-button
-            @click="handleEditAlertConf(item)"
-            type="link"
-            size="large"
-            style="margin-left: 3px"
-            class="control-button ctl-btn-color"
-          >
-            <EditOutlined />
-          </a-button>
-        </Tooltip>
-        <Popconfirm
-          :title="t('flink.setting.alert.delete')"
-          :cancel-text="t('common.no')"
-          :ok-text="t('common.yes')"
-          @confirm="handleDeleteAlertConf(item)"
+
+  <List
+    class="alert-card-list"
+    :grid="{ gutter: 40, lg: 2, xxl: 3 }"
+    :data-source="alerts"
+    :pagination="false"
+  >
+    <template #renderItem="{ item }">
+      <ListItem>
+        <Card
+          class="shadow-xl alert-card"
+          :bordered="false"
+          :bodyStyle="{ height: '260px', padding: '15px', overflowY: 'auto' }"
         >
-          <a-button type="link" size="large" style="margin-left: 3px" 
class="control-button">
-            <DeleteOutlined style="color: red" />
-          </a-button>
-        </Popconfirm>
-      </template>
-    </ListItem>
+          <template #title>
+            {{ item.alertName }}
+            <div class="tag-list mt-4px">
+              <Tag
+                color="blue"
+                size="small"
+                v-for="type in item.alertTypeTags"
+                :key="type"
+                class="!leading-15px"
+              >
+                {{ getAlertTypeName(type) }}
+              </Tag>
+            </div>
+          </template>
+          <template #actions>
+            <Tooltip title="Alert Test">
+              <a-button
+                @click="handleTestAlarm(item)"
+                shape="circle"
+                size="large"
+                style="margin-left: 3px"
+                class="control-button ctl-btn-color"
+              >
+                <ThunderboltOutlined />
+              </a-button>
+            </Tooltip>
+            <Tooltip title="Edit Alert Config">
+              <a-button
+                @click="handleEditAlertConf(item)"
+                shape="circle"
+                size="large"
+                style="margin-left: 3px"
+                class="control-button ctl-btn-color"
+              >
+                <EditOutlined />
+              </a-button>
+            </Tooltip>
+            <Popconfirm
+              :title="t('flink.setting.alert.delete')"
+              :cancel-text="t('common.no')"
+              :ok-text="t('common.yes')"
+              @confirm="handleDeleteAlertConf(item)"
+            >
+              <a-button
+                type="danger"
+                shape="circle"
+                size="large"
+                style="margin-left: 3px"
+                class="control-button"
+              >
+                <DeleteOutlined />
+              </a-button>
+            </Popconfirm>
+          </template>
+
+          <AlertTypeInfo
+            alertType="1"
+            :alertSource="item"
+            v-if="item.alertTypeTags.includes('1')"
+          />
+          <AlertTypeInfo
+            alertType="2"
+            :alertSource="item"
+            v-if="item.alertTypeTags.includes('2')"
+          />
+          <AlertTypeInfo
+            alertType="4"
+            :alertSource="item"
+            v-if="item.alertTypeTags.includes('4')"
+          />
+          <AlertTypeInfo
+            alertType="8"
+            :alertSource="item"
+            v-if="item.alertTypeTags.includes('8')"
+          />
+          <AlertTypeInfo
+            alertType="16"
+            :alertSource="item"
+            v-if="item.alertTypeTags.includes('16')"
+          />
+        </Card>
+      </ListItem>
+    </template>
   </List>
+
   <AlertModal @register="registerAlertModal" @reload="getAlertSetting" 
width="850px" />
 </template>
+<style lang="less">
+  .alert-card {
+    .ant-card-head-title {
+      padding: 8px 0;
+    }
+  }
+  .alert-card-list {
+    .ant-list-empty-text {
+      background-color: white;
+    }
+  }
+</style>
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertTypeInfo.vue
 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertTypeInfo.vue
new file mode 100644
index 000000000..5899f470b
--- /dev/null
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/AlertTypeInfo.vue
@@ -0,0 +1,119 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      https://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script setup lang="ts">
+  import { Descriptions, Tag } from 'ant-design-vue';
+  import { computed, toRefs } from 'vue';
+  import { SvgIcon } from '/@/components/Icon';
+  import { BasicTitle } from '/@/components/Basic';
+  import { alertTypes } from './alert.data';
+  const props = defineProps({
+    alertType: {
+      type: String,
+      validator: (v: string) => ['1', '2', '4', '8', '16'].includes(v),
+      required: true,
+    },
+    alertSource: {
+      type: Object as PropType<Recordable>,
+      required: true,
+    },
+  });
+  const { alertType, alertSource } = toRefs(props);
+  const DescriptionsItem = Descriptions.Item;
+
+  const emailInfo = computed(() => {
+    return JSON.parse(alertSource.value.emailParams || '{}');
+  });
+  const dingTalk = computed(() => {
+    return JSON.parse(alertSource.value.dingTalkParams || '{}');
+  });
+  const weChat = computed(() => {
+    return JSON.parse(alertSource.value.weComParams || '{}');
+  });
+  const lark = computed(() => {
+    return JSON.parse(alertSource.value.larkParams || '{}');
+  });
+  function desensitization(dataString: string) {
+    return String(dataString).replace(/^(.{4})(?:.+)(.{4})$/, 
'\$1********\$2');
+  }
+</script>
+
+<template>
+  <BasicTitle class="mt-10px border-dot">
+    <div class="flex items-center">
+      <SvgIcon :name="alertTypes[alertType].icon" :size="20" 
class="!align-middle" />
+      <span class="pl-10px">
+        {{ alertTypes[alertType].name }}
+      </span>
+    </div>
+  </BasicTitle>
+  <Descriptions size="small" :column="2" class="pl-15px mt-10px">
+    <template v-if="alertType === '1'">
+      <DescriptionsItem label="Alert Email" :span="2">
+        <span class="text-blue-500">{{ emailInfo.contacts || '' }}</span>
+      </DescriptionsItem>
+    </template>
+    <template v-else-if="alertType === '2'">
+      <DescriptionsItem label="DingTalk Url" :span="2">
+        {{ dingTalk.alertDingURL || '' }}
+      </DescriptionsItem>
+      <DescriptionsItem label="Access Token" :span="2">
+        {{ desensitization(dingTalk.token || '') }}
+      </DescriptionsItem>
+      <DescriptionsItem label="Secret Token" v-if="dingTalk.secretToken" 
:span="2">
+        {{ desensitization(dingTalk.secretToken || '') }}
+      </DescriptionsItem>
+      <DescriptionsItem label="DingTalk User">
+        {{ dingTalk.contacts || '' }}
+      </DescriptionsItem>
+      <DescriptionsItem label="At All User">
+        <Tag :color="dingTalk.isAtAll ? 'green' : 'red'" class="!leading-20px">
+          {{ dingTalk.isAtAll }}
+        </Tag>
+      </DescriptionsItem>
+    </template>
+    <template v-else-if="alertType === '4'">
+      <DescriptionsItem label="WeChat token" :span="2">
+        {{ desensitization(weChat.token || '') }}
+      </DescriptionsItem>
+    </template>
+    <template v-else-if="alertType === '16'">
+      <DescriptionsItem label="Lark Token" :span="2">
+        {{ desensitization(lark.token || '') }}
+      </DescriptionsItem>
+      <DescriptionsItem label="Lark Secret Token" :span="2">
+        {{ desensitization(lark.secretToken || '') }}
+      </DescriptionsItem>
+      <DescriptionsItem label="At All User">
+        <Tag :color="lark.isAtAll ? 'green' : 'red'" class="!leading-20px">
+          {{ lark.isAtAll }}
+        </Tag>
+      </DescriptionsItem>
+    </template>
+  </Descriptions>
+</template>
+<style lang="less">
+  .border-dot:before {
+    content: '';
+    width: 0;
+    height: 20px;
+    margin-top: 2px;
+    border: 2px solid #24c6dc;
+    border-radius: 2px;
+    transform: translateX(-10px);
+  }
+</style>
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/SettingList.vue
 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/SettingList.vue
index 51426f76a..b9fa1218b 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/SettingList.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/SettingList.vue
@@ -44,6 +44,7 @@
     'alert.email.password': 'keys',
     'alert.email.ssl': 'ssl',
     'streampark.console.webapp.address': 'http',
+    'ingress.mode.default': 'settings',
   };
 
   const ListItem = List.Item;
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/SystemSetting.vue
 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/SystemSetting.vue
index bb9b86f3f..3d99bf080 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/SystemSetting.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/SystemSetting.vue
@@ -34,24 +34,27 @@
   const settings = ref<SystemSetting[]>([]);
 
   const settingsList = computed(() => {
+    const filterValue = (key: string) => {
+      return settings.value.filter((i) => i.settingKey.indexOf(key) > -1);
+    };
     return [
       {
         key: 1,
         title: 'Maven Setting',
-        isPassword: (item) => item.settingKey === 
'streampark.maven.auth.password',
-        data: settings.value.filter((i) => 
i.settingKey.indexOf('streampark.maven') > -1),
+        isPassword: (item: SystemSetting) => item.settingKey === 
'streampark.maven.auth.password',
+        data: filterValue('streampark.maven'),
       },
       {
         key: 2,
         title: 'Docker Setting',
-        isPassword: (item) => item.settingKey === 'docker.register.password',
-        data: settings.value.filter((i) => 
i.settingKey.indexOf('docker.register') > -1),
+        isPassword: (item: SystemSetting) => item.settingKey === 
'docker.register.password',
+        data: filterValue('docker.register'),
       },
       {
         key: 3,
         title: 'Sender Email Setting',
-        isPassword: (item) => item.settingKey === 'alert.email.password',
-        data: settings.value.filter((i) => i.settingKey.indexOf('alert.email') 
> -1),
+        isPassword: (item: SystemSetting) => item.settingKey === 
'alert.email.password',
+        data: filterValue('alert.email'),
       },
       {
         key: 4,
@@ -63,7 +66,7 @@
         key: 5,
         title: 'Ingrsss Setting',
         isPassword: () => false,
-        data: settings.value.filter((i) => i.settingKey.indexOf('ingrsss') > 
-1),
+        data: filterValue('ingrsss.mode'),
       },
     ];
   });
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/alert.data.ts
 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/alert.data.ts
index 0c7662b8f..b4f1633e9 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/components/alert.data.ts
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/components/alert.data.ts
@@ -22,47 +22,70 @@ export const alertFormSchema: Array<FormSchema> = [
     label: 'Fault Alert Type',
     component: 'Select',
     slot: 'type',
-    dynamicRules: () => {
-      return [{ required: true, message: 'Fault Alert Type is required' }];
-    },
+    dynamicRules: () => [{ required: true, message: 'Fault Alert Type is 
required' }],
+  },
+  {
+    field: 'alertEmail',
+    label: 'Alert Email',
+    component: 'Input',
+    colSlot: 'alertEmail',
   },
-  { field: 'alertEmail', label: 'Alert Email', component: 'Input', colSlot: 
'alertEmail' },
   {
     field: 'alertDingURL',
     label: 'DingTalk Url',
     component: 'Input',
     colSlot: 'alertDingURL',
-    defaultValue: 'https://oapi.dingtalk.com/robot/send',
   },
   {
     field: 'dingtalkToken',
     label: 'Access Token',
     component: 'Input',
-    colSlot: 'dingtalkToken',
+    componentProps: {
+      placeholder: 'Please enter the access token of DingTalk',
+    },
+    rules: [{ required: true, message: 'Access token is required' }],
+    ifShow: ({ model }) => (model.alertType || []).includes('2'),
   },
   {
     field: 'dingtalkSecretEnable',
     label: 'Secret Enable',
-    component: 'Input',
-    colSlot: 'dingtalkSecretEnable',
+    component: 'Switch',
+    componentProps: {
+      checkedChildren: 'ON',
+      unCheckedChildren: 'OFF',
+    },
+    helpMessage: 'DingTalk ecretToken is enable',
+    ifShow: ({ model }) => (model.alertType || []).includes('2'),
   },
   {
     field: 'dingtalkSecretToken',
     label: 'Secret Token',
     component: 'Input',
-    colSlot: 'dingtalkSecretToken',
+    componentProps: {
+      placeholder: 'please enter Secret Token',
+    },
+    ifShow: ({ model }) => (model.alertType || []).includes('2') && 
model.dingtalkSecretEnable,
+    rules: [{ required: true, message: 'DingTalk SecretToken is required', 
trigger: 'blur' }],
   },
   {
     field: 'alertDingUser',
     label: 'DingTalk User',
     component: 'Input',
-    colSlot: 'alertDingUser',
+    componentProps: {
+      placeholder: 'Please enter DingTalk receive user',
+    },
+    ifShow: ({ model }) => (model.alertType || []).includes('2'),
   },
   {
     field: 'dingtalkIsAtAll',
     label: 'At All User',
-    component: 'Input',
-    colSlot: 'dingtalkIsAtAll',
+    component: 'Switch',
+    componentProps: {
+      checkedChildren: 'ON',
+      unCheckedChildren: 'OFF',
+    },
+    helpMessage: 'Whether Notify All',
+    ifShow: ({ model }) => (model.alertType || []).includes('2'),
   },
   {
     field: 'weToken',
@@ -94,6 +117,7 @@ export const alertFormSchema: Array<FormSchema> = [
       rows: 4,
       placeholder: 'SMS Template is required',
     },
+    ifShow: ({ model }) => (model.alertType || []).includes('8'),
     colSlot: 'alertSmsTemplate',
   },
   {
@@ -101,23 +125,46 @@ export const alertFormSchema: Array<FormSchema> = [
     label: 'Lark Token',
     component: 'InputTextArea',
     colSlot: 'larkToken',
+    rules: [{ required: true, message: 'Lark token is required' }],
   },
   {
     field: 'larkIsAtAll',
     label: 'At All User',
     component: 'Switch',
-    colSlot: 'larkIsAtAll',
+    componentProps: {
+      checkedChildren: 'ON',
+      unCheckedChildren: 'OFF',
+    },
+    ifShow: ({ model }) => (model.alertType || []).includes('16'),
+    helpMessage: 'Whether Notify All',
   },
   {
     field: 'larkSecretEnable',
     label: 'Secret Enable',
     component: 'Switch',
-    colSlot: 'larkSecretEnable',
+    componentProps: {
+      checkedChildren: 'ON',
+      unCheckedChildren: 'OFF',
+    },
+    helpMessage: 'Lark secretToken is enable',
+    ifShow: ({ model }) => (model.alertType || []).includes('16'),
   },
   {
     field: 'larkSecretToken',
     label: 'Lark Secret Token',
-    component: 'Switch',
-    colSlot: 'larkSecretToken',
+    component: 'Input',
+    componentProps: {
+      placeholder: 'please enter Lark Secret Token',
+    },
+    ifShow: ({ model }) => (model.alertType || []).includes('16') && 
model.larkSecretEnable,
+    rules: [{ required: true, message: 'Lark SecretToken is required', 
trigger: 'blur' }],
   },
 ];
+
+export const alertTypes = {
+  '1': { name: 'E-mail', value: 1, disabled: false, icon: 'mail' },
+  '2': { name: 'Ding Talk', value: 2, disabled: false, icon: 'dingtalk' },
+  '4': { name: 'Wechat', value: 4, disabled: false, icon: 'wecom' },
+  '8': { name: 'SMS', value: 8, disabled: true, icon: 'message' },
+  '16': { name: 'Lark', value: 16, disabled: false, icon: 'lark' },
+};
diff --git 
a/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts
 
b/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts
index 25df0605e..d131f4867 100644
--- 
a/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts
+++ 
b/streampark-console/streampark-console-newui/src/views/flink/setting/hooks/useClusterSetting.ts
@@ -17,7 +17,7 @@
 import { RuleObject } from 'ant-design-vue/lib/form';
 import { StoreValue } from 'ant-design-vue/lib/form/interface';
 import { computed, onMounted, reactive, ref, unref } from 'vue';
-import { executionModes, k8sRestExposedType, resolveOrder } from 
'../../app/data';
+import { k8sRestExposedType, resolveOrder } from '../../app/data';
 import {
   renderProperties,
   renderInputDropdown,
@@ -102,7 +102,11 @@ export const useClusterSetting = () => {
         component: 'Select',
         componentProps: {
           placeholder: 'Please enter cluster name',
-          options: executionModes,
+          options: [
+            { label: 'remote (standalone)', value: 1 },
+            { label: 'yarn session', value: 3 },
+            { label: 'kubernetes session', value: 5 },
+          ],
         },
         dynamicRules: () => {
           return [{ required: true, validator: handleCheckExecMode }];
diff --git 
a/streampark-console/streampark-console-newui/src/views/system/variable/DependApps.vue
 
b/streampark-console/streampark-console-newui/src/views/system/variable/DependApps.vue
new file mode 100644
index 000000000..22bf4e5c5
--- /dev/null
+++ 
b/streampark-console/streampark-console-newui/src/views/system/variable/DependApps.vue
@@ -0,0 +1,70 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      https://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<script lang="ts">
+  export default {
+    name: 'DependApp',
+  };
+</script>
+<script setup lang="ts" name="DependApp">
+  import { ref } from 'vue';
+  import { useRoute, useRouter } from 'vue-router';
+  import { fetchDependApps } from '/@/api/system/variable';
+  import Icon from '/@/components/Icon';
+  import { PageWrapper } from '/@/components/Page';
+  import { BasicTable } from '/@/components/Table';
+
+  const route = useRoute();
+  const router = useRouter();
+  const tableConfig = ref({
+    api: fetchDependApps,
+    canResize: false,
+    showIndexColumn: false,
+    beforeFetch(params: Recordable) {
+      Object.assign(params, {
+        variableCode: route.query.id,
+      });
+      return params;
+    },
+    columns: [
+      { title: 'Application Name', dataIndex: 'jobName', width: 500 },
+      { title: 'Owner', dataIndex: 'nickName' },
+      { title: 'Create Time', dataIndex: 'createTime' },
+    ],
+  });
+</script>
+
+<template>
+  <PageWrapper content-full-height content-background contentClass="p-24px">
+    <div class="mb-15px">
+      <a-button type="primary" shape="circle" @click="router.back()" 
class="mr-10px -mt-8px">
+        <Icon icon="ant-design:arrow-left-outlined" />
+      </a-button>
+      <span class="app-bar">Variable "{{ route.query.id }}" used list</span>
+    </div>
+    <BasicTable v-bind="tableConfig" />
+  </PageWrapper>
+</template>
+
+<style lang="less">
+  .app-bar {
+    background-color: @background-color-base;
+    height: 100%;
+    font-weight: normal;
+    margin: 0 32px 0 0;
+    padding: 8px 12px;
+  }
+</style>
diff --git 
a/streampark-console/streampark-console-newui/src/views/system/variable/View.vue
 
b/streampark-console/streampark-console-newui/src/views/system/variable/View.vue
index d0be38577..90744f456 100644
--- 
a/streampark-console/streampark-console-newui/src/views/system/variable/View.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/system/variable/View.vue
@@ -38,6 +38,12 @@
                 tooltip: 'view detail',
                 onClick: handleView.bind(null, record),
               },
+              {
+                icon: 'icon-park-outline:mind-mapping',
+                tooltip: 'depend apps',
+                onClick: () =>
+                  router.push('/system/variable/depend_apps?id=' + 
record.variableCode),
+              },
               {
                 icon: 'ant-design:delete-outlined',
                 color: 'error',
@@ -65,16 +71,18 @@
 
 <script lang="ts" setup>
   import { defineComponent } from 'vue';
-  import { BasicTable, useTable, TableAction } from '/@/components/Table';
-  import VariableDrawer from './VariableDrawer.vue';
-  import VariableInfo from './VariableInfo.vue';
+  import { BasicTable, useTable, TableAction, SorterResult } from 
'/@/components/Table';
+  import VariableDrawer from './components/VariableDrawer.vue';
+  import VariableInfo from './components/VariableInfo.vue';
   import { useDrawer } from '/@/components/Drawer';
   import { columns, searchFormSchema } from './variable.data';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { useI18n } from '/@/hooks/web/useI18n';
   import { fetchVariableDelete, fetchVariableList } from 
'/@/api/system/variable';
   import Icon from '/@/components/Icon';
+  import { useRouter } from 'vue-router';
 
+  const router = useRouter();
   const [registerDrawer, { openDrawer }] = useDrawer();
   const [registerInfo, { openDrawer: openInfoDraw }] = useDrawer();
   const { createMessage } = useMessage();
@@ -88,6 +96,19 @@
       colon: true,
       schemas: searchFormSchema,
     },
+    sortFn: (sortInfo: SorterResult) => {
+      const { field, order } = sortInfo;
+      if (field && order) {
+        return {
+          // The sort field passed to the backend you
+          sortField: field,
+          // Sorting method passed to the background asc/desc
+          sortOrder: order === 'ascend' ? 'asc' : 'desc',
+        };
+      } else {
+        return {};
+      }
+    },
     rowKey: 'id',
     pagination: true,
     useSearchForm: true,
diff --git 
a/streampark-console/streampark-console-newui/src/views/system/variable/VariableDrawer.vue
 
b/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableDrawer.vue
similarity index 99%
rename from 
streampark-console/streampark-console-newui/src/views/system/variable/VariableDrawer.vue
rename to 
streampark-console/streampark-console-newui/src/views/system/variable/components/VariableDrawer.vue
index ddfb27903..8a6f70b53 100644
--- 
a/streampark-console/streampark-console-newui/src/views/system/variable/VariableDrawer.vue
+++ 
b/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableDrawer.vue
@@ -69,7 +69,6 @@
         const { data } = await fetchCheckVariableCode({
           variableCode: value,
         });
-        console.log('data', data);
         if (data.status !== 'success') {
           setValidateStatus('error');
           setHelp(data.message);
diff --git 
a/streampark-console/streampark-console-newui/src/views/system/variable/VariableInfo.vue
 
b/streampark-console/streampark-console-newui/src/views/system/variable/components/VariableInfo.vue
similarity index 100%
rename from 
streampark-console/streampark-console-newui/src/views/system/variable/VariableInfo.vue
rename to 
streampark-console/streampark-console-newui/src/views/system/variable/components/VariableInfo.vue

Reply via email to