Add dashboard page
This commit is contained in:
parent
c108202e4e
commit
30295670ae
|
@ -18,7 +18,8 @@ const vendors = [
|
|||
'vuex',
|
||||
'axios',
|
||||
'moment',
|
||||
'raven-js'
|
||||
'raven-js',
|
||||
'browser-detect'
|
||||
];
|
||||
|
||||
// clear old dll
|
||||
|
|
|
@ -281,8 +281,14 @@ export default {
|
|||
data
|
||||
})
|
||||
},
|
||||
getLatestVersion () {
|
||||
return ajax('admin/new_version', 'get')
|
||||
getReleaseNotes () {
|
||||
return ajax('admin/versions', 'get')
|
||||
},
|
||||
getDashboardInfo () {
|
||||
return ajax('admin/dashboard_info', 'get')
|
||||
},
|
||||
getSessions () {
|
||||
return ajax('sessions', 'get')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import Vue from 'vue'
|
|||
import VueRouter from 'vue-router'
|
||||
// 引入 view 组件
|
||||
import { Announcement, Conf, Contest, ContestList, Home, JudgeServer, Login,
|
||||
Problem, ProblemList, User, PruneTestCase } from './views'
|
||||
Problem, ProblemList, User, PruneTestCase, Dashboard } from './views'
|
||||
Vue.use(VueRouter)
|
||||
|
||||
export default new VueRouter({
|
||||
|
@ -21,7 +21,7 @@ export default new VueRouter({
|
|||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: Announcement
|
||||
component: Dashboard
|
||||
},
|
||||
{
|
||||
path: '/announcement',
|
||||
|
|
|
@ -20,22 +20,6 @@
|
|||
Build Version: {{ version }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog :visible.sync="newVersionDialog" :title="'New Version Available! - ' + newVersion.title">
|
||||
<div class="version-body">
|
||||
<p>Level: {{newVersion.level}}</p>
|
||||
<div>
|
||||
<p>Details:</p>
|
||||
<ul v-for="detail in newVersion.details" :key="detail">
|
||||
<li v-html="detail"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Please upgrade to the latest version to enjoy the new features. </p>
|
||||
<p>Reference: <a href="http://docs.onlinejudge.me/#/onlinejudge/guide/upgrade" target="_blank">
|
||||
http://docs.onlinejudge.me/#/onlinejudge/guide/upgrade</a>
|
||||
</p>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -50,9 +34,7 @@
|
|||
name: 'app',
|
||||
data () {
|
||||
return {
|
||||
version: process.env.VERSION,
|
||||
newVersionDialog: false,
|
||||
newVersion: {}
|
||||
version: process.env.VERSION
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
@ -71,15 +53,6 @@
|
|||
}
|
||||
})
|
||||
},
|
||||
mounted () {
|
||||
api.getLatestVersion().then(resp => {
|
||||
let latestVersion = resp.data.data
|
||||
if (latestVersion && latestVersion.version) {
|
||||
this.newVersionDialog = true
|
||||
this.newVersion = latestVersion
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleCommand (command) {
|
||||
if (command === 'logout') {
|
||||
|
@ -162,8 +135,6 @@
|
|||
animation: fadeInUp .8s;
|
||||
}
|
||||
|
||||
.version-body {
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
<template>
|
||||
<el-row type="flex" :gutter="20">
|
||||
<el-col :md="10" :lg="8">
|
||||
<el-card class="admin-info">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<img class="avatar" src="/public/avatar/default.png"/>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<p class="admin-info-name">{{user.username}}</p>
|
||||
<p>{{user.admin_type}}</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<hr/>
|
||||
<div class="last-info">
|
||||
<p class="last-info-title">Last Login</p>
|
||||
<el-form label-width="80px" class="last-info-body">
|
||||
<el-form-item label="Time:">
|
||||
<span>{{session.last_activity | localtime}}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="IP:">
|
||||
<span>{{session.ip}}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="OS">
|
||||
<span>{{os}}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="Browser:">
|
||||
<span>{{browser}}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<panel title="System Overview">
|
||||
<p>Judge Server: {{infoData.judge_server_count}}</p>
|
||||
<p>HTTPS Status:
|
||||
<el-tag :type="https ? 'success' : 'danger'" size="small">
|
||||
{{ https ? 'Enabled' : 'Disabled'}}
|
||||
</el-tag>
|
||||
</p>
|
||||
<p>Force HTTPS:
|
||||
<el-tag :type="forceHttps ? 'success' : 'danger'" size="small">
|
||||
{{forceHttps ? 'Enabled' : 'Disabled'}}
|
||||
</el-tag>
|
||||
</p>
|
||||
<p>CDN HOST:
|
||||
<el-tag :type="cdn ? 'success' : 'warning'" size="small">
|
||||
{{cdn ? cdn : 'Not Use'}}
|
||||
</el-tag>
|
||||
</p>
|
||||
</panel>
|
||||
</el-col>
|
||||
|
||||
<el-col :md="14" :lg="16">
|
||||
<div class="info-container">
|
||||
<info-card color="#909399" icon="el-icon-fa-users" message="Total Users" iconSize="30px" class="info-item"
|
||||
:value="infoData.user_count"></info-card>
|
||||
<info-card color="#67C23A" icon="el-icon-fa-list" message="Today Submissions" class="info-item"
|
||||
:value="infoData.today_submission_count"></info-card>
|
||||
<info-card color="#409EFF" icon="el-icon-fa-trophy" message="Recent Contests" class="info-item"
|
||||
:value="infoData.recent_contest_count"></info-card>
|
||||
</div>
|
||||
<panel>
|
||||
<span slot="title" v-loading="loadingReleases">Release Notes
|
||||
<el-popover placement="right" trigger="hover">
|
||||
<i slot="reference" class="el-icon-fa-question-circle import-user-icon"></i>
|
||||
<p>Please upgrade to the latest version to enjoy the new features. </p>
|
||||
<p>Reference: <a href="http://docs.onlinejudge.me/#/onlinejudge/guide/upgrade" target="_blank">
|
||||
http://docs.onlinejudge.me/#/onlinejudge/guide/upgrade</a>
|
||||
</p>
|
||||
</el-popover>
|
||||
</span>
|
||||
|
||||
<el-collapse v-model="activeNames" v-for="release, index in releases" :key="'release' + index">
|
||||
<el-collapse-item :name="index+1">
|
||||
<template slot="title">
|
||||
<div v-if="release.new_version">{{release.title}}
|
||||
<el-tag size="mini" type="success">New Version</el-tag>
|
||||
</div>
|
||||
<span v-else>{{release.title}}</span>
|
||||
</template>
|
||||
<p>Level: {{release.level}}</p>
|
||||
<p>Details: </p>
|
||||
<div class="release-body">
|
||||
<ul v-for="detail in release.details">
|
||||
<li v-html="detail"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</panel>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import browserDetector from 'browser-detect'
|
||||
import InfoCard from '@admin/components/infoCard.vue'
|
||||
import api from '@admin/api'
|
||||
|
||||
export default {
|
||||
name: 'dashboard',
|
||||
components: {
|
||||
InfoCard
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
infoData: {
|
||||
user_count: 0,
|
||||
recent_contest_count: 0,
|
||||
today_submission_count: 0,
|
||||
judge_server_count: 0,
|
||||
env: {}
|
||||
},
|
||||
activeNames: [1],
|
||||
session: {},
|
||||
loadingReleases: true,
|
||||
releases: []
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
api.getDashboardInfo().then(resp => {
|
||||
this.infoData = resp.data.data
|
||||
}, () => {
|
||||
})
|
||||
api.getSessions().then(resp => {
|
||||
this.parseSession(resp.data.data)
|
||||
}, () => {
|
||||
})
|
||||
api.getReleaseNotes().then(resp => {
|
||||
this.loadingReleases = false
|
||||
let data = resp.data.data
|
||||
if (!data) {
|
||||
return
|
||||
}
|
||||
let currentVersion = data.local_version
|
||||
data.update.forEach(release => {
|
||||
if (release.version > currentVersion) {
|
||||
release.new_version = true
|
||||
}
|
||||
})
|
||||
this.releases = data.update
|
||||
}, () => {
|
||||
this.loadingReleases = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
parseSession (sessions) {
|
||||
let session = sessions[0]
|
||||
if (sessions.length > 1) {
|
||||
session = sessions.filter(s => !s.current_session).sort((a, b) => {
|
||||
return a.last_activity < b.last_activity
|
||||
})[0]
|
||||
}
|
||||
this.session = session
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['profile', 'user']),
|
||||
cdn () {
|
||||
return this.infoData.env.STATIC_CDN_HOST
|
||||
},
|
||||
https () {
|
||||
return document.URL.slice(0, 4) === 'https'
|
||||
},
|
||||
forceHttps () {
|
||||
return this.infoData.env.FORCE_HTTPS
|
||||
},
|
||||
browser () {
|
||||
let b = browserDetector(this.session.user_agent)
|
||||
if (b.name && b.version) {
|
||||
return b.name + ' ' + b.version
|
||||
} else {
|
||||
return 'Unknown'
|
||||
}
|
||||
},
|
||||
os () {
|
||||
let b = browserDetector(this.session.user_agent)
|
||||
return b.os ? b.os : 'Unknown'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.admin-info {
|
||||
margin-bottom: 20px;
|
||||
&-name {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
color: #409EFF;
|
||||
}
|
||||
.avatar {
|
||||
max-width: 100%;
|
||||
}
|
||||
.last-info {
|
||||
&-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
&-body {
|
||||
.el-form-item {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
.info-item {
|
||||
flex: 1 0 auto;
|
||||
min-width: 200px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,3 +1,4 @@
|
|||
import Dashboard from './general/Dashboard.vue'
|
||||
import Announcement from './general/Announcement.vue'
|
||||
import User from './general/User.vue'
|
||||
import Conf from './general/Conf.vue'
|
||||
|
@ -12,5 +13,5 @@ import Home from './Home.vue'
|
|||
|
||||
export {
|
||||
Announcement, User, Conf, JudgeServer, Problem, ProblemList, Contest,
|
||||
ContestList, Login, Home, PruneTestCase
|
||||
ContestList, Login, Home, PruneTestCase, Dashboard
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue