修正特殊判题,增加前台i18n

This commit is contained in:
Himit_ZH 2021-06-07 00:26:52 +08:00
parent b1ed8ca13c
commit 8668f34d64
54 changed files with 1863 additions and 721 deletions

View File

@ -66,6 +66,7 @@ Password: 开启SMTP服务后生成的随机授权码
| 2021-05-24 | 判题调度乐观锁改为悲观锁 | Himit_ZH |
| 2021-05-28 | 增加导入导出题目,增加用户页面的最近登录,开发正式结束,进入维护摸鱼 | Himit_ZH |
| 2021-06-02 | 大更新完善补充前端页面修正判题等待超时时间修补一系列bug | Himit_ZH |
| 2021-06-07 | 修正特殊判题增加前台i18n | Himit_ZH |

View File

@ -73,7 +73,7 @@ public class AdminJudgeController {
// 如果该题已经是AC通过状态更新该题目的用户ac做题表 user_acproblem
if (judge.getStatus().intValue() == Constants.Judge.STATUS_ACCEPTED.getStatus().intValue()) {
QueryWrapper<UserAcproblem> userAcproblemQueryWrapper = new QueryWrapper<>();
userAcproblemQueryWrapper.eq("pid", judge.getPid()).eq("uid", judge.getUid());
userAcproblemQueryWrapper.eq("submit_id", judge.getSubmitId());
userAcproblemService.remove(userAcproblemQueryWrapper);
}
}

View File

