update fe

This commit is contained in:
Himit_ZH 2021-12-26 13:50:04 +08:00
parent f13330ee11
commit ab04560a37
12 changed files with 256 additions and 207 deletions

View File

@ -16,6 +16,7 @@ import top.hcode.hoj.pojo.vo.TrainingRankVo;
import top.hcode.hoj.pojo.vo.TrainingVo;
import top.hcode.hoj.pojo.vo.UserRolesVo;
import top.hcode.hoj.service.training.impl.*;
import top.hcode.hoj.utils.Constants;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@ -91,11 +92,6 @@ public class TrainingController {
return CommonResult.errorResponse("该训练不存在或不允许显示!");
}
CommonResult result = trainingRegisterService.checkTrainingAuth(training, request);
if (result != null) {
return result;
}
TrainingVo trainingVo = BeanUtil.copyProperties(training, TrainingVo.class);
TrainingCategory trainingCategory = trainingCategoryService.getTrainingCategoryByTrainingId(training.getId());
trainingVo.setCategoryName(trainingCategory.getName());
@ -106,9 +102,12 @@ public class TrainingController {
// 获取当前登录的用户
HttpSession session = request.getSession();
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
if (userRolesVo != null) {
if (userRolesVo != null
&& trainingRegisterService.checkTrainingAuth(training, request) == null) {
Integer userTrainingACProblemCount = trainingProblemService.getUserTrainingACProblemCount(userRolesVo.getUid(), trainingProblemIdList);
trainingVo.setAcCount(userTrainingACProblemCount);
} else {
trainingVo.setAcCount(0);
}
return CommonResult.successResponse(trainingVo, "success");

View File

@ -53,6 +53,9 @@ mybatis-plus:
type-aliases-package: top.hcode.hoj.pojo.entity
configuration:
cache-enabled: false
# 关闭打印 mybatis-plus 的 LOGO
global-config:
banner: false
shiro-redis:
enabled: true

View File

@ -62,6 +62,9 @@ mybatis-plus:
type-aliases-package: top.hcode.hoj.pojo.entity
configuration:
cache-enabled: false
# 关闭打印 mybatis-plus 的 LOGO
global-config:
banner: false
shiro-redis:
enabled: true
redis-manager:

View File

@ -31,6 +31,9 @@ spring:
mybatis-plus:
mapper-locations: classpath*:top/hcode/hoj/dao/xml/**Mapper.xml
type-aliases-package: top.hcode.hoj.pojo.entity
# 关闭打印 mybatis-plus 的 LOGO
global-config:
banner: false
logging:

View File

@ -342,8 +342,8 @@ const ojApi = {
})
},
// 注册私有训练
registerTraining(tid, training){
return ajax('/api/register-contest','post',{
registerTraining(tid, password){
return ajax('/api/register-training','post',{
data:{
tid,
password

View File

@ -313,7 +313,7 @@ export const m = {
StartAt: 'StartAt',
EndAt: 'EndAt',
Password_Required: 'Password Required',
To_Enter_Need_Password:'To enter the Private contest,please input the password!',
To_Enter_Need_Password:'To enter the Private contest, please input the password!',
Enter_the_contest_password:'Enter the contest password',
Enter:'Enter',
Overview: 'Overview',
@ -479,5 +479,8 @@ export const m = {
Training_Number:'Number',
Training_Auth:'Training Auth',
Training_Total_Problems:'Total Problems',
Record_List:'Record List'
Record_List:'Record List',
To_Enter_Training_Need_Password:'To enter the Private training, please input the password!',
Enter_the_training_password:'Enter the training password',
Register_training_successfully:'Register training successfully',
}

View File

@ -482,6 +482,8 @@ export const m = {
Training_Number:'训练编号',
Training_Auth:'训练权限',
Training_Total_Problems:'总题数',
Record_List:'记录榜单'
Record_List:'记录榜单',
To_Enter_Training_Need_Password:'请输入该私有训练的密码,方可进入',
Enter_the_training_password:'请输入私有训练的密码',
Register_training_successfully:'验证训练密码成功!',
}

View File

@ -1,7 +1,7 @@
import api from '@/common/api'
import { TRAINING_TYPE } from '@/common/constants'
const state = {
intoAccess: false, // 比赛进入权限
intoAccess: true, // 比赛进入权限
training: {
auth: TRAINING_TYPE.Public.name,
rankShowName:'username'
@ -33,7 +33,7 @@ const getters = {
// 是否需要显示密码验证框
trainingPasswordFormVisible: (state, getters) => {
// 如果是公开训练,或已注册过,管理员都不用再显示
return state.training.auth !== TRAINING_TYPE.Public.name &&!state.intoAccess && !getters.isTrainingAdmin
return !state.intoAccess && state.training.auth != TRAINING_TYPE.Public.name && !getters.isTrainingAdmin
}
}

View File

@ -187,6 +187,7 @@
field="realname"
min-width="96"
:title="$t('m.RealName')"
show-overflow
v-if="isContestAdmin"
>
</vxe-table-column>

View File

@ -192,6 +192,7 @@
min-width="96"
:title="$t('m.RealName')"
v-if="isContestAdmin"
show-overflow
>
</vxe-table-column>
<vxe-table-column

View File

@ -1,5 +1,5 @@
<template>
<el-row>
<div>
<el-card shadow class="training-header">
<div slot="header">
<span class="panel-title">{{ training.title }}</span>
@ -24,186 +24,190 @@
</div>
</template>
</el-card>
<div class="card-top">
<el-tabs @tab-click="tabClick" v-model="route_name">
<el-tab-pane name="TrainingDetails" lazy>
<span slot="label"
><i class="el-icon-s-home"></i>&nbsp;{{
$t('m.Training_Introduction')
}}</span
>
<el-row :gutter="30">
<el-col :sm="24" :md="7">
<el-card
v-if="trainingPasswordFormVisible"
class="password-form-card"
>
<div slot="header">
<span class="panel-title" style="color: #e6a23c;"
><i class="el-icon-warning">
{{ $t('m.Password_Required') }}</i
></span
>
</div>
<h3>
{{ $t('m.To_Enter_Training_Need_Password') }}
</h3>
<el-form>
<el-input
v-model="trainingPassword"
type="password"
:placeholder="$t('m.Enter_the_training_password')"
@keydown.enter.native="checkPassword"
style="width:70%"
/>
<el-button
type="primary"
@click="checkPassword"
:loading="btnLoading"
style="margin:5px"
>{{ $t('m.OK') }}</el-button
>
</el-form>
</el-card>
<el-card>
<div class="info-rows">
<div>
<span>
<span>{{ $t('m.Training_Number') }}</span>
</span>
<span>
<span>{{ training.rank }}</span>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Training_Auth') }}</span>
</span>
<span v-if="training.auth">
<el-tag
:type="TRAINING_TYPE[training.auth]['color']"
effect="dark"
>
{{ training.auth }}
</el-tag>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Training_Category') }}</span>
</span>
<span>
<span
><el-tag
size="medium"
class="category-item"
:style="
'color: #fff;background-color: ' +
training.categoryName +
';background-color: ' +
training.categoryColor
"
>{{ training.categoryName }}</el-tag
></span
>
</span>
</div>
<el-tabs @tab-click="tabClick" v-model="route_name" class="card-top">
<el-tab-pane name="TrainingDetails" lazy>
<span slot="label"
><i class="el-icon-s-home"></i>&nbsp;{{
$t('m.Training_Introduction')
}}</span
<div>
<span>
<span>{{ $t('m.Training_Total_Problems') }}</span>
</span>
<span>
<span>{{ training.problemCount }}</span>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Author') }}</span>
</span>
<span>
<span
><el-link
type="info"
@click="goUserHome(training.author)"
>{{ training.author }}</el-link
></span
>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Recent_Update') }}</span>
</span>
<span>
<span>{{ training.gmtModified | localtime }}</span>
</span>
</div>
</div>
</el-card>
</el-col>
<el-col :sm="24" :md="17">
<el-card>
<div slot="header">
<span class="panel-title">{{
$t('m.Training_Introduction')
}}</span>
</div>
<div
v-html="descriptionHtml"
v-highlight
class="markdown-body"
></div>
</el-card>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane
name="TrainingProblemList"
lazy
:disabled="trainingMenuDisabled"
>
<el-row :gutter="30">
<el-col :sm="24" :md="7">
<el-card
v-if="trainingPasswordFormVisible"
class="password-form-card"
style="text-align:center"
>
<div slot="header">
<span class="panel-title" style="color: #e6a23c;"
><i class="el-icon-warning">
{{ $t('m.Password_Required') }}</i
></span
>
</div>
<h3>
{{ $t('m.To_Enter_Need_Password') }}
</h3>
<el-form>
<el-input
v-model="trainingPassword"
type="password"
:placeholder="$t('m.Enter_the_contest_password')"
@keydown.enter.native="checkPassword"
style="width:70%"
/>
<el-button
type="primary"
@click="checkPassword"
style="margin:5px"
>{{ $t('m.OK') }}</el-button
>
</el-form>
</el-card>
<el-card>
<div class="info-rows">
<div>
<span>
<span>{{ $t('m.Training_Number') }}</span>
</span>
<span>
<span>{{ training.rank }}</span>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Training_Auth') }}</span>
</span>
<span v-if="training.auth">
<el-tag
:type="TRAINING_TYPE[training.auth]['color']"
effect="dark"
>
{{ training.auth }}
</el-tag>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Training_Category') }}</span>
</span>
<span>
<span
><el-tag
size="medium"
class="category-item"
:style="
'color: #fff;background-color: ' +
training.categoryName +
';background-color: ' +
training.categoryColor
"
>{{ training.categoryName }}</el-tag
></span
>
</span>
</div>
<span slot="label"
><i class="fa fa-list" aria-hidden="true"></i>&nbsp;{{
$t('m.Problem_List')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view
v-if="route_name === 'TrainingProblemList'"
></router-view>
</transition>
</el-tab-pane>
<div>
<span>
<span>{{ $t('m.Training_Total_Problems') }}</span>
</span>
<span>
<span>{{ training.problemCount }}</span>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Author') }}</span>
</span>
<span>
<span
><el-link
type="info"
@click="goUserHome(training.author)"
>{{ training.author }}</el-link
></span
>
</span>
</div>
<div>
<span>
<span>{{ $t('m.Recent_Update') }}</span>
</span>
<span>
<span>{{ training.gmtModified | localtime }}</span>
</span>
</div>
</div>
</el-card>
</el-col>
<el-col :sm="24" :md="17">
<el-card>
<div slot="header">
<span class="panel-title">{{
$t('m.Training_Introduction')
}}</span>
</div>
<div
v-html="descriptionHtml"
v-highlight
class="markdown-body"
></div>
</el-card>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane
name="TrainingProblemList"
lazy
:disabled="contestMenuDisabled"
>
<span slot="label"
><i class="fa fa-list" aria-hidden="true"></i>&nbsp;{{
$t('m.Problem_List')
}}</span
<el-tab-pane
name="TrainingRank"
lazy
:disabled="trainingMenuDisabled"
v-if="isPrivateTraining"
>
<transition name="el-zoom-in-bottom">
<router-view
v-if="route_name === 'TrainingProblemList'"
></router-view>
</transition>
</el-tab-pane>
<el-tab-pane
name="TrainingRank"
lazy
:disabled="contestMenuDisabled"
v-if="isPrivateTraining"
>
<span slot="label"
><i class="fa fa-bar-chart" aria-hidden="true"></i>&nbsp;{{
$t('m.Record_List')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view v-if="route_name === 'TrainingRank'"></router-view>
</transition>
</el-tab-pane>
</el-tabs>
</el-row>
<span slot="label"
><i class="fa fa-bar-chart" aria-hidden="true"></i>&nbsp;{{
$t('m.Record_List')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view v-if="route_name === 'TrainingRank'"></router-view>
</transition>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script>
import { TRAINING_TYPE } from '@/common/constants';
import { mapState, mapGetters } from 'vuex';
import { mapState, mapGetters, mapActions } from 'vuex';
import myMessage from '@/common/message';
import api from '@/common/api';
export default {
data() {
return {
route_name: 'TrainingDetails',
TRAINING_TYPE: {},
trainingPassword: '',
btnLoading: false,
customColors: [
{ color: '#909399', percentage: 20 },
{ color: '#f56c6c', percentage: 40 },
@ -215,19 +219,39 @@ export default {
},
created() {
this.route_name = this.$route.name;
if (this.route_name == 'ProblemDetails') {
if (this.route_name == 'TrainingProblemDetails') {
this.route_name = 'TrainingProblemList';
}
this.TRAINING_TYPE = Object.assign({}, TRAINING_TYPE);
this.$store.dispatch('getTraining');
this.$store.dispatch('getTraining').then((res) => {
this.changeDomTitle({ title: res.data.data.title });
});
},
methods: {
...mapActions(['changeDomTitle']),
tabClick(tab) {
let name = tab.name;
if (name !== this.$route.name) {
this.$router.push({ name: name });
}
},
checkPassword() {
if (this.trainingPassword === '') {
myMessage.warning(this.$i18n.t('m.Enter_the_training_password'));
return;
}
this.btnLoading = true;
api.registerTraining(this.training.id + '', this.trainingPassword).then(
(res) => {
myMessage.success(this.$i18n.t('m.Register_training_successfully'));
this.$store.commit('trainingIntoAccess', { intoAccess: true });
this.btnLoading = false;
},
(res) => {
this.btnLoading = false;
}
);
},
goUserHome(username) {
this.$router.push({
name: 'UserHome',
@ -263,6 +287,15 @@ export default {
}
},
},
watch: {
$route(newVal) {
this.route_name = newVal.name;
if (newVal.name == 'TrainingProblemDetails') {
this.route_name = 'TrainingProblemList';
}
this.changeDomTitle({ title: this.training.title });
},
},
beforeDestroy() {
this.$store.commit('clearTraining');
},
@ -281,6 +314,10 @@ export default {
font-size: 18px;
font-weight: 700;
}
.password-form-card {
text-align: center;
margin-bottom: 15px;
}
.info-rows > * {
margin-bottom: var(--info-row-margin-bottom, 1em);

View File

@ -1,9 +1,9 @@
<template>
<el-card shadow>
<div slot="header" class="rank-title">
<span class="panel-title">{{ $t('m.Record_List') }}</span>
</div>
<div>
<div style="margin-top:5px">
<el-card shadow>
<div slot="header" class="rank-title">
<span class="panel-title">{{ $t('m.Record_List') }}</span>
</div>
<vxe-table
round
border
@ -89,6 +89,7 @@
field="realname"
min-width="96"
:title="$t('m.RealName')"
show-overflow
v-if="isTrainingAdmin"
>
</vxe-table-column>
@ -111,8 +112,8 @@
</vxe-table-column>
<vxe-table-column
min-width="70"
v-for="problem in trainingProblemList"
:key="problem.problemId"
v-for="(problem, index) in trainingProblemList"
:key="index"
>
<template v-slot:header>
<span
@ -125,7 +126,7 @@
>
</template>
<template v-slot="{ row }">
<span v-if="row.submissionInfo[problem.problemId]">
<template v-if="row.submissionInfo[problem.problemId]">
<span
class="judge-status"
:style="
@ -147,20 +148,20 @@
: 0
}}ms)
</span>
</span>
</template>
</template>
</vxe-table-column>
</vxe-table>
</div>
<Pagination
:total="total"
:page-size.sync="limit"
:current.sync="page"
@on-change="getTrainingRankData"
@on-page-size-change="getTrainingRankData(1)"
:layout="'prev, pager, next, sizes'"
></Pagination>
</el-card>
<Pagination
:total="total"
:page-size.sync="limit"
:current.sync="page"
@on-change="getTrainingRankData"
@on-page-size-change="getTrainingRankData(1)"
:layout="'prev, pager, next, sizes'"
></Pagination>
</el-card>
</div>
</template>
<script>
import Avatar from 'vue-avatar';
@ -187,13 +188,11 @@ export default {
JUDGE_STATUS: {},
};
},
created() {
mounted() {
this.JUDGE_STATUS = Object.assign({}, JUDGE_STATUS);
if (!this.trainingProblemList.length) {
this.getTrainingProblemList();
}
},
mounted() {
this.trainingID = this.$route.params.trainingID;
this.getTrainingRankData();
},
@ -269,12 +268,10 @@ export default {
</script>
<style scoped>
.rank-title {
margin-bottom: 18px;
text-align: center;
}
/deep/.el-card__body {
padding: 20px !important;
padding-top: 0px !important;
}
.vxe-cell p,