feat:关于页面&对接websocket
This commit is contained in:
parent
8da0127729
commit
8e37bba724
@ -38,5 +38,10 @@ def get_system_info():
|
|||||||
"cpu": f"{random.random() * 100: .2}",
|
"cpu": f"{random.random() * 100: .2}",
|
||||||
"memory": f"{random.random() * 100: .2}",
|
"memory": f"{random.random() * 100: .2}",
|
||||||
"disk": f"{random.random() * 100: .2}",
|
"disk": f"{random.random() * 100: .2}",
|
||||||
}
|
},
|
||||||
|
"performance": {
|
||||||
|
"rps": f"{random.random() * random.randint(1, 50): .2}",
|
||||||
|
"time": f"{random.random() * random.randint(1, 50): .2}",
|
||||||
|
"user": f"{random.randint(1, 50)}",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,12 @@ app.mount("/", ws_app)
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
from fastapi.routing import Mount
|
||||||
|
|
||||||
for i in app.routes:
|
for i in app.routes:
|
||||||
logger.info(f"{i.path}, {i.methods}, {i.__dict__.get('summary')}, {i.endpoint}")
|
if not isinstance(i, Mount):
|
||||||
|
logger.info(
|
||||||
|
f"{i.path}, {i.methods}, {i.__dict__.get('summary')}, {i.endpoint}"
|
||||||
|
)
|
||||||
|
|
||||||
uvicorn.run("main:app", reload=True)
|
uvicorn.run("main:app", reload=True)
|
||||||
|
@ -1,35 +1,13 @@
|
|||||||
aiosqlite==0.17.0
|
|
||||||
anyio==3.6.1
|
|
||||||
attrs==22.1.0
|
|
||||||
bcrypt==4.0.0
|
bcrypt==4.0.0
|
||||||
certifi==2022.6.15.1
|
|
||||||
charset-normalizer==2.1.1
|
|
||||||
click==8.1.3
|
|
||||||
colorama==0.4.5
|
|
||||||
ecdsa==0.18.0
|
|
||||||
fastapi==0.82.0
|
fastapi==0.82.0
|
||||||
h11==0.13.0
|
|
||||||
idna==3.3
|
|
||||||
iniconfig==1.1.1
|
|
||||||
iso8601==1.0.2
|
|
||||||
packaging==21.3
|
|
||||||
passlib==1.7.4
|
passlib==1.7.4
|
||||||
pluggy==1.0.0
|
|
||||||
py==1.11.0
|
|
||||||
pyasn1==0.4.8
|
|
||||||
pydantic==1.10.2
|
|
||||||
pyparsing==3.0.9
|
|
||||||
pypika-tortoise==0.1.6
|
|
||||||
pytest==7.1.3
|
pytest==7.1.3
|
||||||
python-jose==3.3.0
|
python-jose==3.3.0
|
||||||
pytz==2022.2.1
|
|
||||||
requests==2.28.1
|
requests==2.28.1
|
||||||
rsa==4.9
|
|
||||||
six==1.16.0
|
|
||||||
sniffio==1.3.0
|
|
||||||
starlette==0.19.1
|
|
||||||
tomli==2.0.1
|
|
||||||
tortoise-orm==0.19.2
|
|
||||||
typing-extensions==4.3.0
|
|
||||||
urllib3==1.26.12
|
|
||||||
uvicorn==0.18.3
|
uvicorn==0.18.3
|
||||||
|
tortoise-orm==0.19.2
|
||||||
|
websockets==10.3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
5368
frontend/package-lock.json
generated
5368
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@
|
|||||||
"prettier": "prettier --write ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@kangc/v-md-editor": "^2.3.15",
|
||||||
"ant-design-vue": "^3.2.12",
|
"ant-design-vue": "^3.2.12",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"echarts": "^5.3.3",
|
"echarts": "^5.3.3",
|
||||||
|
25
frontend/src/components/card/card.vue
Normal file
25
frontend/src/components/card/card.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
title: { type: String },
|
||||||
|
style: {
|
||||||
|
default: () => ({
|
||||||
|
padding: '0'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="card">
|
||||||
|
<a-card :bodyStyle="style" :title="title">
|
||||||
|
<slot></slot>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.card {
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
68
frontend/src/components/echart/eachart-per-result.vue
Normal file
68
frontend/src/components/echart/eachart-per-result.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import Echart from './echart.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
rps: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const options = computed(() => {
|
||||||
|
return {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
animation: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
boundaryGap: [0, '100%'],
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'RPS',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
data: props.rps
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'RT (ms)',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
data: props.time
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'User',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
data: props.user
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="result">
|
||||||
|
<Echart :options="options"></Echart>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
43
frontend/src/components/echart/eachart-view.vue
Normal file
43
frontend/src/components/echart/eachart-view.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<script setup>
|
||||||
|
import Card from '@/components/card/card.vue'
|
||||||
|
import EchartSystemInfo from './echart-system-info.vue'
|
||||||
|
import EachartPerResult from './eachart-per-result.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
performance: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
systemUsage: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="echart-data">
|
||||||
|
<Card title="资源使用率">
|
||||||
|
<EchartSystemInfo
|
||||||
|
:cpu-value="systemUsage.cpu"
|
||||||
|
:disk-value="systemUsage.disk"
|
||||||
|
:memory-value="systemUsage.memory"
|
||||||
|
:style="{ width: '100%', height: '300px' }"
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<Card title="压测结果">
|
||||||
|
<EachartPerResult
|
||||||
|
:rps="performance.rps"
|
||||||
|
:time="performance.time"
|
||||||
|
:user="performance.user"
|
||||||
|
:style="{ width: '100%', height: '300px' }"
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.echart-data {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
</style>
|
@ -88,7 +88,7 @@ const options = computed(() => {
|
|||||||
height: 14,
|
height: 14,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
backgroundColor: 'auto',
|
backgroundColor: 'inherit',
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
formatter: '{value}%'
|
formatter: '{value}%'
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
// props 变化就重新设置值
|
// props 变化就重新设置值
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
console.log('eachart 基础组件')
|
|
||||||
instance.setOption(props.options)
|
instance.setOption(props.options)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import UserInfo from '@/components/layout/layout-info/layout-info.vue'
|
import UserInfo from '@/components/layout/layout-info/layout-info.vue'
|
||||||
import HeaderCrumb from './header-crumb.vue'
|
import HeaderCrumb from './header-crumb.vue'
|
||||||
import { loadIconCpn } from '@/utils/loadCpn'
|
|
||||||
|
|
||||||
// 记录图标状态
|
// 记录图标状态
|
||||||
const collapsed = ref(false)
|
const collapsed = ref(false)
|
||||||
@ -22,7 +21,7 @@ const clickMenuFold = () => {
|
|||||||
<!-- 左侧菜单收缩控制 -->
|
<!-- 左侧菜单收缩控制 -->
|
||||||
<component
|
<component
|
||||||
class="menu-fold"
|
class="menu-fold"
|
||||||
:is="loadIconCpn(collapsed ? 'MenuUnfoldOutlined' : 'MenuFoldOutlined')"
|
:is="$loadIconCpn(collapsed ? 'MenuUnfoldOutlined' : 'MenuFoldOutlined')"
|
||||||
@click="clickMenuFold"
|
@click="clickMenuFold"
|
||||||
>
|
>
|
||||||
</component>
|
</component>
|
||||||
@ -35,6 +34,9 @@ const clickMenuFold = () => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
div {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { userStore } from '@/stores/user'
|
import { userStore } from '@/stores/user'
|
||||||
|
import { GithubOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
import SelectRole from './select-role.vue'
|
import SelectRole from './select-role.vue'
|
||||||
|
|
||||||
@ -19,10 +20,15 @@ const onClick = ({ key }) => {
|
|||||||
router.push('/login')
|
router.push('/login')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const visitGithub = () => {
|
||||||
|
window.open('https://github.com/zy7y/mini-rbac', '_blank')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="inline">
|
||||||
|
<github-outlined @click="visitGithub" />
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<a class="ant-dropdown-link" @click.prevent>
|
<a class="ant-dropdown-link" @click.prevent>
|
||||||
{{ store.userInfo.nickname }} - {{ store.userInfo.roles[0].name }}
|
{{ store.userInfo.nickname }} - {{ store.userInfo.roles[0].name }}
|
||||||
@ -39,7 +45,7 @@ const onClick = ({ key }) => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
div {
|
span {
|
||||||
font-size: 16px;
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { userStore } from '@/stores/user'
|
import { userStore } from '@/stores/user'
|
||||||
import { loadIconCpn } from '@/utils/loadCpn'
|
|
||||||
|
|
||||||
const store = userStore()
|
const store = userStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -21,14 +20,14 @@ const menuClick = (menu) => {
|
|||||||
<template v-if="menu.type === 0">
|
<template v-if="menu.type === 0">
|
||||||
<a-sub-menu :key="menu.id">
|
<a-sub-menu :key="menu.id">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<component :is="loadIconCpn(menu.meta.icon)"></component>
|
<component :is="$loadIconCpn(menu.meta.icon)"></component>
|
||||||
</template>
|
</template>
|
||||||
<template #title>{{ menu.name }}</template>
|
<template #title>{{ menu.name }}</template>
|
||||||
<!-- 1 组件 子菜单项 -->
|
<!-- 1 组件 子菜单项 -->
|
||||||
<template v-for="sub in menu.children" :key="sub.id">
|
<template v-for="sub in menu.children" :key="sub.id">
|
||||||
<a-menu-item @click="menuClick(sub)">
|
<a-menu-item @click="menuClick(sub)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<component :is="loadIconCpn(sub.meta.icon)"></component>
|
<component :is="$loadIconCpn(sub.meta.icon)"></component>
|
||||||
</template>
|
</template>
|
||||||
<span>{{ sub.name }}</span>
|
<span>{{ sub.name }}</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
52
frontend/src/components/markdown/preview-view.vue
Normal file
52
frontend/src/components/markdown/preview-view.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<script setup>
|
||||||
|
import Markdown from '@/components/markdown/preview.vue'
|
||||||
|
import Card from '@/components/card/card.vue'
|
||||||
|
|
||||||
|
/**https://emoji6.com/emojiall/#symbols
|
||||||
|
*
|
||||||
|
* https://emojixd.com/
|
||||||
|
*/
|
||||||
|
const backend = `
|
||||||
|
💬 编程语言: [Python 3.9](https://docs.python.org/zh-cn/3.9/)
|
||||||
|
🌐 Web服务: [FastAPI](https://fastapi.tiangolo.com/) + [Uvicorn](https://www.uvicorn.org/)
|
||||||
|
📄 数据库: SQLite + [Tortoise ORM](https://tortoise.github.io/)
|
||||||
|
📱 即时通信: [Websockets](https://fastapi.tiangolo.com/advanced/websockets/)
|
||||||
|
🔐 JWT认证:[python-jose](https://python-jose.readthedocs.io/en/latest/)
|
||||||
|
`
|
||||||
|
const info = `
|
||||||
|
🎉 [MiniRBAC](https://github.com/zy7y/mini-rbac)
|
||||||
|
✅ 前端菜单权限
|
||||||
|
✅ 前端路由权限
|
||||||
|
✅ 前端按钮权限
|
||||||
|
✅ 后端接口权限
|
||||||
|
`
|
||||||
|
|
||||||
|
const forntend = `
|
||||||
|
💬 编程语言:Javascript
|
||||||
|
⚛️ 框架:[Vue](https://cn.vuejs.org/)
|
||||||
|
🚵🏽 路由:[Vue Router](https://router.vuejs.org/zh/)
|
||||||
|
♻️ 缓存:[Pinia](https://pinia.vuejs.org/)
|
||||||
|
🛠️ 构建工具:[Vite](https://cn.vitejs.dev/)
|
||||||
|
`
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="content">
|
||||||
|
<Card title="🖥️前端">
|
||||||
|
<Markdown :text="forntend" />
|
||||||
|
</Card>
|
||||||
|
<Card title="🎯控制">
|
||||||
|
<Markdown :text="info" />
|
||||||
|
</Card>
|
||||||
|
<Card title="🌐后端">
|
||||||
|
<Markdown :text="backend" />
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
</style>
|
33
frontend/src/components/markdown/preview.vue
Normal file
33
frontend/src/components/markdown/preview.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<script setup>
|
||||||
|
import VMdPreview from '@kangc/v-md-editor/lib/preview'
|
||||||
|
import '@kangc/v-md-editor/lib/style/preview.css'
|
||||||
|
import githubTheme from '@kangc/v-md-editor/lib/theme/github.js'
|
||||||
|
import '@kangc/v-md-editor/lib/theme/style/github.css'
|
||||||
|
import createEmojiPlugin from '@kangc/v-md-editor/lib/plugins/emoji/index'
|
||||||
|
import '@kangc/v-md-editor/lib/plugins/emoji/emoji.css'
|
||||||
|
|
||||||
|
// highlightjs
|
||||||
|
import hljs from 'highlight.js'
|
||||||
|
|
||||||
|
VMdPreview.use(githubTheme, {
|
||||||
|
Hljs: hljs
|
||||||
|
})
|
||||||
|
VMdPreview.use(createEmojiPlugin())
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
text: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-md-preview :text="text"></v-md-preview>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.v-md-editor-preview /deep/ .github-markdown-body {
|
||||||
|
padding: 5px 20px !important;
|
||||||
|
margin: 0px !important;
|
||||||
|
}
|
||||||
|
</style>
|
@ -11,11 +11,14 @@ import '@/assets/css/base.css'
|
|||||||
|
|
||||||
import 'ant-design-vue/dist/antd.css'
|
import 'ant-design-vue/dist/antd.css'
|
||||||
import hasPermisson from '@/utils/directive'
|
import hasPermisson from '@/utils/directive'
|
||||||
import { formatTime } from './utils/format'
|
import { registerFilter } from './utils'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
// 权限校验自定义指令
|
||||||
hasPermisson(app)
|
hasPermisson(app)
|
||||||
app.config.globalProperties.$formatTime = (value) => formatTime(value)
|
// 注册全局filter函数
|
||||||
|
registerFilter(app)
|
||||||
|
|
||||||
app.use(store)
|
app.use(store)
|
||||||
|
|
||||||
userStore().loadRoleRouter()
|
userStore().loadRoleRouter()
|
||||||
|
7
frontend/src/utils/index.js
Normal file
7
frontend/src/utils/index.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { formatTime } from './format'
|
||||||
|
import { loadIconCpn } from './loadCpn'
|
||||||
|
|
||||||
|
export const registerFilter = (app) => {
|
||||||
|
app.config.globalProperties.$formatTime = (value) => formatTime(value)
|
||||||
|
app.config.globalProperties.$loadIconCpn = (value) => loadIconCpn(value)
|
||||||
|
}
|
@ -25,8 +25,8 @@ const changeSiderFold = (subValue) => {
|
|||||||
<!-- 页头 -->
|
<!-- 页头 -->
|
||||||
<LayoutHeader @changeFold="changeSiderFold" />
|
<LayoutHeader @changeFold="changeSiderFold" />
|
||||||
</a-layout-header>
|
</a-layout-header>
|
||||||
<!-- 面包屑 -->
|
|
||||||
<a-layout-content
|
<a-layout-content
|
||||||
|
class="content"
|
||||||
:style="{
|
:style="{
|
||||||
margin: '24px 16px',
|
margin: '24px 16px',
|
||||||
background: '#F0F2F5',
|
background: '#F0F2F5',
|
||||||
@ -41,8 +41,16 @@ const changeSiderFold = (subValue) => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.main,
|
.main {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.ant-layout {
|
.ant-layout {
|
||||||
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,46 +1,58 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onUnmounted, ref } from 'vue'
|
import { onUnmounted, reactive, toRefs } from 'vue'
|
||||||
|
|
||||||
import EchartSystemInfo from '@/components/echart/echart-system-info.vue'
|
import EachartView from '@/components/echart/eachart-view.vue'
|
||||||
|
import MarkdownView from '@/components/markdown/preview-view.vue'
|
||||||
|
|
||||||
/** websocket */
|
/** websocket */
|
||||||
let ws = new WebSocket('ws://localhost:8000/ws')
|
let ws = new WebSocket('ws://localhost:8000/ws')
|
||||||
|
|
||||||
const wsData = ref()
|
// 响应式数据
|
||||||
|
const data = reactive({
|
||||||
|
systemUsage: {
|
||||||
|
cpu: '0',
|
||||||
|
momery: '0',
|
||||||
|
disk: '0'
|
||||||
|
},
|
||||||
|
performance: {
|
||||||
|
rps: [],
|
||||||
|
time: [],
|
||||||
|
user: []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 接收消息
|
||||||
ws.onmessage = (e) => {
|
ws.onmessage = (e) => {
|
||||||
// 接收消息
|
const wsData = JSON.parse(e.data)
|
||||||
wsData.value = JSON.parse(e.data)
|
data.systemUsage = wsData.usage
|
||||||
|
data.performance.rps.push({
|
||||||
|
value: [Date.now(), wsData.performance.rps]
|
||||||
|
})
|
||||||
|
data.performance.time.push({
|
||||||
|
value: [Date.now(), wsData.performance.time]
|
||||||
|
})
|
||||||
|
data.performance.user.push({
|
||||||
|
value: [Date.now(), wsData.performance.user]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { systemUsage, performance } = toRefs(data)
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
ws.close()
|
ws.close()
|
||||||
|
console.log('关闭socket 连接')
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="about">
|
<div class="about">
|
||||||
<a-card class="system">
|
<EachartView :performance="performance" :system-usage="systemUsage" />
|
||||||
<template #title> 资源使用率(虚拟数据) </template>
|
<MarkdownView class="footer" />
|
||||||
<EchartSystemInfo
|
|
||||||
:cpu-value="wsData?.usage.cpu"
|
|
||||||
:disk-value="wsData?.usage.disk"
|
|
||||||
:memory-value="wsData?.usage.memory"
|
|
||||||
:style="{ width: '100%', height: '300px' }"
|
|
||||||
/>
|
|
||||||
</a-card>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.about {
|
.footer {
|
||||||
width: 100%;
|
margin: 20px 0px;
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.system {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header .ant-card {
|
|
||||||
width: 40%;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -3,7 +3,6 @@ import { ref } from 'vue'
|
|||||||
import { PlusOutlined } from '@ant-design/icons-vue'
|
import { PlusOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
import { columns, menuType, methodColor } from './conf'
|
import { columns, menuType, methodColor } from './conf'
|
||||||
import { loadIconCpn } from '@/utils/loadCpn'
|
|
||||||
import { getMenus } from '@/service/menu'
|
import { getMenus } from '@/service/menu'
|
||||||
|
|
||||||
// 列表数据
|
// 列表数据
|
||||||
@ -67,11 +66,10 @@ const delClick = () => {
|
|||||||
}"
|
}"
|
||||||
:row-key="(record) => record.id"
|
:row-key="(record) => record.id"
|
||||||
@expand="zi"
|
@expand="zi"
|
||||||
:expandedRowKeys="expandRowKeys"
|
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'meta'">
|
<template v-if="column.key === 'meta'">
|
||||||
<component :is="loadIconCpn(record.meta?.icon)"></component>
|
<component :is="$loadIconCpn(record.meta?.icon)"></component>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'type'">
|
<template v-if="column.key === 'type'">
|
||||||
{{ menuType[record.type] }}
|
{{ menuType[record.type] }}
|
||||||
|
@ -238,10 +238,10 @@ watch(
|
|||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'created'">
|
<template v-else-if="column.key === 'created'">
|
||||||
{{ $$formatTime(record.created) }}
|
{{ $formatTime(record.created) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'modified'">
|
<template v-else-if="column.key === 'modified'">
|
||||||
{{ $$formatTime(record.modified) }}
|
{{ $formatTime(record.modified) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'action'">
|
<template v-else-if="column.key === 'action'">
|
||||||
<span>
|
<span>
|
||||||
|
Loading…
Reference in New Issue
Block a user