Merge pull request #2206 from jumpserver/perf_dashboard

Perf dashboard
This commit is contained in:
feng626
2022-11-28 17:14:29 +08:00
committed by GitHub
11 changed files with 280 additions and 49 deletions

View File

@@ -592,6 +592,8 @@
"LoginTo": "Login to", "LoginTo": "Login to",
"LoginUsers": "Active users", "LoginUsers": "Active users",
"Monthly": "Monthly", "Monthly": "Monthly",
"CurrentConnections": "Current connections",
"TodayFailedConnections": "Connections failed today",
"OnlineSessions": "Online sessions", "OnlineSessions": "Online sessions",
"OnlineUsers": "Online users", "OnlineUsers": "Online users",
"ConnectUsers": "Connect users", "ConnectUsers": "Connect users",

View File

@@ -603,6 +603,8 @@
"LoginTo": "ログインしました", "LoginTo": "ログインしました",
"LoginUsers": "アクティブユーザー", "LoginUsers": "アクティブユーザー",
"Monthly": "月ごと", "Monthly": "月ごと",
"CurrentConnections": "現在の接続数",
"TodayFailedConnections": "今日の接続に失敗しました",
"OnlineSessions": "オンラインセッション", "OnlineSessions": "オンラインセッション",
"OnlineUsers": "オンラインユーザー", "OnlineUsers": "オンラインユーザー",
"ConnectUsers": "ユーザーの接続", "ConnectUsers": "ユーザーの接続",

View File

@@ -624,7 +624,9 @@
"LoginTo": "登录了", "LoginTo": "登录了",
"LoginUsers": "活跃用户", "LoginUsers": "活跃用户",
"Monthly": "按月", "Monthly": "按月",
"OnlineSessions": "在线会话", "CurrentConnections": "当前连接数",
"TodayFailedConnections": "今日连接失败数",
"OnlineSessions": "在线会话数",
"OnlineUsers": "在线用户", "OnlineUsers": "在线用户",
"ConnectUsers": "连接用户", "ConnectUsers": "连接用户",
"TimesWeekUnit": "次/周", "TimesWeekUnit": "次/周",

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#646A73" d="M41 27V15H29" data-follow-stroke="#646A73"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="#646A73" d="m6 37 10.338-12.5 9.847 6L41 15" data-follow-stroke="#646A73"/></svg>

After

Width:  |  Height:  |  Size: 365 B

View File

@@ -0,0 +1,65 @@
<template>
<div>
<el-row :gutter="16">
<el-col :lg="12" :sm="24">
<RankTable v-bind="userConfig" />
</el-col>
<el-col :lg="12" :sm="24">
<RankTable v-bind="assetConfig" />
</el-col>
</el-row>
</div>
</template>
<script>
import RankTable from './components/RankTable.vue'
export default {
components: {
RankTable
},
data() {
return {
userConfig: {
title: '登录用户排名',
url: '/api/v1/index/?dates_login_times_top10_users=1',
note: '登录用户排名',
data: 'dates_login_times_top10_users',
columns: [
{
prop: 'user',
label: '用户名'
},
{
prop: 'total',
label: '登录次数'
}
]
},
assetConfig: {
title: '活跃资产排名',
url: '/api/v1/index/?dates_login_times_top10_assets=1',
note: '活跃资产排名',
data: 'dates_login_times_top10_assets',
columns: [
{
prop: 'asset',
label: '资产名称'
},
{
prop: 'total',
label: '访问次数'
}
]
},
columnsMeta: {}
}
},
methods: {
}
}
</script>
<style scoped>
</style>

View File

