mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-15 14:24:39 +00:00
perf: Change secret dashboard (#4473)
* perf: Change secret dashboard * style: Modify layout --------- Co-authored-by: feng <1304903146@qq.com> Co-authored-by: zhaojisen <1301338853@qq.com>
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'AccountChangeDashboard'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>账号改密汇总</h1>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -18,7 +18,7 @@ export default {
|
||||
{
|
||||
title: this.$t('Overview'),
|
||||
name: 'AccountChangeDashboard',
|
||||
component: () => import('@/views/accounts/AccountChangeSecret/AccountChangeDashboard.vue')
|
||||
component: () => import('@/views/dashboard/ChangeSecret')
|
||||
},
|
||||
{
|
||||
title: this.$t('AccountChangeSecret'),
|
||||
|
||||
84
src/views/dashboard/ChangeSecret/AccountSummary.vue
Normal file
84
src/views/dashboard/ChangeSecret/AccountSummary.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class="head">
|
||||
<Title :config="config" />
|
||||
</div>
|
||||
<LineChart v-if="loading" v-bind="lineChartConfig" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Title from '../components/Title.vue'
|
||||
import LineChart from './LineChart.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Title,
|
||||
LineChart
|
||||
},
|
||||
props: {
|
||||
days: {
|
||||
type: [Number, String],
|
||||
default: '7'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
config: {
|
||||
title: '账号成功/失败情况',
|
||||
tip: '账号成功/失败情况'
|
||||
},
|
||||
lineChartConfig: {
|
||||
datesMetrics: [],
|
||||
primaryData: [1],
|
||||
primaryName: '成功',
|
||||
secondaryData: [1],
|
||||
secondaryName: '失败'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
days() {
|
||||
this.getMetricData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
try {
|
||||
this.getMetricData()
|
||||
} finally {
|
||||
this.loading = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getMetricData() {
|
||||
const url = `/api/v1/accounts/change-secret-dashboard/?daily_success_and_failure_metrics=1&days=${this.days}`
|
||||
const data = await this.$axios.get(url)
|
||||
const success = data?.dates_metrics_total_count_success
|
||||
const failed = data?.dates_metrics_total_count_failed
|
||||
this.lineChartConfig.datesMetrics = data?.dates_metrics_date
|
||||
if (success.length > 0) {
|
||||
this.lineChartConfig.primaryData = success
|
||||
}
|
||||
if (failed.length > 0) {
|
||||
this.lineChartConfig.secondaryData = failed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
margin-top: 16px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
122
src/views/dashboard/ChangeSecret/CardSummary.vue
Normal file
122
src/views/dashboard/ChangeSecret/CardSummary.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="16">
|
||||
<el-col :lg="12" :sm="24" class="margin-top-10">
|
||||
<SummaryCountCard :config="logConfig" :items="LogItems" />
|
||||
</el-col>
|
||||
<el-col :lg="12" :sm="24" class="margin-top-10">
|
||||
<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_change_secrets: 0,
|
||||
total_count_periodic_change_secrets: 0,
|
||||
total_count_change_secret_assets: 0,
|
||||
total_count_change_secret_executions: 0,
|
||||
total_count_success_change_secret_executions: 0,
|
||||
total_count_failed_change_secret_executions: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
LogItems() {
|
||||
return [
|
||||
{
|
||||
title: '任务数',
|
||||
body: {
|
||||
route: { name: `LoginLogList` },
|
||||
count: this.data.total_count_change_secrets
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '定时任务数',
|
||||
body: {
|
||||
route: { name: `LoginLogList` },
|
||||
count: this.data.total_count_periodic_change_secrets
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '资产数',
|
||||
body: {
|
||||
route: { name: `OperateLogList` },
|
||||
count: this.data.total_count_change_secret_assets
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
sessionItems() {
|
||||
return [
|
||||
{
|
||||
title: '任务执行数',
|
||||
body: {
|
||||
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
|
||||
count: this.data.total_count_change_secret_executions
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '成功数',
|
||||
body: {
|
||||
route: { name: `SessionList`, params: { activeMenu: 'OfflineList' }},
|
||||
count: this.data.total_count_success_change_secret_executions
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '失败数',
|
||||
body: {
|
||||
route: { name: `FtpLog` },
|
||||
count: this.data.total_count_failed_change_secret_executions
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
days() {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
this.data = await this.$axios.get(`/api/v1/accounts/change-secret-dashboard/?days=${this.days}
|
||||
&total_count_change_secrets=1
|
||||
&total_count_periodic_change_secrets=1
|
||||
&total_count_change_secret_assets=1
|
||||
&total_count_change_secret_status=1
|
||||
`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.margin-top-10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
92
src/views/dashboard/ChangeSecret/DataSummary.vue
Normal file
92
src/views/dashboard/ChangeSecret/DataSummary.vue
Normal file
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="16">
|
||||
<el-col :lg="24" :sm="12" class="margin-top-10">
|
||||
<SummaryCountCard :config="logConfig" :items="LogItems" />
|
||||
</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: '当前正在改密情况'
|
||||
},
|
||||
data: {
|
||||
total_count_ongoing_change_secret: 0,
|
||||
total_count_ongoing_change_secret_assets: 0,
|
||||
total_count_ongoing_change_secret_accounts: 0,
|
||||
total_count_online_sessions: 0,
|
||||
total_count_history_sessions: 0,
|
||||
total_count_ftp_logs: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
LogItems() {
|
||||
return [
|
||||
{
|
||||
title: '任务执行数',
|
||||
body: {
|
||||
route: { name: `LoginLogList` },
|
||||
count: this.data.total_count_ongoing_change_secret
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '资产数',
|
||||
body: {
|
||||
route: { name: `LoginLogList` },
|
||||
count: this.data.total_count_ongoing_change_secret_assets
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '账号数',
|
||||
body: {
|
||||
route: { name: `OperateLogList` },
|
||||
count: this.data.total_count_ongoing_change_secret_accounts
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
days() {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
this.data = await this.$axios.get(`/api/v1/index/?days=${this.days}
|
||||
&total_count_user_login_logs=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-10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
90
src/views/dashboard/ChangeSecret/FailedAccountSummary.vue
Normal file
90
src/views/dashboard/ChangeSecret/FailedAccountSummary.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<HomeCard :table-config="tableConfig" v-bind="cardConfig" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HomeCard from '@/views/workbench/myhome/components/HomeCard.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HomeCard
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
cardConfig: {
|
||||
title: '改密失败账号'
|
||||
},
|
||||
tableConfig: {
|
||||
url: '/api/v1/terminal/my-sessions/?limit=5',
|
||||
columns: [
|
||||
'id', 'asset', 'account', 'remote_addr', 'protocol'
|
||||
],
|
||||
columnsMeta: {
|
||||
id: {
|
||||
prop: 'id',
|
||||
align: 'center',
|
||||
formatter: function(row, column, cellValue, index) {
|
||||
const label = index + 1
|
||||
const route = { to: { name: 'SessionDetail', params: { id: row.id }}}
|
||||
if (vm.$hasPerm('terminal.view_session')) {
|
||||
return <router-link {...{ attrs: route }} >{label}</router-link>
|
||||
} else {
|
||||
return label
|
||||
}
|
||||
}
|
||||
},
|
||||
asset: {
|
||||
'min-width': 200,
|
||||
label: this.$t('Asset')
|
||||
},
|
||||
account: {
|
||||
'min-width': 100
|
||||
},
|
||||
command_amount: {
|
||||
align: 'center',
|
||||
label: this.$t('Command')
|
||||
},
|
||||
remote_addr: {
|
||||
width: 180,
|
||||
label: this.$t('RemoteAddr')
|
||||
},
|
||||
protocol: {
|
||||
width: 100,
|
||||
label: this.$t('Protocol'),
|
||||
el: {
|
||||
disabled: false
|
||||
},
|
||||
sortable: false
|
||||
},
|
||||
actions: {
|
||||
align: 'center',
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
hasClone: false,
|
||||
hasUpdate: false,
|
||||
extraActions: [
|
||||
{
|
||||
name: 'connect',
|
||||
icon: 'fa-desktop',
|
||||
plain: true,
|
||||
type: 'primary',
|
||||
can: ({ row }) => row.is_active,
|
||||
callback: ({ row }) => {
|
||||
window.open(`/luna/?login_to=${row.asset_id}&login_account=${row.account_id}`, '_blank')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
hasSelection: false,
|
||||
paginationSize: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
260
src/views/dashboard/ChangeSecret/LineChart.vue
Normal file
260
src/views/dashboard/ChangeSecret/LineChart.vue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div>
|
||||
<echarts
|
||||
ref="echarts"
|
||||
:options="options"
|
||||
:autoresize="true"
|
||||
theme="light"
|
||||
class="disabled-when-print"
|
||||
@finished="getDataUrl"
|
||||
/>
|
||||
<img v-if="dataUrl" :src="dataUrl" class="enabled-when-print" style="display: none;width: 100%;">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import * as echarts from 'echarts'
|
||||
import { mix } from '@/utils/theme/color'
|
||||
|
||||
export default {
|
||||
name: 'LoginMetric',
|
||||
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 {
|
||||
dataUrl: '',
|
||||
metricsData: {
|
||||
dates_metrics_date: [],
|
||||
dates_metrics_total_count_failed: [],
|
||||
dates_metrics_total_count_success: []
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mixColors() {
|
||||
const documentStyle = document.documentElement.style
|
||||
const primary = documentStyle.getPropertyValue('--color-primary')
|
||||
const colorValue = primary.replace(/#/g, '')
|
||||
const TwoLevelColor = mix(colorValue, 'ffffff', 38)
|
||||
const ThreeLevelColor = mix(colorValue, 'ffffff', 20)
|
||||
const shadowColor = mix(colorValue, 'ffffff', 1)
|
||||
return {
|
||||
primary,
|
||||
TwoLevelColor,
|
||||
ThreeLevelColor,
|
||||
shadowColor
|
||||
}
|
||||
},
|
||||
options() {
|
||||
const { primary, TwoLevelColor, ThreeLevelColor, shadowColor } = this.mixColors
|
||||
return {
|
||||
title: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
label: {
|
||||
backgroundColor: '#6a7985'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
left: 'auto',
|
||||
icon: 'rect',
|
||||
// 图例标记的图形宽度
|
||||
itemWidth: 10,
|
||||
itemHeight: 10
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
color: [primary, '#F3B44B'],
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#8F959E'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
// 坐标轴颜色
|
||||
color: '#8F959E'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
data: this.datesMetrics
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '',
|
||||
axisLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#8F959E'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
// 坐标轴线样式
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#EFF0F1'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
animationDuration: 500,
|
||||
series: [
|
||||
{
|
||||
name: this.primaryName,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
// 区域填充样式
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[{
|
||||
offset: 0,
|
||||
color: primary
|
||||
}, {
|
||||
offset: 0.6,
|
||||
color: TwoLevelColor
|
||||
},
|
||||
{
|
||||
offset: 0.8,
|
||||
color: ThreeLevelColor
|
||||
}
|
||||
],
|
||||
false
|
||||
),
|
||||
shadowColor: shadowColor,
|
||||
shadowBlur: 5
|
||||
}
|
||||
},
|
||||
data: this.primaryData
|
||||
},
|
||||
{
|
||||
name: this.secondaryName,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
// 区域填充样式
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[{
|
||||
offset: 0,
|
||||
color: 'rgba(249, 199, 79, 0.6)'
|
||||
}, {
|
||||
offset: 0.6,
|
||||
color: 'rgba(249, 199, 79, 0.2)'
|
||||
},
|
||||
{
|
||||
offset: 0.8,
|
||||
color: 'rgba(249, 199, 79, 0.1)'
|
||||
}
|
||||
],
|
||||
false
|
||||
),
|
||||
shadowColor: 'rgba(249, 199, 79, 0.1)',
|
||||
shadowBlur: 6
|
||||
}
|
||||
},
|
||||
data: this.secondaryData
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
range() {
|
||||
this.getMetricData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getMetricData()
|
||||
},
|
||||
methods: {
|
||||
getDataUrl() {
|
||||
const instance = this.$refs.echarts.echartsInstance
|
||||
if (instance) {
|
||||
this.dataUrl = instance.getDataURL()
|
||||
}
|
||||
},
|
||||
getMetricData() {
|
||||
this.getDataUrl()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.echarts {
|
||||
width: 100%;
|
||||
height: 272px;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.disabled-when-print {
|
||||
display: none;
|
||||
}
|
||||
.enabled-when-print {
|
||||
display: inherit !important;
|
||||
}
|
||||
.print-margin {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
60
src/views/dashboard/ChangeSecret/TrendSummary.vue
Normal file
60
src/views/dashboard/ChangeSecret/TrendSummary.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<Title :config="config" style="margin-bottom: 16px;" />
|
||||
<ColumnChart v-bind="columnChartConfig" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Title from '../components/Title.vue'
|
||||
import ColumnChart from '../components/ColumnChart'
|
||||
|
||||
export default {
|
||||
components: { Title, ColumnChart },
|
||||
props: {
|
||||
days: {
|
||||
type: [Number, String],
|
||||
default: '7'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
title: this.$t('SessionConnectTrend'),
|
||||
tip: this.$t('SessionConnectTrend')
|
||||
},
|
||||
columnChartConfig: {
|
||||
datesMetrics: [],
|
||||
primaryData: [0],
|
||||
primaryName: this.$t('LoginUserToday')
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
days() {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
const data = await this.$axios.get(`/api/v1/index/?dates_metrics=1&days=${this.days}`)
|
||||
const loginTotal = data?.dates_metrics_total_count_login
|
||||
this.columnChartConfig.datesMetrics = data.dates_metrics_date
|
||||
if (loginTotal.length > 0) {
|
||||
this.columnChartConfig.primaryData = loginTotal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
margin-top: 16px;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
80
src/views/dashboard/ChangeSecret/index.vue
Normal file
80
src/views/dashboard/ChangeSecret/index.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<Page>
|
||||
<div v-if="this.$hasPerm('accounts.view_changesecretautomation')">
|
||||
|
||||
<div>
|
||||
<SwitchDate class="switch-date" @change="onChange" />
|
||||
</div>
|
||||
|
||||
<el-row type="flex">
|
||||
|
||||
<el-col :span="18">
|
||||
<CardSummary class="card-summary" :days="days" />
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6">
|
||||
<DataSummary class="data-summary" :days="days" style="margin-left: 1rem" />
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
||||
<el-row type="flex" :gutter="20">
|
||||
<el-col :span="12" style="margin-top: 2rem">
|
||||
<FailedAccountSummary />
|
||||
</el-col>
|
||||
<el-col :span="12" style="margin-top: 2rem">
|
||||
<FailedAccountSummary />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row type="flex" style="flex-direction: column">
|
||||
<el-col :span="24">
|
||||
<AccountSummary class="account-summary" :days="days" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
<Page403 v-else />
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Page } from '@/layout/components'
|
||||
import SwitchDate from '../components/SwitchDate'
|
||||
import FailedAccountSummary from './FailedAccountSummary.vue'
|
||||
import DataSummary from './DataSummary.vue'
|
||||
import CardSummary from './CardSummary.vue'
|
||||
import AccountSummary from './AccountSummary.vue'
|
||||
import Page403 from '@/views/403'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AccountSummary,
|
||||
Page,
|
||||
SwitchDate,
|
||||
DataSummary,
|
||||
FailedAccountSummary,
|
||||
CardSummary,
|
||||
Page403
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
days: localStorage.getItem('dashboardDays') || '7'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(val) {
|
||||
this.days = val
|
||||
localStorage.setItem('dashboardDays', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.page ::v-deep .page-heading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user