add OI contest rank view

This commit is contained in:
zema1 2017-10-16 14:41:12 +08:00
parent 1b0d2f35ae
commit 7d58f81133
3 changed files with 279 additions and 22 deletions

View File

@ -3,35 +3,31 @@
<component :is="currentView"></component>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import ACMContestRank from './ACMContestRank.vue'
import OIContestRank from './OIContestRank.vue'
const NullComponent = {
name: 'null-component',
template: '<div></div>'
}
export default {
name: 'contest-rank',
components: {
ACMContestRank
},
data () {
return {
currentView: 'ACMContestRank'
}
},
methods: {
switchView () {
this.currentView = this.contest.rule_type === 'ACM' ? 'ACMContestRank' : 'ACMContestRank'
}
},
mounted () {
this.switchView()
ACMContestRank,
OIContestRank,
NullComponent
},
computed: {
contest () {
return this.$store.state.contest.contest
}
},
watch: {
'$route' () {
this.switchView()
...mapGetters(['contestRuleType']),
currentView () {
if (this.contestRuleType === null) {
return 'NullComponent'
}
return this.contestRuleType === 'ACM' ? 'ACMContestRank' : 'OIContestRank'
}
}
}

View File

@ -0,0 +1,262 @@
<template>
<Panel shadow>
<div slot="title">{{ contest.title }}</div>
<div slot="extra">
<Poptip trigger="hover" placement="left-start">
<Icon type="android-settings" size="20"></Icon>
<div slot="content" id="switches">
<p>
<span>Menu</span>
<i-switch v-model="showMenu"></i-switch>
<span>Chart</span>
<i-switch v-model="showChart"></i-switch>
</p>
<p style="margin-top: 10px">
<span>Auto Refresh(10s)</span>
<i-switch @on-change="handleAutoRefresh"></i-switch>
</p>
</div>
</Poptip>
</div>
<div v-if="showChart" class="echarts">
<ECharts :options="options" ref="chart" auto-resize></ECharts>
</div>
<Table ref="tableRank" :columns="columns" :data="dataRank" disabled-hover></Table>
<Pagination :total="total"
:page-size.sync=limit
@on-change="getContestRankData"
@on-page-size-change="getContestRankData(1)"
show-sizer></Pagination>
</Panel>
</template>
<script>
import Pagination from '~/Pagination'
import { mapActions, mapState } from 'vuex'
import { types } from '@/store'
import api from '@/api'
export default {
name: 'acm-contest-rank',
components: {
Pagination
},
data () {
return {
limit: 10,
total: 0,
showChart: true,
contestID: '',
columns: [
{
title: '#',
type: 'index',
width: 60
},
{
title: 'User',
align: 'center',
render: (h, params) => {
return h('Button', {
props: {
type: 'text'
},
style: {
color: '#57a3f3'
},
on: {
click: () => {
this.$router.push(
{
name: 'home',
query: {username: params.row.user.username}
})
}
}
}, params.row.user.username)
}
},
{
title: 'Total Score',
align: 'center',
width: 150,
key: 'total_score'
}
],
dataRank: [],
options: {
title: {
text: 'Top 10 Teams',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
toolbox: {
show: true,
feature: {
dataView: {show: true, readOnly: true},
magicType: {show: true, type: ['line', 'bar']},
saveAsImage: {show: true}
},
right: '10%'
},
calculable: true,
xAxis: [
{
type: 'category',
data: ['root']
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Score',
type: 'bar',
data: [0],
markPoint: {
data: [
{type: 'max', name: 'max'}
]
}
}
]
}
}
},
mounted () {
this.contestID = this.$route.params.contestID
this.getContestRankData(1)
if (this.contestProblems.length === 0) {
this.getContestProblems().then((res) => {
this.addTableColumns(res.data.data)
})
} else {
this.addTableColumns(this.contestProblems)
}
},
methods: {
...mapActions(['getContestProblems']),
getContestRankData (page = 1, refresh = false) {
let offset = (page - 1) * this.limit
if (this.showChart && !refresh) {
this.$refs.chart.showLoading({maskColor: 'rgba(250, 250, 250, 0.8)'})
}
api.getContestRank(offset, this.limit, this.$route.params.contestID).then(res => {
if (this.showChart && !refresh) {
this.$refs.chart.hideLoading()
}
this.total = res.data.data.total
if (page === 1) {
this.applyToChart(res.data.data.results.slice(0, 10))
}
this.applyToTable(res.data.data.results)
})
},
applyToChart (rankData) {
let [usernames, scores] = [[], []]
rankData.forEach(ele => {
usernames.push(ele.user.username)
scores.push(ele.total_score)
})
this.options.xAxis[0].data = usernames
this.options.series[0].data = scores
},
applyToTable (data) {
// deepcopy
let dataRank = JSON.parse(JSON.stringify(data))
// submission_infoproblem_id object,iview tabledata
// https://www.iviewui.com/components/table
dataRank.forEach((rank, i) => {
let info = rank.submission_info
Object.keys(info).forEach(problemID => {
dataRank[i][problemID] = info[problemID]
})
})
this.dataRank = dataRank
},
addTableColumns (problems) {
let i = 1
problems.forEach(ele => {
// problem titlecolumntable
let problemChar = '#' + String(i)
i += 1
this.columns.push({
align: 'center',
key: ele.id,
renderHeader: (h, params) => {
return h('Button', {
props: {
type: 'text',
size: 'large'
},
on: {
click: () => {
this.$router.push({
name: 'contest-problem-details',
params: {
contestID: this.contestID,
problemID: ele._id
}
})
}
}
}, problemChar)
},
render: (h, params) => {
return h('span', params.row[ele.id])
}
})
})
},
handleAutoRefresh (status) {
if (status === true) {
this.refreshFunc = setInterval(() => {
this.getContestRankData(1, true)
}, 10000)
} else {
clearInterval(this.refreshFunc)
}
}
},
computed: {
...mapState({
'contest': state => state.contest.contest,
'contestProblems': state => state.contest.contestProblems
}),
showMenu: {
get () {
return this.$store.state.contest.contestMenuVisible
},
set (value) {
this.$store.commit(types.CHANGE_CONTEST_MENU_VISIBLE, {visible: value})
if (this.showChart) {
this.$nextTick(() => {
this.$refs.chart.resize()
})
}
}
}
},
beforeDestroy () {
clearInterval(this.refreshFunc)
}
}
</script>
<style scoped lang="less">
.echarts {
margin: 30px auto 0 auto;
height: 350px;
width: 95%;
}
#switches {
span {
margin-left: 5px;
}
}
</style>

View File

@ -145,7 +145,6 @@
let bar = this.$refs.chart
bar.showLoading({maskColor: 'rgba(250, 250, 250, 0.8)'})
api.getUserRank(offset, this.limit, 'oi').then(res => {
console.log(res.data.data)
this.initData(res)
bar.hideLoading()
})