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

robocanic pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/develop by this push:
     new 0ed6d1c4 refactor: :art: Optimize UI styles and search functionality 
(#1379)
0ed6d1c4 is described below

commit 0ed6d1c4496ed3105e4826c819011439082f4adb
Author: LGgbond <[email protected]>
AuthorDate: Sun Dec 28 22:23:53 2025 +0800

    refactor: :art: Optimize UI styles and search functionality (#1379)
    
    * feat: enhance error handling for unauthorized access and improve toast 
messages
    
    * feat: enhance error handling for unauthorized access and improve toast 
messages
    
    * fix: correct syntax error in response interceptor for redirect handling
    
    * Update ui-vue3/src/base/http/request.ts
    
    Co-authored-by: Copilot <[email protected]>
    
    * feat: add YAML and XML editor components, update index references, and 
enhance error logging
    
    - Introduced new JavaScript files for YAML and XML syntax highlighting and 
editing capabilities.
    - Added a new component for updating YAML configurations with a structured 
editor interface.
    - Updated the index.html to reference the new JavaScript bundle for 
improved functionality.
    - Enhanced the HTTP request module to log errors during redirection on 401 
responses for better debugging.
    
    * docs: Only supports exact matching; remove the "prefix search" function 
from the placeholder (background word)
    
    * docs: All sorting indicators for lists are initially hidden, including 
but not limited to the list pages for applications, instances, services, and 
traffic management
    
    * refactor: :art: Optimize the styles of some tables and adapt to backend 
changes
    
    * docs: api baseurl
    
    ---------
    
    Co-authored-by: Copilot <[email protected]>
---
 ui-vue3/src/Login.vue                              |  21 +-
 ui-vue3/src/base/i18n/en.ts                        |  19 +-
 ui-vue3/src/base/i18n/zh.ts                        |  13 +-
 ui-vue3/src/layout/header/layout_header.vue        |   2 +-
 ui-vue3/src/utils/SearchUtil.ts                    |   5 +-
 ui-vue3/src/views/resources/applications/index.vue |  12 +-
 .../views/resources/applications/tabs/instance.vue |  18 +-
 .../views/resources/applications/tabs/service.vue  |  67 +++---
 ui-vue3/src/views/resources/instances/index.vue    |  24 +-
 ui-vue3/src/views/resources/services/search.vue    | 115 +++-------
 .../views/resources/services/tabs/distribution.vue | 248 ++++++---------------
 .../src/views/traffic/destinationRule/index.vue    |  13 +-
 ui-vue3/src/views/traffic/dynamicConfig/index.vue  |  34 +--
 ui-vue3/src/views/traffic/routingRule/index.vue    |  24 +-
 ui-vue3/src/views/traffic/tagRule/index.vue        |  24 +-
 ui-vue3/src/views/traffic/virtualService/index.vue |  17 +-
 16 files changed, 233 insertions(+), 423 deletions(-)

diff --git a/ui-vue3/src/Login.vue b/ui-vue3/src/Login.vue
index 1988b7ed..6a67a5aa 100644
--- a/ui-vue3/src/Login.vue
+++ b/ui-vue3/src/Login.vue
@@ -44,8 +44,8 @@ function loginHandle() {
       updateAuthState(true, userinfo.username)
       const { data } = await meshesSearch()
       // if mesh is not set or old mesh is expired
-      if (!meshStore.mesh || !data.some((x: any) => x.name === 
meshStore.mesh)) {
-        meshStore.mesh = data[0]?.name
+      if (!meshStore.mesh || !data.some((x: any) => x.id === meshStore.mesh)) {
+        meshStore.mesh = data[0]?.id
       }
       router.replace(redirect)
     })
@@ -63,25 +63,14 @@ function loginHandle() {
       </a-row>
       <a-row>
         <a-form layout="vertical" :model="userinfo" ref="login-form-ref">
-          <a-form-item
-            class="item"
-            :label="$t('loginDomain.username')"
-            name="username"
-            :rules="[{ required: true }]"
-          >
+          <a-form-item class="item" :label="$t('loginDomain.username')" 
name="username" :rules="[{ required: true }]">
             <a-input type="" v-model:value="userinfo.username"></a-input>
           </a-form-item>
-          <a-form-item
-            class="item"
-            :label="$t('loginDomain.password')"
-            name="password"
-            :rules="[{ required: true }]"
-          >
+          <a-form-item class="item" :label="$t('loginDomain.password')" 
name="password" :rules="[{ required: true }]">
             <a-input type="password" 
v-model:value="userinfo.password"></a-input>
           </a-form-item>
           <a-form-item class="item" label="">
-            <a-button @click="loginHandle" size="large" type="primary" 
class="login-btn"
-              >{{ $t('loginDomain.login') }}
+            <a-button @click="loginHandle" size="large" type="primary" 
class="login-btn">{{ $t('loginDomain.login') }}
             </a-button>
           </a-form-item>
         </a-form>
diff --git a/ui-vue3/src/base/i18n/en.ts b/ui-vue3/src/base/i18n/en.ts
index 6b52d88d..503346f9 100644
--- a/ui-vue3/src/base/i18n/en.ts
+++ b/ui-vue3/src/base/i18n/en.ts
@@ -158,6 +158,12 @@ const words: I18nType = {
     opened: 'Opened',
     paramRoute: 'Param Route'
   },
+  servicesDomain: {
+    appName: 'Application Name',
+    instanceCount: 'Instance Count',
+    deployClusters: 'Deploy Clusters',
+    registryClusters: 'Registry Clusters'
+  },
   appServiceTimeout: 'Adjusting the timeout for application service provision',
   enableAppInstanceLogs: 'Enable access logs for all instances of this 
application',
   appServiceLoadBalance: 'Adjusting the load balancing strategy for 
application service provision',
@@ -198,6 +204,8 @@ const words: I18nType = {
   service: 'Service',
   versionGroup: 'Version & Group',
   avgQPS: 'last 1min QPS',
+  provider: 'Provider',
+  subset: 'Group',
   avgRT: 'last 1min RT',
   requestTotal: 'last 1min request total',
   serviceSearch: 'Search Service',
@@ -368,6 +376,13 @@ const words: I18nType = {
   placeholders: {
     searchService: 'Search by service name'
   },
+  placeholder: {
+    searchService: 'Search by service name',
+    typeAppName: 'Enter application name',
+    typeDefault: 'Please enter',
+    typeRoutingRules: 'Search routing rules',
+    searchAppNameOrIP: 'Search application, IP'
+  },
   methods: 'Methods',
   testModule: {
     searchServiceHint:
@@ -490,10 +505,6 @@ const words: I18nType = {
   backHome: 'Back Home',
   noPageTip: 'Sorry, the page you visited does not exist.',
   globalSearchTip: 'Search ip, application, instance, service',
-  placeholder: {
-    typeAppName: 'please type appName, support for prefix',
-    typeDefault: 'please type '
-  },
   none: 'No Select',
   debug: 'Debug',
   distribution: 'Distribution',
diff --git a/ui-vue3/src/base/i18n/zh.ts b/ui-vue3/src/base/i18n/zh.ts
index b5968662..70af37dd 100644
--- a/ui-vue3/src/base/i18n/zh.ts
+++ b/ui-vue3/src/base/i18n/zh.ts
@@ -175,9 +175,17 @@ const words: I18nType = {
     opened: '开启',
     paramRoute: '参数路由'
   },
+  servicesDomain: {
+    appName: '应用名',
+    instanceCount: '实例数量',
+    deployClusters: '部署集群',
+    registryClusters: '注册集群'
+  },
   service: '服务',
   versionGroup: '版本&分组',
   avgQPS: 'QPS',
+  provider: '提供者',
+  subset: '分组',
   avgRT: 'RT',
   requestTotal: '近1min请求总量',
   serviceSearch: '服务查询',
@@ -478,9 +486,10 @@ const words: I18nType = {
   globalSearchTip: '搜索ip,应用,实例,服务',
 
   placeholder: {
-    typeAppName: '请输入应用名,支持前缀搜索',
+    typeAppName: '请输入应用名',
     typeDefault: '请输入',
-    typeRoutingRules: '搜索路由规则,支持前缀过滤'
+    typeRoutingRules: '搜索路由规则',
+    searchAppNameOrIP: '搜索应用,ip'
   },
   none: '无',
   details: '详情',
diff --git a/ui-vue3/src/layout/header/layout_header.vue 
b/ui-vue3/src/layout/header/layout_header.vue
index b3ea6fe5..98c32be4 100644
--- a/ui-vue3/src/layout/header/layout_header.vue
+++ b/ui-vue3/src/layout/header/layout_header.vue
@@ -56,7 +56,7 @@
                 :options="
                   meshes.map((x: any) => {
                     return {
-                      value: x.name,
+                      value: x.id,
                       label: x.name
                     }
                   })
diff --git a/ui-vue3/src/utils/SearchUtil.ts b/ui-vue3/src/utils/SearchUtil.ts
index a9915be5..980d45c6 100644
--- a/ui-vue3/src/utils/SearchUtil.ts
+++ b/ui-vue3/src/utils/SearchUtil.ts
@@ -98,9 +98,10 @@ export class SearchDomain {
 
     this.searchApi(queryParams)
       .then((res: any) => {
+
         const {
-          data: { list, pageInfo }
-        } = res
+          data: { list = [], pageInfo }
+        } = res || {}
         this.result = handleResult ? handleResult(list) : list
 
         if (!this.noPaged) {
diff --git a/ui-vue3/src/views/resources/applications/index.vue 
b/ui-vue3/src/views/resources/applications/index.vue
index 091a2d76..37d97749 100644
--- a/ui-vue3/src/views/resources/applications/index.vue
+++ b/ui-vue3/src/views/resources/applications/index.vue
@@ -30,10 +30,7 @@
           </a-tag>
         </template>
         <template v-else-if="column.dataIndex === 'appName'">
-          <span
-            class="app-link"
-            
@click="router.push(`/resources/applications/detail/${record[column.key]}`)"
-          >
+          <span class="app-link" 
@click="router.push(`/resources/applications/detail/${record[column.key]}`)">
             <b>
               <Icon style="margin-bottom: -2px" 
icon="material-symbols:attach-file-rounded"></Icon>
               {{ text }}
@@ -70,7 +67,7 @@ let columns = [
     title: 'appName',
     key: 'appName',
     dataIndex: 'appName',
-    sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+    // sorter: (a: any, b: any) => sortString(a.appName, b.appName),
     width: 140,
     ellipsis: true
   },
@@ -79,9 +76,8 @@ let columns = [
     key: 'instanceCount',
     dataIndex: 'instanceCount',
     width: 100,
-    sorter: (a: any, b: any) => sortString(a.instanceCount, b.instanceCount)
+    // sorter: (a: any, b: any) => sortString(a.instanceCount, b.instanceCount)
   },
-
   {
     title: 'applicationDomain.deployClusters',
     key: 'deployClusters',
@@ -131,11 +127,13 @@ watch(route, (a, b) => {
 <style lang="less" scoped>
 .search-table-container {
   min-height: 60vh;
+
   //max-height: 70vh; //overflow: auto;
   .app-link {
     padding: 4px 10px 4px 4px;
     border-radius: 4px;
     color: v-bind('PRIMARY_COLOR');
+
     &:hover {
       cursor: pointer;
       background: rgba(133, 131, 131, 0.13);
diff --git a/ui-vue3/src/views/resources/applications/tabs/instance.vue 
b/ui-vue3/src/views/resources/applications/tabs/instance.vue
index cb7e0faa..e976de95 100644
--- a/ui-vue3/src/views/resources/applications/tabs/instance.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/instance.vue
@@ -113,7 +113,7 @@ const columns = [
     title: 'instanceDomain.ip',
     dataIndex: 'ip',
     key: 'ip',
-    sorter: true,
+    // sorter: true,
     width: 150,
     fixed: 'left'
   },
@@ -121,56 +121,56 @@ const columns = [
     title: 'instanceDomain.name',
     dataIndex: 'name',
     key: 'name',
-    sorter: true,
+    // sorter: true,
     width: 180
   },
   {
     title: 'instanceDomain.deployState',
     dataIndex: 'deployState',
     key: 'deployState',
-    sorter: true,
+    // sorter: true,
     width: 150
   },
   {
     title: 'instanceDomain.deployCluster',
     dataIndex: 'deployClusters',
     key: 'deployClusters',
-    sorter: true,
+    // sorter: true,
     width: 180
   },
   {
     title: 'instanceDomain.registerState',
     dataIndex: 'registerState',
     key: 'registerState',
-    sorter: true,
+    // sorter: true,
     width: 150
   },
   {
     title: 'instanceDomain.registerClusters',
     dataIndex: 'registerCluster',
     key: 'registerCluster',
-    sorter: true,
+    // sorter: true,
     width: 200
   },
   {
     title: 'instanceDomain.cpu',
     dataIndex: 'cpu',
     key: 'cpu',
-    sorter: true,
+    // sorter: true,
     width: 120
   },
   {
     title: 'instanceDomain.memory',
     dataIndex: 'memory',
     key: 'memory',
-    sorter: true,
+    // sorter: true,
     width: 120
   },
   {
     title: 'instanceDomain.startTime',
     dataIndex: 'startTime',
     key: 'startTime',
-    sorter: true,
+    // sorter: true,
     width: 150
   }
   // {
diff --git a/ui-vue3/src/views/resources/applications/tabs/service.vue 
b/ui-vue3/src/views/resources/applications/tabs/service.vue
index d0c029a7..821c6833 100644
--- a/ui-vue3/src/views/resources/applications/tabs/service.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/service.vue
@@ -36,17 +36,6 @@
         <template v-if="column.dataIndex === 'serviceName'">
           <a-button type="link" @click="viewDetail(text)">{{ text }}</a-button>
         </template>
-        <template v-else-if="column.dataIndex === 'versionGroupSelect'">
-          <a-select :value="text?.versionGroupValue" :bordered="false" 
style="width: 80%">
-            <a-select-option
-              v-for="(item, index) in text?.versionGroupArr"
-              :value="item"
-              :key="index"
-            >
-              {{ item }}
-            </a-select-option>
-          </a-select>
-        </template>
       </template>
     </search-table>
   </div>
@@ -108,37 +97,40 @@ const columns = [
   {
     title: 'provideServiceName',
     key: 'service',
-    dataIndex: 'serviceName',
-    sorter: true,
-    width: '30%'
-  },
-  {
-    title: 'versionGroup',
-    key: 'versionGroup',
-    dataIndex: 'versionGroupSelect',
-    width: '25%'
+    dataIndex: 'serviceName'
+    // sorter: true,
   },
   {
-    title: 'avgQPS',
-    key: 'avgQPS',
-    dataIndex: 'avgQPS',
-    sorter: true,
-    width: '15%'
+    title: 'version',
+    key: 'version',
+    dataIndex: 'version'
   },
   {
-    title: 'avgRT',
-    key: 'avgRT',
-    dataIndex: 'avgRT',
-    sorter: true,
-    width: '15%'
-  },
-  {
-    title: 'requestTotal',
-    key: 'requestTotal',
-    dataIndex: 'requestTotal',
-    sorter: true,
-    width: '15%'
+    title: 'subset',
+    key: 'group',
+    dataIndex: 'group'
   }
+  // {
+  //   title: 'avgQPS',
+  //   key: 'avgQPS',
+  //   dataIndex: 'avgQPS',
+  //   // sorter: true,
+  //   width: '15%'
+  // },
+  // {
+  //   title: 'avgRT',
+  //   key: 'avgRT',
+  //   dataIndex: 'avgRT',
+  //   // sorter: true,
+  //   width: '15%'
+  // },
+  // {
+  //   title: 'requestTotal',
+  //   key: 'requestTotal',
+  //   dataIndex: 'requestTotal',
+  //   // sorter: true,
+  //   width: '15%'
+  // }
 ]
 
 const appName = computed(() => {
@@ -213,6 +205,7 @@ provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
   .statistic {
     width: 8vw;
   }
+
   :deep(.ant-card-body) {
     padding: 12px;
   }
diff --git a/ui-vue3/src/views/resources/instances/index.vue 
b/ui-vue3/src/views/resources/instances/index.vue
index 4bb9d7b0..9ed8aed3 100644
--- a/ui-vue3/src/views/resources/instances/index.vue
+++ b/ui-vue3/src/views/resources/instances/index.vue
@@ -19,10 +19,8 @@
     <search-table :search-domain="searchDomain">
       <template #bodyCell="{ text, record, index, column }">
         <template v-if="column.dataIndex === 'ip'">
-          <span
-            class="app-link"
-            
@click="router.push(`/resources/instances/detail/${record.name}/${record[column.key]}`)"
-          >
+          <span class="app-link"
+            
@click="router.push(`/resources/instances/detail/${record.name}/${record[column.key]}`)">
             <b>
               <Icon style="margin-bottom: -2px" 
icon="material-symbols:attach-file-rounded"></Icon>
               {{ text }}
@@ -87,14 +85,14 @@ let columns = [
     title: 'instanceDomain.instanceIP',
     key: 'ip',
     dataIndex: 'ip',
-    sorter: (a: any, b: any) => sortString(a.ip, b.ip),
+    // sorter: (a: any, b: any) => sortString(a.ip, b.ip),
     width: 200
   },
   {
     title: 'instanceDomain.instanceName',
     key: 'name',
     dataIndex: 'name',
-    sorter: (a: any, b: any) => sortString(a.name, b.name),
+    // sorter: (a: any, b: any) => sortString(a.name, b.name),
     width: 140
   },
   {
@@ -102,49 +100,49 @@ let columns = [
     key: 'deployState',
     dataIndex: 'deployState',
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.deployState, b.deployState)
+    // sorter: (a: any, b: any) => sortString(a.deployState, b.deployState)
   },
 
   {
     title: 'instanceDomain.deployCluster',
     key: 'deployCluster',
     dataIndex: 'deployCluster',
-    sorter: (a: any, b: any) => sortString(a.deployCluster, b.deployCluster),
+    // sorter: (a: any, b: any) => sortString(a.deployCluster, 
b.deployCluster),
     width: 120
   },
   {
     title: 'instanceDomain.registerState',
     key: 'registerState',
     dataIndex: 'registerState',
-    sorter: (a: any, b: any) => sortString(a.registerState, b.registerState),
+    // sorter: (a: any, b: any) => sortString(a.registerState, 
b.registerState),
     width: 120
   },
   {
     title: 'instanceDomain.registerCluster',
     key: 'registerClusters',
     dataIndex: 'registerClusters',
-    sorter: (a: any, b: any) => sortString(a.registerClusters, 
b.registerClusters),
+    // sorter: (a: any, b: any) => sortString(a.registerClusters, 
b.registerClusters),
     width: 140
   },
   {
     title: 'instanceDomain.CPU',
     key: 'cpu',
     dataIndex: 'cpu',
-    sorter: (a: any, b: any) => sortString(a.cpu, b.cpu),
+    // sorter: (a: any, b: any) => sortString(a.cpu, b.cpu),
     width: 140
   },
   {
     title: 'instanceDomain.memory',
     key: 'memory',
     dataIndex: 'memory',
-    sorter: (a: any, b: any) => sortString(a.memory, b.memory),
+    // sorter: (a: any, b: any) => sortString(a.memory, b.memory),
     width: 100
   },
   {
     title: 'instanceDomain.startTime_k8s',
     key: 'startTime_k8s',
     dataIndex: 'startTime',
-    sorter: (a: any, b: any) => sortString(a.startTime, b.startTime),
+    // sorter: (a: any, b: any) => sortString(a.startTime, b.startTime),
     width: 200
   }
   // {
diff --git a/ui-vue3/src/views/resources/services/search.vue 
b/ui-vue3/src/views/resources/services/search.vue
index 19dda2d1..96e64832 100644
--- a/ui-vue3/src/views/resources/services/search.vue
+++ b/ui-vue3/src/views/resources/services/search.vue
@@ -17,29 +17,15 @@
 <template>
   <div class="__container_services_index">
     <search-table :search-domain="searchDomain">
-      <template #bodyCell="{ column, record, text, index: tableRowIndex }">
+      <template #bodyCell="{ column, record, text }">
         <template v-if="column.dataIndex === 'serviceName'">
-          {{ record.versionGroup }}
-          <span class="service-link" @click="viewDistribution(text, 
tableRowIndex)">
+          <span class="service-link" @click="viewDistribution(text, 
record.group, record.version)">
             <b>
               <Icon style="margin-bottom: -2px" 
icon="material-symbols:attach-file-rounded"></Icon>
               {{ text }}
             </b>
           </span>
         </template>
-
-        <template v-else-if="column.dataIndex === 'versionGroupSelect'">
-          <a-select :value="text?.versionGroupValue" :bordered="false" 
style="width: 80%">
-            <a-select-option
-              v-for="(item, index) in text?.versionGroupArr"
-              :value="item"
-              @click="selectedVersionAndGroup(tableRowIndex, index, item)"
-              :key="index"
-            >
-              {{ item }}
-            </a-select-option>
-          </a-select>
-        </template>
       </template>
     </search-table>
   </div>
@@ -66,62 +52,49 @@ const columns = [
     title: 'service',
     key: 'service',
     dataIndex: 'serviceName',
-    sorter: true,
-    width: '30%',
+    // sorter: true,
     ellipsis: true
   },
   {
-    title: 'versionGroup',
-    key: 'versionGroup',
-    dataIndex: 'versionGroupSelect',
-    width: '25%'
-  },
-  {
-    title: 'avgQPS',
-    key: 'avgQPS',
-    dataIndex: 'avgQPS',
-    sorter: true,
-    width: '15%'
+    title: 'version',
+    key: 'version',
+    dataIndex: 'version'
   },
   {
-    title: 'avgRT',
-    key: 'avgRT',
-    dataIndex: 'avgRT',
-    sorter: true,
-    width: '15%'
+    title: 'subset',
+    key: 'group',
+    dataIndex: 'group'
   },
   {
-    title: 'requestTotal',
-    key: 'requestTotal',
-    dataIndex: 'requestTotal',
-    sorter: true,
-    width: '15%'
+    title: 'provider',
+    key: 'provider',
+    dataIndex: 'providerAppName'
   }
+  // {
+  //   title: 'avgQPS',
+  //   key: 'avgQPS',
+  //   dataIndex: 'avgQPS',
+  //   // sorter: true,
+  //   width: '15%'
+  // },
+  // {
+  //   title: 'avgRT',
+  //   key: 'avgRT',
+  //   dataIndex: 'avgRT',
+  //   // sorter: true,
+  //   width: '15%'
+  // },
+  // {
+  //   title: 'requestTotal',
+  //   key: 'requestTotal',
+  //   dataIndex: 'requestTotal',
+  //   // sorter: true,
+  //   width: '15%'
+  // }
 ]
 
-const tempServiceList = ref([])
-
-const handleResult = (result: any) => {
-  return result.map((service: any) => {
-    service.versionGroupSelect = {}
-    service.versionGroupSelect.versionGroupArr = 
service.versionGroups.map((item: any) => {
-      return (item.versionGroup =
-        (item.version ? 'version: ' + item.version + ', ' : '') +
-          (item.group ? 'group: ' + item.group : '') || '无')
-    })
-    service.versionGroupSelect.versionGroupValue = 
service.versionGroupSelect.versionGroupArr[0]
-    return service
-  })
-}
-
 function serviceInfo(params: any, table: any) {
   return searchService(params).then(async (res) => {
-    tempServiceList.value = res.data?.list
-    tempServiceList.value.forEach((service: any) => {
-      service.selectedIndex = -1
-    })
-
-    console.log(tempServiceList.value)
     return promQueryList(res, ['avgQPS', 'avgRT', 'requestTotal'], async 
(service: any) => {
       service.avgQPS = await queryMetrics(
         `sum (dubbo_provider_qps_total{interface='${service.serviceName}'}) by 
(interface)`
@@ -152,33 +125,17 @@ const searchDomain = reactive(
     serviceInfo,
     columns,
     undefined,
-    undefined,
-    handleResult
+    undefined
   )
 )
 
-searchDomain.onSearch(handleResult)
+searchDomain.onSearch()
 searchDomain.tableStyle = {
   scrollX: '100',
   scrollY: '367px'
 }
 
-const selectedVersionAndGroup = (
-  tableRowIndex: number,
-  versionAndGroupIndex: number,
-  versionAndGroupText: string
-) => {
-  if (versionAndGroupText === '无') {
-    tempServiceList.value[tableRowIndex].selectedIndex = -1
-  } else {
-    tempServiceList.value[tableRowIndex].selectedIndex = versionAndGroupIndex
-  }
-}
-
-const viewDistribution = (serviceName: string, tableRowIndex: number) => {
-  const selectedIndex = tempServiceList.value[tableRowIndex]?.selectedIndex
-  const group = 
tempServiceList.value[tableRowIndex].versionGroups[selectedIndex]?.group || ''
-  const version = 
tempServiceList.value[tableRowIndex].versionGroups[selectedIndex]?.version || ''
+const viewDistribution = (serviceName: string, group: string, version: string) 
=> {
   router.push({ name: 'distribution', params: { pathId: serviceName, group, 
version } })
 }
 
diff --git a/ui-vue3/src/views/resources/services/tabs/distribution.vue 
b/ui-vue3/src/views/resources/services/tabs/distribution.vue
index 0d10a015..96f3adee 100644
--- a/ui-vue3/src/views/resources/services/tabs/distribution.vue
+++ b/ui-vue3/src/views/resources/services/tabs/distribution.vue
@@ -16,219 +16,113 @@
 -->
 <template>
   <div class="__container_services_tabs_distribution">
-    <a-flex vertical>
-      <a-flex class="service-filter">
-        <a-radio-group v-model:value="type" button-style="solid" 
@click="debounceSearch">
-          <a-radio-button value="provider">生产者</a-radio-button>
-          <a-radio-button value="consumer">消费者</a-radio-button>
-        </a-radio-group>
-        <a-input-search
-          v-model:value="searchValue"
-          placeholder="搜索应用,ip,支持前缀搜索"
-          class="service-filter-input"
-          @search="debounceSearch"
-          enter-button
-        />
-      </a-flex>
-      <a-table
-        :columns="tableColumns"
-        :data-source="tableData"
-        :scroll="{ y: '45vh' }"
-        :pagination="pagination"
-        @change="onTablePageChange"
-      >
-        <template #bodyCell="{ column, text }">
-          <template v-if="column.dataIndex === 'appName'">
-            <span class="link" 
@click="router.push('/resources/applications/detail/' + text)">
-              <b>
-                <Icon
-                  style="margin-bottom: -2px"
-                  icon="material-symbols:attach-file-rounded"
-                ></Icon>
-                {{ text }}
-              </b>
-            </span>
-          </template>
+    <search-table :search-domain="searchDomain">
+      <template #bodyCell="{ column, text }">
+        <template v-if="column.dataIndex === 'appName'">
+          <span class="link" 
@click="router.push('/resources/applications/detail/' + text)">
+            <b>
+              <Icon style="margin-bottom: -2px" 
icon="material-symbols:attach-file-rounded"></Icon>
+              {{ text }}
+            </b>
+          </span>
+        </template>
 
-          <template v-if="column.dataIndex === 'instanceName'">
-            <span class="link" 
@click="router.push('/resources/instances/detail/' + text)">
-              <b>
-                <Icon
-                  style="margin-bottom: -2px"
-                  icon="material-symbols:attach-file-rounded"
-                ></Icon>
-                {{ text }}
-              </b>
-            </span>
-          </template>
+        <template v-if="column.dataIndex === 'instanceName'">
+          <span class="link" 
@click="router.push('/resources/instances/detail/' + text)">
+            <b>
+              <Icon style="margin-bottom: -2px" 
icon="material-symbols:attach-file-rounded"></Icon>
+              {{ text }}
+            </b>
+          </span>
+        </template>
 
-          <template v-if="column.dataIndex === 'timeOut'">
-            {{ formattedDate(text) }}
-          </template>
-          <template v-if="column.dataIndex === 'label'">
-            <a-tag :color="PRIMARY_COLOR">{{ text }}</a-tag>
-          </template>
+        <template v-if="column.dataIndex === 'timeOut'">
+          {{ formattedDate(text) }}
         </template>
-      </a-table>
-    </a-flex>
+        <template v-if="column.dataIndex === 'label'">
+          <a-tag :color="PRIMARY_COLOR">{{ text }}</a-tag>
+        </template>
+      </template>
+    </search-table>
   </div>
 </template>
 
 <script setup lang="ts">
-import type { ComponentInternalInstance } from 'vue'
-import { ref, reactive, getCurrentInstance } from 'vue'
+import { ref, reactive, provide } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { getServiceDistribution } from '@/api/service/service'
-import { debounce } from 'lodash'
 import { PRIMARY_COLOR } from '@/base/constants'
 import { Icon } from '@iconify/vue'
 import { formattedDate } from '@/utils/DateUtil'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
 
 let __null = PRIMARY_COLOR
 const router = useRouter()
 const route = useRoute()
-const {
-  appContext: {
-    config: { globalProperties }
-  }
-} = <ComponentInternalInstance>getCurrentInstance()
-
-const searchValue = ref('')
-const versionAndGroupOptions = reactive([
-  {
-    label: '不指定',
-    value: ''
-  },
-  {
-    label: 'version=1.0.0',
-    value: 'version=1.0.0'
-  },
-  {
-    label: 'group=group1',
-    value: 'group=group1'
-  },
-  {
-    label: 'version=1.0.0,group=group1',
-    value: 'version=1.0.0,group=group1'
-  }
-])
-const versionAndGroup = ref(versionAndGroupOptions[0].value)
-const type = ref('provider')
 
 const tableColumns = [
   {
-    title: '应用名',
+    title: 'servicesDomain.appName',
+    key: 'appName',
     dataIndex: 'appName',
-    width: '20%',
-    customCell: (_, index) => {
-      const currentAppName = tableData.value[index].appName
-      if (index === 0 || tableData.value[index - 1].appName !== 
currentAppName) {
-        const sameAppCount = tableData.value.filter(
-          (item: any) => item.appName === currentAppName
-        ).length
-        return {
-          rowSpan: sameAppCount
-        }
-      } else {
-        return {
-          rowSpan: 0
-        }
-      }
-    }
-  },
-  {
-    title: '实例数',
-    dataIndex: 'instanceNum',
-    width: '15%',
-    customRender: ({ record }) => {
-      const appName = record.appName
-      const instanceNum = tableData.value.filter((item: any) => item.appName 
=== appName).length
-      return instanceNum ?? 0
-    },
-    customCell: (_, index) => {
-      const currentAppName = tableData.value[index].appName
-      if (index === 0 || tableData.value[index - 1].appName !== 
currentAppName) {
-        const sameAppCount = tableData.value.filter(
-          (item: any) => item.appName === currentAppName
-        ).length
-        return {
-          rowSpan: sameAppCount
-        }
-      } else {
-        return {
-          rowSpan: 0
-        }
-      }
-    }
-  },
-  {
-    title: '实例名',
-    dataIndex: 'instanceName',
-    width: '25%',
+    width: 140,
     ellipsis: true
   },
   {
-    title: 'RPC端口',
-    dataIndex: 'rpcPort',
-    width: '8%'
+    title: 'servicesDomain.instanceCount',
+    key: 'instanceCount',
+    dataIndex: 'instanceCount',
+    width: 100
   },
   {
-    title: '超时时间',
-    dataIndex: 'timeOut',
-    width: '10%'
+    title: 'servicesDomain.deployClusters',
+    key: 'deployClusters',
+    dataIndex: 'deployClusters',
+    width: 120
   },
   {
-    title: '重试次数',
-    dataIndex: 'retryNum',
-    width: '10%'
+    title: 'servicesDomain.registryClusters',
+    key: 'registryClusters',
+    dataIndex: 'registryClusters',
+    width: 200
   }
-  // {
-  //   title: '标签',
-  //   dataIndex: 'label',
-  //   width: '15%'
-  // }
 ]
 
-const tableData = ref([])
-
-const pagination = reactive({
-  total: 0,
-  pageSize: 10,
-  current: 1,
-  pageOffset: 0,
-  showTotal: (v: any) =>
-    globalProperties.$t('searchDomain.total') +
-    ': ' +
-    v +
-    ' ' +
-    globalProperties.$t('searchDomain.unit')
-})
-
-const onSearch = async () => {
-  let params = {
+function getDistribution(params: any) {
+  return getServiceDistribution({
     serviceName: route.params?.pathId,
-    side: type.value,
+    side: 'consumer',
     version: route.params?.version || '',
     group: route.params?.group || '',
-    pageOffset: pagination.pageOffset,
-    pageSize: pagination.pageSize
-  }
-  const {
-    data: { list, pageInfo }
-  } = await getServiceDistribution(params)
-  tableData.value = list
-  pagination.total = pageInfo.Total
+    ...params
+  })
 }
-onSearch()
 
-const debounceSearch = debounce(onSearch, 300)
-
-const onTablePageChange = (pageInfo: any) => {
-  pagination.pageSize = pageInfo.pageSize || 10
-  pagination.current = pageInfo.current || 1
-  pagination.pageOffset = (pagination.current - 1) * pagination.pageSize
-  debounceSearch()
+const searchDomain = reactive(
+  new SearchDomain(
+    [
+      {
+        label: 'placeholder.searchAppNameOrIP',
+        param: 'keywords',
+        style: {
+          width: '300px'
+        }
+      }
+    ],
+    getDistribution,
+    tableColumns
+  )
+)
+
+searchDomain.onSearch()
+searchDomain.tableStyle = {
+  scrollX: '100',
+  scrollY: '367px'
 }
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
 </script>
 
 <style lang="less" scoped>
diff --git a/ui-vue3/src/views/traffic/destinationRule/index.vue 
b/ui-vue3/src/views/traffic/destinationRule/index.vue
index dc1fb101..8af1baa5 100644
--- a/ui-vue3/src/views/traffic/destinationRule/index.vue
+++ b/ui-vue3/src/views/traffic/destinationRule/index.vue
@@ -29,12 +29,7 @@
         <template v-if="column.dataIndex === 'operation'">
           <a-button type="link">查看</a-button>
           <a-button type="link">修改</a-button>
-          <a-popconfirm
-            title="确认删除该动态配置?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="confirm"
-          >
+          <a-popconfirm title="确认删除该动态配置?" ok-text="Yes" cancel-text="No" 
@confirm="confirm">
             <a-button type="link">删除</a-button>
           </a-popconfirm>
         </template>
@@ -56,7 +51,7 @@ let columns = [
     title: 'ruleName',
     key: 'ruleName',
     dataIndex: 'ruleName',
-    sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+    // sorter: (a: any, b: any) => sortString(a.appName, b.appName),
     width: 140
   },
   {
@@ -64,7 +59,7 @@ let columns = [
     key: 'createTime',
     dataIndex: 'createTime',
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'operation',
@@ -94,7 +89,7 @@ onMounted(() => {
   searchDomain.onSearch()
 })
 
-const confirm = () => {}
+const confirm = () => { }
 
 provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
 </script>
diff --git a/ui-vue3/src/views/traffic/dynamicConfig/index.vue 
b/ui-vue3/src/views/traffic/dynamicConfig/index.vue
index c82dc6dc..c530f92c 100644
--- a/ui-vue3/src/views/traffic/dynamicConfig/index.vue
+++ b/ui-vue3/src/views/traffic/dynamicConfig/index.vue
@@ -22,10 +22,7 @@
       </template>
       <template #bodyCell="{ text, column, record }">
         <template v-if="column.dataIndex === 'ruleName'">
-          <span
-            class="config-link"
-            
@click="router.push(`/traffic/dynamicConfig/formview/${record.ruleName}/0`)"
-          >
+          <span class="config-link" 
@click="router.push(`/traffic/dynamicConfig/formview/${record.ruleName}/0`)">
             <b>
               <Icon style="margin-bottom: -2px" 
icon="material-symbols:attach-file-rounded"></Icon>
               {{ text }}
@@ -39,23 +36,12 @@
           {{ text ? '启用' : '禁用' }}
         </template>
         <template v-if="column.dataIndex === 'operation'">
-          <a-button
-            type="link"
-            
@click="router.push(`/traffic/dynamicConfig/formview/${record.ruleName}/0`)"
-            >查看</a-button
-          >
-          <a-button
-            type="link"
-            
@click="router.push(`/traffic/dynamicConfig/formview/${record.ruleName}/1`)"
-          >
+          <a-button type="link"
+            
@click="router.push(`/traffic/dynamicConfig/formview/${record.ruleName}/0`)">查看</a-button>
+          <a-button type="link" 
@click="router.push(`/traffic/dynamicConfig/formview/${record.ruleName}/1`)">
             修改
           </a-button>
-          <a-popconfirm
-            title="确认删除该动态配置?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="delDynamicConfig(record)"
-          >
+          <a-popconfirm title="确认删除该动态配置?" ok-text="Yes" cancel-text="No" 
@confirm="delDynamicConfig(record)">
             <a-button type="link">删除</a-button>
           </a-popconfirm>
         </template>
@@ -84,7 +70,7 @@ let columns = [
     title: 'ruleName',
     key: 'ruleName',
     dataIndex: 'ruleName',
-    sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+    // sorter: (a: any, b: any) => sortString(a.appName, b.appName),
     width: 200,
     ellipsis: true
   },
@@ -94,14 +80,14 @@ let columns = [
     dataIndex: 'ruleGranularity',
     render: (text, record) => (record.isService ? '服务' : '应用'),
     width: 100,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'createTime',
     key: 'createTime',
     dataIndex: 'createTime',
     width: 200,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'enabled',
@@ -109,7 +95,7 @@ let columns = [
     dataIndex: 'enabled',
     render: (text, record) => (record.enabled ? '是' : '否'),
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'operation',
@@ -152,10 +138,12 @@ provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
 <style lang="less" scoped>
 .__container_traffic_config_index {
   min-height: 60vh;
+
   .config-link {
     padding: 4px 10px 4px 4px;
     border-radius: 4px;
     color: v-bind('PRIMARY_COLOR');
+
     &:hover {
       cursor: pointer;
       background: rgba(133, 131, 131, 0.13);
diff --git a/ui-vue3/src/views/traffic/routingRule/index.vue 
b/ui-vue3/src/views/traffic/routingRule/index.vue
index 4c72c9f6..d5e62c74 100644
--- a/ui-vue3/src/views/traffic/routingRule/index.vue
+++ b/ui-vue3/src/views/traffic/routingRule/index.vue
@@ -18,8 +18,7 @@
   <div class="routing-rule-container">
     <search-table :search-domain="searchDomain">
       <template #customOperation>
-        <a-button type="primary" 
@click="router.push(`/traffic/addRoutingRule/addByFormView`)"
-          >新增条件路由规则
+        <a-button type="primary" 
@click="router.push(`/traffic/addRoutingRule/addByFormView`)">新增条件路由规则
         </a-button>
       </template>
       <template #bodyCell="{ text, column, record }">
@@ -45,18 +44,10 @@
           <a-button type="link" 
@click="router.push(`formview/${record.ruleName}`)">
             查看
           </a-button>
-          <a-button
-            type="link"
-            
@click="router.push(`/traffic/updateRoutingRule/updateByFormView/${record.ruleName}`)"
-          >
+          <a-button type="link" 
@click="router.push(`/traffic/updateRoutingRule/updateByFormView/${record.ruleName}`)">
             修改
           </a-button>
-          <a-popconfirm
-            title="确认删除该条件路由规则?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="confirm(record.ruleName)"
-          >
+          <a-popconfirm title="确认删除该条件路由规则?" ok-text="Yes" cancel-text="No" 
@confirm="confirm(record.ruleName)">
             <a-button type="link"> 删除</a-button>
           </a-popconfirm>
         </template>
@@ -81,7 +72,7 @@ let columns = [
     title: 'ruleName',
     key: 'ruleName',
     dataIndex: 'ruleName',
-    sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+    // sorter: (a: any, b: any) => sortString(a.appName, b.appName),
     width: 140
   },
   {
@@ -90,21 +81,21 @@ let columns = [
     dataIndex: 'ruleGranularity',
     render: (text, record) => (record.isService ? '服务' : '应用'),
     width: 100,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'createTime',
     key: 'createTime',
     dataIndex: 'createTime',
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'enabled',
     key: 'enabled',
     dataIndex: 'enabled',
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'operation',
@@ -157,6 +148,7 @@ provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
 <style lang="less" scoped>
 .routing-rule-container {
   height: 100%;
+
   .search-table-container {
     height: 100%;
     //min-height: 60vh;
diff --git a/ui-vue3/src/views/traffic/tagRule/index.vue 
b/ui-vue3/src/views/traffic/tagRule/index.vue
index fcbe1a56..7e72a337 100644
--- a/ui-vue3/src/views/traffic/tagRule/index.vue
+++ b/ui-vue3/src/views/traffic/tagRule/index.vue
@@ -24,10 +24,7 @@
       </template>
       <template #bodyCell="{ text, column, record }">
         <template v-if="column.dataIndex === 'ruleName'">
-          <span
-            class="rule-link"
-            
@click="router.push(`/traffic/tagRule/formview/${record[column.key]}`)"
-          >
+          <span class="rule-link" 
@click="router.push(`/traffic/tagRule/formview/${record[column.key]}`)">
             <b>
               <Icon style="margin-bottom: -2px" 
icon="material-symbols:attach-file-rounded"></Icon>
               {{ text }}
@@ -44,18 +41,10 @@
           <a-button type="link" 
@click="router.push(`formview/${record.ruleName}`)">
             查看
           </a-button>
-          <a-button
-            
@click="router.push(`/traffic/updateTagRule/updateByFormView/${record.ruleName}`)"
-            type="link"
-          >
+          <a-button 
@click="router.push(`/traffic/updateTagRule/updateByFormView/${record.ruleName}`)"
 type="link">
             修改
           </a-button>
-          <a-popconfirm
-            title="确认删除该标签路由规则?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="confirm(record.ruleName)"
-          >
+          <a-popconfirm title="确认删除该标签路由规则?" ok-text="Yes" cancel-text="No" 
@confirm="confirm(record.ruleName)">
             <a-button type="link"> 删除 </a-button>
           </a-popconfirm>
         </template>
@@ -86,7 +75,7 @@ let columns = [
     title: 'ruleName',
     key: 'ruleName',
     dataIndex: 'ruleName',
-    sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+    // sorter: (a: any, b: any) => sortString(a.appName, b.appName),
     width: 140
   },
   {
@@ -94,7 +83,7 @@ let columns = [
     key: 'createTime',
     dataIndex: 'createTime',
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'enable',
@@ -102,7 +91,7 @@ let columns = [
     dataIndex: 'enabled',
     // render: (text, record) => (record.enable ? '是' : '否'),
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'operation',
@@ -153,6 +142,7 @@ provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
 <style lang="less" scoped>
 .tag-rule-container {
   height: 100%;
+
   .search-table-container {
     min-height: 60vh;
     //max-height: 70vh; //overflow: auto;
diff --git a/ui-vue3/src/views/traffic/virtualService/index.vue 
b/ui-vue3/src/views/traffic/virtualService/index.vue
index d75a4fc0..f8e5b264 100644
--- a/ui-vue3/src/views/traffic/virtualService/index.vue
+++ b/ui-vue3/src/views/traffic/virtualService/index.vue
@@ -24,17 +24,12 @@
         <template v-if="column.dataIndex === 'ruleName'">
           <a-button type="link" 
@click="router.replace(`formview/${record[column.key]}`)">{{
             text
-          }}</a-button>
+            }}</a-button>
         </template>
         <template v-if="column.dataIndex === 'operation'">
           <a-button type="link">查看</a-button>
           <a-button type="link">修改</a-button>
-          <a-popconfirm
-            title="确认删除该动态配置?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="confirm"
-          >
+          <a-popconfirm title="确认删除该动态配置?" ok-text="Yes" cancel-text="No" 
@confirm="confirm">
             <a-button type="link">删除</a-button>
           </a-popconfirm>
         </template>
@@ -56,7 +51,7 @@ let columns = [
     title: 'ruleName',
     key: 'ruleName',
     dataIndex: 'ruleName',
-    sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+    // sorter: (a: any, b: any) => sortString(a.appName, b.appName),
     width: 140
   },
   {
@@ -64,14 +59,14 @@ let columns = [
     key: 'createTime',
     dataIndex: 'createTime',
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'lastModifiedTime',
     key: 'lastModifiedTime',
     dataIndex: 'lastModifiedTime',
     width: 120,
-    sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+    // sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
   },
   {
     title: 'operation',
@@ -101,7 +96,7 @@ onMounted(() => {
   searchDomain.onSearch()
 })
 
-const confirm = () => {}
+const confirm = () => { }
 
 provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
 </script>


Reply via email to