Merge pull request #239 from Helltab/feature/ui/framework/vue3
feat(#237):
diff --git a/ui-vue3/src/api/mock/mockApp.ts b/ui-vue3/src/api/mock/mockApp.ts
index 8528e82..9a01e18 100644
--- a/ui-vue3/src/api/mock/mockApp.ts
+++ b/ui-vue3/src/api/mock/mockApp.ts
@@ -30,22 +30,30 @@
let total = Mock.mock('@integer(8, 1000)')
let list = []
for (let i = 0; i < total; i++) {
+ let tmp: any = {
+ registerClusters: []
+ }
+ let num = Mock.mock('@integer(1,3)')
+ for (let j = 0; j < num; j++) {
+ let r = Mock.mock('@string(5)')
+ tmp.registerClusters.push(`cluster_${r}`)
+ }
list.push({
appName: 'app_' + Mock.mock('@string(2,10)'),
instanceNum: Mock.mock('@integer(80, 200)'),
deployCluster: 'cluster_' + Mock.mock('@string(5)'),
- 'registerClusters|1-3': ['cluster_' + Mock.mock('@string(5)')]
+ ...tmp
})
}
return {
code: 200,
message: 'success',
- data: Mock.mock({
+ data: {
total: total,
curPage: 1,
pageSize: 10,
data: list
- })
+ }
}
})
Mock.mock('/mock/application/instance/statistics', 'get', () => {
diff --git a/ui-vue3/src/assets/nav_logo.svg b/ui-vue3/src/assets/nav_logo.svg
new file mode 100644
index 0000000..40ab68b
--- /dev/null
+++ b/ui-vue3/src/assets/nav_logo.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 321.39 78.54" version="1.1">
+ <title id="title19">DUBBO LOGO</title>
+ <path class="cls-1"
+ d="M68.46,50.38c0,14.06,11.39,22.11,25.45,22.11s25.45-8.05,25.45-22.11V7.25H68.46Zm21.24-28h8.6V31H89.7Zm0,22.25h8.6v8.6H89.7ZM33.24,7.25H4.06v64H33.24c10.95,0,19.3-7.18,23.29-17.15a45.12,45.12,0,0,0,2.38-14.87A45.12,45.12,0,0,0,56.53,24.4C52.84,14.62,44.19,7.25,33.24,7.25Zm.43,14.63H30.34a3.44,3.44,0,0,0-3.44,3.44V53.23a3.44,3.44,0,0,0,3.44,3.44h3.33v4.63h-8.3a6.87,6.87,0,0,1-6.87-6.87V24.12a6.87,6.87,0,0,1,6.87-6.87h8.3ZM285.51,6.06c-17.05,0-30.88,10.28-30.88,33.21s13.83,33.21,30.88,33.21,30.88-10.28,30.88-33.21S302.56,6.06,285.51,6.06Zm7.59,48.36a6.87,6.87,0,0,1-6.87,6.87h-8.3V56.67h3.33a3.44,3.44,0,0,0,3.44-3.44V25.31a3.44,3.44,0,0,0-3.44-3.44h-3.33V17.25h8.3a6.87,6.87,0,0,1,6.87,6.87Zm-53.4-17.56A17.39,17.39,0,0,0,227.31,7.25H195.1v64h32.21a19.44,19.44,0,0,0,12.38-34.44ZM211.63,61.29h-6.08l18.68-44h6.08ZM177,36.85A17.39,17.39,0,0,0,164.65,7.25H132.43v64h32.21A19.44,19.44,0,0,0,177,36.85ZM149,61.29h-6.08l18.68-44h6.08Z"
+ style="fill:#ffffff;fill-opacity:1"/>
+</svg>
diff --git a/ui-vue3/src/base/constants.ts b/ui-vue3/src/base/constants.ts
index 0b063b8..08aa943 100644
--- a/ui-vue3/src/base/constants.ts
+++ b/ui-vue3/src/base/constants.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import { ref } from 'vue'
+import { computed, h, reactive, ref } from 'vue'
export const PRIMARY_COLOR_DEFAULT = '#17b392'
@@ -25,11 +25,24 @@
let item = localStorage.getItem(LOCAL_STORAGE_THEME)
export const PRIMARY_COLOR = ref(item || PRIMARY_COLOR_DEFAULT)
+export const PRIMARY_COLOR_T = (percent: string) => computed(() => PRIMARY_COLOR.value + percent)
export const INSTANCE_REGISTER_COLOR: { [key: string]: string } = {
HEALTHY: 'green'
}
+export const TAB_HEADER_TITLE_VNODE = reactive({
+ vnode: h('div', 'something')
+})
+export const TAB_HEADER_TITLE = {
+ functional: true,
+ render: () => {
+ return TAB_HEADER_TITLE_VNODE.vnode
+ // console.log(h)
+ // return h("div", "foo")
+ }
+}
+
/**
* 'Running','Pending', 'Terminating', 'Crashing'
*/
diff --git a/ui-vue3/src/base/i18n/en.ts b/ui-vue3/src/base/i18n/en.ts
index 6fd0c80..c95132c 100644
--- a/ui-vue3/src/base/i18n/en.ts
+++ b/ui-vue3/src/base/i18n/en.ts
@@ -347,6 +347,9 @@
applications: 'Applications',
instances: 'Instances',
applicationDomain: {
+ operatorLog: 'OperatorLog',
+ flowWeight: 'FlowWeight',
+ gray: 'Gray',
detail: 'Detail',
instance: 'Instance',
service: 'Service',
@@ -388,7 +391,9 @@
tracing: 'Tracing',
provideService: 'Provide Service',
- dependentService: 'Dependent Service'
+ dependentService: 'Dependent Service',
+ submit: 'Submit',
+ reset: 'Reset'
}
export default words
diff --git a/ui-vue3/src/base/i18n/zh.ts b/ui-vue3/src/base/i18n/zh.ts
index be83c89..aa36396 100644
--- a/ui-vue3/src/base/i18n/zh.ts
+++ b/ui-vue3/src/base/i18n/zh.ts
@@ -314,6 +314,9 @@
applications: '应用',
instances: '实例',
applicationDomain: {
+ operatorLog: '执行日志',
+ flowWeight: '流量权重',
+ gray: '灰度隔离',
name: '应用名',
detail: '详情',
instance: '实例',
@@ -363,7 +366,9 @@
provideService: '提供服务',
dependentService: '依赖服务',
- idx: '序号'
+ idx: '序号',
+ submit: '提交',
+ reset: '重置'
}
export default words
diff --git a/ui-vue3/src/components/ConfigPage.vue b/ui-vue3/src/components/ConfigPage.vue
new file mode 100644
index 0000000..2fb3c0a
--- /dev/null
+++ b/ui-vue3/src/components/ConfigPage.vue
@@ -0,0 +1,167 @@
+<!--
+ ~ 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_common_config">
+ <a-row :gutter="20">
+ <a-col :span="6">
+ <a-card class="__opt">
+ <template #title>
+ <div class="title">
+ <div class="bg"></div>
+ <Icon class="title-icon" icon="icon-park-twotone:application-one"></Icon>
+
+ {{ route.params?.pathId }}
+ </div>
+ </template>
+ <a-menu v-model:selectedKeys="options.current">
+ <a-menu-item v-for="(item, i) in options.list" :key="i">
+ <Icon
+ v-if="i === options.current[0]"
+ style="margin-bottom: -5px; font-size: 20px"
+ icon="material-symbols:settings-b-roll-rounded"
+ ></Icon>
+ <Icon
+ v-else
+ style="margin-bottom: -5px; font-size: 20px; color: grey"
+ icon="material-symbols:settings-b-roll-outline-rounded"
+ ></Icon>
+ {{ $t(item.title) }}
+ </a-menu-item>
+ </a-menu>
+ </a-card>
+ </a-col>
+
+ <a-col :span="18">
+ <a-card>
+ <template #title>
+ {{ $t(currentOption.title) }}
+ </template>
+ <a-spin :spinning="waitResponse">
+ <a-form
+ ref="__config_form"
+ :key="options.current"
+ :wrapper-col="{ span: 14 }"
+ :model="currentOption.form"
+ :label-col="{ style: { width: '100px' } }"
+ layout="horizontal"
+ >
+ <slot :name="'form_' + currentOption.key" :current="currentOption"></slot>
+ <a-form-item style="margin-left: 100px">
+ <a-button type="primary" @click="submit">{{ $t('submit') }}</a-button>
+ <a-button style="margin-left: 10px" @click="reset">{{ $t('reset') }}</a-button>
+ </a-form-item>
+ </a-form>
+ </a-spin>
+ </a-card>
+ </a-col>
+ </a-row>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { Icon } from '@iconify/vue'
+import { useRoute } from 'vue-router'
+import { computed, ref } from 'vue'
+import { message } from 'ant-design-vue'
+
+let props = defineProps<{
+ options: {
+ list: {
+ key: String
+ title: String
+ form: {}
+ submit: Function | any
+ reset: Function | any
+ }[]
+ current: number[]
+ }
+}>()
+
+let currentOption: any = computed(() => {
+ return props.options.list[props.options.current[0]]
+})
+
+let __config_form: any = ref(null)
+
+// wait the server's response, we need show a spin icon
+let waitResponse = ref(false)
+let route = useRoute()
+
+async function submit() {
+ waitResponse.value = true
+ await __config_form.value.validate().catch((e: any) => {
+ message.error('submit failed [form check]: ' + e)
+ waitResponse.value = false
+ })
+
+ let cur = currentOption.value
+ await cur.submit(cur.form).catch((e: any) => {
+ message.error('submit failed [server error]: ' + e)
+ })
+ waitResponse.value = false
+ message.success('submit success')
+}
+
+function reset() {
+ currentOption.value.reset(currentOption.value.form)
+}
+</script>
+<style lang="less" scoped>
+.__container_common_config {
+ :deep(.ant-segmented-group) {
+ flex-flow: column;
+ }
+
+ .__opt {
+ .title {
+ font-size: 30px;
+ text-align: center;
+ color: #605f5f;
+ position: relative;
+ }
+
+ .title-icon {
+ margin-bottom: -5px;
+ }
+
+ :deep(.ant-menu-item) {
+ width: 80%;
+
+ &:hover {
+ //translate: 10px; //transition: all 0.4s;
+ }
+ }
+
+ :deep(.ant-menu) {
+ border: none;
+ }
+
+ :deep(.ant-card-head) {
+ border: none;
+ background: url('@/assets/nav_logo.svg') #fafafa;
+ background-size: 100% auto;
+ padding: 20px 0;
+ }
+
+ :deep(.ant-menu-item-selected) {
+ transition: all 0.4s;
+ translate: 10px;
+ transform: scale(1.1);
+ }
+ }
+}
+</style>
diff --git a/ui-vue3/src/components/SearchTable.vue b/ui-vue3/src/components/SearchTable.vue
index db51dff..db40551 100644
--- a/ui-vue3/src/components/SearchTable.vue
+++ b/ui-vue3/src/components/SearchTable.vue
@@ -16,53 +16,82 @@
-->
<template>
<div class="__container_search_table">
- <a-form>
- <a-flex wrap="wrap" gap="large">
- <template v-for="q in searchDomain.params">
- <a-form-item :label="$t(q.label)">
- <template v-if="q.dict && q.dict.length > 0">
- <a-radio-group
- button-style="solid"
- v-model:value="searchDomain.queryForm[q.param]"
- v-if="q.dictType === 'BUTTON'"
- >
- <a-radio-button v-for="item in q.dict" :value="item.value">
- {{ $t(item.label) }}
- </a-radio-button>
- </a-radio-group>
- <a-select
- v-else
- class="select-type"
- :style="q.style"
- v-model:value="searchDomain.queryForm[q.param]"
- >
- <a-select-option
- :value="item.value"
- v-for="item in [...q.dict, { label: 'none', value: '' }]"
- >
- {{ $t(item.label) }}
- </a-select-option>
- </a-select>
- </template>
+ <div class="search-query-container">
+ <a-row>
+ <a-col :span="20">
+ <a-form>
+ <a-flex wrap="wrap" gap="large">
+ <template v-for="q in searchDomain.params">
+ <a-form-item :label="$t(q.label)">
+ <template v-if="q.dict && q.dict.length > 0">
+ <a-radio-group
+ button-style="solid"
+ v-model:value="searchDomain.queryForm[q.param]"
+ v-if="q.dictType === 'BUTTON'"
+ >
+ <a-radio-button v-for="item in q.dict" :value="item.value">
+ {{ $t(item.label) }}
+ </a-radio-button>
+ </a-radio-group>
+ <a-select
+ v-else
+ class="select-type"
+ :style="q.style"
+ v-model:value="searchDomain.queryForm[q.param]"
+ >
+ <a-select-option
+ :value="item.value"
+ v-for="item in [...q.dict, { label: 'none', value: '' }]"
+ >
+ {{ $t(item.label) }}
+ </a-select-option>
+ </a-select>
+ </template>
- <a-input
- v-else
- :style="q.style"
- :placeholder="$t('placeholder.' + (q.placeholder || `typeDefault`))"
- v-model:value="searchDomain.queryForm[q.param]"
- ></a-input>
- </a-form-item>
- </template>
- <a-form-item :label="''">
- <a-button type="primary" @click="searchDomain.onSearch()">
- <Icon
- style="margin-bottom: -2px; font-size: 1.3rem"
- icon="ic:outline-manage-search"
- ></Icon>
- </a-button>
- </a-form-item>
- </a-flex>
- </a-form>
+ <a-input
+ v-else
+ :style="q.style"
+ :placeholder="$t('placeholder.' + (q.placeholder || `typeDefault`))"
+ v-model:value="searchDomain.queryForm[q.param]"
+ ></a-input>
+ </a-form-item>
+ </template>
+ <a-form-item :label="''">
+ <a-button type="primary" @click="searchDomain.onSearch()">
+ <Icon
+ style="margin-bottom: -2px; font-size: 1.3rem"
+ icon="ic:outline-manage-search"
+ ></Icon>
+ </a-button>
+ </a-form-item>
+ </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>
+
+ <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-col>
+ </a-row>
+ </div>
<div class="search-table-container">
<a-table
@@ -96,11 +125,17 @@
<script setup lang="ts">
import type { ComponentInternalInstance } from 'vue'
-import { computed, getCurrentInstance, inject } from 'vue'
+import { computed, getCurrentInstance, inject, reactive } 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 commonTool = reactive({
+ customColumns: false
+})
+let __ = PRIMARY_COLOR
const {
appContext: {
@@ -142,8 +177,48 @@
</script>
<style lang="less" scoped>
.__container_search_table {
+ .search-query-container {
+ border-radius: 10px 10px 0 0;
+ border-bottom: 1px solid rgba(220, 219, 219, 0.29);
+ background: #fafafa;
+ padding: 20px 20px 0 20px;
+ //margin-bottom: 20px;
+ }
+
.select-type {
width: 200px;
}
+
+ :deep(.ant-pagination) {
+ padding: 0 10px 20px 0;
+ }
+
+ :deep(.ant-spin-container) {
+ background: #fafafa;
+ }
+
+ :deep(.ant-popover-arrow) {
+ display: none;
+ }
+
+ .common-tool {
+ margin-top: 5px;
+
+ .button {
+ vertical-align: center;
+ line-height: 24px;
+ font-size: 24px;
+ float: right;
+
+ &:hover {
+ color: v-bind('PRIMARY_COLOR');
+ }
+
+ svg {
+ margin-left: 10px;
+ }
+ }
+ }
}
</style>
+<style lang="less"></style>
diff --git a/ui-vue3/src/layout/index.vue b/ui-vue3/src/layout/index.vue
index 227c081..06f9199 100644
--- a/ui-vue3/src/layout/index.vue
+++ b/ui-vue3/src/layout/index.vue
@@ -36,13 +36,7 @@
<a-layout-content class="layout-content">
<router-view v-slot="{ Component }">
<transition name="slide-fade">
- <component :is="Component">
- <template v-slot:tabTitle>
- <h1>
- {{ route.params && Object.values(route.params)[0] }}
- </h1>
- </template>
- </component>
+ <component :is="Component"> </component>
</transition>
</router-view>
</a-layout-content>
@@ -54,13 +48,13 @@
</div>
</template>
<script lang="ts" setup>
-import { provide, ref } from 'vue'
+import { h, provide, ref } from 'vue'
import layoutMenu from './menu/layout_menu.vue'
import logo from '@/assets/logo.png'
import Layout_header from '@/layout/header/layout_header.vue'
import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
import Layout_bread from '@/layout/breadcrumb/layout_bread.vue'
-import { PRIMARY_COLOR } from '@/base/constants'
+import { PRIMARY_COLOR, TAB_HEADER_TITLE_VNODE } from '@/base/constants'
import { useRoute, useRouter } from 'vue-router'
let __null = PRIMARY_COLOR
@@ -76,6 +70,7 @@
transitionFlag.value = true
}, 500)
})
+TAB_HEADER_TITLE_VNODE.vnode = h('div', route.params?.pathId)
</script>
<style lang="less" scoped>
.__container_layout_index {
@@ -103,7 +98,7 @@
.layout-content {
margin: 16px;
padding: 16px 16px 24px;
- background: #fff;
+ //background: #fff;
overflow-y: auto;
height: calc(100vh - 140px);
}
diff --git a/ui-vue3/src/layout/tab/layout_tab.vue b/ui-vue3/src/layout/tab/layout_tab.vue
index 2836ef2..45f5e11 100644
--- a/ui-vue3/src/layout/tab/layout_tab.vue
+++ b/ui-vue3/src/layout/tab/layout_tab.vue
@@ -17,21 +17,29 @@
<template>
<div class="__container_router_tab_index">
<div :key="key">
- <slot name="tabTitle"></slot>
- <a-tabs
- v-if="tabRoute.meta.tab"
- @change="router.push({ name: activeKey || '' })"
- v-model:activeKey="activeKey"
- >
- <a-tab-pane :key="v.name" v-for="v in tabRouters">
- <template #tab>
- <span>
- <Icon style="margin-bottom: -2px" :icon="v.meta.icon"></Icon>
- {{ $t(v.name) }}
+ <div v-if="tabRoute.meta.tab" class="header">
+ <a-row>
+ <a-col :span="1">
+ <span @click="router.push('../')" style="float: left">
+ <Icon icon="material-symbols:keyboard-backspace-rounded" class="back" />
</span>
- </template>
- </a-tab-pane>
- </a-tabs>
+ </a-col>
+ <a-col :span="18">
+ <TAB_HEADER_TITLE :route="tabRoute" />
+ </a-col>
+ </a-row>
+ <a-tabs @change="router.push({ name: activeKey || '' })" v-model:activeKey="activeKey">
+ <a-tab-pane :key="v.name" v-for="v in tabRouters">
+ <template #tab>
+ <span>
+ <Icon style="margin-bottom: -2px" :icon="v.meta.icon"></Icon>
+ {{ $t(v.name) }}
+ </span>
+ </template>
+ </a-tab-pane>
+ </a-tabs>
+ </div>
+
<a-spin class="tab-spin" :spinning="transitionFlag">
<router-view v-show="!transitionFlag" />
</a-spin>
@@ -44,9 +52,11 @@
import { Icon } from '@iconify/vue'
import { useRoute, useRouter } from 'vue-router'
import _ from 'lodash'
+import { PRIMARY_COLOR, TAB_HEADER_TITLE } from '@/base/constants'
const router = useRouter()
const tabRoute = useRoute()
+let __ = PRIMARY_COLOR
let meta: any = tabRoute.meta
const tabRouters = computed(() => {
@@ -72,5 +82,22 @@
:deep(.tab-spin) {
margin-top: 20vh;
}
+
+ :deep(.ant-tabs-nav) {
+ margin: 0;
+ }
+
+ .header {
+ background: #fafafa;
+ padding: 20px 20px 0 20px;
+ border-radius: 10px;
+ margin-bottom: 20px;
+ }
+
+ .back {
+ font-size: 20px;
+ margin-bottom: -2px;
+ color: v-bind('PRIMARY_COLOR');
+ }
}
</style>
diff --git a/ui-vue3/src/main.ts b/ui-vue3/src/main.ts
index 7e2e5f8..7bf241f 100644
--- a/ui-vue3/src/main.ts
+++ b/ui-vue3/src/main.ts
@@ -29,6 +29,8 @@
import 'vue3-colorpicker/style.css'
import 'nprogress/nprogress.css'
+import { PRIMARY_COLOR } from '@/base/constants'
+
const app = createApp(App)
app.use(Antd).use(Vue3ColorPicker).use(i18n).use(router).mount('#app')
diff --git a/ui-vue3/src/views/resources/applications/index.vue b/ui-vue3/src/views/resources/applications/index.vue
index 5597766..a0f3808 100644
--- a/ui-vue3/src/views/resources/applications/index.vue
+++ b/ui-vue3/src/views/resources/applications/index.vue
@@ -19,17 +19,20 @@
<search-table :search-domain="searchDomain">
<template #bodyCell="{ text, record, index, column }">
<template v-if="column.dataIndex === 'registerClusters'">
- <a-tag v-for="t in text" color="warning">
+ <a-tag v-for="t in text" color="grey">
{{ t }}
</a-tag>
</template>
<template v-else-if="column.dataIndex === 'deployCluster'">
- <a-tag color="success">
- {{ text }}
- </a-tag>
+ {{ text }}
</template>
<template v-else-if="column.dataIndex === 'appName'">
- <router-link :to="`detail/${record[column.key]}`">{{ text }}</router-link>
+ <span class="app-link" @click="router.replace(`detail/${record[column.key]}`)">
+ <b>
+ <Icon style="margin-bottom: -2px" icon="material-symbols:attach-file-rounded"></Icon>
+ {{ text }}
+ </b>
+ </span>
</template>
</template>
</search-table>
@@ -42,14 +45,18 @@
import SearchTable from '@/components/SearchTable.vue'
import { SearchDomain, sortString } from '@/utils/SearchUtil'
import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
+import { Icon } from '@iconify/vue'
+import router from '@/router'
+import { PRIMARY_COLOR } from '@/base/constants'
+let __null = PRIMARY_COLOR
let columns = [
- {
- title: 'idx',
- key: 'idx',
- dataIndex: 'idx',
- width: 80
- },
+ // {
+ // title: 'idx',
+ // key: 'idx',
+ // dataIndex: 'idx',
+ // width: 50
+ // },
{
title: 'appName',
key: 'appName',
@@ -105,5 +112,14 @@
.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);
+ }
+ }
}
</style>
diff --git a/ui-vue3/src/views/resources/applications/tabs/config.vue b/ui-vue3/src/views/resources/applications/tabs/config.vue
index 6bdd89e..080cbc1 100644
--- a/ui-vue3/src/views/resources/applications/tabs/config.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/config.vue
@@ -15,14 +15,65 @@
~ limitations under the License.
-->
<template>
- <div class="__container_app_config">config</div>
+ <div class="__container_app_config">
+ <config-page :options="options">
+ <template v-slot:form_log="{ current }">
+ <a-form-item :label="$t('applicationDomain.operatorLog')" name="logFlag">
+ <a-switch v-model:checked="current.form.logFlag"></a-switch>
+ </a-form-item>
+ </template>
+ <template v-slot:form_flow="{ current }"> 2 </template>
+ <template v-slot:form_gray="{ current }"> 3 </template>
+ </config-page>
+ </div>
</template>
<script setup lang="ts">
-import { onMounted } from 'vue'
-
+import { onMounted, reactive, ref } from 'vue'
+import ConfigPage from '@/components/ConfigPage.vue'
+let options: any = reactive({
+ list: [
+ {
+ title: 'applicationDomain.operatorLog',
+ key: 'log',
+ form: {
+ logFlag: false
+ },
+ submit: (form: {}) => {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(1)
+ }, 1000)
+ })
+ },
+ reset(form: any) {
+ form.logFlag = false
+ }
+ },
+ {
+ title: 'applicationDomain.flowWeight',
+ form: {},
+ key: 'flow',
+ submit(form: {}) {
+ console.log(form)
+ }
+ },
+ {
+ title: 'applicationDomain.gray',
+ form: {},
+ key: 'gray',
+ submit(form: {}) {
+ console.log(form)
+ }
+ }
+ ],
+ current: [0]
+})
onMounted(() => {
console.log(333)
})
</script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.__container_app_config {
+}
+</style>
diff --git a/ui-vue3/src/views/resources/applications/tabs/detail.vue b/ui-vue3/src/views/resources/applications/tabs/detail.vue
index c24fc63..0734e72 100644
--- a/ui-vue3/src/views/resources/applications/tabs/detail.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/detail.vue
@@ -17,33 +17,71 @@
<template>
<div class="__container_app_detail">
<a-flex>
- <a-descriptions class="description-column" :column="2" layout="vertical">
- <a-descriptions-item
- v-for="(v, key, idx) in apiData.detail?.data"
- v-show="!!v"
- :labelStyle="{ fontWeight: 'bold' }"
- :label="$t('applicationDomain.' + key)"
- >
- <template #title> 111 </template>
- <template v-if="v.length < 3">
- <p v-for="item in v" class="description-item-content no-card">
- {{ item }}
- </p>
- </template>
+ <a-card-grid>
+ <a-row :gutter="10">
+ <a-col :span="12">
+ <a-card class="_detail">
+ <a-descriptions class="description-column" :column="1">
+ <a-descriptions-item
+ v-for="(v, key, idx) in detailMap.left"
+ v-show="!!v"
+ :labelStyle="{ fontWeight: 'bold', width: '100px' }"
+ :label="$t('applicationDomain.' + key)"
+ >
+ {{ v[0] }}
+ </a-descriptions-item>
+ </a-descriptions>
+ </a-card>
+ </a-col>
+ <a-col :span="12">
+ <a-card class="_detail">
+ <a-descriptions class="description-column" :column="1">
+ <a-descriptions-item
+ v-for="(v, key, idx) in detailMap.right"
+ v-show="!!v"
+ :labelStyle="{ fontWeight: 'bold', width: '100px' }"
+ :label="$t('applicationDomain.' + key)"
+ >
+ {{ v[0] }}
+ </a-descriptions-item>
+ </a-descriptions>
+ </a-card>
+ </a-col>
+ </a-row>
- <a-card class="description-item-card" v-else>
- <p v-for="item in v" @click="copyIt(item)" class="description-item-content with-card">
- {{ item }} <CopyOutlined />
- </p>
- </a-card>
- </a-descriptions-item>
- </a-descriptions>
+ <a-card style="margin-top: 10px" class="_detail">
+ <a-descriptions class="description-column" :column="1">
+ <a-descriptions-item
+ v-for="(v, key, idx) in detailMap.bottom"
+ v-show="!!v"
+ :labelStyle="{ fontWeight: 'bold' }"
+ :label="$t('applicationDomain.' + key)"
+ >
+ <template v-if="v?.length < 3">
+ <p v-for="item in v" class="description-item-content no-card">
+ {{ item }}
+ </p>
+ </template>
+
+ <a-card class="description-item-card" v-else>
+ <p
+ v-for="item in v"
+ @click="copyIt(item)"
+ class="description-item-content with-card"
+ >
+ {{ item }} <CopyOutlined />
+ </p>
+ </a-card>
+ </a-descriptions-item>
+ </a-descriptions>
+ </a-card>
+ </a-card-grid>
</a-flex>
</div>
</template>
<script setup lang="ts">
-import { PRIMARY_COLOR } from '@/base/constants'
+import { PRIMARY_COLOR, PRIMARY_COLOR_T } from '@/base/constants'
import { getApplicationDetail } from '@/api/service/app'
import { computed, onMounted, reactive, getCurrentInstance } from 'vue'
import { CopyOutlined } from '@ant-design/icons-vue'
@@ -58,8 +96,46 @@
} = <ComponentInternalInstance>getCurrentInstance()
let __ = PRIMARY_COLOR
+let PRIMARY_COLOR_20 = PRIMARY_COLOR_T('20')
+let detailMap = reactive({
+ left: {},
+ right: {},
+ bottom: {}
+})
+
onMounted(async () => {
apiData.detail = await getApplicationDetail({})
+ let {
+ appName,
+ rpcProtocols,
+ dubboVersions,
+ dubboPorts,
+ serialProtocols,
+ appTypes,
+ images,
+ workloads,
+ deployCluster,
+ registerCluster,
+ registerMode
+ } = apiData.detail.data
+ detailMap.left = {
+ appName,
+ appTypes,
+ serialProtocols
+ }
+ detailMap.right = {
+ rpcProtocols,
+ dubboPorts,
+ dubboVersions
+ }
+ detailMap.bottom = {
+ images,
+ workloads,
+ deployCluster,
+ registerCluster,
+ registerMode
+ }
+ console.log(appName)
})
const toClipboard = useClipboard().toClipboard
@@ -70,6 +146,9 @@
</script>
<style lang="less" scoped>
.__container_app_detail {
+ ._detail {
+ box-shadow: 8px 8px 4px rgba(162, 162, 162, 0.19);
+ }
.description-item-content {
&.no-card {
padding-left: 20px;
@@ -79,7 +158,12 @@
}
}
.description-item-card {
+ :deep(.ant-card-body) {
+ padding: 10px;
+ }
width: 80%;
+ margin-left: 20px;
+ border: 1px dashed rgba(162, 162, 162, 0.19);
}
}
</style>