mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-15 14:24:39 +00:00
perf: 调整审计台仪表盘显示内容
This commit is contained in:
130
src/views/dashboard/Audit/CardSummary.vue
Normal file
130
src/views/dashboard/Audit/CardSummary.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="16">
|
||||
<el-col :lg="12" :sm="24" class="margin-top-16">
|
||||
<SummaryCountCard :config="logConfig" :items="LogItems" />
|
||||
</el-col>
|
||||
<el-col :lg="12" :sm="24" class="margin-top-16">
|
||||
<SummaryCountCard :config="sessionConfig" :items="sessionItems" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SummaryCountCard from '../components/SummaryCountCard.vue'
|
||||
|
||||
export default {
|
||||
components: { SummaryCountCard },
|
||||
props: {
|
||||
days: {
|
||||
type: [Number, String],
|
||||
default: 7
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
logConfig: {
|
||||
title: '日志数据',
|
||||
tip: '日志数据'
|
||||
},
|
||||
sessionConfig: {
|
||||
title: '会话数据',
|
||||
tip: '会话数据'
|
||||
},
|
||||
data: {
|
||||
total_count_login_users: 0,
|
||||
total_count_operate_logs: 0,
|
||||
total_count_change_password_logs: 0,
|
||||
total_count_online_sessions: 0,
|
||||
total_count_history_sessions: 0,
|
||||
total_count_ftp_logs: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
LogItems() {
|
||||
return [
|
||||
{
|
||||
title: '登录数',
|
||||
body: {
|
||||
route: { name: `LoginLog` },
|
||||
count: this.data.total_count_login_users,
|
||||
disabled: !this.$hasPerm('audits.view_userloginlog')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作日志数',
|
||||
body: {
|
||||
route: { name: `OperateLog` },
|
||||
count: this.data.total_count_operate_logs,
|
||||
disabled: !this.$hasPerm('audits.view_operatelog')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '改密日志数',
|
||||
body: {
|
||||
route: { name: `PasswordChangeLog` },
|
||||
count: this.data.total_count_change_password_logs,
|
||||
disabled: !this.$hasPerm('audits.view_passwordchangelog')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
sessionItems() {
|
||||
return [
|
||||
{
|
||||
title: '在线会话数',
|
||||
body: {
|
||||
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
|
||||
count: this.data.total_count_online_sessions,
|
||||
disabled: !this.$hasPerm('terminal.view_session')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '历史会话数',
|
||||
body: {
|
||||
route: { name: `SessionList`, params: { activeMenu: 'OfflineList' }},
|
||||
count: this.data.total_count_history_sessions,
|
||||
disabled: !this.$hasPerm('terminal.view_session')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '文件传输数',
|
||||
body: {
|
||||
route: { name: `FtpLog` },
|
||||
count: this.data.total_count_ftp_logs,
|
||||
disabled: !this.$hasPerm('audits.view_ftplog')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
days() {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
this.data = await this.$axios.get(`/api/v1/index/?days=${this.days}
|
||||
&total_count_login_users=1
|
||||
&total_count_operate_logs=1
|
||||
&total_count_change_password_logs=1
|
||||
&total_count_online_sessions=1
|
||||
&total_count_history_sessions=1
|
||||
&total_count_ftp_logs=1
|
||||
`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.margin-top-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
93
src/views/dashboard/Audit/DataSummary.vue
Normal file
93
src/views/dashboard/Audit/DataSummary.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<el-row :gutter="16">
|
||||
<el-col :lg="12" :sm="12" class="margin-top-16">
|
||||
<DataCard :config="logConfig" />
|
||||
</el-col>
|
||||
<el-col :lg="12" :sm="12" class="margin-top-16">
|
||||
<DataCard :config="assetConfig" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DataCard from '../components/DataCard.vue'
|
||||
export default {
|
||||
components: {
|
||||
DataCard
|
||||
},
|
||||
props: {
|
||||
days: {
|
||||
type: [Number, String],
|
||||
default: 7
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const documentStyle = document.documentElement.style
|
||||
const themeColor = documentStyle.getPropertyValue('--color-primary')
|
||||
|
||||
return {
|
||||
logConfig: {
|
||||
title: '登录日志',
|
||||
tip: '登录日志总数',
|
||||
subTitle: '登录日志总数',
|
||||
icon: 'log',
|
||||
color: themeColor,
|
||||
chartTitle: '登录成功日志数',
|
||||
data: []
|
||||
},
|
||||
assetConfig: {
|
||||
title: '命令记录',
|
||||
tip: '命令记录总数',
|
||||
subTitle: '登录日志总数',
|
||||
icon: 'session',
|
||||
color: '#ED612B',
|
||||
chartTitle: '危险命令数',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
days() {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
const data = await this.$axios.get(`/api/v1/index/?days=${this.days}
|
||||
&total_count_user_login_logs=1
|
||||
&total_count_user_login_success_logs=1
|
||||
&total_count_commands=1
|
||||
&total_count_commands_danger=1
|
||||
`)
|
||||
const logs = [
|
||||
{ name: this.$t('dashboard.ActiveUser'), value: data.total_count_user_login_logs },
|
||||
{ name: this.$t('dashboard.InActiveUser'), value: data.total_count_user_login_success_logs }
|
||||
]
|
||||
this.$set(this.logConfig, 'data', logs)
|
||||
this.$set(this.logConfig, 'total', data.total_count_user_login_logs)
|
||||
this.$set(this.logConfig, 'active', data.total_count_user_login_success_logs)
|
||||
this.$set(this.logConfig, 'weekAdd', data.total_count_user_login_success_logs)
|
||||
const assets = [
|
||||
{ name: this.$t('dashboard.ActiveAsset'), value: data.total_count_commands },
|
||||
{ name: this.$t('dashboard.InActiveAsset'), value: data.total_count_commands_danger }
|
||||
]
|
||||
this.$set(this.assetConfig, 'data', assets)
|
||||
this.$set(this.assetConfig, 'total', data.total_count_commands)
|
||||
this.$set(this.assetConfig, 'active', data.total_count_commands_danger)
|
||||
this.$set(this.assetConfig, 'weekAdd', data.total_count_commands_danger)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.left, .right {
|
||||
display: inline-block;
|
||||
}
|
||||
.margin-top-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
117
src/views/dashboard/Audit/RightSummary.vue
Normal file
117
src/views/dashboard/Audit/RightSummary.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="box">
|
||||
<div class="head">
|
||||
<Title :config="config" />
|
||||
</div>
|
||||
<LineChart v-bind="chartConfig" />
|
||||
</div>
|
||||
<SummaryCountCard :config="config" :items="summaryItems" class="margin-top-16" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Title from '../components/Title.vue'
|
||||
import LineChart from '../components/LineChart.vue'
|
||||
import SummaryCountCard from '../components/SummaryCountCard.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Title,
|
||||
LineChart,
|
||||
SummaryCountCard
|
||||
},
|
||||
props: {
|
||||
days: {
|
||||
type: [Number, String],
|
||||
default: 7
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
title: '批量命令',
|
||||
tip: '批量命令'
|
||||
},
|
||||
chartConfig: {
|
||||
datesMetrics: [],
|
||||
secondaryName: '指标名称',
|
||||
secondaryData: [0]
|
||||
},
|
||||
data: {
|
||||
total_count_online_sessions: 0,
|
||||
total_count_history_sessions: 0,
|
||||
total_count_ftp_logs: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
summaryItems() {
|
||||
return [
|
||||
{
|
||||
title: '批量命令数',
|
||||
body: {
|
||||
route: { name: `CommandList` },
|
||||
count: this.data.total_count_online_sessions,
|
||||
disabled: !this.$hasPerm('terminal.view_command')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '未执行批量命令',
|
||||
body: {
|
||||
route: { name: `CommandList` },
|
||||
count: this.data.total_count_history_sessions,
|
||||
disabled: !this.$hasPerm('terminal.view_command')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '执行失败命令',
|
||||
body: {
|
||||
route: { name: `CommandList` },
|
||||
count: this.data.total_count_ftp_logs,
|
||||
disabled: !this.$hasPerm('audits.view_command')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
days() {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
const data = await this.$axios.get(`/api/v1/index/?days=${this.days}
|
||||
&total_count_online_sessions=1
|
||||
&total_count_history_sessions=1
|
||||
&total_count_ftp_logs=1
|
||||
&session_dates_metrics=1
|
||||
`)
|
||||
this.chartConfig.datesMetrics = data.dates_metrics_date
|
||||
if (this.chartConfig.secondaryData.length > 1) {
|
||||
this.chartConfig.secondaryData = data.dates_metrics_total_count_session
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.margin-top-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.box {
|
||||
margin-top: 16px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
.head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,28 +1,43 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<Title :config="config" style="margin-bottom: 16px;" />
|
||||
<ColumnChart />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Title from '../components/Title.vue'
|
||||
import ColumnChart from '../components/ColumnChart'
|
||||
export default {
|
||||
components: {
|
||||
ColumnChart
|
||||
},
|
||||
components: { Title, ColumnChart },
|
||||
props: {
|
||||
|
||||
days: {
|
||||
type: [Number, String],
|
||||
default: 7
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
config: {
|
||||
title: '用户登录趋势',
|
||||
tip: '用户登录趋势'
|
||||
},
|
||||
data: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
watch: {
|
||||
days() {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
|
||||
async getData() {
|
||||
this.data = await this.$axios.get(`/api/v1/index/?days=${this.days}
|
||||
&total_count_login_users=1`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
<Page>
|
||||
<div v-if="this.$hasPerm('rbac.view_audit')">
|
||||
<Announcement />
|
||||
<SwitchDate class="switch-date" @change="onChange" />
|
||||
<CardSummary :days="days" />
|
||||
<el-row :gutter="16">
|
||||
<el-col :lg="12" :sm="24">
|
||||
审计台仪表盘
|
||||
<DataSummary :days="days" />
|
||||
</el-col>
|
||||
<el-col :lg="12" :sm="24">
|
||||
审计台仪表盘
|
||||
<RightSummary :days="days" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<TrendSummary />
|
||||
<TrendSummary :days="days" />
|
||||
</div>
|
||||
<Page403 v-else />
|
||||
</Page>
|
||||
@@ -19,33 +21,53 @@
|
||||
<script>
|
||||
import { Announcement } from '@/components'
|
||||
import { Page } from '@/layout/components'
|
||||
import SwitchDate from '../components/SwitchDate'
|
||||
import TrendSummary from './TrendSummary'
|
||||
import DataSummary from './DataSummary'
|
||||
import CardSummary from './CardSummary.vue'
|
||||
import RightSummary from './RightSummary.vue'
|
||||
import Page403 from '@/views/403'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Page,
|
||||
Announcement,
|
||||
SwitchDate,
|
||||
TrendSummary,
|
||||
DataSummary,
|
||||
CardSummary,
|
||||
RightSummary,
|
||||
Page403
|
||||
},
|
||||
props: {
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
days: 7
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
onChange(val) {
|
||||
this.days = val
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.switch-date >>> .switch {
|
||||
background: #DEE0E3!important;
|
||||
.el-radio-button {
|
||||
.el-radio-button__inner {
|
||||
background: #DEE0E3!important;
|
||||
}
|
||||
}
|
||||
.el-radio-button.is-active {
|
||||
border-radius: 4px!important;
|
||||
padding: 4px 0!important;
|
||||
.el-radio-button__inner {
|
||||
color: var(--color-primary)!important;
|
||||
background-color: #FFF!important;
|
||||
border-radius: 4px!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,6 +26,8 @@ export default {
|
||||
title: this.$t('dashboard.UserData'),
|
||||
tip: this.$t('dashboard.UserData'),
|
||||
subTitle: this.$t('dashboard.UsersTotal'),
|
||||
icon: 'users',
|
||||
subIcon: 'broken-line',
|
||||
color: '#FFD260',
|
||||
chartTitle: this.$t('dashboard.LoginUserToday'),
|
||||
data: []
|
||||
@@ -34,6 +36,8 @@ export default {
|
||||
title: this.$t('dashboard.AssetData'),
|
||||
tip: this.$t('dashboard.AssetData'),
|
||||
subTitle: this.$t('dashboard.AssetsTotal'),
|
||||
icon: 'assets',
|
||||
subIcon: 'broken-line',
|
||||
color: themeColor,
|
||||
chartTitle: this.$t('dashboard.LoginAssetToday'),
|
||||
data: []
|
||||
|
||||
67
src/views/dashboard/Console/UserAssetActivity.vue
Normal file
67
src/views/dashboard/Console/UserAssetActivity.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class="head">
|
||||
<Title :config="config" />
|
||||
</div>
|
||||
<LineChart v-bind="metricsData" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Title from '../components/Title.vue'
|
||||
import LineChart from '../components/LineChart.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Title,
|
||||
LineChart
|
||||
},
|
||||
props: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
title: this.$t('dashboard.UserAssetActivity'),
|
||||
tip: this.$t('dashboard.UserAssetActivity')
|
||||
},
|
||||
metricsData: {
|
||||
datesMetrics: [],
|
||||
primaryData: [0],
|
||||
primaryName: this.$t('dashboard.LoginUsers'),
|
||||
secondaryData: [0],
|
||||
secondaryName: this.$t('dashboard.LoginAssets')
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getMetricData()
|
||||
},
|
||||
methods: {
|
||||
async getMetricData() {
|
||||
const url = '/api/v1/index/?dates_metrics=1&days=7'
|
||||
const data = await this.$axios.get(url)
|
||||
this.metricsData.datesMetrics = data.dates_metrics_date
|
||||
if (this.metricsData.primaryData.length > 1) {
|
||||
this.metricsData.primaryData = data.dates_metrics_total_count_active_users
|
||||
}
|
||||
if (this.metricsData.secondaryData.length > 1) {
|
||||
this.metricsData.secondaryData = data.dates_metrics_total_count_active_assets
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
margin-top: 16px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
.head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<el-row :gutter="16">
|
||||
<el-col :lg="12" :sm="24">
|
||||
<RealTimeSummary />
|
||||
<LineChart />
|
||||
<UserAssetActivity />
|
||||
</el-col>
|
||||
<el-col :lg="12" :sm="24">
|
||||
<DataSummary />
|
||||
@@ -23,7 +23,7 @@ import { Announcement } from '@/components'
|
||||
import { Page } from '@/layout/components'
|
||||
import Page403 from '@/views/403'
|
||||
import RealTimeSummary from '../components/RealTimeSummary.vue'
|
||||
import LineChart from '../components/LineChart.vue'
|
||||
import UserAssetActivity from './UserAssetActivity.vue'
|
||||
import DataSummary from './DataSummary'
|
||||
import AssetProportionSummary from './AssetProportionSummary'
|
||||
import RankSummary from './RankSummary'
|
||||
@@ -37,7 +37,7 @@ export default {
|
||||
AssetProportionSummary,
|
||||
RankSummary,
|
||||
RealTimeSummary,
|
||||
LineChart,
|
||||
UserAssetActivity,
|
||||
Page403
|
||||
},
|
||||
data() {
|
||||
@@ -48,5 +48,4 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<div class="head">
|
||||
<span class="title">
|
||||
用户/资产活跃情况
|
||||
<i class="fa fa-exclamation-circle icon" />
|
||||
</span>
|
||||
<span class="time">更新时间:2022-11-17</span>
|
||||
</div>
|
||||
<echarts
|
||||
ref="echarts"
|
||||
:options="options"
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
<div class="add">
|
||||
<span class="add-num">
|
||||
{{ $tc('dashboard.WeekAdd') }}:{{ config.weekAdd }}
|
||||
<svg-icon icon-class="broken-line" style="font-size: 18px;" />
|
||||
<svg-icon v-if="config.subIcon" :icon-class="config.subIcon" class="font" />
|
||||
</span>
|
||||
<span class="add-icon">
|
||||
<svg-icon icon-class="users" style="font-size: 18px;" />
|
||||
<svg-icon v-if="config.icon" :icon-class="config.icon" class="font" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -77,5 +77,8 @@ export default {
|
||||
height: 272px!important;
|
||||
}
|
||||
}
|
||||
.font {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class="head">
|
||||
<Title :config="config" />
|
||||
</div>
|
||||
<div>
|
||||
<echarts
|
||||
ref="echarts"
|
||||
:options="options"
|
||||
@@ -18,24 +15,38 @@
|
||||
<script>
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import * as echarts from 'echarts'
|
||||
import Title from './Title.vue'
|
||||
import { mix } from '@/utils/theme/color'
|
||||
|
||||
export default {
|
||||
name: 'LoginMetric',
|
||||
components: { Title },
|
||||
props: {
|
||||
range: {
|
||||
type: String,
|
||||
default: 'weekly'
|
||||
},
|
||||
datesMetrics: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
primaryName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
primaryData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
secondaryName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
secondaryData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
config: {
|
||||
title: this.$t('dashboard.UserAssetActivity'),
|
||||
tip: this.$t('dashboard.UserAssetActivity')
|
||||
},
|
||||
dataUrl: '',
|
||||
metricsData: {
|
||||
dates_metrics_date: [],
|
||||
@@ -79,12 +90,7 @@ export default {
|
||||
icon: 'rect',
|
||||
// 图例标记的图形宽度
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
data: [
|
||||
this.$t('dashboard.LoginCount'),
|
||||
this.$t('dashboard.LoginUsers'),
|
||||
this.$t('dashboard.LoginAssets')
|
||||
]
|
||||
itemHeight: 10
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
@@ -111,7 +117,7 @@ export default {
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
data: this.metricsData.dates_metrics_date
|
||||
data: this.datesMetrics
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
@@ -145,7 +151,7 @@ export default {
|
||||
animationDuration: 500,
|
||||
series: [
|
||||
{
|
||||
name: this.$t('dashboard.LoginUsers'),
|
||||
name: this.primaryName,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
@@ -174,10 +180,10 @@ export default {
|
||||
shadowBlur: 5
|
||||
}
|
||||
},
|
||||
data: this.metricsData.dates_metrics_total_count_active_users
|
||||
data: this.primaryData
|
||||
},
|
||||
{
|
||||
name: this.$t('dashboard.LoginAssets'),
|
||||
name: this.secondaryName,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
@@ -206,7 +212,7 @@ export default {
|
||||
shadowBlur: 6
|
||||
}
|
||||
},
|
||||
data: this.metricsData.dates_metrics_total_count_active_assets
|
||||
data: this.secondaryData
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -217,60 +223,15 @@ export default {
|
||||
this.getMetricData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getMetricData()
|
||||
},
|
||||
methods: {
|
||||
async getMetricData() {
|
||||
const url = '/api/v1/index/?dates_metrics=1&days=7'
|
||||
const data = await this.$axios.get(url)
|
||||
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]
|
||||
}
|
||||
},
|
||||
getDataUrl() {
|
||||
this.dataUrl = this.$refs.echarts.getDataURL({
|
||||
})
|
||||
this.dataUrl = this.$refs.echarts.getDataURL({})
|
||||
}
|
||||
}
|
||||
}
|
||||
</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;
|
||||
}
|
||||
.time {
|
||||
font-weight: 400;
|
||||
font-size: 10px;
|
||||
line-height: 26px;
|
||||
text-align: right;
|
||||
color: #8F959E;
|
||||
}
|
||||
}
|
||||
}
|
||||
.echarts {
|
||||
width: 100%;
|
||||
height: 266px;
|
||||
|
||||
@@ -2,18 +2,7 @@
|
||||
<div class="box">
|
||||
<div class="head">
|
||||
<Title :config="config" />
|
||||
<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>
|
||||
<SwitchDate @change="onChange" />
|
||||
</div>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
@@ -37,10 +26,12 @@
|
||||
|
||||
<script>
|
||||
import Title from './Title.vue'
|
||||
import SwitchDate from './SwitchDate.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Title
|
||||
Title,
|
||||
SwitchDate
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
@@ -53,24 +44,8 @@ export default {
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const defaultOptions = [
|
||||
{
|
||||
label: this.$t('dashboard.Today'),
|
||||
value: '1'
|
||||
},
|
||||
{
|
||||
label: this.$t('dashboard.Last7Days'),
|
||||
value: '7'
|
||||
},
|
||||
{
|
||||
label: this.$t('dashboard.Last30Days'),
|
||||
value: '30'
|
||||
}
|
||||
]
|
||||
return {
|
||||
select: '1',
|
||||
tableData: [],
|
||||
options: this.config.options || defaultOptions,
|
||||
tableUrl: this.config.url + `&days=1`
|
||||
}
|
||||
},
|
||||
@@ -83,8 +58,8 @@ export default {
|
||||
this.tableData = this.config.data ? res?.[this.config.data] : res
|
||||
})
|
||||
},
|
||||
onChange() {
|
||||
this.tableUrl = this.config.url + `&days=${this.select}`
|
||||
onChange(val) {
|
||||
this.tableUrl = this.config.url + `&days=${val}`
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
@@ -100,30 +75,6 @@ export default {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
.switch {
|
||||
background: #EFF0F1;
|
||||
border-radius: 4px;
|
||||
padding: 0 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 {
|
||||
|
||||
@@ -28,8 +28,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
options() {
|
||||
const { total, active, title } = this.config
|
||||
const percentage = ((active / total) * 100).toFixed(0)
|
||||
const { total, active = 0, title, color } = this.config
|
||||
const percentage = active === 0 ? 0 : ((active / total) * 100).toFixed(0)
|
||||
return {
|
||||
title: [
|
||||
{
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
left: '48%',
|
||||
top: '42%',
|
||||
textAlign: 'center',
|
||||
text: this.config.active,
|
||||
text: active,
|
||||
textStyle: {
|
||||
fontSize: 24,
|
||||
color: '#646A73'
|
||||
@@ -61,7 +61,7 @@ export default {
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
color: [this.config.color, 'rgba(43, 147, 124, 0.05)'],
|
||||
color: [color, 'rgba(43, 147, 124, 0.05)'],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
|
||||
77
src/views/dashboard/components/SummaryCountCard.vue
Normal file
77
src/views/dashboard/components/SummaryCountCard.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<div style="margin-bottom: 12px;">
|
||||
<Title :config="config" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<el-row type="flex" justify="space-between">
|
||||
<el-col v-for="item of items" :key="item.title" :md="8" :sm="12" :xs="12">
|
||||
<SummaryCard :title="item.title" :body="item.body" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Title from '../components/Title.vue'
|
||||
import SummaryCard from '../components/SummaryCard'
|
||||
|
||||
export default {
|
||||
components: { Title, SummaryCard },
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
title: '',
|
||||
tip: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
console.log(this.items, 'i---------------------------------------------------------')
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
padding: 20px;
|
||||
background: #FFFFFF;
|
||||
.content {
|
||||
.el-col {
|
||||
padding-left: 16px;
|
||||
border-left: 1px solid #EFF0F1;
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
.sub {
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: #646A73;
|
||||
}
|
||||
.num {
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
77
src/views/dashboard/components/SwitchDate.vue
Normal file
77
src/views/dashboard/components/SwitchDate.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<span>
|
||||
<el-radio-group
|
||||
v-model="select"
|
||||
class="switch"
|
||||
size="mini"
|
||||
@change="onChange"
|
||||
>
|
||||
<el-radio-button v-for="i in iOptions" :key="i.value" :label="i.value">
|
||||
{{ i.label }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const defaultOptions = [
|
||||
{
|
||||
label: this.$t('dashboard.Today'),
|
||||
value: '1'
|
||||
},
|
||||
{
|
||||
label: this.$t('dashboard.Last7Days'),
|
||||
value: '7'
|
||||
},
|
||||
{
|
||||
label: this.$t('dashboard.Last30Days'),
|
||||
value: '30'
|
||||
}
|
||||
]
|
||||
return {
|
||||
select: '1',
|
||||
iOptions: this.options.length > 0 ? this.options : defaultOptions
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(val) {
|
||||
this.$emit('change', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.switch {
|
||||
background: #EFF0F1;
|
||||
border-radius: 4px;
|
||||
padding: 0 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;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user