@ -15,7 +15,6 @@ import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
@ -26,10 +25,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.error.YAMLException;
import top.hcode.hoj.common.result.CommonResult;
import top.hcode.hoj.pojo.dto.ProblemDto;
import top.hcode.hoj.pojo.dto.QDOJProblemDto;
@ -271,6 +266,13 @@ public class FileController {
problemCaseQueryWrapper.eq("pid", pid);
List<ProblemCase> problemCaseList = problemCaseService.list(problemCaseQueryWrapper);
Assert.notEmpty(problemCaseList, "对不起,该题目的评测数据为空!");
boolean hasTestCase = true;
if (problemCaseList.get(0).getInput().endsWith(".in") && (problemCaseList.get(0).getOutput().endsWith(".out") ||
problemCaseList.get(0).getOutput().endsWith(".ans"))) {
hasTestCase = false;
}
Assert.isTrue(hasTestCase, "对不起,该题目的评测数据为空!");
workDir = Constants.File.FILE_DOWNLOAD_TMP_FOLDER.getPath() + File.separator + IdUtil.simpleUUID();
FileUtil.mkdir(workDir);
// 写入本地

View File

@ -169,7 +169,10 @@ public class AccountController {
}
QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
userInfoQueryWrapper.eq("email", email.trim());
UserInfo userInfo = userInfoDao.getOne(userInfoQueryWrapper);
UserInfo userInfo = userInfoDao.getOne(userInfoQueryWrapper, false);
if (userInfo == null) {
return CommonResult.errorResponse("对不起,该邮箱无注册用户,请重新检查!");
}
String code = IdUtil.simpleUUID().substring(0, 21); // 随机生成20位数字与字母的组合
redisUtils.set(Constants.Email.RESET_PASSWORD_KEY_PREFIX.getValue() + userInfo.getUsername(), code, 10 * 60);//默认链接有效10分钟
// 发送邮件
@ -454,11 +457,10 @@ public class AccountController {
public CommonResult changeEmail(@RequestBody Map params, HttpServletRequest request) {
String password = (String) params.get("password");
String oldEmail = (String) params.get("oldEmail");
String newEmail = (String) params.get("newEmail");
// 数据可用性判断
if (StringUtils.isEmpty(password) || StringUtils.isEmpty(newEmail) || StringUtils.isEmpty(oldEmail)) {
return CommonResult.errorResponse("请求参数不能为空!");
if (StringUtils.isEmpty(password) || StringUtils.isEmpty(newEmail)) {
return CommonResult.errorResponse("密码或新邮箱不能为空!");
}
if (!Validator.isEmail(newEmail)) {
return CommonResult.errorResponse("邮箱格式错误!");

View File

@ -239,7 +239,7 @@ public class JudgeController {
// 如果该题已经是AC通过状态更新该题目的用户ac做题表 user_acproblem
if (judge.getStatus().intValue() == Constants.Judge.STATUS_ACCEPTED.getStatus().intValue()) {
QueryWrapper<UserAcproblem> userAcproblemQueryWrapper = new QueryWrapper<>();
userAcproblemQueryWrapper.eq("pid", judge.getPid()).eq("uid", judge.getUid());
userAcproblemQueryWrapper.eq("submit_id", judge.getSubmitId());
userAcproblemService.remove(userAcproblemQueryWrapper);
}
}

View File

@ -3,7 +3,7 @@
<mapper namespace="top.hcode.hoj.dao.JudgeMapper">
<select id="getCommonJudgeList" resultType="top.hcode.hoj.pojo.vo.JudgeVo" useCache="false">
select j.uid,j.submit_id,j.submit_time,j.uid,j.username,j.uid,j.pid,j.status,j.share,
j.time,j.memory,j.length,j.language,j.cid,j.cpid,j.judger,p.problem_id as display_pid,p.title
j.time,j.memory,j.score,j.length,j.language,j.cid,j.cpid,j.judger,p.problem_id as display_pid,p.title
from judge j,problem p
<where>
p.id = j.pid AND j.cid = 0 AND j.cpid = 0
@ -30,7 +30,7 @@
<select id="getContestJudgeList" resultType="top.hcode.hoj.pojo.vo.JudgeVo" useCache="false">
select j.uid,j.submit_id,j.submit_time,j.uid,j.username,j.uid,cp.display_id,cp.display_title as title,
j.status,j.share,j.time,j.memory,j.length,j.language,j.cid,j.cpid,j.judger
j.status,j.share,j.time,j.memory,j.score,j.length,j.language,j.cid,j.cpid,j.judger
from judge j,contest_problem cp
<where>
j.pid=cp.pid AND j.cid = cp.cid
@ -88,6 +88,6 @@
COUNT(IF(status=4,status,NULL)) AS se,
COUNT(IF(status=8,status,NULL)) AS pa,
COUNT(*) AS total
FROM judge where pid=#{pid}
FROM judge where pid=#{pid} AND cid=0
</select>
</mapper>

View File

@ -49,7 +49,7 @@
, COUNT(IF(j.status = 8, STATUS, NULL)) AS pa
, COUNT(*) AS total
FROM judge j
WHERE j.pid
WHERE j.cid=0
GROUP BY j.pid
) j
ON j.pid = p.id

View File

@ -5,7 +5,7 @@
SELECT u.uuid as uid,u.nickname,u.username,u.signature,u.avatar,
(SELECT COUNT( DISTINCT pid ) FROM user_acproblem WHERE uid =u.uuid) AS solved,
(SELECT COUNT(pid) FROM user_acproblem WHERE uid =u.uuid) AS ac,
(SELECT COUNT(uid) FROM judge WHERE uid=u.uuid) AS total
(SELECT COUNT(uid) FROM judge WHERE uid=u.uuid AND cid=0) AS total
FROM user_info u WHERE u.status = 0
ORDER BY solved DESC,ac DESC
</select>
@ -17,7 +17,7 @@
and DATE(gmt_create) >= DATE_SUB(CURDATE(),INTERVAL 7 DAY) ) AS solved,
(SELECT COUNT(pid) FROM user_acproblem WHERE uid =u.uuid
and DATE(gmt_create) >= DATE_SUB(CURDATE(),INTERVAL 7 DAY)) AS ac,
(SELECT COUNT(uid) FROM judge WHERE uid=u.uuid) AS total
(SELECT COUNT(uid) FROM judge WHERE uid=u.uuid AND cid=0) AS total
FROM user_info u WHERE u.status = 0
ORDER BY solved DESC,ac DESC LIMIT 10
</select>
@ -43,7 +43,7 @@
FROM user_info u, (
SELECT MAX(score) AS score, uid, pid
FROM judge
WHERE score IS NOT NULL
WHERE cid=0 AND score IS NOT NULL
GROUP BY pid, uid
) s
WHERE u.status = 0
@ -70,14 +70,14 @@
<select id="getUserHomeInfo" resultMap="map_UserHomeVo">
SELECT u.uuid as uid,u.username,u.signature,u.school,u.github,u.blog,u.avatar,ur.rating,
(SELECT COUNT(uid) FROM judge WHERE uid=u.uuid) AS total
(SELECT COUNT(uid) FROM judge WHERE uid=u.uuid AND cid=0) AS total
FROM user_info u,user_record ur WHERE u.uuid = ur.uid AND u.status = 0 AND u.uuid = #{uid}
</select>
<!-- 子查询-->
<select id="getProblemScore" resultType="java.lang.Integer">
SELECT MAX(score) AS sum_score FROM judge
WHERE uid=#{uid} AND score IS NOT NULL GROUP BY pid
WHERE uid=#{uid} AND cid=0 AND score IS NOT NULL GROUP BY pid
</select>
</mapper>

View File

@ -54,6 +54,9 @@ public class JudgeVo {
@ApiModelProperty(value = "运行内存b")
private Integer memory;
@ApiModelProperty(value = "题目得分ACM题目默认为null")
private Integer score;
@ApiModelProperty(value = "代码长度")
private Integer length;

View File

@ -118,8 +118,8 @@ public class ProblemTestCaseUtils {
throw new SystemError("problemID:[" + problemId + "] test case has not found.", null, null);
}
// 可能zip上传记录的是文件名这是也是说明文件丢失了
if (problemCases.get(0).getInput().endsWith(".in") && (problemCases.get(0).getInput().endsWith(".out") ||
problemCases.get(0).getInput().endsWith(".ans"))) {
if (problemCases.get(0).getInput().endsWith(".in") && (problemCases.get(0).getOutput().endsWith(".out") ||
problemCases.get(0).getOutput().endsWith(".ans"))) {
throw new SystemError("problemID:[" + problemId + "] test case has not found.", null, null);
}

View File

@ -10873,6 +10873,11 @@
"integrity": "sha1-UylVzB6yCKPZkLOp+acFdGV+CPI=",
"dev": true
},
"vue-i18n": {
"version": "8.24.4",
"resolved": "https://registry.nlark.com/vue-i18n/download/vue-i18n-8.24.4.tgz",
"integrity": "sha1-sVhhTB332xg9nK3du3Ph1UAmlJI="
},
"vue-loader": {
"version": "15.9.4",
"resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-15.9.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-loader%2Fdownload%2Fvue-loader-15.9.4.tgz",

View File

@ -28,6 +28,7 @@
"vue-codemirror-lite": "^1.0.4",
"vue-cropper": "^0.5.5",
"vue-echarts": "^5.0.0-beta.0",
"vue-i18n": "^8.24.4",
"vue-m-message": "^3.0.0",
"vue-monoplasty-slide-verify": "^1.1.3",
"vue-particles": "^1.0.9",

View File

@ -21,19 +21,23 @@
<el-divider></el-divider>
</el-col>
<el-col :md="6" :xs="24">
<h1>Service</h1>
<p><a @click="goRoute('/status')">Judging Queue</a></p>
<p><a @click="goRoute('/developer')">System Info</a></p>
<h1>{{ $t('m.Service') }}</h1>
<p>
<a @click="goRoute('/status')">{{ $t('m.Judging_Queue') }}</a>
</p>
<p>
<a @click="goRoute('/developer')">{{ $t('m.System_Info') }}</a>
</p>
</el-col>
<el-col class="hr-none">
<el-divider></el-divider>
</el-col>
<el-col :md="6" :xs="24">
<h1>Development</h1>
<h1>{{ $t('m.Development') }}</h1>
<p class="mb-1">
<a :href="websiteConfig.projectUrl" target="_blank"
>Open Source</a
>
<a :href="websiteConfig.projectUrl" target="_blank">{{
$t('m.Open_Source')
}}</a>
</p>
<p class="mb-1"><a @click="goRoute('/#')">API</a></p>
</el-col>
@ -41,10 +45,10 @@
<el-divider></el-divider>
</el-col>
<el-col :md="6" :xs="24">
<h1>Support</h1>
<h1>{{ $t('m.Support') }}</h1>
<p>
<i class="fa fa-info-circle" aria-hidden="true"></i
><a @click="goRoute('/introduction')"> Help</a>
><a @click="goRoute('/introduction')"> {{ $t('m.Help') }}</a>
</p>
<p>
<i class="fa fa-envelope" aria-hidden="true"></i>
@ -64,6 +68,19 @@
target="_blank"
>{{ websiteConfig.projectName }}</a
>
<span style="margin-left:10px">
<el-dropdown @command="changeLanguage" placement="top">
<span class="el-dropdown-link">
<i class="fa fa-globe" aria-hidden="true">
{{ this.webLanguage == 'zh-CN' ? '简体中文' : 'English' }}</i
><i class="el-icon-arrow-up el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="zh-CN">简体中文</el-dropdown-item>
<el-dropdown-item command="en-US">English</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
</div>
</footer>
</div>
@ -79,7 +96,7 @@
<script>
import NavBar from '@/components/oj/common/NavBar';
import { mapActions, mapState } from 'vuex';
import { mapActions, mapState, mapGetters } from 'vuex';
export default {
name: 'app-content',
components: {
@ -102,6 +119,9 @@ export default {
return str.toUpperCase();
}
},
changeLanguage(language) {
this.$store.commit('changeWebLanguage', { language: language });
},
},
watch: {
$route(newVal, oldVal) {
@ -118,6 +138,7 @@ export default {
},
computed: {
...mapState(['websiteConfig']),
...mapGetters(['webLanguage']),
},
created: function() {
this.$nextTick(function() {

View File

@ -175,21 +175,21 @@ export const CONTEST_TYPE_REVERSE = {
'0': {
name:'Public',
color:'success',
tips:'公开赛,每个用户都可查看与提交',
tips:'Public_Tips',
submit:true, // 公开赛可看可提交
look:true,
},
'1':{
name:'Private',
color:'danger',
tips:'私有赛,需要密码才可查看与提交',
tips:'Private_Tips',
submit:false, // 私有赛 必须要密码才能看和提交
look:false,
},
'2':{
name:'Protect',
name:'Protected',
color:'warning',
tips:'保护赛,每个用户都可查看,提交需要密码',
tips:'Protected_Tips',
submit:false, //保护赛,可以看但是不能提交,提交需要附带比赛密码
look:true,
}
@ -198,7 +198,7 @@ export const CONTEST_TYPE_REVERSE = {
export const CONTEST_TYPE = {
PUBLIC: 0,
PRIVATE: 1,
PROTECT: 2
PROTECTED: 2
}
export const USER_TYPE = {

View File

@ -1,4 +1,8 @@
import moment from 'moment'
import i18n from '@/i18n'
// 全局设定语言
moment.locale(i18n.locale);
// convert utc time to localtime
function utcToLocal (utcDt, format = 'YYYY-MM-DD HH:mm:ss') {

View File

@ -4,11 +4,17 @@ import { STORAGE_KEY } from '@/common/constants'
import myMessage from '@/common/message'
import api from "@/common/api";
function submissionMemoryFormat (memory) {
if (memory === undefined || memory ===null || memory === '') return '--'
// 1048576 = 1024 * 1024
let t = parseInt(memory)
return String(t.toFixed(0)) + 'KB'
// function submissionMemoryFormat (memory) {
// if (memory === undefined || memory ===null || memory === '') return '--'
// // 1048576 = 1024 * 1024
// let t = parseInt(memory)
// return String(t.toFixed(0)) + 'KB'
// }
function submissionMemoryFormat(a,b){
if(0===a || a ===null || a === ''||a=== undefined)return"--";
var c=1024,d=b||1,e=["KB","MB","GB","TB","PB","EB","ZB","YB"],
f=Math.floor(Math.log(a)/Math.log(c));
return parseFloat((a/Math.pow(c,f)).toFixed(d))+" "+e[f]
}
function submissionTimeFormat (time) {

View File

@ -8,11 +8,11 @@
type="textarea"
:rows="8"
id="own-textarea"
placeholder="快来写下你的评论吧~😘"
:placeholder="$t('m.Come_and_write_down_your_comments') + '~😘'"
>
</el-input>
<div class="input-bottom">
<span title="emoji表情">
<span title="emoji">
<el-popover
placement="top-start"
width="300"
@ -34,7 +34,7 @@
</span>
<span
class="markdown-key"
title="行内代码"
:title="$t('m.Inline_Code')"
@click="addContentTips(0, false)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -53,7 +53,7 @@
</span>
<span
class="markdown-key"
title="代码块"
:title="$t('m.Code_Block')"
@click="addContentTips(1, false)"
>
<svg
@ -73,7 +73,7 @@
</span>
<span
class="markdown-key"
title="链接"
:title="$t('m.Link')"
@click="addContentTips(2, false)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -91,7 +91,7 @@
></span>
<span
class="markdown-key"
title="无序列表"
:title="$t('m.Unordered_list')"
@click="addContentTips(3, false)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -109,7 +109,7 @@
></span>
<span
class="markdown-key"
title="有序列表"
:title="$t('m.Ordered_List')"
@click="addContentTips(4, false)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -127,14 +127,17 @@
></span>
<span class="own-btn-comment">
<el-button class="btn" type="primary" round @click="commitComment"
><i class="el-icon-edit"> 提交评论</i></el-button
><i class="el-icon-edit">
{{ $t('m.Submit_Comment') }}</i
></el-button
>
</span>
</div>
</div>
<h3 class="comment-total">
<div class="text">
<span>全部评论</span><span class="number">{{ totalComment }}</span>
<span>{{ $t('m.All_Comment') }}</span
><span class="number">{{ totalComment }}</span>
</div>
</h3>
<div
@ -201,7 +204,7 @@
>
<i class="iconfont fa fa-thumbs-o-up"></i>
<span class="like-num">{{
item.likeNum > 0 ? item.likeNum + '人赞' : '赞'
item.likeNum > 0 ? item.likeNum + $t('m.Like') : $t('m.Like')
}}</span>
</span>
<span
@ -209,7 +212,7 @@
@click="showCommentInput(item)"
>
<i class="iconfont el-icon-chat-square"></i>
<span>回复</span>
<span>{{ $t('m.Reply') }}</span>
</span>
<span
v-if="item.fromUid == userInfo.uid || isAdminRole"
@ -217,7 +220,7 @@
@click="deleteComment(item, commentIndex)"
>
<i class="iconfont el-icon-delete"></i>
<span>删除</span>
<span>{{ $t('m.Delete') }}</span>
</span>
</div>
<div class="reply">
@ -254,7 +257,7 @@
v-if="reply.fromRole == 'admin'"
>ADM</span
>
<span class="reply-text">回复</span>
<span class="reply-text">{{ $t('m.Reply') }}</span>
<span
class="to-name"
:title="reply.toName"
@ -283,7 +286,7 @@
@click="showCommentInput(item, reply)"
>
<i class="iconfont el-icon-chat-square"></i>
<span>回复</span>
<span>{{ $t('m.Reply') }}</span>
</span>
<span
class="reply-opt reply-delete"
@ -291,20 +294,22 @@
@click="deleteReply(reply, commentIndex, replyIndex)"
>
<i class="iconfont el-icon-delete"></i>
<span>删除</span>
<span>{{ $t('m.Delete') }}</span>
</span>
</div>
</div>
<div class="view-more item" v-if="item.totalReplyNum > 3">
<b>{{ item.totalReplyNum }}</b
>条回复,
{{ $t('m.Reply_Total') }}<b>{{ item.totalReplyNum }}</b
>{{ $t('m.Replies') }},
<a
class="btn-more"
@click="showAllReply(item)"
v-if="!item.hadOpen"
>点击查看全部</a
>{{ $t('m.Click_Show_All') }}</a
>
<a class="btn-more" @click="pickWayReply(item)" v-else>收起</a>
<a class="btn-more" @click="pickWayReply(item)" v-else>{{
$t('m.Pick_up')
}}</a>
</div>
<transition name="fade">
<div class="input-wrapper" v-if="showItemId === item.id">
@ -318,7 +323,7 @@
>
</el-input>
<div class="input-bottom">
<span title="emoji表情">
<span title="emoji">
<el-popover
placement="top-start"
width="300"
@ -343,7 +348,7 @@
</span>
<span
class="markdown-key"
title="行内代码"
:title="$t('m.Inline_Code')"
@click="addContentTips(0, true)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -362,7 +367,7 @@
</span>
<span
class="markdown-key"
title="代码块"
:title="$t('m.Code_Block')"
@click="addContentTips(1, true)"
>
<svg
@ -382,7 +387,7 @@
</span>
<span
class="markdown-key"
title="链接"
:title="$t('m.Link')"
@click="addContentTips(2, true)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -400,7 +405,7 @@
></span>
<span
class="markdown-key"
title="无序列表"
:title="$t('m.Unordered_list')"
@click="addContentTips(3, true)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -418,7 +423,7 @@
></span>
<span
class="markdown-key"
title="有序列表"
:title="$t('m.Ordered_List')"
@click="addContentTips(4, true)"
><svg
xmlns="http://www.w3.org/2000/svg"
@ -441,7 +446,7 @@
round
@click="cancel"
size="small"
>取消</el-button
>{{ $t('m.Cancel') }}</el-button
>
<el-button
class="btn"
@ -449,7 +454,7 @@
round
@click="commitReply(item.id)"
size="small"
>发送</el-button
>{{ $t('m.OK') }}</el-button
>
</span>
</div>
@ -461,7 +466,7 @@
</div>
<div class="container loading-text" v-if="showloading">
<a style="background: #fff;padding:10px;" @click="loadMoreComment"
><span>加载更多...</span></a
><span>{{ $t('m.Load_More') }}...</span></a
>
</div>
</div>
@ -497,7 +502,7 @@ export default {
commentLikeMap: {},
facelistVisiable: false,
replyFacelistVisiable: false,
replyPlaceholder: '写下你的评论吧~',
replyPlaceholder: '',
query: {
limit: 10,
currentPage: 1,
@ -537,6 +542,9 @@ export default {
methods: {
init() {
let queryParams = Object.assign({}, this.query);
this.replyPlaceholder = this.$i18n.t(
'm.Come_and_write_down_your_comments'
);
api.getCommentList(queryParams).then((res) => {
let moreCommentList = res.data.data.commentList.records;
for (let i = 0; i < moreCommentList.length; i++) {
@ -582,7 +590,7 @@ export default {
*/
commitComment() {
if (!this.isAuthenticated) {
myMessage.warning('请先登录');
myMessage.warning(this.$i18n.t('m.Please_login_first'));
this.$store.dispatch('changeModalStatus', { visible: true });
return;
}
@ -609,7 +617,7 @@ export default {
commitReply() {
if (!this.isAuthenticated) {
myMessage.warning('请先登录');
myMessage.warning(this.$i18n.t('m.Please_login_first'));
this.$store.dispatch('changeModalStatus', { visible: true });
return;
}
@ -657,7 +665,9 @@ export default {
this.replyObj.toName = reply.fromName;
this.replyObj.toAvatar = reply.fromAvatar;
} else {
this.replyPlaceholder = '快来写下你的评论吧~';
this.replyPlaceholder = this.$i18n.t(
'm.Come_and_write_down_your_comments'
);
this.replyObj.commentId = item.id;
this.replyObj.toUid = item.fromUid;
this.replyObj.toName = item.fromName;
@ -671,9 +681,9 @@ export default {
*/
deleteComment(comment, commentIndex) {
this.$confirm('此操作将删除该评论及其所有回复, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$i18n.t('m.Delete_Comment_Tips'), 'Tips', {
confirmButtonText: this.$i18n.t('m.OK'),
cancelButtonText: this.$i18n.t('m.Cancel'),
type: 'warning',
})
.then(() => {
@ -697,9 +707,9 @@ export default {
*/
deleteReply(reply, commentIndex, replyIndex) {
this.$confirm('此操作将删除该回复, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$i18n.t('m.Delete_Reply_Tips'), 'Tips', {
confirmButtonText: this.$i18n.t('m.OK'),
cancelButtonText: this.$i18n.t('m.Cancel'),
type: 'warning',
})
.then(() => {
@ -794,10 +804,10 @@ export default {
tips = '[HOJ](https://hcode.top)';
break;
case 3:
tips = '\n- 无序列表';
tips = '\n- ...';
break;
case 4:
tips = '\n1. 有序列表';
tips = '\n1. ...';
break;
}
if (isReply) {

View File

@ -11,7 +11,7 @@
size="small"
icon="el-icon-refresh"
:loading="btnLoading"
>Refresh</el-button
>{{ $t('m.Refresh') }}</el-button
>
<el-button
v-else
@ -19,7 +19,7 @@
icon="el-icon-back"
@click="goBack"
size="small"
>Back</el-button
>{{ $t('m.Back') }}</el-button
>
</span>
</div>
@ -29,7 +29,7 @@
v-if="!announcements.length"
key="no-announcement"
>
<p>暂无公告</p>
<p>{{ $t('m.No_Announcements') }}</p>
</div>
<template v-if="listVisible">
<ul class="announcements-container" key="list">
@ -155,7 +155,9 @@ export default {
computed: {
title() {
if (this.listVisible) {
return this.isContest ? 'Contest Announcements' : 'Announcements';
return this.isContest
? this.$i18n.t('m.Contest_Announcement')
: this.$i18n.t('m.Announcement');
} else {
return this.announcement.title;
}

View File

@ -3,7 +3,7 @@
<el-row class="header">
<el-col :xs="24" :sm="14" :md="14" :lg="14">
<div class="select-row">
<span>Lang:</span>
<span>{{ $t('m.Lang') }}:</span>
<span>
<el-select
:value="this.language"
@ -17,7 +17,7 @@
</el-select>
</span>
<span>
<el-tooltip content="重置代码" placement="top" style="">
<el-tooltip :content="$t('m.Reset_Code')" placement="top">
<el-button
icon="el-icon-refresh"
@click="onResetClick"
@ -26,7 +26,7 @@
</el-tooltip>
</span>
<span>
<el-tooltip content="上传文件" placement="top" style="">
<el-tooltip :content="$t('m.Upload_file')" placement="top">
<el-button
icon="el-icon-upload"
@click="onUploadFile"
@ -46,7 +46,7 @@
</el-col>
<el-col :xs="24" :sm="10" :md="10" :lg="10">
<div class="select-row fl-right">
<span>Theme:</span>
<span>{{ $t('m.Theme') }}:</span>
<el-select
:value="this.theme"
@change="onThemeChange"
@ -56,8 +56,9 @@
<el-option
v-for="item in themes"
:key="item.label"
:label="$t('m.' + item.label)"
:value="item.value"
>{{ item.label }}
>{{ $t('m.' + item.label) }}
</el-option>
</el-select>
</div>

View File

@ -10,7 +10,7 @@
<el-input
v-model="formLogin.username"
prefix-icon="el-icon-user-solid"
placeholder="Username"
:placeholder="$t('m.Login_Username')"
width="100%"
@keyup.enter.native="enterHandleLogin"
></el-input>
@ -19,7 +19,7 @@
<el-input
v-model="formLogin.password"
prefix-icon="el-icon-lock"
placeholder="Password"
:placeholder="$t('m.Login_Password')"
type="password"
@keyup.enter.native="enterHandleLogin"
></el-input>
@ -31,7 +31,7 @@
v-if="!needVerify"
@click="handleLogin"
:loading="btnLoginLoading"
>登录</el-button
>{{ $t('m.Login_Btn') }}</el-button
>
<el-popover
placement="bottom"
@ -40,9 +40,9 @@
trigger="click"
v-else
>
<el-button type="primary" :loading="btnLoginLoading" slot="reference"
>登录</el-button
>
<el-button type="primary" :loading="btnLoginLoading" slot="reference">{{
$t('m.Login_Btn')
}}</el-button>
<slide-verify
:l="42"
:r="10"
@ -50,13 +50,13 @@
:h="100"
:accuracy="3"
@success="handleLogin"
slider-text="请向右滑动验证"
:slider-text="$t('m.Login_Verify')"
ref="slideBlock"
v-if="!verify.loginSuccess"
>
</slide-verify>
<el-alert
title="验证成功"
:title="$t('m.Login_Verify_Success')"
type="success"
:description="verify.loginMsg"
v-show="verify.loginSuccess"
@ -70,13 +70,13 @@
v-if="allow_register"
type="primary"
@click="switchMode('Register')"
>没有账户? 现在注册!</el-link
>{{ $t('m.Login_No_Account') }}</el-link
>
<el-link
type="primary"
@click="switchMode('ResetPwd')"
style="float: right"
>忘记密码</el-link
>{{ $t('m.Login_Forget_Password') }}</el-link
>
</div>
</div>
@ -104,25 +104,25 @@ export default {
username: [
{
required: true,
message: 'The username is required',
message: this.$i18n.t('m.Username_Check'),
trigger: 'blur',
},
{
max: 255,
message: 'The longest length of a username is 255',
message: this.$i18n.t('m.Username_Check_Max'),
trigger: 'blur',
},
],
password: [
{
required: true,
message: 'The password is required',
message: this.$i18n.t('m.Password_Check_Required'),
trigger: 'blur',
},
{
min: 6,
max: 20,
message: 'The length of the password is between 6 and 20',
message: this.$i18n.t('m.Password_Check_Between'),
trigger: 'blur',
},
],
@ -148,7 +148,7 @@ export default {
if (this.needVerify) {
this.verify.loginSuccess = true;
let time = (times / 1000).toFixed(1);
this.verify.loginMsg = '本次耗时' + time + 's';
this.verify.loginMsg = 'Total time ' + time + 's';
setTimeout(() => {
this.loginSlideBlockVisible = false;
this.verify.loginSuccess = false;
@ -167,7 +167,7 @@ export default {
this.$store.commit('changeUserToken', jwt);
this.$store.dispatch('setUserInfo', res.data.data);
this.$store.dispatch('incrLoginFailNum', true);
mMessage.success('欢迎回来~');
mMessage.success(this.$i18n.t('m.Welcome_Back'));
},
(_) => {
this.$store.dispatch('incrLoginFailNum', false);

View File

@ -16,37 +16,53 @@
></el-image>
</div>
<el-menu-item index="/home"
><i class="el-icon-s-home"></i>Home</el-menu-item
><i class="el-icon-s-home"></i>{{ $t('m.NavBar_Home') }}</el-menu-item
>
<el-menu-item index="/problem"
><i class="el-icon-s-grid"></i>Problem</el-menu-item
><i class="el-icon-s-grid"></i
>{{ $t('m.NavBar_Problem') }}</el-menu-item
>
<el-menu-item index="/contest"
><i class="el-icon-trophy"></i>Contest</el-menu-item
><i class="el-icon-trophy"></i
>{{ $t('m.NavBar_Contest') }}</el-menu-item
>
<el-menu-item index="/status"
><i class="el-icon-s-marketing"></i>Status</el-menu-item
><i class="el-icon-s-marketing"></i
>{{ $t('m.NavBar_Status') }}</el-menu-item
>
<el-submenu index="rank">
<template slot="title"><i class="el-icon-s-data"></i>Rank</template>
<el-menu-item index="/acm-rank">ACM Rank</el-menu-item>
<el-menu-item index="/oi-rank">OI Rank</el-menu-item>
<template slot="title"
><i class="el-icon-s-data"></i>{{ $t('m.NavBar_Rank') }}</template
>
<el-menu-item index="/acm-rank">{{
$t('m.NavBar_ACM_Rank')
}}</el-menu-item>
<el-menu-item index="/oi-rank">{{
$t('m.NavBar_OI_Rank')
}}</el-menu-item>
</el-submenu>
<el-menu-item index="/discussion"
><i class="el-icon-s-comment"></i>Discussion</el-menu-item
><i class="el-icon-s-comment"></i
>{{ $t('m.NavBar_Discussion') }}</el-menu-item
>
<el-submenu index="about">
<template slot="title"><i class="el-icon-info"></i>About</template>
<el-menu-item index="/introduction">Introduction</el-menu-item>
<el-menu-item index="/developer">Developer</el-menu-item>
<template slot="title"
><i class="el-icon-info"></i>{{ $t('m.NavBar_About') }}</template
>
<el-menu-item index="/introduction">{{
$t('m.NavBar_Introduction')
}}</el-menu-item>
<el-menu-item index="/developer">{{
$t('m.NavBar_Developer')
}}</el-menu-item>
</el-submenu>
<template v-if="!isAuthenticated">
<div class="btn-menu">
<el-button type="primary" round @click="handleBtnClick('Login')"
>Login
>{{ $t('m.NavBar_Login') }}
</el-button>
<el-button
v-if="websiteConfig.register"
@ -54,7 +70,7 @@
type="danger"
@click="handleBtnClick('Register')"
style="margin-left: 5px"
>Register
>{{ $t('m.NavBar_Register') }}
</el-button>
</div>
</template>
@ -70,17 +86,21 @@
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="/user-home">Home</el-dropdown-item>
<el-dropdown-item command="/status?onlyMine=true"
>Submissions</el-dropdown-item
>
<el-dropdown-item command="/setting">Setting</el-dropdown-item>
<el-dropdown-item v-if="isAdminRole" command="/admin"
>Management</el-dropdown-item
>
<el-dropdown-item divided command="/logout"
>Logout</el-dropdown-item
>
<el-dropdown-item command="/user-home">{{
$t('m.NavBar_UserHome')
}}</el-dropdown-item>
<el-dropdown-item command="/status?onlyMine=true">{{
$t('m.NavBar_Submissions')
}}</el-dropdown-item>
<el-dropdown-item command="/setting">{{
$t('m.NavBar_Setting')
}}</el-dropdown-item>
<el-dropdown-item v-if="isAdminRole" command="/admin">{{
$t('m.NavBar_Management')
}}</el-dropdown-item>
<el-dropdown-item divided command="/logout">{{
$t('m.NavBar_Logout')
}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<avatar
@ -108,14 +128,14 @@
slot="right"
@click="handleBtnClick('Login')"
v-show="!isAuthenticated"
>Login</mu-button
>{{ $t('m.NavBar_Login') }}</mu-button
>
<mu-button
flat
slot="right"
@click="handleBtnClick('Register')"
v-show="!isAuthenticated && websiteConfig.register"
>Register</mu-button
>{{ $t('m.NavBar_Register') }}</mu-button
>
<mu-menu
@ -129,31 +149,41 @@
<mu-list slot="content" @change="handleCommand">
<mu-list-item button value="/user-home">
<mu-list-item-content>
<mu-list-item-title>Home</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_UserHome')
}}</mu-list-item-title>
</mu-list-item-content>
</mu-list-item>
<mu-list-item button value="/status?onlyMine=true">
<mu-list-item-content>
<mu-list-item-title>Submissions</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Submissions')
}}</mu-list-item-title>
</mu-list-item-content>
</mu-list-item>
<mu-list-item button value="/setting">
<mu-list-item-content>
<mu-list-item-title>Setting</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Setting')
}}</mu-list-item-title>
</mu-list-item-content>
</mu-list-item>
<mu-list-item button value="/admin" v-show="isAdminRole">
<mu-list-item-content>
<mu-list-item-title>Management</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Management')
}}</mu-list-item-title>
</mu-list-item-content>
</mu-list-item>
<mu-divider></mu-divider>
<mu-list-item button value="/logout">
<mu-list-item-content>
<mu-list-item-title>Logout</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Logout')
}}</mu-list-item-title>
</mu-list-item-content>
</mu-list-item>
</mu-list>
@ -175,7 +205,7 @@
<mu-list-item-action>
<mu-icon value="home" size="24"></mu-icon>
</mu-list-item-action>
<mu-list-item-title>Home</mu-list-item-title>
<mu-list-item-title>{{ $t('m.NavBar_Home') }}</mu-list-item-title>
</mu-list-item>
<mu-list-item
@ -187,7 +217,9 @@
<mu-list-item-action>
<mu-icon value=":el-icon-s-grid" size="24"></mu-icon>
</mu-list-item-action>
<mu-list-item-title>Problem</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Problem')
}}</mu-list-item-title>
</mu-list-item>
<mu-list-item
@ -199,7 +231,9 @@
<mu-list-item-action>
<mu-icon value=":el-icon-trophy" size="24"></mu-icon>
</mu-list-item-action>
<mu-list-item-title>Contest</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Contest')
}}</mu-list-item-title>
</mu-list-item>
<mu-list-item
@ -211,7 +245,7 @@
<mu-list-item-action>
<mu-icon value=":el-icon-s-marketing" size="24"></mu-icon>
</mu-list-item-action>
<mu-list-item-title>Status</mu-list-item-title>
<mu-list-item-title>{{ $t('m.NavBar_Status') }}</mu-list-item-title>
</mu-list-item>
<mu-list-item
@ -224,7 +258,7 @@
<mu-list-item-action>
<mu-icon value=":el-icon-s-data" size="24"></mu-icon>
</mu-list-item-action>
<mu-list-item-title>Rank</mu-list-item-title>
<mu-list-item-title>{{ $t('m.NavBar_Rank') }}</mu-list-item-title>
<mu-list-item-action>
<mu-icon
class="toggle-icon"
@ -240,7 +274,7 @@
@click="opendrawer = !opendrawer"
active-class="mobile-menu-active"
>
<mu-list-item-title>ACM Rank</mu-list-item-title>
<mu-list-item-title>{{ $t('m.NavBar_Rank') }}</mu-list-item-title>
</mu-list-item>
<mu-list-item
button
@ -250,7 +284,9 @@
@click="opendrawer = !opendrawer"
active-class="mobile-menu-active"
>
<mu-list-item-title>OI Rank</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_OI_Rank')
}}</mu-list-item-title>
</mu-list-item>
</mu-list-item>
@ -263,7 +299,9 @@
<mu-list-item-action>
<mu-icon value=":fa fa-comments" size="24"></mu-icon>
</mu-list-item-action>
<mu-list-item-title>Discussion</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Discussion')
}}</mu-list-item-title>
</mu-list-item>
<mu-list-item
@ -276,7 +314,7 @@
<mu-list-item-action>
<mu-icon value=":el-icon-info" size="24"></mu-icon>
</mu-list-item-action>
<mu-list-item-title>About</mu-list-item-title>
<mu-list-item-title>{{ $t('m.NavBar_About') }}</mu-list-item-title>
<mu-list-item-action>
<mu-icon
class="toggle-icon"
@ -292,7 +330,9 @@
@click="opendrawer = !opendrawer"
active-class="mobile-menu-active"
>
<mu-list-item-title>Introduction</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Introduction')
}}</mu-list-item-title>
</mu-list-item>
<mu-list-item
button
@ -302,7 +342,9 @@
@click="opendrawer = !opendrawer"
active-class="mobile-menu-active"
>
<mu-list-item-title>Developer</mu-list-item-title>
<mu-list-item-title>{{
$t('m.NavBar_Developer')
}}</mu-list-item-title>
</mu-list-item>
</mu-list-item>
</mu-list>
@ -415,10 +457,15 @@ export default {
},
title: {
get() {
let ojName = this.websiteConfig.shortName
? this.websiteConfig.shortName.toUpperCase()
: 'OJ';
if (this.modalStatus.mode == 'ResetPwd') {
return 'Reset Password - HOJ';
return this.$i18n.t('m.Dialog_Reset_Password') + ' - ' + ojName;
} else {
return this.modalStatus.mode + ' - HOJ';
return (
this.$i18n.t('m.Dialog_' + this.modalStatus.mode) + ' - ' + ojName
);
}
},
},

View File

@ -5,7 +5,7 @@
<el-input
v-model="registerForm.username"
prefix-icon="el-icon-user-solid"
placeholder="Please Enter Username"
:placeholder="$t('m.Register_Username')"
@keyup.enter.native="handleRegister"
width="100%"
></el-input>
@ -15,7 +15,7 @@
<el-input
v-model="registerForm.password"
prefix-icon="el-icon-lock"
placeholder="Please Enter Password"
:placeholder="$t('m.Register_Password')"
@keyup.enter.native="handleRegister"
type="password"
></el-input>
@ -24,7 +24,7 @@
<el-input
v-model="registerForm.passwordAgain"
prefix-icon="el-icon-lock"
placeholder="Please Enter Password Again"
:placeholder="$t('m.Register_Password_Again')"
@keyup.enter.native="handleRegister"
type="password"
></el-input>
@ -33,7 +33,7 @@
<el-input
v-model="registerForm.email"
prefix-icon="el-icon-message"
placeholder="Please Enter Email"
:placeholder="$t('m.Register_Email')"
@keyup.enter.native="handleRegister"
>
<el-button
@ -51,7 +51,7 @@
<el-input
v-model="registerForm.code"
prefix-icon="el-icon-s-check"
placeholder="Please enter the captcha from the email"
:placeholder="$t('m.Register_Email_Captcha')"
@keyup.enter.native="handleRegister"
></el-input>
</el-form-item>
@ -62,11 +62,11 @@
@click="handleRegister()"
:loading="btnRegisterLoading"
>
注册
{{ $t('m.Register_Btn') }}
</el-button>
<el-link type="primary" @click="switchMode('Login')"
>已有账户? 返回登录!</el-link
>
<el-link type="primary" @click="switchMode('Login')">{{
$t('m.Register_Already_Registed')
}}</el-link>
</div>
</div>
</template>
@ -80,7 +80,7 @@ export default {
api.checkUsernameOrEmail(value, undefined).then(
(res) => {
if (res.data.data.username === true) {
callback(new Error('The username already exists'));
callback(new Error(this.$i18n.t('m.The_username_already_exists')));
} else {
callback();
}
@ -92,7 +92,7 @@ export default {
api.checkUsernameOrEmail(undefined, value).then(
(res) => {
if (res.data.data.email === true) {
callback(new Error('The email already exists'));
callback(new Error(this.$i18n.t('m.The_email_already_exists')));
} else {
callback();
}
@ -110,7 +110,7 @@ export default {
const CheckAgainPassword = (rule, value, callback) => {
if (value !== this.registerForm.password) {
callback(new Error('Password does not match'));
callback(new Error(this.$i18n.t('m.Password_does_not_match')));
}
callback();
};
@ -128,15 +128,19 @@ export default {
sendEmailError: false,
rules: {
username: [
{ required: true, message: 'Username is required', trigger: 'blur' },
{
required: true,
message: this.$i18n.t('m.Username_Check_Required'),
trigger: 'blur',
},
{
validator: CheckUsernameNotExist,
trigger: 'blur',
message: 'The username already exists',
message: this.$i18n.t('m.The_username_already_exists'),
},
{
max: 255,
message: 'The longest length of a username is 255',
message: this.$i18n.t('m.Username_Check_Max'),
trigger: 'blur',
},
],
@ -144,30 +148,30 @@ export default {
email: [
{
required: true,
message: 'The email is required',
message: this.$i18n.t('m.Email_Check_Required'),
trigger: 'blur',
},
{
type: 'email',
message: 'The email format is incorrect',
message: this.$i18n.t('m.Email_Check_Format'),
trigger: 'blur',
},
{
validator: CheckEmailNotExist,
message: 'The email already exists',
message: this.$i18n.t('m.The_email_already_exists'),
trigger: 'blur',
},
],
password: [
{
required: true,
message: 'The password is required',
message: this.$i18n.t('m.Password_Check_Required'),
trigger: 'blur',
},
{
min: 6,
max: 20,
message: 'The length of the password is between 6 and 20',
message: this.$i18n.t('m.Password_Check_Between'),
trigger: 'blur',
},
{ validator: CheckPassword, trigger: 'blur' },
@ -175,7 +179,7 @@ export default {
passwordAgain: [
{
required: true,
message: 'The password again is required',
message: this.$i18n.t('m.Password_Again_Check_Required'),
trigger: 'blur',
},
{ validator: CheckAgainPassword, trigger: 'change' },
@ -183,13 +187,13 @@ export default {
code: [
{
required: true,
message: 'The captcha must be six digits',
message: this.$i18n.t('m.Code_Check_Required'),
trigger: 'blur',
},
{
min: 6,
max: 6,
message: 'The captcha must be six digits',
message: this.$i18n.t('m.Code_Check_Length'),
trigger: 'blur',
},
],
@ -222,13 +226,13 @@ export default {
sendRegisterEmail() {
var emailReg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
if (!emailReg.test(this.registerForm.email)) {
mMessage.error('请检查邮箱格式!');
mMessage.error(this.$i18n.t('m.Email_Check_Format'));
return;
}
this.btnEmailLoading = true;
this.countdownNum = '正在处理...';
this.countdownNum = 'Waiting...';
if (this.registerForm.email) {
mMessage.info('请稍后...系统正在处理中...');
mMessage.info(this.$i18n.t('m.The_system_is_processing'));
api.getRegisterEmail(this.registerForm.email).then(
(res) => {
if (res.data.msg != null) {
@ -253,7 +257,7 @@ export default {
this.btnRegisterLoading = true;
api.register(formData).then(
(res) => {
mMessage.success(res.data.msg);
mMessage.success(this.$i18n.t('m.Thanks_for_registering'));
this.switchMode('Login');
this.btnRegisterLoading = false;
},

View File

@ -5,7 +5,7 @@
<el-input
v-model="formResetPassword.email"
prefix-icon="el-icon-message"
placeholder="Please Enter Your Email"
:placeholder="$t('m.Reset_Password_Email')"
>
</el-input>
</el-form-item>
@ -15,7 +15,7 @@
<el-input
v-model="formResetPassword.captcha"
prefix-icon="el-icon-s-check"
placeholder="Please Enter the captcha"
:placeholder="$t('m.Reset_Password_Captcha')"
></el-input>
</div>
<div id="captchaImg">
@ -35,9 +35,9 @@
>
{{ resetText }}
</el-button>
<el-link type="primary" @click="switchMode('Login')"
>想起密码? 返回登录!</el-link
>
<el-link type="primary" @click="switchMode('Login')">{{
$t('m.Remember_Passowrd_To_Login')
}}</el-link>
</div>
</div>
</template>
@ -60,7 +60,7 @@ export default {
);
};
return {
resetText: '发送重置密码的邮件',
resetText: 'Send Password Reset Email',
btnResetPwdLoading: false,
btnResetPwdDisabled: false,
captchaSrc: '',
@ -92,6 +92,7 @@ export default {
};
},
mounted() {
this.resetText = this.$i18n.t('m.Send_Password_Reset_Email');
this.getCaptcha();
},
methods: {
@ -110,10 +111,10 @@ export default {
},
countDown() {
let i = this.time;
this.resetText = i + '秒后,可重新发送重置密码的邮件...';
this.resetText = i + 's, ' + this.$i18n.t('m.Watting_Can_Resend_Email');
if (i == 0) {
this.btnResetPwdDisabled = false;
this.resetText = '发送重置密码的邮件';
this.resetText = this.$i18n.t('m.Send_Password_Reset_Email');
return;
}
setTimeout(() => {
@ -123,8 +124,8 @@ export default {
handleResetPwd() {
this.$refs['formResetPassword'].validate((valid) => {
if (valid) {
this.resetText = '正在处理...';
mMessage.info('请稍后...系统正在处理中...');
this.resetText = 'Waiting...';
mMessage.info(this.$i18n.t('m.The_system_is_processing'));
this.btnResetPwdLoading = true;
this.btnResetPwdDisabled = true;
api.applyResetPassword(this.formResetPassword).then(
@ -142,7 +143,7 @@ export default {
this.formResetPassword.captchaKey = '';
this.btnResetPwdLoading = false;
this.btnResetPwdDisabled = false;
this.resetText = '重新发送';
this.resetText = this.$i18n.t('m.Send_Password_Reset_Email');
this.getCaptcha();
}
);

View File

@ -3,7 +3,7 @@
<el-row :gutter="20">
<el-col :sm="24" :md="10" :lg="10">
<div class="left">
<p class="section-title">Change Password</p>
<p class="section-title">{{ $t('m.Change_Password') }}</p>
<el-form
class="setting-content"
ref="formPassword"
@ -31,7 +31,7 @@
slot="reference"
:loading="loading.btnPassword"
:disabled="disabled.btnPassword"
>Update Password</el-button
>{{ $t('m.Update_Password') }}</el-button
>
<slide-verify
:l="42"
@ -41,13 +41,13 @@
:accuracy="3"
@success="changePassword"
@again="onAgain('password')"
slider-text="请向右滑动验证"
:slider-text="$t('m.Slide_Verify')"
ref="passwordSlideBlock"
v-show="!verify.passwordSuccess"
>
</slide-verify>
<el-alert
title="验证成功"
:title="$t('m.Slide_Verify_Success')"
type="success"
:description="verify.passwordMsg"
v-show="verify.passwordSuccess"
@ -76,7 +76,7 @@
</el-col>
<el-col :sm="24" :md="10" :lg="10">
<div class="right">
<p class="section-title">Change Email</p>
<p class="section-title">{{ $t('m.Change_Email') }}</p>
<el-form
class="setting-content"
ref="formEmail"
@ -104,7 +104,7 @@
slot="reference"
:loading="loading.btnEmailLoading"
:disabled="disabled.btnEmail"
>Update Email</el-button
>{{ $t('m.Update_Email') }}</el-button
>
<slide-verify
:l="42"
@ -114,13 +114,13 @@
:accuracy="3"
@success="changeEmail"
@again="onAgain('email')"
slider-text="请向右滑动验证"
:slider-text="$t('m.Slide_Verify')"
ref="emailSlideBlock"
v-show="!verify.emailSuccess"
>
</slide-verify>
<el-alert
title="验证成功"
:title="$t('m.Slide_Verify_Success')"
type="success"
:description="verify.emailMsg"
v-show="verify.emailSuccess"
@ -157,25 +157,26 @@ export default {
{
required: true,
trigger: 'blur',
message: 'The old password is required',
},
{
trigger: 'blur',
min: 6,
max: 20,
message: 'The length of the password is between 6 and 20',
message: this.$i18n.t('m.Password_Check_Between'),
},
];
const CheckAgainPassword = (rule, value, callback) => {
if (value !== this.formPassword.newPassword) {
callback(new Error('Password does not match'));
callback(new Error(this.$i18n.t('m.Password_does_not_match')));
}
callback();
};
const CheckNewPassword = (rule, value, callback) => {
if (this.formPassword.oldPassword !== '') {
if (this.formPassword.oldPassword === this.formPassword.newPassword) {
callback(new Error("The new password doesn't change"));
callback(
new Error(this.$i18n.t('m.The_new_password_does_not_change'))
);
} else {
//
this.$refs.formPassword.validateField('again_password');
@ -186,7 +187,7 @@ export default {
const CheckEmail = (rule, value, callback) => {
if (this.formEmail.oldEmail !== '') {
if (this.formEmail.oldEmail === this.formEmail.newEmail) {
callback(new Error("The new email doesn't change"));
callback(new Error(this.$i18n.t('m.The_new_email_does_not_change')));
}
}
callback();
@ -238,13 +239,12 @@ export default {
{
required: true,
trigger: 'blur',
message: 'The new password is required',
},
{
trigger: 'blur',
min: 6,
max: 20,
message: 'The length of the password is between 6 and 20',
message: this.$i18n.t('m.Password_Check_Between'),
},
{ validator: CheckNewPassword, trigger: 'blur' },
],
@ -252,7 +252,7 @@ export default {
{
required: true,
trigger: 'blur',
message: 'The again password is required',
message: this.$i18n.t('m.Password_Again_Check_Required'),
},
{ validator: CheckAgainPassword, trigger: 'blur' },
],
@ -262,13 +262,13 @@ export default {
newEmail: [
{
required: true,
message: 'The new email is required',
message: this.$i18n.t('m.Email_Check_Required'),
trigger: 'blur',
},
{
type: 'email',
trigger: 'change',
message: 'The email format is incorrect',
message: this.$i18n.t('m.Email_Check_Format'),
},
{ validator: CheckEmail, trigger: 'blur' },
],
@ -282,7 +282,7 @@ export default {
changePassword(times) {
this.verify.passwordSuccess = true;
let time = (times / 1000).toFixed(1);
this.verify.passwordMsg = '本次耗时' + time + 's';
this.verify.passwordMsg = 'Total time ' + time + 's';
setTimeout(() => {
this.visible.passwordSlideBlock = false;
this.verify.passwordSuccess = false;
@ -299,10 +299,10 @@ export default {
(res) => {
this.loading.btnPassword = false;
if (res.data.data.code == 200) {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Update_Successfully'));
this.visible.passwordAlert = {
show: true,
title: '修改成功',
title: this.$i18n.t('m.Update_Successfully'),
type: 'success',
description: res.data.data.msg,
};
@ -314,7 +314,7 @@ export default {
myMessage.error(res.data.msg);
this.visible.passwordAlert = {
show: true,
title: '修改失败',
title: this.$i18n.t('m.Update_Failed'),
type: 'warning',
description: res.data.data.msg,
};
@ -334,7 +334,7 @@ export default {
changeEmail(times) {
this.verify.emailSuccess = true;
let time = (times / 1000).toFixed(1);
this.verify.emailMsg = '本次耗时' + time + 's';
this.verify.emailMsg = 'Total time ' + time + 's';
setTimeout(() => {
this.visible.emailSlideBlock = false;
this.verify.emailSuccess = false;
@ -349,10 +349,10 @@ export default {
(res) => {
this.loading.btnEmail = false;
if (res.data.data.code == 200) {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Update_Successfully'));
this.visible.emailAlert = {
show: true,
title: '修改成功',
title: this.$i18n.t('m.Update_Successfully'),
type: 'success',
description: res.data.data.msg,
};
@ -364,7 +364,7 @@ export default {
myMessage.error(res.data.msg);
this.visible.emailAlert = {
show: true,
title: '修改失败',
title: this.$i18n.t('m.Update_Failed'),
type: 'warning',
description: res.data.data.msg,
};
@ -387,7 +387,7 @@ export default {
} else {
this.$refs.emailSlideBlock.reset();
}
myMessage.warning('速度过快,可能为机器操作!请重新验证!');
myMessage.warning(this.$i18n.t('m.Guess_robot'));
},
},
};

View File

@ -1,6 +1,6 @@
<template>
<div>
<div class="section-title">Avatar Setting</div>
<div class="section-title">{{ $t('m.Avatar_Setting') }}</div>
<div class="section-main">
<avatar
:username="formProfile.username"
@ -19,7 +19,7 @@
>
<div style="padding: 20px 0">
<i class="el-icon-upload" style="color: #3399ff;font-size:52px"></i>
<p>将头像图片拖放到此处或者单击手动选择</p>
<p>{{ $t('m.Upload_avatar_hint') }}</p>
</div>
</el-upload>
</template>
@ -108,11 +108,11 @@
</template>
<el-dialog
:visible.sync="uploadModalVisible"
title="上传头像"
:title="$t('m.Upload')"
width="350px"
>
<div class="upload-modal">
<p class="notice">你的头像将被设置为如下:</p>
<p class="notice">{{ $t('m.Your_new_avatar') + ':' }}</p>
<img :src="uploadImgSrc" />
</div>
<div slot="footer">
@ -120,13 +120,13 @@
@click="uploadAvatar"
:loading="loadingUploadBtn"
type="primary"
>Upload</el-button
>{{ $t('m.Upload') }}</el-button
>
</div>
</el-dialog>
</div>
<div class="section-title">UserInfo Setting</div>
<div class="section-title">{{ $t('m.UserInfo_Setting') }}</div>
<el-form ref="formProfile" :model="formProfile">
<el-row :gutter="30" justify="space-around">
<el-col :md="10" :xs="24">
@ -168,7 +168,7 @@
type="primary"
@click="updateUserInfo"
:loading="loadingSaveBtn"
>Save All</el-button
>{{ $t('m.Save') }}</el-button
>
</div>
</div>

30
hoj-vue/src/i18n/index.js Normal file
View File

@ -0,0 +1,30 @@
import Vue from 'vue'
import store from "@/store"
import VueI18n from 'vue-i18n'
import elenUS from 'element-ui/lib/locale/lang/en'
import elzhCN from 'element-ui/lib/locale/lang/zh-CN'
Vue.use(VueI18n)
const languages = [
{value: 'en-US', label: 'English', el: elenUS},
{value: 'zh-CN', label: '简体中文', el: elzhCN},
]
const messages = {}
// combine admin and oj
for (let lang of languages) {
let locale = lang.value
let m = require(`./oj/${locale}`).m
// Object.assign(m, require(`./admin/${locale}`).m)
messages[locale] = Object.assign({m: m}, lang.el);
}
// load language packages
export default new VueI18n({
locale: store.getters.webLanguage,
messages: messages
})
export {languages}

View File

@ -0,0 +1,391 @@
export const m = {
// /components/oj/common/NavBar.vue 导航栏
NavBar_Home: 'Home',
NavBar_Problem: 'Problem',
NavBar_Contest: 'Contest',
NavBar_Status: 'Status',
NavBar_Rank: 'Rank',
NavBar_ACM_Rank: 'ACM Rank',
NavBar_OI_Rank: 'OI Rank',
NavBar_Discussion: 'Discussion',
NavBar_About: 'About',
NavBar_Introduction: 'Introduction',
NavBar_Developer:'Developer',
NavBar_Login: 'Login',
NavBar_Register: 'Register',
NavBar_UserHome: 'Home',
NavBar_Submissions: 'Submissions',
NavBar_Setting:'Setting',
NavBar_Management: 'Management',
NavBar_Logout: 'Logout',
Dialog_Login: 'Login',
Dialog_Register:'Register',
Dialog_Reset_Password:'Reset Password',
// /components/oj/common/Login.vue 登录弹窗
Login_Username: 'Username',
Login_Password: 'Password',
Login_Btn:'Login',
Slide_Verify:'Please slide right to verify',
Slide_Verify_Success:'Success',
Login_No_Account: 'No account? Register now!',
Login_Forget_Password: 'Forget Password',
Username_Check_Required:'The username is required.',
Username_Check_Max:'The longest length of a username is 255.',
Password_Check_Required:'The password is required.',
Password_Check_Between:'The length of the password is between 6 and 20.',
Welcome_Back: 'Welcome back~',
// /components/oj/common/Register.vue 注册弹窗
Register_Username: 'Please Enter Username',
Register_Password: 'Please Enter Password',
Register_Password_Again: 'Please Enter Password Again',
Register_Email: 'Please Enter Email',
Register_Email_Captcha: 'Please enter the captcha from the email',
Register_Btn: 'Register',
Register_Already_Registed: 'Already registed? Login now!',
The_username_already_exists: 'The username already exists.',
The_email_already_exists: 'The email already exists.',
Password_does_not_match: 'Password does not match.',
Email_Check_Required:'The email is required.',
Email_Check_Format:'The email format is incorrect.',
Password_Again_Check_Required:'The password again is required.',
Code_Check_Required:'The captcha is required.',
Code_Check_Length:'The captcha must be six digits.',
The_system_is_processing:'Please Waiting... The system is processing...',
Thanks_for_registering: 'Thanks for your registering, you can login now.',
// /components/oj/common/ResetPassword.vue 重置密码弹窗
// /views/oj/user/SetNeWPassword.vue 设置新密码页
Reset_Password_Email: 'Please Enter Your Email',
Reset_Password_Captcha: 'Please Enter the captcha',
Send_Password_Reset_Email: 'Send Password Reset Email',
Waiting_Can_Resend_Email:'resend the Reset Email...',
Remember_Passowrd_To_Login:'Remember password? To login!',
Set_New_Password:'Set New Password',
Set_New_Password_Msg: 'Please Enter New Password',
Set_New_Password_Again_Msg: 'Please Enter New Password Again',
The_username_does_not_exists:'The username does not exists.',
Your_password_has_been_reset: 'Your password has been reset.',
// /components/oj/setting/Account.vue 账号信息管理页面
Change_Password: 'Change Password',
Change_Email: 'Change Email',
Update_Password: 'Update Password',
Update_Email: 'Update Email',
The_new_password_does_not_change:"The new password doesn't change.",
The_new_email_does_not_change:"The new email doesn't change.",
Update_Successfully:'Update successfully',
Update_Failed:'Update Failed',
Guess_robot:'Speed too fast, may be machine operation! Please verify again!',
// /components/oj/setting/UserInfo.vue
Avatar_Setting: 'Avatar Setting',
UserInfo_Setting: 'UserInfo Setting',
Upload_avatar_hint:'Drag and drop the avatar here, or click here.',
Save:'Save',
Upload:'Upload',
Your_new_avatar:'Your new avatar',
// /views/oj/user/UserHome.vue
Recent_login_time:'Recently launched',
Not_set_yet:'Not set yet',
UserHome_Solved: 'Solved',
UserHome_Submissions: 'Submissions',
UserHome_Score: 'Score',
UserHome_Rating:'Rating',
List_Solved_Problems: 'List of solved problems',
UserHome_Not_Data: 'The guy is so lazy that has not solved any problem yet.',
// /views/oj/user/Setting.vue
Account_Setting:'Account Setting',
UserInfo_Setting:'UserInfo Setting',
// App.vue 底部文案
Service:'Service',
Judging_Queue:'Judging Queue',
System_Info:'System Info',
Development:'Development',
Open_Source:'Open Source',
Support:'Support',
Help:'Help',
// /views/oj/Home.vue
Welcome_to:'Welcome to ',
Recent_7_Days_AC_Rank:'Recent 7 Days AC Top 10 Rank',
Other_OJ_Contest:'Other Online Judge Contest',
// 表格通用列名,按钮,搜索框等
Enter_keyword:'Enter keyword',
Reset:'Reset',
Username:'Username',
Solved:'Solved',
AC:'AC',
OJ:'OJ',
Title:'Title',
Begin_Time:'Begin Time',
End_Time:'End Time',
Problem_ID:'Problem ID',
Total:'Total',
AC_Rate:'AC Rate',
Score: 'Score',
// /views/oj/problem/problemList.vue
Problem_List:'Problem List',
All:'All',
Mine:'Mine',
Level:'Level',
Tags:'Tags',
Pick_a_random_question:'Pick a random question',
Touch_Get_Status:'Please touch or hover the mouse to the designated problem line to view the submission status',
Good_luck_to_you:'Good luck to you!',
// /views/oj/problem/Problem.vue
Contest_Problem:'Contest Problem',
Show_Tags:'Show tags',
No_tag:'No tag',
Statistic: 'Statistic',
Solution:'Solution',
Description: 'Description',
Input: 'Input',
Output: 'Output',
Sample_Input: 'Sample Input',
Sample_Output: 'Sample Output',
Hint: 'Hint',
Source: 'Source',
Status: 'Status',
Information: 'Information',
Time_Limit: 'Time Limit',
Memory_Limit: 'Memory Limit',
Other:'Other',
Created: 'Created By',
Please_login_first:'Please login first',
Submit: 'Submit',
Submitting: 'Submitting',
Judging: 'Judging',
Wrong_Answer: 'Wrong Answer',
View_Contest: 'View Contest',
Are_you_sure_you_want_to_reset_your_code: 'Are you sure you want to reset your code?',
Code_can_not_be_empty: 'Code can not be empty',
Submit_code_successfully: 'Submit code successfully',
You_have_solved_the_problem: 'You have solved the problem',
Submitted_successfully: 'Submitted successfully',
You_have_submitted_a_solution: 'You have submitted a solution.',
Contest_has_ended: 'Contest has ended',
You_have_submission_in_this_problem_sure_to_cover_it: 'You have submission in this problem, sure to cover it?',
Close:'Close',
Cancel:'Cancel',
OK:'OK',
Copied_successfully:'Copied successfully',
Copied_failed:'Copied failed',
// 状态码表示的结果
Accepted: 'Accepted',
Time_Limit_Exceeded: 'Time Limit Exceeded',
Memory_Limit_Exceeded: 'Memory Limit Exceeded',
Runtime_Error: 'Runtime Error',
System_Error: 'System Error',
Pending: 'Pending',
Partial_Accepted: 'Partial Accepted',
Compile_Error: 'Compile Error',
// /views/oj/status/SubmissionList.vue
When: 'When',
Time: 'Time',
Memory: 'Memory',
Length:'Length',
Language:'Language',
View_submission_details:'View submission details',
Judger:'Judger',
Author: 'Author',
Submit_Time:'Submit Time',
Option: 'Option',
Rejudge: 'Rejudge',
Refresh:'Refresh',
Enter_Problem_ID:'Enter Problem ID',
Enter_Author:'Enter Author',
Run_ID:'Run ID',
Problem:'Problem',
// /views/oj/status/SubmissionDetails.vue
Test_point_details:'Test point details',
Copy:'Copy',
Shared:'Shared',
Unshared:'Unshared',
Shared_successfully:'Shared successfully',
// /views/oj/rank/ACMRank.vue
ACM_Ranklist: 'ACM Ranklist',
User:'User',
Nickname:'Nickname',
Mood: 'Mood',
Rating: 'Rating',
// /views/oj/rank/OIRank.vue
OI_Ranklist: 'OI Ranklist',
// /views/oj/discussion/discussionList.vue
Created_Time:'Created Time',
Likes:'Likes',
Views:'Views',
Edit:'Edit',
Delete:'Delete',
Post_discussion:'Post Discussion',
Post_problem_discussion:'Post Problem Discussion',
General_discussion:'General Discussion',
Return:'Return',
Category:'Category',
Discussion_title:'Title',
Discussion_Desc:'Description',
Discussion_Category:'Category',
Discussion_top:'Top',
Discussion_content:'Content',
Create_Discussion:'Create Discussion',
Edit_Discussion:'Edit Discussion',
Delete_Discussion_Tips:'This operation will delete the discussion, including the associated comments and replies. Do you want to continue?',
Delete_successfully:'Delete successfully',
Post_successfully:'Post successfully',
// /views/oj/discussion/discussionList.vue
Report:'Report',
Like:'Like',
Liked:'Liked',
Report_Reason:'Report Reason',
// 404.vue
Page_Not_Found:"Sorry, the page can't be found",
Go_Home:'Go Home',
Back:'Back',
// /views/oj/contest/ContestList.vue
Rule: 'Rule',
Running: 'Running',
Scheduled: 'Scheduled',
Ended: 'Ended',
No_contest: 'No contest',
Contests:'Contests',
Public:'Public',
Private:'Private',
Protected:'Protected',
Public_Tips:'Public - Any one can see and submit.',
Private_Tips:'Private - Only users knowing contest password can see and submit.',
Protected_Tips:'Protected - Any one can see, but only users knowing contest password can submit.',
// /views/oj/contest/ContestDetail.vue
StartAt: 'StartAt',
EndAt: 'EndAt',
Password_Required: 'Password Required',
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',
Announcement: 'Announcement',
Submissions: 'Submissions',
Rankings: 'Rankings',
Comment:'Comment',
Admin_Helper: 'AC Info',
Register_contest_successfully:'Register contest successfully',
// /views/oj/contest/children/ACMContestRank.vue
Contest_Rank:'Contest Rank',
Menu: 'Menu',
Chart: 'Chart',
Table:'Table',
Auto_Refresh: 'Auto Refresh',
RealName: 'RealName',
Force_Update: 'Force Update',
Download_as_CSV: 'Download as CSV',
TotalTime: 'TotalTime',
Top_10_Teams: 'Top 10 Teams',
save_as_image: 'save as image',
// /views/oj/contest/children/ACMInfo.vue
AC_Time: 'AC Time',
First_Blood: 'First Blood',
Checked: 'Checked',
Not_Checked: 'Not Checked',
Check_It: 'Check It',
Accepted:'Accepted',
// /views/oj/contest/children/ContestRejudgeAdmin.vue
Contest_Rejudge:'Contest Rejudge',
ID: 'ID',
Contest_Rejudge_Tips:'Are you sure you want to rejudge all submissions of the questions?',
Rejudge_All:'Rejudge All',
Rejudge_successfully:'Rejudge successfully',
// /views/oj/contest/children/OIContestRank.vue
Total_Score: 'Total Score',
// /views/oj/about/Introduction.vue
Compiler: 'Compiler',
Example:'Example',
Result_Explanation: 'Result Explanation',
Pending_Description: 'Your solution is waiting be judged, please wait for the result...',
Submitted_Faild_Description:'Your submission failed this time, please click the button to submit again.',
Compiling_Description:'Your source code is being compiled, please wait for the result...',
Judging_Description:'Your program is running with test data. Please wait for the result...',
Compile_Error_Description: "Failed to compile your source code. Click on the link to see compiler's output.",
Persentation_Error_Description:'The code you submitted is very close to the correct answer. Please check whether there are extra spaces, newlines and other blanks in the code format output.',
Accepted_Description: 'Congratulations! Your solution is correct.',
Wrong_Answer_Description: "Your program's output doesn't match judger's answer.",
Runtime_Error_Description: 'Your program terminated abnormally. Possible reasons are: segment fault, divided by zero or exited with code other than 0.',
Time_Limit_Exceeded_Description: 'The time your program used has exceeded limit.',
Memory_Limit_Exceeded_Description: 'The memory your program actually used has exceeded limit.',
System_Error_Description: 'Oops, something has gone wrong with the judger. Please report this to administrator.',
Compile_Explanation:'Compile Explanation',
Compile_Tips1:"`__int64` is not defined by ANSI standard and can only be used in `VC`. It should be written as `long long` type in `GNU C++`. For `scanf` and `printf`, please use `%lld` as the format.",
Compile_Tips2:"The return value of `main()` must be defined as `int`, not `void`",
Compile_Tips3:"`i` lost definition outside the loop,\"for(int i=0...){...}\"",
Compile_Tips4:"`itoa` is not an ANSI standard function (not available in standard `C/C++`)",
// /views/oj/about/Developer.vue
Leader_BackEnd_FrontEnd_Engineer:'Leader & BackEnd | FrontEnd Engineer',
Distributed:'Distributed',
Distributed_Desc:'It is divided into frontend and backend separation, and supports the micro service cluster',
Customization:'Customization',
Customization_Desc:'The website configuration is highly integrated and supports customized modification',
Security:'Security',
Security_Desc:'The Sandbox is isolated by CGroup, and the website authority control is perfect',
Diversity:'Diversity',
Diversity_Desc:'Support codefoces, HDU remote judge',
Available:'Available',
Faulty:'Faulty',
// /components/oj/common/Announcements.vue
Contest_Announcement: 'Contest Announcement',
No_Announcements: 'No Announcements',
// /components/oj/common/CodeMirror.vue
Lang: 'Lang',
Theme: 'Theme',
Reset_Code: 'Reset Code',
Upload_file: 'Upload file',
monokai: 'Mnokai',
solarized: 'Molarized Light',
material: 'Material',
// /components/oj/comment/CodeMirror.vue
Come_and_write_down_your_comments:'Come and write down your comments',
Inline_Code:'Inline Code',
Code_Block:'Code Block',
Link:'Link',
Unordered_list:'Unordered List',
Ordered_List:'Ordered List',
Submit_Comment:'Submit',
All_Comment:'All Comment',
Reply:'Reply',
Reply_Total:'Total',
Replies:'replies',
Click_Show_All:'Click to Show All',
Pick_up:"Pick up",
Load_More:'Load More',
Delete_Comment_Tips:'This operation will delete the comment and all its replies. Do you want to continue?',
Delete_Reply_Tips:'This operation will delete the reply. Do you want to continue?',
}

View File

@ -0,0 +1,381 @@
export const m = {
// /components/oj/common/NavBar.vue 导航栏
NavBar_Home: '首页',
NavBar_Problem: '题目',
NavBar_Contest: '比赛',
NavBar_Status: '状态',
NavBar_Rank: '排名',
NavBar_ACM_Rank: 'ACM 排名',
NavBar_OI_Rank: 'OI 排名',
NavBar_Discussion: '讨论',
NavBar_About: '关于',
NavBar_Introduction: '简介',
NavBar_Developer:'开发者',
NavBar_Login: '登录',
NavBar_Register: '注册',
NavBar_UserHome: '我的首页',
NavBar_Submissions: '我的提交',
NavBar_Setting:'我的设置',
NavBar_Management: '后台管理',
NavBar_Logout: '退出登录',
Dialog_Login: '登录',
Dialog_Register:'注册',
Dialog_Reset_Password:'重置密码',
// /components/oj/common/Login.vue 登录弹窗
Login_Username: '用户名',
Login_Password: '密码',
Login_Btn:'登录',
Slide_Verify:'请向右滑动验证',
Slide_Verify_Success:'验证成功',
Login_No_Account: '没有账号?立即注册!',
Login_Forget_Password: '忘记密码',
Username_Check_Required:'The username is required.',
Username_Check_Max:'The longest length of a username is 255.',
Password_Check_Required:'The password is required.',
Password_Check_Between:'The length of the password is between 6 and 20.',
Welcome_Back: '欢迎回来~',
// /components/oj/common/Register.vue 注册弹窗
Register_Username: 'Please Enter Username',
Register_Password: 'Please Enter Password',
Register_Password_Again: 'Please Enter Password Again',
Register_Email: 'Please Enter Email',
Register_Email_Captcha: 'Please enter the captcha from the email',
Register_Btn: '注册',
Register_Already_Registed: '已有账号?立即登录!',
The_username_already_exists: 'The username already exists.',
The_email_already_exists: 'The email already exists.',
Password_does_not_match: 'Password does not match.',
Email_Check_Required:'The email is required.',
Email_Check_Format:'The email format is incorrect.',
Password_Again_Check_Required:'The password again is required.',
Code_Check_Required:'The captcha is required.',
Code_Check_Length:'The captcha must be six digits.',
The_system_is_processing:'Please Waiting... The system is processing...',
Thanks_for_registering: 'Thanks for your registering, you can login now.',
// /components/oj/common/ResetPassword.vue 重置密码弹窗
// /views/oj/user/SetNeWPassword.vue 设置新密码页
Reset_Password_Email: 'Please Enter Your Email',
Reset_Password_Captcha: 'Please Enter the captcha',
Send_Password_Reset_Email: 'Send Password Reset Email',
Waiting_Can_Resend_Email:'resend the Reset Email...',
Remember_Passowrd_To_Login:'Remember password? To login!',
Set_New_Password:'Set New Password',
Set_New_Password_Msg: 'Please Enter New Password',
Set_New_Password_Again_Msg: 'Please Enter New Password Again',
The_username_does_not_exists:'The username does not exists.',
Your_password_has_been_reset: 'Your password has been reset.',
// /components/oj/setting/Account.vue 账号信息管理页面
Change_Password: 'Change Password',
Change_Email: 'Change Email',
Update_Password: 'Update Password',
Update_Email: 'Update Email',
The_new_password_does_not_change:"The new password doesn't change.",
The_new_email_does_not_change:"The new email doesn't change.",
Update_Successfully:'Update successfully',
Update_Failed:'Update Failed',
Guess_robot:'Speed too fast, may be machine operation! Please verify again!',
// /components/oj/setting/UserInfo.vue
Avatar_Setting: 'Avatar Setting',
UserInfo_Setting: 'UserInfo Setting',
Upload_avatar_hint:'Drag and drop the avatar here, or click here.',
Save:'保存',
Upload:'上传',
Your_new_avatar:'你的新头像',
// /views/oj/user/UserHome.vue
Recent_login_time:'Recently launched',
Not_set_yet:'Not set yet',
UserHome_Solved: 'Solved',
UserHome_Submissions: 'Submissions',
UserHome_Score: 'Score',
UserHome_Rating:'Rating',
List_Solved_Problems: 'List of solved problems',
UserHome_Not_Data: 'The guy is so lazy that has not solved any problem yet.',
// /views/oj/user/Setting.vue
Account_Setting:'Account Setting',
UserInfo_Setting:'UserInfo Setting',
// App.vue 底部文案
Service:'服务',
Judging_Queue:'评测队列',
System_Info:'系统信息',
Development:'开发',
Open_Source:'开源',
Support:'支持',
Help:'帮助',
// /views/oj/Home.vue
Welcome_to:'欢迎使用 ',
Recent_7_Days_AC_Rank:'7天内做题数排名前10',
Other_OJ_Contest:'其它在线评测平台的近期比赛',
// 表格通用列名,按钮,搜索框等
Enter_keyword:'输入关键词',
Reset:'Reset',
Username:'Username',
Solved:'Solved',
AC:'AC',
OJ:'OJ',
Title:'Title',
Begin_Time:'Begin Time',
End_Time:'End Time',
Problem_ID:'Problem ID',
Total:'Total',
AC_Rate:'AC Rate',
Score: 'Score',
// /views/oj/problem/problemList.vue
Problem_List:'Problem List',
All:'All',
Mine:'Mine',
Level:'Level',
Tags:'Tags',
Pick_a_random_question:'Pick a random question',
Touch_Get_Status:'Please touch or hover the mouse to the designated problem line to view the submission status',
Good_luck_to_you:'Good luck to you!',
// /views/oj/problem/Problem.vue
Contest_Problem:'Contest Problem',
Show_Tags:'Show tags',
No_tag:'No tag',
Statistic: 'Statistic',
Solution:'Solution',
Description: 'Description',
Input: 'Input',
Output: 'Output',
Sample_Input: 'Sample Input',
Sample_Output: 'Sample Output',
Hint: 'Hint',
Source: 'Source',
Status: 'Status',
Information: 'Information',
Time_Limit: 'Time Limit',
Memory_Limit: 'Memory Limit',
Other:'Other',
Created: 'Created By',
Please_login_first:'Please login first',
Submit: 'Submit',
Submitting: 'Submitting',
Judging: 'Judging',
Wrong_Answer: 'Wrong Answer',
View_Contest: 'View Contest',
Are_you_sure_you_want_to_reset_your_code: 'Are you sure you want to reset your code?',
Code_can_not_be_empty: 'Code can not be empty',
Submit_code_successfully: 'Submit code successfully',
You_have_solved_the_problem: 'You have solved the problem',
Submitted_successfully: 'Submitted successfully',
You_have_submitted_a_solution: 'You have submitted a solution.',
Contest_has_ended: 'Contest has ended',
You_have_submission_in_this_problem_sure_to_cover_it: 'You have submission in this problem, sure to cover it?',
Close:'Close',
Cancel:'Cancel',
OK:'OK',
Copied_successfully:'Copied successfully',
Copied_failed:'Copied failed',
// /views/oj/status/SubmissionList.vue
When: 'When',
ID: 'ID',
Time: 'Time',
Memory: 'Memory',
Length:'Length',
Language:'Language',
View_submission_details:'View submission details',
Judger:'Judger',
Author: 'Author',
Submit_Time:'Submit Time',
Option: 'Option',
Rejudge: 'Rejudge',
Refresh:'Refresh',
Enter_Problem_ID:'Enter Problem ID',
Enter_Author:'Enter Author',
Run_ID:'Run ID',
Problem:'Problem',
// /views/oj/status/SubmissionDetails.vue
Test_point_details:'Test point details',
Copy:'Copy',
Shared:'Shared',
Unshared:'Unshared',
Shared_successfully:'Shared successfully',
// /views/oj/rank/ACMRank.vue
ACM_Ranklist: 'ACM Ranklist',
User:'User',
Nickname:'Nickname',
Mood: 'Mood',
Rating: 'Rating',
// /views/oj/rank/OIRank.vue
OI_Ranklist: 'OI Ranklist',
// /views/oj/discussion/discussionList.vue
Created_Time:'Created Time',
Likes:'Likes',
Views:'Views',
Edit:'Edit',
Delete:'Delete',
Post_discussion:'Post Discussion',
Post_problem_discussion:'Post Problem Discussion',
General_discussion:'General Discussion',
Return:'Return',
Category:'Category',
Discussion_title:'Title',
Discussion_Desc:'Description',
Discussion_Category:'Category',
Discussion_top:'Top',
Discussion_content:'Content',
Create_Discussion:'Create Discussion',
Edit_Discussion:'Edit Discussion',
Delete_Discussion_Tips:'This operation will delete the discussion, including the associated comments and replies. Do you want to continue?',
Delete_successfully:'Delete successfully',
Post_successfully:'Post successfully',
// /views/oj/discussion/discussionList.vue
Report:'Report',
Like:'Like',
Liked:'Liked',
Report_Reason:'Report Reason',
// 404.vue
Page_Not_Found:"Sorry, the page can't be found",
Go_Home:'Go Home',
Back:'Back',
// /views/oj/contest/ContestList.vue
Rule: 'Rule',
Running: 'Running',
Scheduled: 'Scheduled',
Ended: 'Ended',
No_contest: 'No contest',
Contests:'Contests',
Public:'公开赛',
Private:'私有赛',
Protected:'保护赛',
Public_Tips:'公开赛 - 每个用户都可查看与提交',
Private_Tips:'私有赛 - 用户需要密码才可查看与提交',
Protected_Tips:'保护赛 - 每个用户都可查看,但是提交需要密码',
// /views/oj/contest/ContestDetail.vue
StartAt: 'StartAt',
EndAt: 'EndAt',
Password_Required: 'Password Required',
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',
Announcement: '公告',
Submissions: 'Submissions',
Rankings: 'Rankings',
Comment:'Comment',
Admin_Helper: 'AC Info',
Register_contest_successfully:'Register contest successfully',
// /views/oj/contest/children/ACMContestRank.vue
Contest_Rank:'Contest Rank',
Menu: 'Menu',
Chart: 'Chart',
Table:'Table',
Auto_Refresh: 'Auto Refresh',
RealName: 'RealName',
Force_Update: 'Force Update',
Download_as_CSV: 'Download as CSV',
TotalTime: 'TotalTime',
Top_10_Teams: 'Top 10 Teams',
save_as_image: 'save as image',
// /views/oj/contest/children/ACMInfo.vue
AC_Time: 'AC Time',
First_Blood: 'First Blood',
Checked: 'Checked',
Not_Checked: 'Not Checked',
Check_It: 'Check It',
Accepted:'Accepted',
// /views/oj/contest/children/ContestRejudgeAdmin.vue
Contest_Rejudge:'Contest Rejudge',
ID: 'ID',
Rejudge_All:'Rejudge All',
Contest_Rejudge_Tips:'Are you sure you want to rejudge all submissions of the questions?',
Rejudge_successfully:'Rejudge successfully',
// /views/oj/contest/children/OIContestRank.vue
Total_Score: 'Total Score',
// /views/oj/about/Introduction.vue
Compiler: '编译器',
Example:'例题',
Result_Explanation: '结果说明',
Pending_Description: '您的解答正在排队等待测评中,请等待结果...',
Submitted_Faild_Description:'您的此次提交失败,请点击按钮重新提交...',
Compiling_Description:'正在对您的源代码进行编译中,请等待结果...',
Judging_Description:'正在使用测试数据运行您的程序中,请等待结果...',
Compile_Error_Description: "无法编译您的源代码,点击链接查看编译器的输出。",
Persentation_Error_Description:'您提交的代码已经很接近正确答案,请检查代码格式输出是否有多余空格,换行等空白符。',
Accepted_Description: '恭喜! 您的解题方法是正确的。',
Wrong_Answer_Description: "您的程序输出结果与判题程序的答案不符。",
Runtime_Error_Description: '您的程序异常终止可能的原因是段错误被零除或用非0的代码退出程序。',
Time_Limit_Exceeded_Description: '您的程序运行时间已超出题目限制。',
Memory_Limit_Exceeded_Description: '您的程序实际使用的内存已超出题目限制。',
System_Error_Description: '糟糕,判题机系统出了问题。请报告给管理员。',
Compile_Explanation:'编译说明',
Compile_Tips1:"__int64不是ANSI标准定义只能在VC使用在 GNU C++ 中应写成 long long 类型, scanf和printf 请使用%lld作为格式",
Compile_Tips2:"main() 返回值必须定义为 int ,而不是 void",
Compile_Tips3:"i 在循环外失去定义 \"for(int i=0...){...}\"",
Compile_Tips4:"itoa 不是ansi标准函数标准 C/C++ 中无此函数)",
// /views/oj/about/Developer.vue
Leader_BackEnd_FrontEnd_Engineer:'主导 & 后端 | 前端 开发者',
Distributed:'分布式',
Distributed_Desc:'前后端分离,支持判题微服务集群',
Customization:'定制化',
Customization_Desc:'网站配置高度集成,支持定制化修改',
Security:'安全性',
Security_Desc:'判题沙盒使用cgroup隔离网站权限控制完善',
Diversity:'多样性',
Diversity_Desc:'支持CodefocesHDU的远程判题',
Available:'有效',
Faulty:'不完善',
// /components/oj/common/Announcements.vue
Contest_Announcement: '比赛公告',
No_Announcements: '暂无公告',
// /components/oj/common/CodeMirror.vue
Lang: '语言',
Theme: '风格',
Reset_Code: '重置密码',
Upload_file: '上传文件',
monokai: 'Mnokai',
solarized: 'Molarized Light',
material: 'Material',
// /components/oj/comment/CodeMirror.vue
Come_and_write_down_your_comments:'快来写下你的评论吧',
Inline_Code:'行内代码',
Code_Block:'代码块',
Link:'链接',
Unordered_list:'无序列表',
Ordered_List:'有序列表',
Submit_Comment:'提交评论',
All_Comment:'全部评论',
Reply:'回复',
Reply_Total:'总共',
Replies:'条回复',
Click_Show_All:'点击查看全部',
Pick_up:'收起',
Load_More:'加载更多',
Delete_Comment_Tips:'此操作将删除该评论及其所有回复, 是否继续?',
Delete_Reply_Tips:'此操作将删除该回复, 是否继续?',
}

View File

@ -2,6 +2,7 @@ import Vue from 'vue'
import App from './App.vue'
import store from './store'
import Element from 'element-ui'
import i18n from '@/i18n'
// import "element-ui/lib/theme-chalk/index.css"
import 'font-awesome/css/font-awesome.min.css'
@ -84,5 +85,6 @@ Vue.config.productionTip = false
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount('#app')

View File

@ -3,6 +3,9 @@ import Vuex from 'vuex'
import user from '@/store/user'
import contest from "@/store/contest"
import api from '@/common/api'
import i18n from '@/i18n'
import storage from '@/common/storage'
import moment from 'moment'
Vue.use(Vuex)
const rootState = {
modalStatus: {
@ -18,6 +21,7 @@ const rootState = {
},
registerTimeOut: 60,
resetTimeOut: 90,
language:storage.get('Web_Language') || 'zh-CN',
}
const rootGetters = {
@ -33,6 +37,9 @@ const rootGetters = {
'websiteConfig' (state) {
return state.websiteConfig
},
'webLanguage'(state){
return state.language
}
}
const rootMutations = {
@ -74,6 +81,14 @@ const rootMutations = {
changeWebsiteConfig(state, payload) {
state.websiteConfig = payload.websiteConfig
},
changeWebLanguage (state, {language}) {
if (language) {
state.language = language
i18n.locale = language
moment.locale(language);
}
storage.set('Web_Language', language)
}
}
const rootActions = {
changeModalStatus({ commit }, payload) {

View File

@ -1,53 +1,58 @@
<template>
<el-card shadow>
<div class="error">
<div class="container-floud">
<div style="text-align: center">
<div class="container-error-404">
<div class="clip">
<div class="shadow">
<span class="digit thirdDigit">{{thirdDigit}}</span>
<el-card shadow>
<div class="error">
<div class="container-floud">
<div style="text-align: center">
<div class="container-error-404">
<div class="clip">
<div class="shadow">
<span class="digit thirdDigit">{{ thirdDigit }}</span>
</div>
</div>
<div class="clip">
<div class="shadow">
<span class="digit secondDigit">{{ secondDigit }}</span>
</div>
</div>
<div class="clip">
<div class="shadow">
<span class="digit firstDigit">{{ firstDigit }}</span>
</div>
</div>
<div class="msg">
OH!
<span class="triangle"></span>
</div>
</div>
<div class="clip">
<div class="shadow">
<span class="digit secondDigit">{{secondDigit}}</span>
</div>
</div>
<div class="clip">
<div class="shadow">
<span class="digit firstDigit">{{firstDigit}}</span>
</div>
</div>
<div class="msg">
OH!
<span class="triangle"></span>
</div>
<h2 class="h1">{{ $t('m.Page_Not_Found') }}</h2>
<el-button @click="goHome" size="large" style="width: 150px;">
<i class="el-icon-s-home"></i> {{ $t('m.Go_Home') }}
</el-button>
<el-button
@click="backPage"
size="large"
style="width: 150px;margin-left: 40px;"
type="primary"
>
<i class="el-icon-back"></i> {{ $t('m.Back') }}
</el-button>
</div>
<h2 class="h1">很抱歉你访问的页面找不到了</h2>
<el-button @click="goHome" size="large" style="width: 150px;">
<i class="el-icon-s-home"></i> Go Home
</el-button>
<el-button @click="backPage" size="large" style="width: 150px;margin-left: 40px;" type="primary">
<i class="el-icon-back"></i> Back
</el-button>
</div>
</div>
</div>
</el-card>
</el-card>
</template>
<script>
export default {
name: "NotFound404",
data(){
return{
firstDigit:null,
secondDigit:null,
thirdDigit:null
}
name: 'NotFound404',
data() {
return {
firstDigit: null,
secondDigit: null,
thirdDigit: null,
};
},
mounted(){
this.init()
mounted() {
this.init();
},
methods: {
backPage() {
@ -55,9 +60,8 @@ export default {
},
goHome() {
this.$router.push({
name: "Home",
name: 'Home',
});
},
init() {
var loop1,
@ -66,7 +70,7 @@ export default {
time = 30,
i = 0,
number;
loop3 = setInterval(()=> {
loop3 = setInterval(() => {
if (i > 40) {
clearInterval(loop3);
this.thirdDigit = 4;
@ -75,16 +79,16 @@ export default {
i++;
}
}, time);
loop2 = setInterval(()=> {
loop2 = setInterval(() => {
if (i > 80) {
clearInterval(loop2);
this.secondDigit = 0;
} else {
this.secondDigit= Math.floor(Math.random() * 9) + 1;
this.secondDigit = Math.floor(Math.random() * 9) + 1;
i++;
}
}, time);
loop1 = setInterval(()=> {
loop1 = setInterval(() => {
if (i > 100) {
clearInterval(loop1);
this.firstDigit = 4;
@ -98,7 +102,6 @@ export default {
};
</script>
<style scoped>
.error .clip .shadow {
height: 180px;
}
@ -135,7 +138,7 @@ export default {
border-bottom: 15px solid transparent;
}
.error .container-error-404 {
margin:0 auto;
margin: 0 auto;
position: relative;
height: 250px;
padding-top: 40px;
@ -155,7 +158,7 @@ export default {
}
.error .clip:nth-of-type(3) .shadow:after,
.error .clip:nth-of-type(1) .shadow:after {
content: "";
content: '';
position: absolute;
right: -8px;
bottom: 0px;
@ -214,7 +217,7 @@ export default {
position: absolute;
z-index: 999;
transform: rotate(45deg);
content: "";
content: '';
width: 0;
height: 0;
}
@ -257,4 +260,4 @@ export default {
height: 150px;
}
}
</style>
</style>

View File

@ -68,7 +68,8 @@
<el-card v-else>
<div slot="header" class="content-center">
<span class="panel-title home-title welcome-title"
>Welcome to {{ toUpper(websiteConfig.shortName) }}</span
>{{ $t('m.Welcome_to')
}}{{ toUpper(websiteConfig.shortName) }}</span
>
</div>
<el-carousel
@ -87,9 +88,9 @@
<el-col :md="10" :sm="24" class="phone-margin">
<el-card>
<div slot="header" class="clearfix">
<span class="panel-title home-title"
>Recent 7 Days AC Top 10 Rank</span
>
<span class="panel-title home-title">{{
$t('m.Recent_7_Days_AC_Rank')
}}</span>
</div>
<vxe-table
border="inner"
@ -110,7 +111,7 @@
</vxe-table-column>
<vxe-table-column
field="username"
title="Username"
:title="$t('m.Username')"
min-width="130"
align="left"
>
@ -130,11 +131,16 @@
>
</template>
</vxe-table-column>
<vxe-table-column field="ac" title="AC" min-width="30" align="left">
<vxe-table-column
field="ac"
:title="$t('m.AC')"
min-width="30"
align="left"
>
</vxe-table-column>
<vxe-table-column
field="solved"
title="Solved"
:title="$t('m.Solved')"
min-width="50"
align="left"
>
@ -147,9 +153,9 @@
<el-col :md="14" :sm="24" style="margin-top: 20px;">
<el-card>
<div slot="header" class="clearfix">
<span class="panel-title home-title"
>Other Online Judge Contest</span
>
<span class="panel-title home-title">{{
$t('m.Other_OJ_Contest')
}}</span>
</div>
<vxe-table
border="inner"
@ -162,24 +168,28 @@
>
<vxe-table-column
field="oj"
title="OJ"
:title="$t('m.OJ')"
min-width="100"
></vxe-table-column>
<vxe-table-column
field="title"
title="Title"
:title="$t('m.Title')"
min-width="200"
></vxe-table-column>
<vxe-table-column
field="beginTime"
title="Begin Time"
:title="$t('m.Begin_Time')"
min-width="150"
>
<template v-slot="{ row }">
<span>{{ row.beginTime | localtime }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="endTime" title="End Time" min-width="150">
<vxe-table-column
field="endTime"
:title="$t('m.End_Time')"
min-width="150"
>
<template v-slot="{ row }">
<span>{{ row.endTime | localtime }}</span>
</template>

View File

@ -9,60 +9,58 @@
>
</h1>
<p>
Leader & BackEnd | FrontEnd Engineer / Himit_ZH
{{ $t('m.Leader_BackEnd_FrontEnd_Engineer') }} / Himit_ZH
<a href="https://github.com/HimitZH" class="icon" target="_blank"
><i class="fa fa-github"></i>
</a>
</p>
<p>
BackEnd Engineer / Howie
<a href="https://github.com/Huangyan0804" class="icon" target="_blank"
><i class="fa fa-github"></i>
</a>
</p>
<p>
Maintainer Engineer / Alteria
<a href="https://github.com/HackerMac" class="icon" target="_blank"
><i class="fa fa-github"></i>
</a>
</p>
<p class="teal-text">
<i class="el-icon-circle-check"></i> Open Source
<i class="el-icon-circle-check"></i> {{ $t('m.Open_Source') }}
</p>
</paper-card>
</div>
<el-row :gutter="20">
<el-col :xs="24" :md="12">
<paper-card type="server">
<h1>分布式</h1>
<p><small>前后端分离支持判题微服务集群</small></p>
<h1>{{ $t('m.Distributed') }}</h1>
<p>
<small>{{ $t('m.Distributed_Desc') }}</small>
</p>
<p class="teal-text">
<i class="el-icon-circle-check"></i> Distributed
<i class="el-icon-circle-check"></i> {{ $t('m.Available') }}
</p>
</paper-card>
</el-col>
<el-col :xs="24" :md="12">
<paper-card type="server">
<h1>定制化</h1>
<p><small>网站配置高度集成支持定制化修改</small></p>
<h1>{{ $t('m.Customization') }}</h1>
<p>
<small>{{ $t('m.Customization_Desc') }}</small>
</p>
<p class="teal-text">
<i class="el-icon-circle-check"></i> Customization
<i class="el-icon-circle-check"></i> {{ $t('m.Available') }}
</p>
</paper-card>
</el-col>
<el-col :xs="24" :md="12">
<paper-card type="server">
<h1>安全性</h1>
<p><small>判题沙盒使用cgroup隔离网站权限控制完善</small></p>
<p class="teal-text"><i class="el-icon-circle-check"></i> Security</p>
<h1>{{ $t('m.Security') }}</h1>
<p>
<small>{{ $t('m.Security_Desc') }}</small>
</p>
<p class="teal-text">
<i class="el-icon-circle-check"></i> {{ $t('m.Available') }}
</p>
</paper-card>
</el-col>
<el-col :xs="24" :md="12">
<paper-card type="server">
<h1>多样性</h1>
<p><small>支持CodefocesHDU的远程判题</small></p>
<h1>{{ $t('m.Diversity') }}</h1>
<p>
<small>{{ $t('m.Diversity_Desc') }}</small>
</p>
<p class="teal-text">
<i class="el-icon-circle-check"></i> Diversity
<i class="el-icon-circle-check"></i> {{ $t('m.Faulty') }}
</p>
</paper-card>
</el-col>

View File

@ -4,15 +4,21 @@
<el-col :md="12" :sm="24">
<el-card class="container">
<div slot="header">
<span class="panel-title home-title">Compiler & Example</span>
<span class="panel-title home-title">{{
$t('m.Compiler') + ' & ' + $t('m.Example')
}}</span>
</div>
<div class="content">
<ul>
<li v-for="lang in languages" :key="lang.name">
{{ lang.name }} ( {{ lang.description }} )
<p style="color: #409EFF;font-size:16px">Compiler</p>
<p style="color: #409EFF;font-size:16px">
{{ $t('m.Compiler') }}
</p>
<pre>{{ lang.compileCommand }}</pre>
<p style="color: #409EFF;font-size:16px">A+B Problem</p>
<p style="color: #409EFF;font-size:16px">
A+B {{ $t('m.Problem') }}
</p>
<Highlight
:code="lang.template"
:language="lang.name"
@ -25,77 +31,72 @@
<el-col :md="12" :sm="24">
<el-card class="container">
<div slot="header">
<span class="panel-title home-title">Result Explanation</span>
<span class="panel-title home-title">{{
$t('m.Result_Explanation')
}}</span>
</div>
<ul class="result">
<li>
<span :class="getStatusColor(5)">Pending</span>
您的解答正在排队等待测评中请等待结果...
{{ $t('m.Pending_Description') }}
</li>
<li>
<span :class="getStatusColor(10)">Submitted Failed</span>
您的此次提交失败请点击按钮重新提交...
{{ $t('m.Submitted_Faild_Description') }}
</li>
<li>
<span :class="getStatusColor(6)">Compiling</span>
正在对您的源代码进行编译中请等待结果...
{{ $t('m.Compiling_Description') }}
</li>
<li>
<span :class="getStatusColor(7)">Judging</span>
正在使用测试数据运行您的程序中请等待结果...
{{ $t('m.Judging_Description') }}
</li>
<li>
<span :class="getStatusColor(-2)">Compile Error</span> :
无法编译您的源代码点击链接查看编译器的输出
{{ $t('m.Compile_Error_Description') }}
</li>
<li>
<span :class="getStatusColor(-3)">Presentation Error</span> :
您提交的代码已经很接近正确答案请检查代码格式输出是否有多余空格换行等空白符
{{ $t('m.Persentation_Error_Description') }}
</li>
<li>
<span :class="getStatusColor(0)">Accepted</span> :
您的解题方法是正确的
{{ $t('m.Accepted_Description') }}
</li>
<li>
<span :class="getStatusColor(-1)">Wrong Answer</span> :
您的程序输出结果与判题程序的答案不符
{{ $t('m.Wrong_Answer_Description') }}
</li>
<li>
<span :class="getStatusColor(3)">Runtime Error</span> :
您的程序异常终止可能的原因是段错误被零除或用非0的代码退出程序
{{ $t('m.Runtime_Error_Description') }}
</li>
<li>
<span :class="getStatusColor(1)">Time Limit Exceeded</span> :
您的程序使用的 CPU 时间已超出题目限制
{{ $t('m.Time_Limit_Exceeded_Description') }}
</li>
<li>
<span :class="getStatusColor(2)">Memory Limit Exceeded</span> :
您的程序实际使用的内存已超出题目限制
{{ $t('m.Memory_Limit_Exceeded_Description') }}
</li>
<li>
<span :class="getStatusColor(4)">System Error</span> :
糟糕判题机系统出了问题请报告给管理员
{{ $t('m.System_Error_Description') }}
</li>
</ul>
</el-card>
<el-card class="container">
<div slot="header">
<span class="panel-title home-title">Compile Explanation</span>
<span class="panel-title home-title">{{
$t('m.Compile_Explanation')
}}</span>
</div>
<ul class="result">
<li>
1. __int64不是ANSI标准定义只能在VC使用 GNU C++ 中应写成 long
long 类型 scanf和printf 请使用%lld作为格式
</li>
<li>
2. main() 返回值必须定义为 int 而不是 void
</li>
<li>
3. i 在循环外失去定义 "for(int i=0...){...}"
</li>
<li>
4. itoa 不是ansi标准函数标准 C/C++ 中无此函数
</li>
<li>1. {{ $t('m.Compile_Tips1') }}</li>
<li>2. {{ $t('m.Compile_Tips2') }}</li>
<li>3. {{ $t('m.Compile_Tips2') }}</li>
<li>4. {{ $t('m.Compile_Tips4') }}</li>
</ul>
</el-card>
</el-col>

View File

@ -12,14 +12,14 @@
<el-col :span="12" class="text-align:left">
<el-tooltip
v-if="contest.auth != null && contest.auth != undefined"
:content.sync="CONTEST_TYPE_REVERSE[contest.auth]['tips']"
:content="$t('m.' + CONTEST_TYPE_REVERSE[contest.auth]['tips'])"
placement="top"
>
<el-tag
:type.sync="CONTEST_TYPE_REVERSE[contest.auth]['color']"
effect="plain"
>
{{ CONTEST_TYPE_REVERSE[contest.auth]['name'] }}
{{ $t('m.' + CONTEST_TYPE_REVERSE[contest.auth]['name']) }}
</el-tag>
</el-tooltip>
</el-col>
@ -34,13 +34,13 @@
<el-col :xs="24" :md="12" class="left">
<p>
<i class="fa fa-hourglass-start" aria-hidden="true"></i>
StartAt{{ contest.startTime | localtime }}
{{ $t('m.StartAt') }}{{ contest.startTime | localtime }}
</p>
</el-col>
<el-col :xs="24" :md="12" class="right">
<p>
<i class="fa fa-hourglass-end" aria-hidden="true"></i>
EndAt{{ contest.endTime | localtime }}
{{ $t('m.EndAt') }}{{ contest.endTime | localtime }}
</p>
</el-col>
</el-row>
@ -71,30 +71,32 @@
style="text-align:center"
>
<div slot="header">
<span class="panel-title">Password required</span>
<span class="panel-title">{{ $t('m.Password_Required') }}</span>
</div>
<p class="password-form-tips">
To enter the Private contest,please input the password!
{{ $t('m.To_Enter_Need_Password') }}
</p>
<el-form>
<el-input
v-model="contestPassword"
type="password"
placeholder="Enter the contest password"
:placeholder="$t('m.Enter_the_contest_password')"
@keydown.enter.native="checkPassword"
/>
<el-button
type="primary"
@click="checkPassword"
style="float:right;margin:5px"
>Enter</el-button
>{{ $t('m.Enter') }}</el-button
>
</el-form>
</el-card>
<el-tabs v-else @tab-click="tabClick" v-model="route_name">
<el-tab-pane name="ContestDetails" lazy>
<span slot="label"><i class="el-icon-s-home"></i>&nbsp;Overview</span>
<span slot="label"
><i class="el-icon-s-home"></i>&nbsp;{{ $t('m.Overview') }}</span
>
<el-card class="box-card">
<div
v-html="descriptionHtml"
@ -111,7 +113,9 @@
:disabled="contestMenuDisabled"
>
<span slot="label"
><i class="fa fa-list" aria-hidden="true"></i>&nbsp;Problem</span
><i class="fa fa-list" aria-hidden="true"></i>&nbsp;{{
$t('m.Problem')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view
@ -125,7 +129,9 @@
lazy
:disabled="contestMenuDisabled"
>
<span slot="label"><i class="el-icon-menu"></i>&nbsp;Status</span>
<span slot="label"
><i class="el-icon-menu"></i>&nbsp;{{ $t('m.Status') }}</span
>
<transition name="el-zoom-in-bottom">
<router-view
v-if="route_name === 'ContestSubmissionList'"
@ -135,7 +141,9 @@
<el-tab-pane name="ContestRank" lazy :disabled="contestMenuDisabled">
<span slot="label"
><i class="fa fa-bar-chart" aria-hidden="true"></i>&nbsp;Rank</span
><i class="fa fa-bar-chart" aria-hidden="true"></i>&nbsp;{{
$t('m.NavBar_Rank')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view v-if="route_name === 'ContestRank'"></router-view>
@ -148,8 +156,9 @@
:disabled="contestMenuDisabled"
>
<span slot="label"
><i class="fa fa-bullhorn" aria-hidden="true"></i
>&nbsp;Announcement</span
><i class="fa fa-bullhorn" aria-hidden="true"></i>&nbsp;{{
$t('m.Announcement')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view
@ -160,8 +169,9 @@
<el-tab-pane name="ContestComment" lazy :disabled="contestMenuDisabled">
<span slot="label"
><i class="fa fa-commenting" aria-hidden="true"></i
>&nbsp;Comment</span
><i class="fa fa-commenting" aria-hidden="true"></i>&nbsp;{{
$t('m.Comment')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view v-if="route_name === 'ContestComment'"></router-view>
@ -175,8 +185,9 @@
v-if="showAdminHelper"
>
<span slot="label"
><i class="el-icon-s-help" aria-hidden="true"></i>&nbsp;AC
Info</span
><i class="el-icon-s-help" aria-hidden="true"></i>&nbsp;{{
$t('m.Admin_Helper')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view v-if="route_name === 'ContestACInfo'"></router-view>
@ -190,8 +201,9 @@
v-if="isSuperAdmin"
>
<span slot="label"
><i class="el-icon-refresh" aria-hidden="true"></i
>&nbsp;Rejudge</span
><i class="el-icon-refresh" aria-hidden="true"></i>&nbsp;{{
$t('m.Rejudge')
}}</span
>
<transition name="el-zoom-in-bottom">
<router-view
@ -273,13 +285,13 @@ export default {
},
checkPassword() {
if (this.contestPassword === '') {
myMessage.warning('请输入该比赛的密码!');
myMessage.warning(this.$i18n.t('m.Enter_the_contest_password'));
return;
}
this.btnLoading = true;
api.registerContest(this.contestID + '', this.contestPassword).then(
(res) => {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Register_contest_successfully'));
this.$store.commit('contestIntoAccess', { intoAccess: true });
this.btnLoading = false;
},

View File

@ -5,9 +5,9 @@
<div slot="header">
<span class="panel-title"
>{{
query.type === '' ? 'All' : parseContestType(query.type)
query.type === '' ? $t('m.All') : parseContestType(query.type)
}}
Contests</span
{{ $t('m.Contests') }}</span
>
<div class="filter-row">
<span>
@ -18,11 +18,17 @@
class="drop-menu"
>
<span class="el-dropdown-link">
{{ query.type == '' ? 'Rule' : parseContestType(query.type) }}
{{
query.type == ''
? $t('m.Rule')
: parseContestType(query.type)
}}
<i class="el-icon-caret-bottom"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="">All</el-dropdown-item>
<el-dropdown-item command="">{{
$t('m.All')
}}</el-dropdown-item>
<el-dropdown-item command="0">ACM</el-dropdown-item>
<el-dropdown-item command="1">OI</el-dropdown-item>
</el-dropdown-menu>
@ -39,16 +45,24 @@
<span class="el-dropdown-link">
{{
query.status === ''
? 'Status'
? $t('m.Status')
: CONTEST_STATUS_REVERSE[query.status]['name']
}}
<i class="el-icon-caret-bottom"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="">All</el-dropdown-item>
<el-dropdown-item command="-1">Scheduled</el-dropdown-item>
<el-dropdown-item command="0">Running</el-dropdown-item>
<el-dropdown-item command="1">Ended</el-dropdown-item>
<el-dropdown-item command="">{{
$t('m.All')
}}</el-dropdown-item>
<el-dropdown-item command="-1">{{
$t('m.Scheduled')
}}</el-dropdown-item>
<el-dropdown-item command="0">{{
$t('m.Running')
}}</el-dropdown-item>
<el-dropdown-item command="1">{{
$t('m.Ended')
}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
@ -56,7 +70,7 @@
<span>
<vxe-input
v-model="query.keyword"
placeholder="Enter keyword"
:placeholder="$t('m.Enter_keyword')"
type="search"
size="medium"
@keyup.enter.native="filterByChange"
@ -65,7 +79,9 @@
</span>
</div>
</div>
<p id="no-contest" v-show="contests.length == 0">暂无比赛</p>
<p id="no-contest" v-show="contests.length == 0">
{{ $t('m.No_contest') }}
</p>
<ol id="contest-list">
<li
v-for="contest in contests"
@ -127,7 +143,9 @@
</li>
<li>
<el-tooltip
:content="CONTEST_TYPE_REVERSE[contest.auth].tips"
:content="
$t('m.' + CONTEST_TYPE_REVERSE[contest.auth].tips)
"
placement="top"
effect="light"
>
@ -135,7 +153,9 @@
:type="CONTEST_TYPE_REVERSE[contest.auth]['color']"
effect="plain"
>
{{ CONTEST_TYPE_REVERSE[contest.auth]['name'] }}
{{
$t('m.' + CONTEST_TYPE_REVERSE[contest.auth]['name'])
}}
</el-tag>
</el-tooltip>
</li>
@ -154,7 +174,9 @@
size="medium"
>
<i class="fa fa-circle" aria-hidden="true"></i>
{{ CONTEST_STATUS_REVERSE[contest.status]['name'] }}
{{
$t('m.' + CONTEST_STATUS_REVERSE[contest.status]['name'])
}}
</el-tag>
</el-col>
</el-row>
@ -257,7 +279,7 @@ export default {
},
toContest(contest) {
if (contest.type !== CONTEST_TYPE.PUBLIC && !this.isAuthenticated) {
myMessage.warning('请先登录');
myMessage.warning(this.$i18n.t('m.Please_login_first'));
this.$store.dispatch('changeModalStatus', { visible: true });
} else {
this.$router.push({

View File

@ -1,21 +1,21 @@
<template>
<el-card shadow>
<div slot="header">
<span class="panel-title">Contest Rank</span>
<span class="panel-title">{{ $t('m.Contest_Rank') }}</span>
<span style="float:right;font-size: 20px;">
<el-popover trigger="hover" placement="left-start">
<i class="el-icon-s-tools" slot="reference"></i>
<div id="switches">
<p>
<span>Chart</span>
<span>{{ $t('m.Chart') }}</span>
<el-switch v-model="showChart"></el-switch>
</p>
<p>
<span>Table</span>
<span>{{ $t('m.Table') }}</span>
<el-switch v-model="showTable"></el-switch>
</p>
<p>
<span>Auto Refresh(10s)</span>
<span>{{ $t('m.Auto_Refresh') }}(10s)</span>
<el-switch
:disabled="refreshDisabled"
v-model="autoRefresh"
@ -24,7 +24,7 @@
</p>
<template v-if="isContestAdmin">
<p>
<span>Force Update</span>
<span>{{ $t('m.Force_Update') }}</span>
<el-switch
:disabled="refreshDisabled"
v-model="forceUpdate"
@ -32,9 +32,9 @@
</p>
</template>
<template>
<el-button type="primary" size="small" @click="downloadRankCSV"
>Download as CSV</el-button
>
<el-button type="primary" size="small" @click="downloadRankCSV">{{
$t('m.Download_as_CSV')
}}</el-button>
</template>
</div>
</el-popover>
@ -59,7 +59,11 @@
min-width="50"
fixed="left"
></vxe-table-column>
<vxe-table-column field="username" min-width="150" title="User">
<vxe-table-column
field="username"
min-width="150"
:title="$t('m.User')"
>
<template v-slot="{ row }">
<span
><a
@ -73,11 +77,15 @@
<vxe-table-column
field="realname"
min-width="100"
title="RealName"
:title="$t('m.RealName')"
v-if="isContestAdmin"
>
</vxe-table-column>
<vxe-table-column field="rating" title="AC / Total" min-width="80">
<vxe-table-column
field="rating"
:title="$t('m.AC') + ' / ' + $t('m.Total')"
min-width="80"
>
<template v-slot="{ row }">
<span
>{{ row.ac }} /
@ -89,7 +97,11 @@
</span>
</template>
</vxe-table-column>
<vxe-table-column field="totalTime" title="TotalTime" min-width="80">
<vxe-table-column
field="totalTime"
:title="$t('m.TotalTime')"
min-width="80"
>
<template v-slot="{ row }">
<span>{{ parseTotalTime(row.totalTime) }}</span>
</template>
@ -155,7 +167,7 @@ export default {
dataRank: [],
options: {
title: {
text: 'Top 10 Teams',
text: this.$i18n.t('m.Top_10_Teams'),
left: 'center',
top: 0,
},
@ -171,7 +183,7 @@ export default {
toolbox: {
show: true,
feature: {
saveAsImage: { show: true, title: 'save as image' },
saveAsImage: { show: true, title: this.$i18n.t('m.save_as_image') },
},
right: '0',
},

View File

@ -1,10 +1,10 @@
<template>
<el-card shadow="always">
<div slot="header">
<span class="panel-title">AC Info</span>
<span class="panel-title">{{ $t('m.Admin_Helper') }}</span>
<div class="filter-row">
<span>
Auto Refresh(10s)
{{ $t('m.Auto_Refresh') }}(10s)
<el-switch
@change="handleAutoRefresh"
v-model="autoRefresh"
@ -17,7 +17,7 @@
size="small"
icon="el-icon-refresh"
:loading="btnLoading"
>Refresh</el-button
>{{ $t('m.Refresh') }}</el-button
>
</span>
</div>
@ -29,25 +29,35 @@
align="center"
:data="acInfoList"
>
<vxe-table-column field="submitTime" min-width="150" title="AC Time">
<vxe-table-column
field="submitTime"
min-width="150"
:title="$t('m.AC_Time')"
>
<template v-slot="{ row }">
<span>{{ row.submitTime | localtime }}</span>
</template>
</vxe-table-column>
<vxe-table-column
field="displayId"
title="Problem ID"
:title="$t('m.Problem_ID')"
min-width="100"
></vxe-table-column>
<vxe-table-column field="first_blood" title="AC Status" min-width="80">
<template v-slot="{ row }">
<el-tag effect="dark" color="#ed3f14" v-if="row.firstBlood"
>First Blood</el-tag
>
<el-tag effect="dark" color="#19be6b" v-else>Accepet</el-tag>
<el-tag effect="dark" color="#ed3f14" v-if="row.firstBlood">{{
$t('m.First_Blood')
}}</el-tag>
<el-tag effect="dark" color="#19be6b" v-else>{{
$t('m.Accepted')
}}</el-tag>
</template>
</vxe-table-column>
<vxe-table-column field="username" title="Username" min-width="150">
<vxe-table-column
field="username"
:title="$t('m.Username')"
min-width="150"
>
<template v-slot="{ row }">
<span
><a
@ -60,15 +70,17 @@
</vxe-table-column>
<vxe-table-column
field="realname"
title="RealName"
:title="$t('m.RealName')"
min-width="150"
></vxe-table-column>
<vxe-table-column field="checked" title="Status" min-width="150">
<vxe-table-column field="checked" :title="$t('m.Status')" min-width="150">
<template v-slot="{ row }">
<el-tag effect="dark" color="#19be6b" v-if="row.checked"
>Checked</el-tag
>
<el-tag effect="dark" color="#f90" v-else>Not Checked</el-tag>
<el-tag effect="dark" color="#19be6b" v-if="row.checked">{{
$t('m.Checked')
}}</el-tag>
<el-tag effect="dark" color="#f90" v-else>{{
$t('m.Not_Checked')
}}</el-tag>
</template>
</vxe-table-column>
<vxe-table-column field="option" title="Option" min-width="150">
@ -79,7 +91,7 @@
icon="el-icon-circle-check"
@click="updateCheckedStatus(row)"
round
>Check It</el-button
>{{ $t('m.Check_It') }}</el-button
>
</template>
</vxe-table-column>
@ -93,8 +105,7 @@
</el-card>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import moment from 'moment';
import { mapState } from 'vuex';
import Pagination from '@/components/oj/common/Pagination.vue';
import api from '@/common/api';
import myMessage from '@/common/message';
@ -152,7 +163,7 @@ export default {
api
.updateACInfoCheckedStatus(data)
.then((res) => {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Update_Successfully'));
this.getACInfo();
})
.catch(() => {});

View File

@ -69,26 +69,26 @@
></vxe-table-column>
<vxe-table-column
field="displayTitle"
title="Title"
:title="$t('m.Title')"
min-width="200"
></vxe-table-column>
<!-- 以下列只有在实时刷新榜单的情况下才显示 -->
<vxe-table-column
field="ac"
title="AC"
:title="$t('m.AC')"
min-width="80"
v-if="ContestRealTimePermission"
></vxe-table-column>
<vxe-table-column
field="total"
title="Total"
:title="$t('m.Total')"
min-width="80"
v-if="ContestRealTimePermission"
></vxe-table-column>
<vxe-table-column
field="ACRating"
title="AC Rate"
:title="$t('m.AC_Rate')"
min-width="80"
v-if="ContestRealTimePermission"
>

View File

@ -1,7 +1,7 @@
<template>
<el-card shadow="always">
<div slot="header">
<span class="panel-title">Admin Contest Rejudge</span>
<span class="panel-title">{{ $t('m.Contest_Rejudge') }}</span>
</div>
<vxe-table
border="inner"
@ -10,23 +10,27 @@
align="center"
:data="contestProblems"
>
<vxe-table-column field="pid" min-width="50" title="Problem ID">
<vxe-table-column field="pid" min-width="50" :title="$t('m.ID')">
</vxe-table-column>
<vxe-table-column
field="displayId"
title="Display ID"
:title="$t('m.Problem_ID')"
min-width="100"
></vxe-table-column>
<vxe-table-column field="displayTitle" title="Title" min-width="200">
<vxe-table-column
field="displayTitle"
:title="$t('m.Title')"
min-width="200"
>
</vxe-table-column>
<vxe-table-column field="ac" title="AC" min-width="80">
<vxe-table-column field="ac" :title="$t('m.AC')" min-width="80">
</vxe-table-column>
<vxe-table-column
field="total"
title="Total"
:title="$t('m.Total')"
min-width="80"
></vxe-table-column>
<vxe-table-column field="option" title="Option" min-width="150">
<vxe-table-column field="option" :title="$t('m.Option')" min-width="150">
<template v-slot="{ row }">
<el-button
type="primary"
@ -35,7 +39,7 @@
icon="el-icon-refresh-right"
@click="rejudgeProblem(row)"
round
>Rejudge All</el-button
>{{ $t('m.Rejudge_All') }}</el-button
>
</template>
</vxe-table-column>
@ -63,26 +67,29 @@ export default {
methods: {
...mapActions(['getContestProblems']),
rejudgeProblem(row) {
this.$confirm('你是否确定将该题的所有提交全部重判?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$i18n.t('m.Contest_Rejudge_Tips'), 'Tips', {
confirmButtonText: this.$i18n.t('m.OK'),
cancelButtonText: this.$i18n.t('m.Cancel'),
type: 'warning',
}).then(() => {
let params = {
pid: row.pid,
cid: row.cid,
};
this.btnLoading = true;
api
.ContestRejudgeProblem(params)
.then((res) => {
myMessage.success(res.data.msg);
this.btnLoading = false;
})
.catch(() => {
this.btnLoading = false;
});
});
}).then(
() => {
let params = {
pid: row.pid,
cid: row.cid,
};
this.btnLoading = true;
api
.ContestRejudgeProblem(params)
.then((res) => {
myMessage.success(this.$i18n.t('m.Rejudge_successfully'));
this.btnLoading = false;
})
.catch(() => {
this.btnLoading = false;
});
},
() => {}
);
},
},
computed: {

View File

@ -1,21 +1,21 @@
<template>
<el-card shadow>
<div slot="header">
<span class="panel-title">Contest Rank</span>
<span class="panel-title">{{ $t('m.Contest_Rank') }}</span>
<span style="float:right;font-size: 20px;">
<el-popover trigger="hover" placement="left-start">
<i class="el-icon-s-tools" slot="reference"></i>
<div id="switches">
<p>
<span>Chart</span>
<span>{{ $t('m.Chart') }}</span>
<el-switch v-model="showChart"></el-switch>
</p>
<p>
<span>Table</span>
<span>{{ $t('m.Table') }}</span>
<el-switch v-model="showTable"></el-switch>
</p>
<p>
<span>Auto Refresh(10s)</span>
<span>{{ $t('m.Auto_Refresh') }}(10s)</span>
<el-switch
:disabled="refreshDisabled"
@change="handleAutoRefresh"
@ -24,7 +24,7 @@
</p>
<template v-if="isContestAdmin">
<p>
<span>Force Update</span>
<span>{{ $t('m.Force_Update') }}</span>
<el-switch
:disabled="refreshDisabled"
v-model="forceUpdate"
@ -32,9 +32,9 @@
</p>
</template>
<template>
<el-button type="primary" size="small" @click="downloadRankCSV"
>Download as CSV</el-button
>
<el-button type="primary" size="small" @click="downloadRankCSV">{{
$t('m.Download_as_CSV')
}}</el-button>
</template>
</div>
</el-popover>
@ -60,7 +60,11 @@
min-width="50"
fixed="left"
></vxe-table-column>
<vxe-table-column field="username" min-width="150" title="User">
<vxe-table-column
field="username"
min-width="150"
:title="$t('m.User')"
>
<template v-slot="{ row }">
<span
><a
@ -74,11 +78,15 @@
<vxe-table-column
field="realname"
min-width="100"
title="RealName"
:title="$t('m.RealName')"
v-if="isContestAdmin"
>
</vxe-table-column>
<vxe-table-column field="totalScore" title="TotalScore" min-width="80">
<vxe-table-column
field="totalScore"
:title="$t('m.Total_Score')"
min-width="80"
>
<template v-slot="{ row }">
<span
><a
@ -141,7 +149,7 @@ export default {
autoRefresh: false,
options: {
title: {
text: 'Top 10 Teams',
text: this.$i18n.t('m.Top_10_Teams'),
left: 'center',
},
tooltip: {
@ -152,7 +160,7 @@ export default {
feature: {
dataView: { show: true, readOnly: true },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true },
saveAsImage: { show: true, title: this.$i18n.t('m.save_as_image') },
},
right: '10%',
top: '5%',
@ -187,7 +195,7 @@ export default {
},
series: [
{
name: 'Score',
name: this.$i18n.t('m.Score'),
type: 'bar',
barMaxWidth: '80',
data: [0],

View File

@ -36,7 +36,7 @@
>ADM</span
>
<span class="c999" style="padding:0 6px;"
><i class="el-icon-folder-opened"> 分类</i
><i class="el-icon-folder-opened"> {{ $t('m.Category') }}</i
><a
class="c999"
@click="toAllDiscussionByCid(discussion.categoryId)"
@ -45,35 +45,39 @@
>
<span class="c999"
><i class="fa fa-thumbs-o-up"></i
><span> 点赞{{ discussion.likeNum }}</span></span
><span> {{ $t('m.Likes') }}{{ discussion.likeNum }}</span></span
>
<span class="c999"
><i class="fa fa-eye"></i
><span> 浏览{{ discussion.viewNum }}</span></span
><span> {{ $t('m.Views') }}{{ discussion.viewNum }}</span></span
>
<a @click="showReportDialog = true" class="report" title="举报"
><i class="fa fa-envira"></i><span>举报</span></a
<a
@click="showReportDialog = true"
class="report"
:title="$t('m.Report')"
><i class="fa fa-envira"></i><span>{{ $t('m.Report') }}</span></a
>
<a
@click="toLikeDiscussion(discussion.id, true)"
class="like"
title="点赞"
:title="$t('m.Like')"
v-if="!discussion.hasLike"
>
<i class="fa fa-thumbs-o-up"></i> <span>点赞</span></a
<i class="fa fa-thumbs-o-up"></i>
<span>{{ $t('m.Like') }}</span></a
>
<a
@click="toLikeDiscussion(discussion.id, false)"
class="like"
title="已点赞"
:title="$t('m.Liked')"
v-else
>
<i class="fa fa-thumbs-up"></i> <span>已点赞</span></a
<i class="fa fa-thumbs-up"></i> <span>{{ $t('m.Liked') }}</span></a
>
<span>
<i class="fa fa-clock-o"> 创建时间</i>
<i class="fa fa-clock-o"> {{ $t('m.Created_Time') }}</i>
<span>
<el-tooltip
:content="discussion.gmtCreate | localtime"
@ -86,7 +90,7 @@
<span style="padding:0 6px;" v-show="userInfo.uid == discussion.uid"
><a style="color:#8fb0c9" @click="showEditDiscussionDialog = true"
><i class="el-icon-edit-outline"> 编辑</i></a
><i class="el-icon-edit-outline"> {{ $t('m.Edit') }}</i></a
></span
>
</div>
@ -100,9 +104,13 @@
></div>
</div>
</div>
<el-dialog title="举报" :visible.sync="showReportDialog" width="350px">
<el-dialog
:title="$t('m.Report')"
:visible.sync="showReportDialog"
width="350px"
>
<el-form label-position="top" :model="report">
<el-form-item label="标签" required>
<el-form-item :label="$t('m.Tags')" required>
<el-checkbox-group v-model="report.tagList">
<el-checkbox label="垃圾广告"></el-checkbox>
<el-checkbox label="违法违规"></el-checkbox>
@ -112,11 +120,11 @@
<el-checkbox label="恶意抄袭"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="理由" required>
<el-form-item :label="$t('m.Report_Reason')" required>
<el-input
type="textarea"
v-model="report.content"
placeholder="请写下举报的理由"
:placeholder="$t('m.Report_Reason')"
maxlength="200"
show-word-limit
:rows="4"
@ -125,10 +133,12 @@
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="danger" @click.native="showReportDialog = false"
>取消</el-button
>
<el-button type="primary" @click.native="submitReport">提交</el-button>
<el-button type="danger" @click.native="showReportDialog = false">{{
$t('m.Cancel')
}}</el-button>
<el-button type="primary" @click.native="submitReport">{{
$t('m.OK')
}}</el-button>
</span>
</el-dialog>
@ -140,28 +150,24 @@
@open="onOpenEditDialog"
>
<el-form label-position="top" :model="discussion">
<el-form-item label="讨论标题" required>
<el-form-item :label="$t('m.Discussion_title')" required>
<el-input
v-model="discussion.title"
placeholder="请输入讨论标题"
:placeholder="$t('m.Discussion_title')"
class="title-input"
>
</el-input>
</el-form-item>
<el-form-item label="讨论简介" required>
<el-form-item :label="$t('m.Discussion_Desc')" required>
<el-input
v-model="discussion.description"
placeholder="请输入讨论简介"
:placeholder="$t('m.Discussion_Desc')"
class="title-input"
>
</el-input>
</el-form-item>
<el-form-item label="讨论分类" required>
<el-select
v-model="discussion.categoryId"
placeholder="请选择"
disabled
>
<el-form-item :label="$t('m.Discussion_Category')" required>
<el-select v-model="discussion.categoryId" placeholder="---" disabled>
<el-option
:label="discussion.categoryName"
:value="discussion.categoryId"
@ -169,10 +175,14 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item label="是否置顶" required v-if="isAdminRole">
<el-form-item
:label="$t('m.Discussion_top')"
required
v-if="isAdminRole"
>
<el-switch v-model="discussion.topPriority"> </el-switch>
</el-form-item>
<el-form-item label="讨论内容" required>
<el-form-item :label="$t('m.Discussion_content')" required>
<Editor :value.sync="discussion.content"></Editor>
</el-form-item>
</el-form>
@ -180,11 +190,11 @@
<el-button
type="danger"
@click.native="showEditDiscussionDialog = false"
>取消</el-button
>
<el-button type="primary" @click.native="submitDiscussion"
>发布</el-button
>{{ $t('m.Cancel') }}</el-button
>
<el-button type="primary" @click.native="submitDiscussion">{{
$t('m.OK')
}}</el-button>
</span>
</el-dialog>
<comment :did="$route.params.discussionID"></comment>
@ -260,7 +270,7 @@ export default {
toLikeDiscussion(did, toLike) {
if (!this.isAuthenticated) {
myMessage.warning('请先登录');
myMessage.warning(this.$i18n.t('m.Please_login_first'));
return;
}
api.toLikeDiscussion(did, toLike).then((res) => {
@ -281,14 +291,14 @@ export default {
delete discussion.viewNum;
delete discussion.likeNum;
api.updateDiscussion(discussion).then((res) => {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Update_Successfully'));
this.showEditDiscussionDialog = false;
this.init();
});
},
submitReport() {
if (!this.isAuthenticated) {
myMessage.warning('请先登录');
myMessage.warning(this.$i18n.t('m.Please_login_first'));
return;
}
if (this.report.tagList.length == 0 && !this.report.content) {
@ -306,7 +316,7 @@ export default {
did: this.discussionID,
};
api.toReportDiscussion(discussionReport).then((res) => {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Post_successfully'));
this.showReportDialog = false;
});
},
@ -388,7 +398,7 @@ export default {
.title-article .title-msg a.like {
position: absolute;
top: 30px;
right: 60px;
right: 68px;
color: #ff6700 !important;
font-weight: bold;
font-size: 14px;

View File

@ -7,7 +7,8 @@
<el-breadcrumb separator-class="el-icon-arrow-right">
<template v-if="currentCategory">
<el-breadcrumb-item :to="{ name: routeName, query: null }">
{{ query.onlyMine ? '我的' : '' }}全部</el-breadcrumb-item
{{ query.onlyMine ? $t('m.Mine') : ''
}}{{ $t('m.All') }}</el-breadcrumb-item
>
<el-breadcrumb-item
>{{ currentCategory }} ( {{ total }} )</el-breadcrumb-item
@ -15,7 +16,7 @@
</template>
<template v-else>
<el-breadcrumb-item :to="{ name: routeName }"
>{{ query.onlyMine ? '我的' : '' }}全部 (
>{{ query.onlyMine ? $t('m.Mine') : '' }}{{ $t('m.All') }} (
{{ total }} )</el-breadcrumb-item
>
</template>
@ -24,7 +25,7 @@
<span class="search"
><vxe-input
v-model="query.keyword"
placeholder="Enter the keyword"
:placeholder="$t('m.Enter_keyword')"
type="search"
@keyup.enter.native="handleQueryChange"
@search-click="handleQueryChange"
@ -103,7 +104,7 @@
<span class="pr pl hidden-xs-only"
><label class="fw"><i class="fa fa-clock-o"></i></label
><span>
创建时间<el-tooltip
{{ $t('m.Created_Time') }}<el-tooltip
:content="discussion.gmtCreate | localtime"
placement="top"
>
@ -113,11 +114,15 @@
>
<span class="pr"
><label class="fw"><i class="fa fa-thumbs-o-up"></i></label
><span> 点赞{{ discussion.likeNum }}</span></span
><span>
{{ $t('m.Likes') }}{{ discussion.likeNum }}</span
></span
>
<span class="pr"
><label class="fw"><i class="fa fa-eye"></i></label
><span> 浏览{{ discussion.viewNum }}</span></span
><span>
{{ $t('m.Views') }}{{ discussion.viewNum }}</span
></span
>
<span
><label class="fw"><i class="el-icon-folder-opened"></i></label>
@ -148,13 +153,13 @@
icon="el-icon-edit-outline"
:command="'edit:' + index"
v-show="discussion.uid === userInfo.uid"
>编辑</el-dropdown-item
>{{ $t('m.Edit') }}</el-dropdown-item
>
<el-dropdown-item
icon="el-icon-delete"
:command="'delete:' + index"
v-show="discussion.uid === userInfo.uid || isAdminRole"
>删除</el-dropdown-item
>{{ $t('m.Delete') }}</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
@ -173,13 +178,13 @@
icon="el-icon-edit-outline"
:command="'edit:' + index"
v-show="discussion.uid === userInfo.uid"
>编辑</el-dropdown-item
>{{ $t('m.Edit') }}</el-dropdown-item
>
<el-dropdown-item
icon="el-icon-delete"
:command="'delete:' + index"
v-show="discussion.uid === userInfo.uid || isAdminRole"
>删除</el-dropdown-item
>{{ $t('m.Delete') }}</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
@ -206,7 +211,11 @@
@click="toEditDiscussion"
style="width: 100%;"
><i class="el-icon-edit">
{{ this.query.pid == '' ? '发布讨论' : '发布题目讨论' }}</i
{{
this.query.pid == ''
? $t('m.Post_discussion')
: $t('m.Post_problem_discussion')
}}</i
>
</el-button>
<el-button
@ -216,7 +225,7 @@
@click="toOnlyMyDiscussion(!query.onlyMine)"
style="width: 100%;margin-left:0;margin-top:10px"
><i class="el-icon-search">
{{ query.onlyMine ? '查看所有讨论' : '只看自己' }}</i
{{ query.onlyMine ? $t('m.All') : $t('m.Mine') }}</i
>
</el-button>
<template v-if="this.query.pid">
@ -225,7 +234,7 @@
type="success"
@click="toAllDiscussion"
style="width: 100%;margin-left:0;margin-top:10px"
><i class="el-icon-s-home"> 综合讨论区</i>
><i class="el-icon-s-home"> {{ $t('m.General_discussion') }}</i>
</el-button>
<el-button
@ -239,7 +248,7 @@
)
"
style="width: 100%;margin-left:0;margin-top:10px"
><i class="el-icon-back"> 返回 ({{ query.pid }}) 题目</i>
><i class="el-icon-back"> {{ $t('m.Return') }} ({{ query.pid }})</i>
</el-button>
</template>
<div class="category-body">
@ -252,7 +261,7 @@
routeName
)
"
><i class="el-icon-folder-opened"></i> 讨论分类</a
><i class="el-icon-folder-opened"></i> {{ $t('m.Category') }}</a
>
</h3>
<el-row>
@ -292,24 +301,24 @@
@open="onOpenEditDialog"
>
<el-form label-position="top" :model="discussion">
<el-form-item label="讨论标题" required>
<el-form-item :label="$t('m.Discussion_title')" required>
<el-input
v-model="discussion.title"
placeholder="请输入讨论标题"
:placeholder="$t('m.Discussion_title')"
class="title-input"
>
</el-input>
</el-form-item>
<el-form-item label="讨论简介" required>
<el-form-item :label="$t('m.Discussion_Desc')" required>
<el-input
v-model="discussion.description"
placeholder="请输入讨论简介"
:placeholder="$t('m.Discussion_Desc')"
class="title-input"
>
</el-input>
</el-form-item>
<el-form-item label="讨论分类" required>
<el-select v-model="discussion.categoryId" placeholder="请选择">
<el-form-item :label="$t('m.Discussion_Category')" required>
<el-select v-model="discussion.categoryId" placeholder="---">
<el-option
v-for="category in categoryList"
:key="category.id"
@ -319,10 +328,14 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item label="是否置顶" required v-if="isAdminRole">
<el-form-item
:label="$t('m.Discussion_top')"
required
v-if="isAdminRole"
>
<el-switch v-model="discussion.topPriority"> </el-switch>
</el-form-item>
<el-form-item label="讨论内容" required>
<el-form-item :label="$t('m.Discussion_content')" required>
<Editor :value.sync="discussion.content"></Editor>
</el-form-item>
</el-form>
@ -330,11 +343,11 @@
<el-button
type="danger"
@click.native="showEditDiscussionDialog = false"
>取消</el-button
>
<el-button type="primary" @click.native="submitDiscussion"
>发布</el-button
>{{ $t('m.Cancel') }}</el-button
>
<el-button type="primary" @click.native="submitDiscussion">{{
$t('m.OK')
}}</el-button>
</span>
</el-dialog>
</div>
@ -372,7 +385,7 @@ export default {
},
backupDiscussion: {}, //
//
discussionDialogTitle: 'Edit Discussion',
discussionDialogTitle: '',
discussionList: [],
categoryList: [],
cidMapName: {},
@ -389,6 +402,7 @@ export default {
};
},
mounted() {
this.discussionDialogTitle = this.$i18n.t('m.Edit_Discussion');
api.getCategoryList().then((res) => {
this.categoryList = res.data.data;
for (let i = 0; i < this.categoryList.length; i++) {
@ -443,10 +457,10 @@ export default {
toEditDiscussion() {
if (!this.isAuthenticated) {
myMessage.warning('请先登录');
myMessage.warning(this.$i18n.t('m.Please_login_first'));
this.$store.dispatch('changeModalStatus', { visible: true });
} else {
this.discussionDialogTitle = 'Create Discussion';
this.discussionDialogTitle = this.$i18n.t('m.Create_Discussion');
if (this.backupDiscussion) {
this.discussion = this.backupDiscussion;
//
@ -524,18 +538,18 @@ export default {
submitDiscussion() {
//
let discussion = Object.assign({}, this.discussion);
if (this.discussionDialogTitle == 'Create Discussion') {
if (this.discussionDialogTitle == this.$i18n.t('m.Create_Discussion')) {
if (discussion.pid) {
discussion.title = '[' + discussion.pid + '] ' + discussion.title;
}
api.addDiscussion(discussion).then((res) => {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Post_successfully'));
this.showEditDiscussionDialog = false;
this.init();
});
} else {
api.updateDiscussion(discussion).then((res) => {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Update_Successfully'));
this.showEditDiscussionDialog = false;
this.init();
});
@ -545,7 +559,7 @@ export default {
let tmpArr = command.split(':');
switch (tmpArr[0]) {
case 'edit':
this.discussionDialogTitle = 'Edit Discussion';
this.discussionDialogTitle = this.$i18n.t('m.Edit_Discussion');
this.discussion = Object.assign(
{},
this.discussionList[parseInt(tmpArr[1])]
@ -553,19 +567,15 @@ export default {
this.showEditDiscussionDialog = true;
break;
case 'delete':
this.$confirm(
'此操作将删除该讨论包括关联的评论与回复, 是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
this.$confirm(this.$i18n.t('m.Delete_Discussion_Tips'), 'Tips', {
confirmButtonText: this.$i18n.t('m.OK'),
cancelButtonText: this.$i18n.t('m.Cancel'),
type: 'warning',
}).then(() => {
api
.deleteDiscussion(this.discussionList[parseInt(tmpArr[1])].id)
.then((res) => {
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Delete_successfully'));
this.init();
});
});
@ -582,7 +592,7 @@ export default {
},
discussion(newVal, oldVal) {
if (
this.discussionDialogTitle == 'Create Discussion' &&
this.discussionDialogTitle == this.$i18n.t('m.Create_Discussion') &&
newVal != oldVal
) {
this.backupDiscussion = this.discussion;

View File

@ -9,7 +9,9 @@
<span>{{ problemData.problem.title }}</span
><br />
<span v-if="contestID && !contestEnded"
><el-tag effect="plain" size="small">比赛题目</el-tag></span
><el-tag effect="plain" size="small">{{
$t('m.Contest_Problem')
}}</el-tag></span
>
<div v-else-if="problemData.tags.length > 0" class="problem-tag">
<el-popover placement="right-start" width="60" trigger="hover">
@ -19,7 +21,7 @@
type="primary"
style="cursor: pointer;"
effect="plain"
>Show Tags</el-tag
>{{ $t('m.Show_Tags') }}</el-tag
>
<el-tag
v-for="tag in problemData.tags"
@ -32,7 +34,9 @@
</el-popover>
</div>
<div v-else-if="problemData.tags.length == 0" class="problem-tag">
<el-tag effect="plain" size="small">暂无标签</el-tag>
<el-tag effect="plain" size="small">{{
$t('m.No_tag')
}}</el-tag>
</div>
<div class="problem-menu">
<span v-if="!contestID">
@ -41,7 +45,7 @@
:underline="false"
@click="goProblemDiscussion"
><i class="fa fa-comments" aria-hidden="true"></i>
Discussion</el-link
{{ $t('m.NavBar_Discussion') }}</el-link
></span
>
<span>
@ -50,7 +54,7 @@
:underline="false"
@click="graphVisible = !graphVisible"
><i class="fa fa-pie-chart" aria-hidden="true"></i>
Statistic</el-link
{{ $t('m.Statistic') }}</el-link
></span
>
<span>
@ -59,45 +63,45 @@
:underline="false"
@click="goProblemSubmission"
><i class="fa fa-bars" aria-hidden="true"></i>
Solution</el-link
{{ $t('m.Solution') }}</el-link
></span
>
</div>
<div class="question-intr">
<span
>Time LimitC/C++
{{ problemData.problem.timeLimit }}MSOther
>{{ $t('m.Time_Limit') }}C/C++
{{ problemData.problem.timeLimit }}MS{{ $t('m.Other') }}
{{ problemData.problem.timeLimit * 2 }}MS</span
><br />
<span
>Memory LimitC/C++
{{ problemData.problem.memoryLimit }}MBOther
>{{ $t('m.Memory_Limit') }}C/C++
{{ problemData.problem.memoryLimit }}MB{{ $t('m.Other') }}
{{ problemData.problem.memoryLimit * 2 }}MB</span
><br />
<span
>Level{{
>{{ $t('m.Level') }}{{
PROBLEM_LEVEL[problemData.problem.difficulty]['name']
}}</span
><span
v-if="problemData.problem.type == 1"
style="margin-left: 10px;"
>Score{{ problemData.problem.ioScore }}</span
>{{ $t('m.Score') }}{{ problemData.problem.ioScore }}</span
><br />
<span v-show="problemData.problem.author"
>Create By{{ problemData.problem.author }}</span
>{{ $t('m.Created') }}{{ problemData.problem.author }}</span
><br />
</div>
</div>
<div id="problem-content">
<p class="title">Description</p>
<p class="title">{{ $t('m.Description') }}</p>
<p
class="content markdown-body"
v-html="problemData.problem.description"
v-katex
v-highlight
></p>
<p class="title">Input</p>
<p class="title">{{ $t('m.Input') }}</p>
<p
class="content markdown-body"
v-html="problemData.problem.input"
@ -105,7 +109,7 @@
v-highlight
></p>
<p class="title">Output</p>
<p class="title">{{ $t('m.Output') }}</p>
<p
class="content markdown-body"
v-html="problemData.problem.output"
@ -120,7 +124,7 @@
<div class="flex-container example">
<div class="example-input">
<p class="title">
Sample Input {{ index + 1 }}
{{ $t('m.Sample_Input') }} {{ index + 1 }}
<a
class="copy"
v-clipboard:copy="example.input"
@ -134,7 +138,7 @@
</div>
<div class="example-output">
<p class="title">
Sample Output {{ index + 1 }}
{{ $t('m.Sample_Output') }} {{ index + 1 }}
<a
class="copy"
v-clipboard:copy="example.output"
@ -149,22 +153,22 @@
</div>
</div>
<div v-if="problemData.problem.hint">
<p class="title">Hint</p>
<template v-if="problemData.problem.hint">
<p class="title">{{ $t('m.Hint') }}</p>
<el-card dis-hover>
<div
<p
class="hint-content markdown-body"
v-html="problemData.problem.hint"
v-katex
v-highlight
></div>
></p>
</el-card>
</div>
</template>
<div v-if="problemData.problem.source && !contestID">
<p class="title">Source</p>
<template v-if="problemData.problem.source && !contestID">
<p class="title">{{ $t('m.Source') }}</p>
<p class="content" v-html="problemData.problem.source"></p>
</div>
</template>
</div>
</el-card>
</el-col>
@ -192,12 +196,12 @@
show-icon
effect="dark"
:closable="false"
>Please login first</el-alert
>{{ $t('m.Please_login_first') }}</el-alert
>
</div>
<div class="status" v-if="statusVisible">
<template v-if="result.status == JUDGE_STATUS_RESERVE['sf']">
<span>Status:</span>
<span>{{ $t('m.Status') }}:</span>
<el-tag
effect="dark"
:color="submissionStatus.color"
@ -217,7 +221,7 @@
this.contestRuleType == RULE_TYPE.ACM)
"
>
<span>Status:</span>
<span>{{ $t('m.Status') }}:</span>
<el-tag
effect="dark"
:color="submissionStatus.color"
@ -239,7 +243,7 @@
show-icon
effect="dark"
:closable="false"
>Submitted successfully</el-alert
>{{ $t('m.Submitted_successfully') }}</el-alert
>
</template>
</div>
@ -254,7 +258,7 @@
show-icon
effect="dark"
:closable="false"
>You have solved the problem</el-alert
>{{ $t('m.You_have_solved_the_problem') }}</el-alert
>
</div>
<div
@ -270,7 +274,7 @@
show-icon
effect="dark"
:closable="false"
>You have submitted a solution</el-alert
>{{ $t('m.You_have_submitted_a_solution') }}</el-alert
>
</div>
<div v-if="contestEnded">
@ -279,7 +283,7 @@
show-icon
effect="dark"
:closable="false"
>Contest has ended</el-alert
>{{ $t('m.Contest_has_ended') }}</el-alert
>
</div>
</el-col>
@ -306,8 +310,8 @@
:disabled="problemSubmitDisabled || submitted"
class="fl-right"
>
<span v-if="submitting">Submitting</span>
<span v-else>Submit</span>
<span v-if="submitting">{{ $t('m.Submitting') }}</span>
<span v-else>{{ $t('m.Submit') }}</span>
</el-button>
</el-col>
</el-row>
@ -321,9 +325,9 @@
<ECharts :options="largePie" :initOptions="largePieInitOpts"></ECharts>
</div>
<div slot="footer">
<el-button type="ghost" @click="graphVisible = false" size="small"
>Close</el-button
>
<el-button type="ghost" @click="graphVisible = false" size="small">{{
$t('m.Close')
}}</el-button>
</div>
</el-dialog>
@ -342,7 +346,7 @@
style="margin-left:130px"
@click="submitCode"
>
OK
{{ $t('m.Submit') }}
</el-button>
</el-form>
</el-dialog>
@ -367,7 +371,7 @@ import api from '@/common/api';
import myMessage from '@/common/message';
import { addCodeBtn } from '@/common/codeblock';
//
const filtedStatus = ['wa', 'ce', 'ac', 'tle', 'mle', 're', 'pe'];
const filtedStatus = ['wa', 'ce', 'ac', 'pa', 'tle', 'mle', 're', 'pe'];
export default {
name: 'ProblemDetails',
@ -601,11 +605,15 @@ export default {
this.theme = newTheme;
},
onResetToTemplate() {
this.$confirm('是否确定要重置代码模板?', '提示', {
cancelButtonText: '取消',
confirmButtonText: '确定',
type: 'warning',
})
this.$confirm(
this.$i18n.t('m.Are_you_sure_you_want_to_reset_your_code'),
'Tips',
{
cancelButtonText: this.$i18n.t('m.Cancel'),
confirmButtonText: this.$i18n.t('m.OK'),
type: 'warning',
}
)
.then(() => {
let codeTemplate = this.problemData.codeTemplate;
if (codeTemplate && codeTemplate[this.language]) {
@ -659,7 +667,7 @@ export default {
},
submitCode() {
if (this.code.trim() === '') {
myMessage.error('提交的代码不能为空!');
myMessage.error(this.$i18n.t('m.Code_can_not_be_empty'));
return;
}
@ -699,7 +707,7 @@ export default {
if (!detailsVisible) {
this.$Modal.success({
title: 'Success',
content: '代码提交成功!',
content: this.$i18n.t('m.Submit_code_successfully'),
});
return;
} else {
@ -729,11 +737,13 @@ export default {
) {
if (this.submissionExists) {
this.$confirm(
'你已经有该题目的提交了,确定要再一次提交覆盖之前的提交记录?',
'警告',
this.$i18n.t(
'm.You_have_submission_in_this_problem_sure_to_cover_it'
),
'Warning',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
confirmButtonText: this.$i18n.t('m.OK'),
cancelButtonText: this.$i18n.t('m.Cancel'),
type: 'warning',
}
)
@ -771,10 +781,10 @@ export default {
},
onCopy(event) {
myMessage.success('Sample copied successfully');
myMessage.success(this.$i18n.t('m.Copied_successfully'));
},
onCopyError(e) {
myMessage.success('Sample copy failed');
myMessage.success(this.$i18n.t('m.Copied_failed'));
},
},
computed: {
@ -845,6 +855,11 @@ export default {
},
};
</script>
<style>
.katex .katex-mathml {
display: none;
}
</style>
<style scoped>
#problem-main {

View File

@ -5,7 +5,9 @@
<div slot="header">
<el-row :gutter="18">
<el-col :sm="5" :md="5" :lg="7">
<span class="panel-title hidden-xs-only">Problem List</span>
<span class="panel-title hidden-xs-only">{{
$t('m.Problem_List')
}}</span>
</el-col>
<el-col :xs="8" :sm="3" :md="3" :lg="3" style="padding-top: 6px;">
<el-dropdown
@ -16,7 +18,9 @@
>
<span class="el-dropdown-link">
{{
query.oj === 'Mine' || query.oj === '' ? 'Mine' : query.oj
query.oj === 'Mine' || query.oj === ''
? $t('m.Mine')
: query.oj
}}
<i class="el-icon-caret-bottom"></i>
</span>
@ -42,13 +46,15 @@
<span class="el-dropdown-link">
{{
query.difficulty === 'All' || query.difficulty === ''
? 'Level'
? $t('m.Level')
: query.difficulty
}}
<i class="el-icon-caret-bottom"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="All">All</el-dropdown-item>
<el-dropdown-item command="All">{{
$t('m.All')
}}</el-dropdown-item>
<el-dropdown-item
:command="key"
v-for="(value, key, index) in PROBLEM_LEVEL_RESERVE"
@ -62,13 +68,13 @@
<vxe-checkbox
v-model="tagVisible"
@change="changeTagVisible(tagVisible)"
>Tag</vxe-checkbox
>{{ $t('m.Tags') }}</vxe-checkbox
>
</el-col>
<el-col :xs="18" :sm="7" :md="7" :lg="5" class="top-pt">
<vxe-input
v-model="query.keyword"
placeholder="Enter keyword"
:placeholder="$t('m.Enter_keyword')"
type="search"
size="medium"
@search-click="filterByKeyword"
@ -82,7 +88,7 @@
icon="el-icon-refresh"
round
@click="onReset"
>Reset</el-button
>{{ $t('m.Reset') }}</el-button
>
</el-col>
<el-col :xs="6" class="hidden-sm-and-up top-pt">
@ -130,11 +136,15 @@
</vxe-table-column>
<vxe-table-column
field="problemId"
title="Problem ID"
:title="$t('m.Problem_ID')"
min-width="100"
></vxe-table-column>
<vxe-table-column field="title" title="Title" min-width="180">
<vxe-table-column
field="title"
:title="$t('m.Title')"
min-width="180"
>
<template v-slot="{ row }">
<a @click="getProblemUri(row.problemId)" class="title-a">{{
row.title
@ -142,7 +152,11 @@
</template>
</vxe-table-column>
<vxe-table-column field="difficulty" title="Level" min-width="100">
<vxe-table-column
field="difficulty"
:title="$t('m.Level')"
min-width="100"
>
<template v-slot="{ row }">
<span :class="getLevelColor(row.difficulty)">{{
PROBLEM_LEVEL[row.difficulty].name
@ -152,7 +166,7 @@
<vxe-table-column
field="tag"
title="Tag"
:title="$t('m.Tags')"
min-width="250"
visible="false"
>
@ -168,10 +182,10 @@
</vxe-table-column>
<vxe-table-column
field="total"
title="Total"
:title="$t('m.Total')"
min-width="80"
></vxe-table-column>
<vxe-table-column title="AC Rate" min-width="80">
<vxe-table-column :title="$t('m.AC_Rate')" min-width="80">
<template v-slot="{ row }">
<span>{{ getPercentage(row.ac, row.total) }}%</span>
</template>
@ -209,7 +223,9 @@
</el-row>
</el-card>
<el-card :padding="10" style="margin-top:20px">
<div slot="header"><span class="taglist-title">Tags</span></div>
<div slot="header">
<span class="taglist-title">{{ $t('m.Tags') }}</span>
</div>
<el-button
v-for="tag in tagList"
:key="tag.id"
@ -223,7 +239,7 @@
<el-button long id="pick-one" @click="pickone">
<i class="fa fa-random"></i>
Pick a random question
{{ $t('m.Pick_a_random_question') }}
</el-button>
</el-card>
</el-col>
@ -257,7 +273,7 @@ export default {
REMOTE_OJ: {},
tagList: [],
tagVisible: false,
currentProblemTitle: '请触碰或鼠标悬浮到指定题目行即可查看提交情况',
currentProblemTitle: '',
problemRecord: [],
problemList: [],
limit: 20,
@ -290,6 +306,7 @@ export default {
this.JUDGE_STATUS_RESERVE = Object.assign({}, JUDGE_STATUS_RESERVE);
this.JUDGE_STATUS = Object.assign({}, JUDGE_STATUS);
this.REMOTE_OJ = Object.assign({}, REMOTE_OJ);
this.currentProblemTitle = this.$i18n.t('m.Touch_Get_Status');
//
this.problemRecord = [
{ status: 0, count: 100 },
@ -464,7 +481,7 @@ export default {
},
pickone() {
api.pickone().then((res) => {
myMessage.success('随机题目获取成功,祝你好运');
myMessage.success(this.$i18n.t('m.Good_luck_to_you'));
this.$router.push({
name: 'ProblemDetails',
params: { problemID: res.data.data.problemId },

View File

@ -4,8 +4,8 @@ const pieColorMap = {
'TLE': {color: '#ff9300'},
'MLE': {color: '#f7de00'},
'RE': {color: '#ff6104'},
'CE': {color: '#80848f'},
'PAC': {color: '#2d8cf0'},
'CE': {color: '#f90'},
'PA': {color: '#2d8cf0'},
'PE':{color:'#f90'}
}
@ -64,7 +64,7 @@ const largePie = {
itemGap:
10,
data:
['AC', 'RE', 'WA', 'TLE', 'PAC', 'MLE','PE']
['AC','PA','PE','CE','RE', 'WA', 'TLE', 'MLE']
},
series: [
{
@ -80,9 +80,10 @@ const largePie = {
{value: 0, name: 'WA'},
{value: 0, name: 'TLE'},
{value: 0, name: 'AC'},
{value: 0, name: 'PA'},
{value: 0, name: 'MLE'},
{value: 0, name: 'PAC'},
{value: 0, name: 'PE'}
{value: 0, name: 'PE'},
{value: 0, name: 'CE'}
],
label: {
normal: {

View File

@ -2,7 +2,9 @@
<el-row type="flex" justify="space-around">
<el-col :span="24">
<el-card :padding="10">
<div slot="header"><span class="panel-title">ACM Ranklist</span></div>
<div slot="header">
<span class="panel-title">{{ $t('m.ACM_Ranklist') }}</span>
</div>
<div class="echarts">
<ECharts :options="options" ref="chart" :autoresize="true"></ECharts>
</div>
@ -16,7 +18,11 @@
style="font-weight: 500;"
>
<vxe-table-column type="seq" min-width="50"></vxe-table-column>
<vxe-table-column field="username" title="User" min-width="150">
<vxe-table-column
field="username"
:title="$t('m.User')"
min-width="150"
>
<template v-slot="{ row }">
<a
@click="getInfoByUsername(row.uid, row.username)"
@ -27,20 +33,20 @@
</vxe-table-column>
<vxe-table-column
field="nickname"
title="Nickname"
:title="$t('m.Nickname')"
min-width="180"
></vxe-table-column>
<vxe-table-column
field="signature"
title="Mood"
:title="$t('m.Mood')"
min-width="180"
></vxe-table-column>
<vxe-table-column
field="solved"
title="Solved"
:title="$t('m.Solved')"
min-width="80"
></vxe-table-column>
<vxe-table-column title="AC" min-width="80">
<vxe-table-column :title="$t('m.AC')" min-width="80">
<template v-slot="{ row }">
<a
@click="goUserACStatus(row.username)"
@ -51,10 +57,10 @@
</vxe-table-column>
<vxe-table-column
field="total"
title="Total"
:title="$t('m.Total')"
min-width="80"
></vxe-table-column>
<vxe-table-column title="Rating" min-width="80">
<vxe-table-column :title="$t('m.Rating')" min-width="80">
<template v-slot="{ row }">
<span>{{ getACRate(row.ac, row.total) }}</span>
</template>
@ -153,7 +159,7 @@ export default {
],
series: [
{
name: 'AC',
name: this.$i18n.t('m.AC'),
type: 'bar',
data: [0],
itemStyle: {
@ -164,7 +170,7 @@ export default {
},
},
{
name: 'Total',
name: this.$i18n.t('m.Total'),
type: 'bar',
data: [0],
itemStyle: {

View File

@ -2,7 +2,9 @@
<el-row type="flex" justify="space-around">
<el-col :span="24">
<el-card :padding="10">
<div slot="header"><span class="panel-title">OI Ranklist</span></div>
<div slot="header">
<span class="panel-title">{{ $t('m.OI_Ranklist') }}</span>
</div>
<div class="echarts">
<ECharts :options="options" ref="chart" auto-resize></ECharts>
</div>
@ -16,7 +18,11 @@
style="font-weight: 500;"
>
<vxe-table-column type="seq" min-width="50"></vxe-table-column>
<vxe-table-column field="username" title="User" min-width="150">
<vxe-table-column
field="username"
:title="$t('m.User')"
min-width="150"
>
<template v-slot="{ row }">
<a
@click="getInfoByUsername(row.uid, row.username)"
@ -27,20 +33,20 @@
</vxe-table-column>
<vxe-table-column
field="nickname"
title="Nickname"
:title="$t('m.Nickname')"
min-width="180"
></vxe-table-column>
<vxe-table-column
field="signature"
title="Mood"
:title="$t('m.Mood')"
min-width="180"
></vxe-table-column>
<vxe-table-column title="Score" min-width="80">
<vxe-table-column :title="$t('m.Score')" min-width="80">
<template v-slot="{ row }">
<span>{{ row.score }}</span>
</template>
</vxe-table-column>
<vxe-table-column title="AC" min-width="80">
<vxe-table-column :title="$t('m.AC')" min-width="80">
<template v-slot="{ row }">
<a
@click="goUserACStatus(row.username)"
@ -51,10 +57,10 @@
</vxe-table-column>
<vxe-table-column
field="total"
title="Total"
:title="$t('m.Total')"
min-width="80"
></vxe-table-column>
<vxe-table-column title="Rating" min-width="80">
<vxe-table-column :title="$t('m.Rating')" min-width="80">
<template v-slot="{ row }">
<span>{{ getACRate(row.ac, row.total) }}</span>
</template>
@ -156,7 +162,7 @@ export default {
],
series: [
{
name: 'Score',
name: this.$i18n.t('m.Score'),
type: 'bar',
data: [0],
barMaxWidth: '80',

View File

@ -18,16 +18,23 @@
</div>
<div v-else class="content">
<span class="span-row"
>Time: {{ submissionTimeFormat(submission.time) }}</span
>{{ $t('m.Time') }}:
{{ submissionTimeFormat(submission.time) }}</span
>
<span class="span-row"
>Memory: {{ submissionMemoryFormat(submission.memory) }}</span
>{{ $t('m.Memory') }}:
{{ submissionMemoryFormat(submission.memory) }}</span
>
<span class="span-row"
>Length: {{ submissionLengthFormat(submission.length) }}</span
>{{ $t('m.Length') }}:
{{ submissionLengthFormat(submission.length) }}</span
>
<span class="span-row"
>{{ $t('m.Language') }}: {{ submission.language }}</span
>
<span class="span-row"
>{{ $t('m.Author') }}: {{ submission.username }}</span
>
<span class="span-row">Language: {{ submission.language }}</span>
<span class="span-row">Author: {{ submission.username }}</span>
</div>
</template>
</el-alert>
@ -44,44 +51,52 @@
>
<vxe-table-column
field="submitId"
title="ID"
:title="$t('m.Run_ID')"
min-width="100"
></vxe-table-column>
<vxe-table-column title="Submit time" min-width="150">
<vxe-table-column :title="$t('m.Submit_Time')" min-width="150">
<template v-slot="{ row }">
<span>{{ row.submitTime | localtime }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="pid" title="Problem ID" min-width="100">
<vxe-table-column
field="pid"
:title="$t('m.Problem_ID')"
min-width="100"
>
<template v-slot="{ row }">
<a @click="getProblemUri(row)" style="color: rgb(87, 163, 243)">{{
row.displayPid
}}</a>
</template>
</vxe-table-column>
<vxe-table-column field="status" title="Status" min-width="170">
<vxe-table-column field="status" :title="$t('m.Staus')" min-width="170">
<template v-slot="{ row }">
<span :class="getStatusColor(row.status)">{{
JUDGE_STATUS[row.status].name
}}</span>
</template>
</vxe-table-column>
<vxe-table-column title="Time" min-width="96">
<vxe-table-column :title="$t('m.Time')" min-width="96">
<template v-slot="{ row }">
<span>{{ submissionTimeFormat(row.time) }}</span>
</template>
</vxe-table-column>
<vxe-table-column title="Memory" min-width="96">
<vxe-table-column :title="$t('m.Memory')" min-width="96">
<template v-slot="{ row }">
<span>{{ submissionMemoryFormat(row.memory) }}</span>
</template>
</vxe-table-column>
<vxe-table-column title="Score" min-width="64" v-if="isIOProblem">
<vxe-table-column
:title="$t('m.Score')"
min-width="64"
v-if="isIOProblem"
>
<template v-slot="{ row }">
<span>{{ row.score }}</span>
</template>
</vxe-table-column>
<vxe-table-column title="Length" min-width="80">
<vxe-table-column :title="$t('m.Length')" min-width="80">
<template v-slot="{ row }">
<span>{{ submissionLengthFormat(row.length) }}</span>
</template>
@ -91,7 +106,9 @@
<el-col :span="24" v-if="testCaseResult">
<el-card style="margin-top: 13px;" shadow="hover">
<div slot="header">
<span class="panel-title home-title">测试点详情</span>
<span class="panel-title home-title">{{
$t('m.Test_point_details')
}}</span>
</div>
<el-row :gutter="10">
<el-col
@ -114,7 +131,7 @@
</div>
<div class="test-run-static">
<span v-if="item.score != null">
{{ item.score }} <i class="el-icon-success"></i>
{{ item.score }} <i class="el-icon-success"></i>
</span>
<span v-else>
<i class="el-icon-success"></i>
@ -134,7 +151,7 @@
</div>
<div class="test-run-static">
<span v-if="item.score != null">
{{ item.score }} <i class="el-icon-error"></i>
{{ item.score }} <i class="el-icon-error"></i>
</span>
<span v-else>
<i class="el-icon-error"></i>
@ -160,7 +177,7 @@
size="large"
@click="doCopy"
v-if="submission.code"
>Copy</el-button
>{{ $t('m.Copy') }}</el-button
>
<template v-if="codeShare">
<el-button
@ -170,7 +187,7 @@
icon="el-icon-circle-close"
@click="shareSubmission(false)"
>
Unshared
{{ $t('m.Unshared') }}
</el-button>
<el-button
v-else-if="isAuthenticated && !submission.share && isMeSubmisson"
@ -179,7 +196,7 @@
icon="el-icon-share"
@click="shareSubmission(true)"
>
Shared
{{ $t('m.Shared') }}
</el-button>
</template>
</div>
@ -306,7 +323,6 @@ export default {
}
}
//
console.log(this.$route.params.problemID);
if (this.$route.params.problemID && data.submission.cid != 0) {
data.submission.displayPid = this.$route.params.problemID;
}
@ -345,7 +361,7 @@ export default {
api.updateSubmission(data).then(
(res) => {
this.getSubmission();
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Shared_successfully'));
},
() => {}
);

View File

@ -5,16 +5,18 @@
<div slot="header">
<el-row :gutter="18">
<el-col :md="4" :lg="2">
<span class="panel-title hidden-md-and-down">Status</span>
<span class="panel-title hidden-md-and-down">{{
$t('m.Status')
}}</span>
</el-col>
<el-col :xs="10" :sm="8" :md="4" :lg="4">
<el-switch
style="display: block"
v-model="formFilter.onlyMine"
active-text="Mine"
:active-text="$t('m.Mine')"
:width="40"
@change="handleOnlyMine"
inactive-text="All"
:inactive-text="$t('m.All')"
>
</el-switch>
</el-col>
@ -31,7 +33,9 @@
<i class="el-icon-caret-bottom"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="All">All</el-dropdown-item>
<el-dropdown-item command="All">{{
$t('m.All')
}}</el-dropdown-item>
<el-dropdown-item
v-for="result in Object.keys(JUDGE_STATUS_LIST)"
:key="result"
@ -50,7 +54,7 @@
icon="el-icon-refresh"
round
@click="getSubmissions"
>Refresh</el-button
>{{ $t('m.Refresh') }}</el-button
>
</el-col>
<el-col :xs="4" class="hidden-sm-and-up">
@ -66,7 +70,7 @@
<el-col :xs="24" :sm="12" :md="5" :lg="5" class="search">
<vxe-input
v-model="formFilter.problemID"
placeholder="Enter Problem ID"
:placeholder="$t('m.Enter_Problem_ID')"
type="search"
size="medium"
@keyup.enter.native="handleQueryChange"
@ -77,7 +81,7 @@
<vxe-input
v-model="formFilter.username"
:disabled="formFilter.onlyMine"
placeholder="Enter Author"
:placeholder="$t('m.Enter_Author')"
type="search"
size="medium"
@keyup.enter.native="handleQueryChange"
@ -101,10 +105,14 @@
>
<vxe-table-column
field="submitId"
title="Run ID"
min-width="100"
:title="$t('m.Run_ID')"
width="100"
></vxe-table-column>
<vxe-table-column field="pid" title="Problem" min-width="150">
<vxe-table-column
field="pid"
:title="$t('m.Problem')"
min-width="150"
>
<template v-slot="{ row }">
<span
v-if="contestID"
@ -120,7 +128,11 @@
</span>
</template>
</vxe-table-column>
<vxe-table-column field="status" title="Status" min-width="170">
<vxe-table-column
field="status"
:title="$t('m.Status')"
min-width="180"
>
<template v-slot="{ row }">
<span :class="getStatusColor(row.status)">
<i
@ -139,28 +151,43 @@
"
@click="reSubmit(row)"
></i>
{{ JUDGE_STATUS[row.status].name }}
{{
(row.score != null ? row.score + ' ' : '') +
JUDGE_STATUS[row.status].name
}}
</span>
</template>
</vxe-table-column>
<vxe-table-column field="time" title="Time" min-width="96">
<vxe-table-column field="time" :title="$t('m.Time')" min-width="96">
<template v-slot="{ row }">
<span>{{ submissionTimeFormat(row.time) }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="memory" title="Memory" min-width="96">
<vxe-table-column
field="memory"
:title="$t('m.Memory')"
min-width="96"
>
<template v-slot="{ row }">
<span>{{ submissionMemoryFormat(row.memory) }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="length" title="Length" min-width="80">
<vxe-table-column
field="length"
:title="$t('m.Length')"
min-width="80"
>
<template v-slot="{ row }">
<span>{{ submissionLengthFormat(row.length) }}</span>
</template>
</vxe-table-column>
<vxe-table-column field="language" title="Language" min-width="130">
<vxe-table-column
field="language"
:title="$t('m.Language')"
min-width="130"
>
<template v-slot="{ row }">
<span
v-if="!row.share && row.uid != userInfo.uid && !isAdminRole"
@ -169,7 +196,7 @@
<el-tooltip
class="item"
effect="dark"
content="查看提交详情"
:content="$t('m.View_submission_details')"
placement="top"
v-else
>
@ -179,13 +206,21 @@
</el-tooltip>
</template>
</vxe-table-column>
<vxe-table-column field="judger" title="Judger" min-width="100">
<vxe-table-column
field="judger"
:title="$t('m.Judger')"
min-width="100"
>
<template v-slot="{ row }">
<span v-if="row.judger">{{ row.judger }}</span>
<span v-else>--</span>
</template>
</vxe-table-column>
<vxe-table-column field="username" title="Author" min-width="100">
<vxe-table-column
field="username"
:title="$t('m.Author')"
min-width="100"
>
<template v-slot="{ row }">
<a
@click="goUserHome(row.username, row.uid)"
@ -196,7 +231,7 @@
</vxe-table-column>
<vxe-table-column
field="submitTime"
title="Submit Time"
:title="$t('m.Submit_Time')"
min-width="96"
>
<template v-slot="{ row }">
@ -213,7 +248,7 @@
<!-- 非比赛提交记录超级管理员可以对提交进行重判 -->
<vxe-table-column
v-if="rejudgeColumnVisible"
title="Option"
:title="$t('m.Option')"
min-width="90"
>
<template v-slot="{ row }">
@ -222,7 +257,7 @@
@click="handleRejudge(row)"
size="mini"
:loading="row.loading"
>Rejudge</vxe-button
>{{ $t('m.Rejudge') }}</vxe-button
>
</template>
</vxe-table-column>
@ -372,7 +407,7 @@ export default {
this.formFilter.username = '';
} else {
this.formFilter.onlyMine = false;
myMessage.error('请您先登陆!');
myMessage.error(this.$i18n.t('m.Please_login_first'));
return;
}
}
@ -545,7 +580,7 @@ export default {
this.submissions[row.index] = res.data.data;
this.submissions[row.index].loading = false;
myMessage.success(res.data.msg);
myMessage.success(this.$i18n.t('m.Rejudge_successfully'));
//
this.needCheckSubmitIds[row.submitId] = row.index;
@ -567,7 +602,7 @@ export default {
this.formFilter.username = '';
} else {
this.formFilter.onlyMine = false;
myMessage.error('请您先登陆!');
myMessage.error(this.$i18n.t('m.Please_login_first'));
return;
}
}
@ -579,7 +614,7 @@ export default {
showSubmitDetail(row) {
if (!this.isAuthenticated) {
this.changeModalStatus({ mode: 'Login', visible: true });
myMessage.warning('请先登录后再查看代码!');
myMessage.warning(this.$i18n.t('m.Please_login_first'));
return;
}
if (row.cid != 0) {

View File

@ -2,7 +2,9 @@
<div>
<div class="container">
<el-card shadow="always" body-style="{backgroud-color:gray}">
<h2 style="text-align: center;">Set New Password - HOJ</h2>
<h2 style="text-align: center;">
{{ $t('m.Set_New_Password') }}
</h2>
<el-form
:model="formResetPassword"
:rules="rules"
@ -20,7 +22,7 @@
v-model="formResetPassword.password"
prefix-icon="el-icon-lock"
type="password"
placeholder="Please Enter New Password"
:placeholder="$t('m.Set_New_Password_Msg')"
></el-input>
</el-form-item>
<el-form-item prop="passwordAgain">
@ -28,7 +30,7 @@
v-model="formResetPassword.passwordAgain"
prefix-icon="el-icon-lock"
type="password"
placeholder="Please Enter New Password Again"
:placeholder="$t('m.Set_New_Password_Again_Msg')"
></el-input>
</el-form-item>
</el-form>
@ -38,7 +40,7 @@
@click="handleResetPwd"
:loading="btnLoading"
>
重置密码
{{ $t('m.Set_New_Password') }}
</el-button>
</div>
</el-card>
@ -47,7 +49,7 @@
</template>
<script>
import api from '@/common/api';
import { mapGetters, mapActions } from 'vuex';
import { mapActions } from 'vuex';
import mMessage from '@/common/message';
export default {
data() {
@ -55,7 +57,7 @@ export default {
api.checkUsernameOrEmail(value, undefined).then(
(res) => {
if (res.data.data.username === false) {
callback(new Error('The username does not exists'));
callback(new Error(this.$i18n.t('m.The_username_does_not_exists')));
} else {
callback();
}
@ -73,7 +75,7 @@ export default {
const CheckAgainPassword = (rule, value, callback) => {
if (value !== this.formResetPassword.password) {
callback(new Error('Password does not match'));
callback(new Error(this.$i18n.t('m.Password_does_not_match')));
}
callback();
};
@ -89,7 +91,7 @@ export default {
username: [
{
required: true,
message: 'The username is required',
message: this.$i18n.t('m.Username_Check_Required'),
trigger: 'blur',
},
{ validator: CheckUsernameNotExist, trigger: 'blur' },
@ -97,21 +99,21 @@ export default {
password: [
{
required: true,
message: 'The password is required',
message: this.$i18n.t('m.Password_Check_Required'),
trigger: 'blur',
},
{
min: 6,
max: 20,
trigger: 'blur',
message: 'The length of the password is between 6 and 20',
message: this.$i18n.t('m.Password_Check_Between'),
},
{ validator: CheckPassword, trigger: 'blur' },
],
passwordAgain: [
{
required: true,
message: 'The password again is required',
message: this.$i18n.t('m.Password_Again_Check_Required'),
trigger: 'blur',
},
{ validator: CheckAgainPassword, trigger: 'change' },
@ -140,7 +142,7 @@ export default {
api.resetPassword(data).then(
(res) => {
this.btnLoading = false;
mMessage.success('重置密码成功');
mMessage.success(this.$i18n.t('m.Your_password_has_been_reset'));
this.$router.replace({
path: '/',
});

View File

@ -3,13 +3,13 @@
<el-collapse v-model="activeName" accordion>
<el-collapse-item name="Account">
<template slot="title">
<i class="fa fa-gear"> Account Setting</i>
<i class="fa fa-gear"> {{ $t('m.Account_Setting') }}</i>
</template>
<component :is="Account"></component>
</el-collapse-item>
<el-collapse-item name="UserInfo">
<template slot="title">
<i class="fa fa-gear"> UserInfo Setting</i>
<i class="fa fa-gear"> {{ $t('m.UserInfo_Setting') }}</i>
</template>
<component :is="UserInfo"></component>
</el-collapse-item>

View File

@ -17,7 +17,8 @@
>
<el-tag type="success" effect="plain" size="medium">
<i class="fa fa-circle">
最近上线{{ profile.recentLoginTime | fromNow }}</i
{{ $t('m.Recent_login_time')
}}{{ profile.recentLoginTime | fromNow }}</i
>
</el-tag>
</el-tooltip>
@ -32,12 +33,12 @@
<p>
<span
><i class="fa fa-graduation-cap" aria-hidden="true"></i>
{{ profile.school ? profile.school : '暂未设置' }}</span
{{ profile.school ? profile.school : $t('m.Not_set_yet') }}</span
>
</p>
<p class="mood">
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
{{ profile.signature ? profile.signature : '暂无个性签名' }}
{{ profile.signature ? profile.signature : $t('m.Not_set_yet') }}
</p>
<hr id="split" />
@ -45,27 +46,37 @@
<el-row :gutter="12">
<el-col :md="6" :sm="24">
<el-card shadow="always" class="submission">
<p><i class="fa fa-th" aria-hidden="true"></i> Submissions</p>
<p>
<i class="fa fa-th" aria-hidden="true"></i>
{{ $t('m.UserHome_Submissions') }}
</p>
<p class="data-number">{{ profile.total }}</p>
</el-card>
</el-col>
<el-col :md="6" :sm="24">
<el-card shadow="always" class="solved">
<p>
<i class="fa fa-check-circle" aria-hidden="true"></i> Solved
<i class="fa fa-check-circle" aria-hidden="true"></i>
{{ $t('m.UserHome_Solved') }}
</p>
<p class="data-number">{{ profile.solvedList.length }}</p>
</el-card>
</el-col>
<el-col :md="6" :sm="24">
<el-card shadow="always" class="score">
<p><i class="fa fa-star" aria-hidden="true"></i> Score</p>
<p>
<i class="fa fa-star" aria-hidden="true"></i>
{{ $t('m.UserHome_Score') }}
</p>
<p class="data-number">{{ getSumScore(profile.scoreList) }}</p>
</el-card>
</el-col>
<el-col :md="6" :sm="24">
<el-card shadow="always" class="rating">
<p><i class="fa fa-user-secret" aria-hidden="true"></i> Rating</p>
<p>
<i class="fa fa-user-secret" aria-hidden="true"></i>
{{ $t('m.UserHome_Rating') }}
</p>
<p class="data-number">
{{ profile.rating ? profile.rating : '--' }}
</p>
@ -75,7 +86,7 @@
<div id="problems">
<div v-if="profile.solvedList.length">
List of AC problems
{{ $t('m.List_Solved_Problems') }}
<el-button
type="primary"
icon="el-icon-refresh"
@ -84,7 +95,7 @@
@click="freshProblemDisplayID"
></el-button>
</div>
<p v-else>暂无数据</p>
<p v-else>{{ $t('m.UserHome_Not_Data') }}</p>
<div class="btns">
<div
class="problem-btn"
@ -131,10 +142,10 @@ export default {
data() {
return {
profile: {
username: '暂无数据',
username: '',
avatar: '',
school: '暂无数据',
signature: '暂无数据',
school: '',
signature: '',
total: 0,
rating: 0,
score: 0,
@ -162,14 +173,16 @@ export default {
},
freshProblemDisplayID() {
this.init();
myMessage.success('更新成功!');
myMessage.success(this.$i18n.t('m.Update_Successfully'));
},
getSumScore(scoreList) {
var sum = 0;
for (let i = 0; i < scoreList.length; i++) {
sum += scoreList[i];
if (scoreList) {
var sum = 0;
for (let i = 0; i < scoreList.length; i++) {
sum += scoreList[i];
}
return sum;
}
return sum;
},
},
watch: {

View File

@ -17,7 +17,6 @@ const cdn = {
vuex:'Vuex',
'element-ui':'ELEMENT',
'highlight.js': 'hljs',
'katex':'katex',
'vxe-table':'VXETable',
"moment": "moment",
'vue-echarts': 'VueECharts',
@ -27,7 +26,6 @@ const cdn = {
// cdn的css链接
css: [
'https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.0/theme-chalk/index.min.css',
"https://cdn.bootcdn.net/ajax/libs/KaTeX/0.12.0/katex.min.css",
"https://cdn.bootcdn.net/ajax/libs/github-markdown-css/4.0.0/github-markdown.min.css",
"https://cdn.jsdelivr.net/npm/vxe-table@2.9.26/lib/style.css"
],
@ -39,11 +37,11 @@ const cdn = {
"https://cdn.bootcdn.net/ajax/libs/vuex/3.5.1/vuex.min.js",
"https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.0/index.min.js",
"https://cdn.bootcdn.net/ajax/libs/highlight.js/10.3.2/highlight.min.js",
"https://cdn.bootcdn.net/ajax/libs/KaTeX/0.12.0/katex.min.js",
"https://cdn.jsdelivr.net/npm/xe-utils",
"https://cdn.jsdelivr.net/npm/vxe-table@2.9.26",
"https://cdn.bootcss.com/moment.js/2.29.1/moment.min.js",
"https://cdn.bootcss.com/moment.js/2.29.1/locale/zh-cn.js",
"https://cdn.bootcss.com/moment.js/2.29.1/locale/zh-cn.min.js",
"https://cdn.bootcdn.net/ajax/libs/moment.js/2.29.1/locale/es-us.min.js",
"https://cdn.bootcdn.net/ajax/libs/echarts/4.9.0-rc.1/echarts.min.js",
"https://cdn.bootcdn.net/ajax/libs/vue-echarts/5.0.0-beta.0/vue-echarts.min.js"
// "https://unpkg.com/mavon-editor@2.9.1/dist/mavon-editor.js"