Merge pull request #244 from jianyi-gronk/feature/ui/traffic_control
add traffic control pages
diff --git a/ui-vue3/src/api/mock/mockDestinationRule.ts b/ui-vue3/src/api/mock/mockDestinationRule.ts
new file mode 100644
index 0000000..4206b29
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockDestinationRule.ts
@@ -0,0 +1,39 @@
+/*
+ * 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
+ *
+ * http://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.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/destinationRule/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ createTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/mock/mockDynamicConfig.ts b/ui-vue3/src/api/mock/mockDynamicConfig.ts
new file mode 100644
index 0000000..879df89
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockDynamicConfig.ts
@@ -0,0 +1,41 @@
+/*
+ * 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
+ *
+ * http://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.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/dynamicConfig/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ ruleGranularity: Mock.mock('@boolean'),
+ enable: Mock.mock('@boolean'),
+ createTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/mock/mockRoutingRule.ts b/ui-vue3/src/api/mock/mockRoutingRule.ts
index bd352da..e9fe0b5 100644
--- a/ui-vue3/src/api/mock/mockRoutingRule.ts
+++ b/ui-vue3/src/api/mock/mockRoutingRule.ts
@@ -23,10 +23,9 @@
for (let i = 0; i < total; i++) {
list.push({
ruleName: 'app_' + Mock.mock('@string(2,10)'),
- ruleGranularity: Mock.mock('@integer(80, 200)'),
+ ruleGranularity: Mock.mock('@boolean'),
enable: Mock.mock('@boolean'),
- effectiveTime: Mock.mock('@datetime'),
- protection: Mock.mock('@boolean')
+ createTime: Mock.mock('@datetime')
})
}
return {
diff --git a/ui-vue3/src/api/mock/mockTagRule.ts b/ui-vue3/src/api/mock/mockTagRule.ts
new file mode 100644
index 0000000..6dd1984
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockTagRule.ts
@@ -0,0 +1,40 @@
+/*
+ * 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
+ *
+ * http://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.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/tagRule/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ enable: Mock.mock('@boolean'),
+ createTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/mock/mockVirtualService.ts b/ui-vue3/src/api/mock/mockVirtualService.ts
new file mode 100644
index 0000000..5469277
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockVirtualService.ts
@@ -0,0 +1,40 @@
+/*
+ * 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
+ *
+ * http://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.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/virtualService/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ createTime: Mock.mock('@datetime'),
+ lastModifiedTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/service/traffic.ts b/ui-vue3/src/api/service/traffic.ts
index 380f230..24f97d6 100644
--- a/ui-vue3/src/api/service/traffic.ts
+++ b/ui-vue3/src/api/service/traffic.ts
@@ -24,3 +24,35 @@
params
})
}
+
+export const searchTagRule = (params: any): Promise<any> => {
+ return request({
+ url: '/tagRule/search',
+ method: 'get',
+ params
+ })
+}
+
+export const searchDynamicConfig = (params: any): Promise<any> => {
+ return request({
+ url: '/dynamicConfig/search',
+ method: 'get',
+ params
+ })
+}
+
+export const searchVirtualService = (params: any): Promise<any> => {
+ return request({
+ url: '/virtualService/search',
+ method: 'get',
+ params
+ })
+}
+
+export const searchDestinationRule = (params: any): Promise<any> => {
+ return request({
+ url: '/destinationRule/search',
+ method: 'get',
+ params
+ })
+}
diff --git a/ui-vue3/src/base/i18n/en.ts b/ui-vue3/src/base/i18n/en.ts
index c95132c..03deca7 100644
--- a/ui-vue3/src/base/i18n/en.ts
+++ b/ui-vue3/src/base/i18n/en.ts
@@ -332,6 +332,8 @@
editMockRule: 'Edit Mock Rule',
deleteRuleTitle: 'Are you sure to delete this mock rule?',
+ createTime: 'Create Time',
+ lastModifiedTime: 'Last Modified Time',
trafficTimeout: 'Timeout',
trafficRetry: 'Retry',
trafficRegion: 'Region Aware',
diff --git a/ui-vue3/src/base/i18n/zh.ts b/ui-vue3/src/base/i18n/zh.ts
index aa36396..8428a8c 100644
--- a/ui-vue3/src/base/i18n/zh.ts
+++ b/ui-vue3/src/base/i18n/zh.ts
@@ -291,7 +291,8 @@
ruleName: '规则名',
ruleGranularity: '规则粒度',
- effectiveTime: '生效时间',
+ createTime: '创建时间',
+ lastModifiedTime: '最后修改时间',
enable: '是否启用',
protection: '容错保护',
trafficTimeout: '超时时间',
diff --git a/ui-vue3/src/components/SearchTable.vue b/ui-vue3/src/components/SearchTable.vue
index db40551..d9f53e8 100644
--- a/ui-vue3/src/components/SearchTable.vue
+++ b/ui-vue3/src/components/SearchTable.vue
@@ -18,7 +18,7 @@
<div class="__container_search_table">
<div class="search-query-container">
<a-row>
- <a-col :span="20">
+ <a-col :span="18">
<a-form>
<a-flex wrap="wrap" gap="large">
<template v-for="q in searchDomain.params">
@@ -67,28 +67,31 @@
</a-flex>
</a-form>
</a-col>
- <a-col :span="4">
- <div class="common-tool">
- <a-dropdown placement="bottom" :trigger="['click']">
- <div class="custom-column button">
- <Icon icon="material-symbols-light:format-list-bulleted-rounded"></Icon>
- </div>
+ <a-col :span="6">
+ <a-flex style="justify-content: flex-end;">
+ <slot name="customOperation"></slot>
+ <div class="common-tool">
+ <a-dropdown placement="bottom" :trigger="['click']">
+ <div class="custom-column button">
+ <Icon icon="material-symbols-light:format-list-bulleted-rounded"></Icon>
+ </div>
- <template #overlay>
- <a-card title="Custom Column">
- <a-menu>
- <a-menu-item>
- <Icon
- style="margin-bottom: -3px; font-size: 1rem"
- icon="material-symbols-light:format-list-bulleted-rounded"
- ></Icon>
- 3
- </a-menu-item>
- </a-menu>
- </a-card>
- </template>
- </a-dropdown>
- </div>
+ <template #overlay>
+ <a-card title="Custom Column">
+ <a-menu>
+ <a-menu-item>
+ <Icon
+ style="margin-bottom: -3px; font-size: 1rem"
+ icon="material-symbols-light:format-list-bulleted-rounded"
+ ></Icon>
+ 3
+ </a-menu-item>
+ </a-menu>
+ </a-card>
+ </template>
+ </a-dropdown>
+ </div>
+ </a-flex>
</a-col>
</a-row>
</div>
@@ -125,13 +128,15 @@
<script setup lang="ts">
import type { ComponentInternalInstance } from 'vue'
-import { computed, getCurrentInstance, inject, reactive } from 'vue'
+import { computed, getCurrentInstance, inject, reactive, useSlots } from 'vue'
import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
import type { SearchDomain } from '@/utils/SearchUtil'
import { Icon } from '@iconify/vue'
import { PRIMARY_COLOR } from '@/base/constants'
+const customOperation = !!useSlots().customOperation;
+
const commonTool = reactive({
customColumns: false
})
@@ -215,7 +220,7 @@
}
svg {
- margin-left: 10px;
+ margin-left: 20px;
}
}
}
diff --git a/ui-vue3/src/router/defaultRoutes.ts b/ui-vue3/src/router/defaultRoutes.ts
index 70884b9..f2e528c 100644
--- a/ui-vue3/src/router/defaultRoutes.ts
+++ b/ui-vue3/src/router/defaultRoutes.ts
@@ -290,6 +290,22 @@
name: 'dynamicConfig',
component: () => import('../views/traffic/dynamicConfig/index.vue'),
meta: {}
+ },
+ {
+ path: '/meshRule',
+ name: 'meshRule',
+ children: [
+ {
+ path: '/virtualService',
+ name: 'virtualService',
+ component: () => import('../views/traffic/virtualService/index.vue')
+ },
+ {
+ path: '/destinationRule',
+ name: 'destinationRule',
+ component: () => import('../views/traffic/destinationRule/index.vue')
+ }
+ ]
}
]
},
diff --git a/ui-vue3/src/views/traffic/destinationRule/index.vue b/ui-vue3/src/views/traffic/destinationRule/index.vue
new file mode 100644
index 0000000..05b92be
--- /dev/null
+++ b/ui-vue3/src/views/traffic/destinationRule/index.vue
@@ -0,0 +1,103 @@
+<!--
+ ~ 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
+ ~
+ ~ http://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.
+-->
+<template>
+ <div class="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增 Destination Rule</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</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-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, provide, reactive } from 'vue'
+import { searchDestinationRule } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
+
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchDestinationRule,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
+</script>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>
diff --git a/ui-vue3/src/views/traffic/dynamicConfig/index.vue b/ui-vue3/src/views/traffic/dynamicConfig/index.vue
index c97d821..fbef790 100644
--- a/ui-vue3/src/views/traffic/dynamicConfig/index.vue
+++ b/ui-vue3/src/views/traffic/dynamicConfig/index.vue
@@ -15,15 +15,112 @@
~ limitations under the License.
-->
<template>
- <div class="__container_home_index">
- <h1>{{ $t(routeName) }}</h1>
+ <div class="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增动态配置</a-button>
+ <a-button type="primary" style="margin-left: 10px">从模版创建</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
+ </template>
+ <template v-if="column.dataIndex === 'ruleGranularity'">
+ {{ text ? '服务' : '应用' }}
+ </template>
+ <template v-if="column.dataIndex === 'enable'">
+ {{ text ? '启用' : '禁用' }}
+ </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-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
</div>
</template>
<script setup lang="ts">
-import { Icon } from '@iconify/vue'
+import { onMounted, provide, reactive } from 'vue'
+import { searchDynamicConfig } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
-import { useRoute } from 'vue-router'
-const routeName = <string>useRoute().name
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'ruleGranularity',
+ key: 'ruleGranularity',
+ dataIndex: 'ruleGranularity',
+ render: (text, record) => (record.isService ? '服务' : '应用'),
+ width: 100,
+ 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)
+ },
+ {
+ title: 'enable',
+ key: 'enable',
+ dataIndex: 'enable',
+ render: (text, record) => (record.enable ? '是' : '否'),
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchDynamicConfig,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
</script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>
diff --git a/ui-vue3/src/views/traffic/routingRule/index.vue b/ui-vue3/src/views/traffic/routingRule/index.vue
index c899666..14e82ed 100644
--- a/ui-vue3/src/views/traffic/routingRule/index.vue
+++ b/ui-vue3/src/views/traffic/routingRule/index.vue
@@ -17,12 +17,30 @@
<template>
<div class="__container_resources_application_index">
<search-table :search-domain="searchDomain">
- <template #bodyCell="{ text, record, index, column }">
- <template v-if="column.dataIndex === 'enable'">
- {{ text ? '是' : '否' }}
+ <template #customOperation>
+ <a-button type="primary">新增条件路由规则</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
</template>
- <template v-if="column.dataIndex === 'protection'">
- {{ text ? '是' : '否' }}
+ <template v-if="column.dataIndex === 'ruleGranularity'">
+ {{ text ? '服务' : '应用' }}
+ </template>
+ <template v-if="column.dataIndex === 'enable'">
+ {{ text ? '启用' : '禁用' }}
+ </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-button type="link">删除</a-button>
+ </a-popconfirm>
</template>
</template>
</search-table>
@@ -48,27 +66,29 @@
title: 'ruleGranularity',
key: 'ruleGranularity',
dataIndex: 'ruleGranularity',
+ render: (text, record) => (record.isService ? '服务' : '应用'),
width: 100,
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)
+ },
+ {
title: 'enable',
key: 'enable',
dataIndex: 'enable',
render: (text, record) => (record.enable ? '是' : '否'),
- width: 120
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
},
{
- title: 'effectiveTime',
- key: 'effectiveTime',
- dataIndex: 'effectiveTime',
- width: 120
- },
- {
- title: 'protection',
- key: 'protection',
- dataIndex: 'protection',
- render: (text, record) => (record.protection ? '是' : '否'),
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
width: 200
}
]
@@ -93,6 +113,8 @@
searchDomain.onSearch()
})
+const confirm = () => {}
+
provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
</script>
<style lang="less" scoped>
diff --git a/ui-vue3/src/views/traffic/tagRule/index.vue b/ui-vue3/src/views/traffic/tagRule/index.vue
index c97d821..d72618b 100644
--- a/ui-vue3/src/views/traffic/tagRule/index.vue
+++ b/ui-vue3/src/views/traffic/tagRule/index.vue
@@ -15,15 +15,100 @@
~ limitations under the License.
-->
<template>
- <div class="__container_home_index">
- <h1>{{ $t(routeName) }}</h1>
+ <div class="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增标签路由规则</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
+ </template>
+ <template v-if="column.dataIndex === 'enable'">
+ {{ text ? '启用' : '禁用' }}
+ </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-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
</div>
</template>
<script setup lang="ts">
-import { Icon } from '@iconify/vue'
+import { onMounted, provide, reactive } from 'vue'
+import { searchTagRule } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
-import { useRoute } from 'vue-router'
-const routeName = <string>useRoute().name
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'enable',
+ key: 'enable',
+ dataIndex: 'enable',
+ render: (text, record) => (record.enable ? '是' : '否'),
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchTagRule,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
</script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>
diff --git a/ui-vue3/src/views/traffic/virtualService/index.vue b/ui-vue3/src/views/traffic/virtualService/index.vue
new file mode 100644
index 0000000..4e1f049
--- /dev/null
+++ b/ui-vue3/src/views/traffic/virtualService/index.vue
@@ -0,0 +1,110 @@
+<!--
+ ~ 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
+ ~
+ ~ http://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.
+-->
+<template>
+ <div class="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增路由规则</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</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-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, provide, reactive } from 'vue'
+import { searchVirtualService } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
+
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ 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)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchVirtualService,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
+</script>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>