@@ -7,10 +7,10 @@
<div class="add"> <div class="add">
<span class="add-num"> <span class="add-num">
本周新增0 本周新增0
<i class="fa fa-line-chart" /> <svg-icon icon-class="broken-line" style="font-size: 18px;" />
</span> </span>
<span class="add-icon"> <span class="add-icon">
<i class="fa fa-users" /> <svg-icon icon-class="users" style="font-size: 18px;" />
</span> </span>
</div> </div>
</div> </div>
@@ -27,7 +27,10 @@ export default {
RingChart RingChart
}, },
props: { props: {
object: {
type: Object,
default: () => ({})
}
}, },
data() { data() {
return { return {

View File

@@ -5,7 +5,7 @@
用户/资产活跃情况 用户/资产活跃情况
<i class="fa fa-exclamation-circle icon" /> <i class="fa fa-exclamation-circle icon" />
</span> </span>
<span class="time">更新时间2022-11-17</span> <!-- <span class="time">更新时间2022-11-17</span> -->
</div> </div>
<echarts <echarts
ref="echarts" ref="echarts"
@@ -20,8 +20,8 @@
</template> </template>
<script> <script>
import 'echarts/lib/chart/line' // eslint-disable-next-line no-unused-vars
import 'echarts/lib/component/legend' import * as echarts from 'echarts'
export default { export default {
name: 'LoginMetric', name: 'LoginMetric',
@@ -37,8 +37,7 @@ export default {
metricsData: { metricsData: {
dates_metrics_date: [], dates_metrics_date: [],
dates_metrics_total_count_active_assets: [], dates_metrics_total_count_active_assets: [],
dates_metrics_total_count_active_users: [], dates_metrics_total_count_active_users: []
dates_metrics_total_count_login: []
} }
} }
}, },
@@ -46,13 +45,11 @@ export default {
themeColor() { themeColor() {
const documentStyle = document.documentElement.style const documentStyle = document.documentElement.style
return { return {
primary: documentStyle.getPropertyValue('--color-primary'), primary: documentStyle.getPropertyValue('--color-primary')
info: documentStyle.getPropertyValue('--color-info'),
success: documentStyle.getPropertyValue('--color-success')
} }
}, },
options() { options() {
const { primary, info, success } = this.themeColor const { primary } = this.themeColor
return { return {
title: { title: {
show: false show: false
@@ -84,7 +81,7 @@ export default {
bottom: '3%', bottom: '3%',
containLabel: true containLabel: true
}, },
color: [primary, info, success], color: [primary, '#F3B44B'],
xAxis: [ xAxis: [
{ {
type: 'category', type: 'category',
@@ -136,13 +133,6 @@ export default {
animationDuration: 500, animationDuration: 500,
series: [ series: [
{
name: this.$t('dashboard.LoginCount'),
type: 'line',
areaStyle: {},
smooth: true,
data: this.metricsData.dates_metrics_total_count_login
},
{ {
name: this.$t('dashboard.LoginUsers'), name: this.$t('dashboard.LoginUsers'),
type: 'line', type: 'line',
@@ -171,11 +161,17 @@ export default {
}, },
methods: { methods: {
async getMetricData() { async getMetricData() {
let url = '/api/v1/index/?dates_metrics=1&' const url = '/api/v1/index/?dates_metrics=1&'
if (this.range === 'monthly') { const data = await this.$axios.get(url)
url = `${url}&monthly=1` this.metricsData = data
const activeAssets = 'dates_metrics_total_count_active_assets'
const activeUsers = 'dates_metrics_total_count_active_users'
if (data[activeAssets].length < 1) {
this.metricsData[activeAssets] = [0]
}
if (data[activeUsers].length < 1) {
this.metricsData[activeUsers] = [0]
} }
this.metricsData = await this.$axios.get(url)
}, },
getDataUrl() { getDataUrl() {
this.dataUrl = this.$refs.echarts.getDataURL({ this.dataUrl = this.$refs.echarts.getDataURL({

View File

@@ -0,0 +1,167 @@
<template>
<div class="box">
<div class="head">
<span class="title">
{{ title }}
<el-tooltip
v-if="note"
effect="dark"
:content="note"
placement="top"
>
<i class="fa fa-exclamation-circle icon" />
</el-tooltip>
<i v-else class="fa fa-exclamation-circle icon" />
</span>
<span>
<el-radio-group
v-model="select"
class="switch"
size="mini"
@change="onChange"
>
<el-radio-button v-for="i in options" :key="i.value" :label="i.value">
{{ i.label }}
</el-radio-button>
</el-radio-group>
</span>
</div>
<el-table
:data="tableData"
style="width: 100%"
class="table"
>
<el-table-column :label="'排名'">
<template v-slot="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column
v-for="i in columns"
:key="i.prop"
:prop="i.prop"
:label="i.label"
>
{{ i.prop }}
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
components: {
},
props: {
title: {
type: String,
default: ''
},
url: {
type: String,
default: ''
},
note: {
type: String,
default: ''
},
data: {
type: String,
default: () => ''
},
columns: {
type: Array,
default: () => []
},
options: {
type: Array,
default: () => [
{
label: '今天',
value: '1'
},
{
label: '近7天',
value: '7'
},
{
label: '近30天',
value: '30'
}
]
}
},
data() {
return {
select: '1',
tableData: [],
tableUrl: this.url + `&days=1`
}
},
created() {
this.init()
},
methods: {
init() {
this.$axios.get(this.tableUrl).then(res => {
this.tableData = this.data ? res?.[this.data] : res
})
},
onChange() {
this.tableUrl = this.url + `&days=${this.select}`
this.init()
}
}
}
</script>
<style lang="scss" scoped>
.box {
margin-top: 16px;
padding: 20px;
background: #fff;
.head {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
.title {
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 26px;
color: #1F2329;
}
.icon {
color: #BBBFC4;
cursor: pointer;
}
.switch {
background: #EFF0F1;
border-radius: 4px;
&>>> .el-radio-button {
.el-radio-button__inner {
border: none;
color: #8F959E;
background: #EFF0F1;
}
&.is-active {
border-radius: 4px;
padding: 4px 0;
.el-radio-button__inner {
color: var(--color-primary);
background-color: #FFF;
border-radius: 4px;
}
}
}
&>>> .el-radio-button__orig-radio:checked+.el-radio-button__inner {
box-shadow: none;
}
}
}
}
>>> .el-table th, .el-table tr {
background-color: #F5F6F7!important;
}
</style>

View File

@@ -2,7 +2,7 @@
<div class="box"> <div class="box">
<div style="margin-bottom: 12px;"> <div style="margin-bottom: 12px;">
<span class="title">实时数据</span> <span class="title">实时数据</span>
<span class="time">更新时间2022-11-17</span> <!-- <span class="time">更新时间2022-11-17</span> -->
</div> </div>
<div class="content"> <div class="content">
<el-row type="flex" justify="space-between"> <el-row type="flex" justify="space-between">
@@ -25,10 +25,9 @@ export default {
data() { data() {
return { return {
counter: { counter: {
total_count_assets: '.', total_count_online_sessions: '.',
total_count_users: '.',
total_count_online_users: '.', total_count_online_users: '.',
total_count_online_sessions: '.' total_count_today_failed_sessions: '.'
} }
} }
}, },
@@ -36,15 +35,15 @@ export default {
summaryItems() { summaryItems() {
return [ return [
{ {
title: this.$t('dashboard.AssetsTotal'), title: this.$t('dashboard.OnlineSessions'),
body: { body: {
route: { name: 'AssetList' }, route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
count: this.counter.total_count_assets, count: this.counter.total_count_online_sessions,
disabled: !this.$hasPerm('assets.view_asset') disabled: !this.$hasPerm('terminal.view_session')
} }
}, },
{ {
title: this.$t('dashboard.ConnectUsers'), title: this.$t('dashboard.CurrentConnections'),
body: { body: {
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }}, route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
count: this.counter.total_count_online_users, count: this.counter.total_count_online_users,
@@ -52,11 +51,10 @@ export default {
} }
}, },
{ {
title: this.$t('dashboard.OnlineSessions'), title: this.$t('dashboard.TodayFailedConnections'),
body: { body: {
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }}, count: this.counter.total_count_today_failed_sessions,
count: this.counter.total_count_online_sessions, disabled: true
disabled: !this.$hasPerm('terminal.view_session')
} }
} }
] ]

View File

@@ -2,18 +2,15 @@
<Page> <Page>
<div v-if="this.$hasPerm('rbac.view_console|rbac.view_audit')"> <div v-if="this.$hasPerm('rbac.view_console|rbac.view_audit')">
<Announcement /> <Announcement />
<!-- <ResourceSummary /> -->
<!-- <DatesLoginSummary /> -->
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :lg="12" :sm="24"> <el-col :lg="12" :sm="24">
<Left /> <LeftSummary />
</el-col> </el-col>
<el-col :lg="12" :sm="24"> <el-col :lg="12" :sm="24">
<DataSummary /> <DataSummary />
</el-col> </el-col>
</el-row> </el-row>
<TrendSummary /> <RankSummary />
<TopAndLatestSummary />
</div> </div>
<Page403 v-else /> <Page403 v-else />
</Page> </Page>
@@ -22,21 +19,19 @@
<script> <script>
import { Announcement } from '@/components' import { Announcement } from '@/components'
import { Page } from '@/layout/components' import { Page } from '@/layout/components'
import TopAndLatestSummary from './TopAndLatestSummary'
import Page403 from '@/views/403' import Page403 from '@/views/403'
import DataSummary from './DataSummary' import DataSummary from './DataSummary'
import Left from './Left' import LeftSummary from './LeftSummary'
import TrendSummary from './TrendSummary' import RankSummary from './RankSummary'
export default { export default {
name: 'Dashboard', name: 'Dashboard',
components: { components: {
Page, Page,
TopAndLatestSummary,
Announcement, Announcement,
DataSummary, DataSummary,
Left, LeftSummary,
TrendSummary, RankSummary,
Page403 Page403
}, },
data() { data() {