mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2024-09-21 16:33:22 +00:00
Accept Merge Request #287 重构后台部分功能;修复 bug : (virusdefender-dev -> master)
Merge Request: 重构后台部分功能;修复 bug Created By: @virusdefender Accepted By: @virusdefender URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/287
This commit is contained in:
commit
49ff0d1028
@ -16,10 +16,11 @@ from rest_framework.views import APIView
|
|||||||
from utils.shortcuts import (serializer_invalid_response, error_response,
|
from utils.shortcuts import (serializer_invalid_response, error_response,
|
||||||
success_response, paginate, error_page, paginate_data)
|
success_response, paginate, error_page, paginate_data)
|
||||||
from account.models import SUPER_ADMIN, User
|
from account.models import SUPER_ADMIN, User
|
||||||
from account.decorators import login_required
|
from account.decorators import login_required, super_admin_required
|
||||||
from group.models import Group
|
from group.models import Group
|
||||||
from utils.cache import get_cache_redis
|
from utils.cache import get_cache_redis
|
||||||
from submission.models import Submission
|
from submission.models import Submission
|
||||||
|
from problem.models import Problem
|
||||||
from .models import (Contest, ContestProblem, CONTEST_ENDED,
|
from .models import (Contest, ContestProblem, CONTEST_ENDED,
|
||||||
CONTEST_NOT_START, CONTEST_UNDERWAY, ContestRank)
|
CONTEST_NOT_START, CONTEST_UNDERWAY, ContestRank)
|
||||||
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST
|
from .models import GROUP_CONTEST, PUBLIC_CONTEST, PASSWORD_PROTECTED_CONTEST
|
||||||
@ -90,8 +91,8 @@ class ContestAdminAPIView(APIView):
|
|||||||
try:
|
try:
|
||||||
# 超级管理员可以编辑所有的
|
# 超级管理员可以编辑所有的
|
||||||
contest = Contest.objects.get(id=data["id"])
|
contest = Contest.objects.get(id=data["id"])
|
||||||
if request.user.admin_type != SUPER_ADMIN:
|
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
|
||||||
contest = contest.get(created_by=request.user)
|
return error_response(u"无权访问!")
|
||||||
except Contest.DoesNotExist:
|
except Contest.DoesNotExist:
|
||||||
return error_response(u"该比赛不存在!")
|
return error_response(u"该比赛不存在!")
|
||||||
try:
|
try:
|
||||||
@ -144,6 +145,18 @@ class ContestAdminAPIView(APIView):
|
|||||||
---
|
---
|
||||||
response_serializer: ContestSerializer
|
response_serializer: ContestSerializer
|
||||||
"""
|
"""
|
||||||
|
contest_id = request.GET.get("contest_id", None)
|
||||||
|
if contest_id:
|
||||||
|
try:
|
||||||
|
# 普通管理员只能获取自己创建的题目
|
||||||
|
# 超级管理员可以获取全部的题目
|
||||||
|
contest = Contest.objects.get(id=contest_id)
|
||||||
|
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
|
||||||
|
return error_response(u"题目不存在")
|
||||||
|
return success_response(ContestSerializer(contest).data)
|
||||||
|
except Contest.DoesNotExist:
|
||||||
|
return error_response(u"题目不存在")
|
||||||
|
|
||||||
if request.user.admin_type == SUPER_ADMIN:
|
if request.user.admin_type == SUPER_ADMIN:
|
||||||
contest = Contest.objects.all().order_by("-create_time")
|
contest = Contest.objects.all().order_by("-create_time")
|
||||||
else:
|
else:
|
||||||
@ -171,8 +184,8 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
data = serializer.data
|
data = serializer.data
|
||||||
try:
|
try:
|
||||||
contest = Contest.objects.get(id=data["contest_id"])
|
contest = Contest.objects.get(id=data["contest_id"])
|
||||||
if request.user.admin_type != SUPER_ADMIN:
|
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
|
||||||
contest = contest.get(created_by=request.user)
|
return error_response(u"比赛不存在")
|
||||||
except Contest.DoesNotExist:
|
except Contest.DoesNotExist:
|
||||||
return error_response(u"比赛不存在")
|
return error_response(u"比赛不存在")
|
||||||
contest_problem = ContestProblem.objects.create(title=data["title"],
|
contest_problem = ContestProblem.objects.create(title=data["title"],
|
||||||
@ -186,8 +199,7 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
created_by=request.user,
|
created_by=request.user,
|
||||||
hint=data["hint"],
|
hint=data["hint"],
|
||||||
contest=contest,
|
contest=contest,
|
||||||
sort_index=data["sort_index"],
|
sort_index=data["sort_index"])
|
||||||
score=data["score"])
|
|
||||||
return success_response(ContestProblemSerializer(contest_problem).data)
|
return success_response(ContestProblemSerializer(contest_problem).data)
|
||||||
else:
|
else:
|
||||||
return serializer_invalid_response(serializer)
|
return serializer_invalid_response(serializer)
|
||||||
@ -221,7 +233,6 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
contest_problem.hint = data["hint"]
|
contest_problem.hint = data["hint"]
|
||||||
contest_problem.visible = data["visible"]
|
contest_problem.visible = data["visible"]
|
||||||
contest_problem.sort_index = data["sort_index"]
|
contest_problem.sort_index = data["sort_index"]
|
||||||
contest_problem.score = data["score"]
|
|
||||||
contest_problem.last_update_time = now()
|
contest_problem.last_update_time = now()
|
||||||
contest_problem.save()
|
contest_problem.save()
|
||||||
return success_response(ContestProblemSerializer(contest_problem).data)
|
return success_response(ContestProblemSerializer(contest_problem).data)
|
||||||
@ -238,8 +249,8 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
if contest_problem_id:
|
if contest_problem_id:
|
||||||
try:
|
try:
|
||||||
contest_problem = ContestProblem.objects.get(id=contest_problem_id)
|
contest_problem = ContestProblem.objects.get(id=contest_problem_id)
|
||||||
if request.user.admin_type != SUPER_ADMIN:
|
if request.user.admin_type != SUPER_ADMIN and contest_problem.created_by != request.user:
|
||||||
contest_problem = contest_problem.get(created_by=request.user)
|
return error_response(u"比赛题目不存在")
|
||||||
return success_response(ContestProblemSerializer(contest_problem).data)
|
return success_response(ContestProblemSerializer(contest_problem).data)
|
||||||
except ContestProblem.DoesNotExist:
|
except ContestProblem.DoesNotExist:
|
||||||
return error_response(u"比赛题目不存在")
|
return error_response(u"比赛题目不存在")
|
||||||
@ -261,6 +272,26 @@ class ContestProblemAdminAPIView(APIView):
|
|||||||
return paginate(request, contest_problems, ContestProblemSerializer)
|
return paginate(request, contest_problems, ContestProblemSerializer)
|
||||||
|
|
||||||
|
|
||||||
|
class MakeContestProblemPublicAPIView(APIView):
|
||||||
|
@super_admin_required
|
||||||
|
def post(self, request):
|
||||||
|
problem_id = request.data.get("problem_id", -1)
|
||||||
|
try:
|
||||||
|
problem = ContestProblem.objects.get(id=problem_id)
|
||||||
|
except ContestProblem.DoesNotExist:
|
||||||
|
return error_response(u"比赛不存在")
|
||||||
|
Problem.objects.create(title=problem.title, description=problem.description,
|
||||||
|
input_description=problem.input_description,
|
||||||
|
output_description=problem.output_description,
|
||||||
|
samples=problem.samples,
|
||||||
|
test_case_id=problem.test_case_id,
|
||||||
|
hint=problem.hint, created_by=problem.created_by,
|
||||||
|
time_limit=problem.time_limit, memory_limit=problem.memory_limit,
|
||||||
|
visible=False, difficulty=-1, source=problem.contest.title)
|
||||||
|
return success_response(u"创建成功")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ContestPasswordVerifyAPIView(APIView):
|
class ContestPasswordVerifyAPIView(APIView):
|
||||||
@login_required
|
@login_required
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
|
@ -10,7 +10,7 @@ from judge.judger.result import result
|
|||||||
from submission.models import Submission
|
from submission.models import Submission
|
||||||
from problem.models import Problem
|
from problem.models import Problem
|
||||||
from utils.cache import get_cache_redis
|
from utils.cache import get_cache_redis
|
||||||
from contest.models import ContestProblem, Contest, ContestSubmission, CONTEST_UNDERWAY, ContestRank
|
from contest.models import ContestProblem, Contest, CONTEST_UNDERWAY, ContestRank
|
||||||
from account.models import User
|
from account.models import User
|
||||||
|
|
||||||
logger = logging.getLogger("app_info")
|
logger = logging.getLogger("app_info")
|
||||||
|
@ -11,7 +11,8 @@ from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterA
|
|||||||
from announcement.views import AnnouncementAdminAPIView
|
from announcement.views import AnnouncementAdminAPIView
|
||||||
|
|
||||||
from contest.views import (ContestAdminAPIView, ContestProblemAdminAPIView,
|
from contest.views import (ContestAdminAPIView, ContestProblemAdminAPIView,
|
||||||
ContestPasswordVerifyAPIView, ContestTimeAPIView)
|
ContestPasswordVerifyAPIView, ContestTimeAPIView,
|
||||||
|
MakeContestProblemPublicAPIView)
|
||||||
|
|
||||||
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
|
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
|
||||||
JoinGroupAPIView, JoinGroupRequestAdminAPIView)
|
JoinGroupAPIView, JoinGroupRequestAdminAPIView)
|
||||||
@ -65,6 +66,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
|
url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
|
||||||
url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"),
|
url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"),
|
||||||
|
url(r'^api/admin/contest_problem/public/', MakeContestProblemPublicAPIView.as_view(), name="make_contest_problem_public"),
|
||||||
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
|
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
|
||||||
url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
|
url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
|
||||||
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(),
|
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(),
|
||||||
|
@ -136,8 +136,8 @@ class ProblemAdminAPIView(APIView):
|
|||||||
# 普通管理员只能获取自己创建的题目
|
# 普通管理员只能获取自己创建的题目
|
||||||
# 超级管理员可以获取全部的题目
|
# 超级管理员可以获取全部的题目
|
||||||
problem = Problem.objects.get(id=problem_id)
|
problem = Problem.objects.get(id=problem_id)
|
||||||
if request.user.admin_type != SUPER_ADMIN:
|
if request.user.admin_type != SUPER_ADMIN and problem.created_by != request.user:
|
||||||
problem = problem.get(created_by=request.user)
|
return error_response(u"题目不存在")
|
||||||
return success_response(ProblemSerializer(problem).data)
|
return success_response(ProblemSerializer(problem).data)
|
||||||
except Problem.DoesNotExist:
|
except Problem.DoesNotExist:
|
||||||
return error_response(u"题目不存在")
|
return error_response(u"题目不存在")
|
||||||
@ -248,17 +248,31 @@ class TestCaseUploadAPIView(APIView):
|
|||||||
"output_name": str(i + 1) + ".out",
|
"output_name": str(i + 1) + ".out",
|
||||||
"output_md5": md5.hexdigest(),
|
"output_md5": md5.hexdigest(),
|
||||||
"striped_output_md5": striped_md5.hexdigest(),
|
"striped_output_md5": striped_md5.hexdigest(),
|
||||||
|
"input_size": os.path.getsize(test_case_dir + str(i + 1) + ".in"),
|
||||||
"output_size": os.path.getsize(test_case_dir + str(i + 1) + ".out")}
|
"output_size": os.path.getsize(test_case_dir + str(i + 1) + ".out")}
|
||||||
# 写入配置文件
|
# 写入配置文件
|
||||||
with open(test_case_dir + "info", "w") as f:
|
with open(test_case_dir + "info", "w") as f:
|
||||||
f.write(json.dumps(file_info))
|
f.write(json.dumps(file_info))
|
||||||
|
|
||||||
return success_response({"test_case_id": problem_test_dir,
|
return success_response({"test_case_id": problem_test_dir,
|
||||||
"file_list": {"input": l[0::2],
|
"file_list": file_info["test_cases"]})
|
||||||
"output": l[1::2]}})
|
|
||||||
else:
|
else:
|
||||||
return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩")
|
return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩")
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
test_case_id = request.GET.get("test_case_id", None)
|
||||||
|
if not test_case_id:
|
||||||
|
return error_response(u"参数错误")
|
||||||
|
test_case_config = settings.TEST_CASE_DIR + test_case_id + "/info"
|
||||||
|
try:
|
||||||
|
f = open(test_case_config)
|
||||||
|
config = json.loads(f.read())
|
||||||
|
f.close()
|
||||||
|
except Exception as e:
|
||||||
|
return error_response(u"读取测试用例出错")
|
||||||
|
return success_response({"file_list": config["test_cases"]})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def problem_list_page(request, page=1):
|
def problem_list_page(request, page=1):
|
||||||
"""
|
"""
|
||||||
|
@ -52,10 +52,6 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
|||||||
{ name: "首页",
|
{ name: "首页",
|
||||||
children: [{name: "主页", hash: "#index/index"}]
|
children: [{name: "主页", hash: "#index/index"}]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "通用",
|
|
||||||
children: [{name: "公告管理", hash: "#announcement/announcement"}]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "比赛管理",
|
name: "比赛管理",
|
||||||
children: [{name: "比赛列表", hash: "#contest/contest_list"},
|
children: [{name: "比赛列表", hash: "#contest/contest_list"},
|
||||||
@ -72,12 +68,14 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
|||||||
$id: "admin",
|
$id: "admin",
|
||||||
template_url: "template/" + hash + ".html",
|
template_url: "template/" + hash + ".html",
|
||||||
username: "",
|
username: "",
|
||||||
|
adminType: 1,
|
||||||
groupId: -1,
|
groupId: -1,
|
||||||
problemId: -1,
|
problemId: -1,
|
||||||
adminNavList: [],
|
adminNavList: [],
|
||||||
$contestMode: -1,
|
|
||||||
$problemId: -1,
|
contestId: -1,
|
||||||
$contestId: -1,
|
contestProblemStatus: "edit",
|
||||||
|
|
||||||
hide_loading: function () {
|
hide_loading: function () {
|
||||||
$("#loading-gif").hide();
|
$("#loading-gif").hide();
|
||||||
},
|
},
|
||||||
@ -94,6 +92,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
|||||||
success: function(data){
|
success: function(data){
|
||||||
if(!data.code){
|
if(!data.code){
|
||||||
vm.username = data.data.username;
|
vm.username = data.data.username;
|
||||||
|
vm.adminType = data.data.admin_type;
|
||||||
if (data.data.admin_type == 2){
|
if (data.data.admin_type == 2){
|
||||||
vm.adminNavList = superAdminNav;
|
vm.adminNavList = superAdminNav;
|
||||||
}
|
}
|
||||||
@ -113,24 +112,6 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
|||||||
vm.template_url = "template/group/group.html";
|
vm.template_url = "template/group/group.html";
|
||||||
});
|
});
|
||||||
|
|
||||||
vm.$watch("showContestProblemPage", function (problemId, contestId, contestMode) {
|
|
||||||
vm.$problemId = problemId;
|
|
||||||
vm.$contestId = contestId;
|
|
||||||
vm.$contestMode = contestMode
|
|
||||||
vm.template_url = "template/contest/edit_problem.html";
|
|
||||||
});
|
|
||||||
|
|
||||||
vm.$watch("showContestListPage", function () {
|
|
||||||
vm.template_url = "template/contest/contest_list.html";
|
|
||||||
});
|
|
||||||
|
|
||||||
vm.$watch("showContestSubmissionPage", function (problemId, contestId, contestMode) {
|
|
||||||
vm.$problemId = problemId;
|
|
||||||
vm.$contestId = contestId;
|
|
||||||
vm.$contestMode = contestMode
|
|
||||||
vm.template_url = "template/contest/submission_list.html";
|
|
||||||
});
|
|
||||||
|
|
||||||
avalon.scan();
|
avalon.scan();
|
||||||
|
|
||||||
window.onhashchange = function () {
|
window.onhashchange = function () {
|
||||||
|
@ -104,6 +104,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date
|
|||||||
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
|
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
vm.allGroups = [];
|
||||||
for (var i = 0; i < data.data.length; i++) {
|
for (var i = 0; i < data.data.length; i++) {
|
||||||
var item = data.data[i];
|
var item = data.data[i];
|
||||||
item["isSelected"] = false;
|
item["isSelected"] = false;
|
||||||
|
@ -20,6 +20,15 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
|||||||
search: function () {
|
search: function () {
|
||||||
getPage(1);
|
getPage(1);
|
||||||
avalon.vmodels.contestListPager.currentPage = 1;
|
avalon.vmodels.contestListPager.currentPage = 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
editContest: function(contestId){
|
||||||
|
avalon.vmodels.admin.contestId = contestId;
|
||||||
|
avalon.vmodels.admin.template_url = "template/contest/edit_contest.html";
|
||||||
|
},
|
||||||
|
showContestProblems: function(contestId){
|
||||||
|
avalon.vmodels.admin.contestId = contestId;
|
||||||
|
avalon.vmodels.admin.template_url = "template/contest/problem_list.html";
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -42,7 +51,6 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
|
|||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (!data.code) {
|
if (!data.code) {
|
||||||
vm.contestList = data.data.results;
|
vm.contestList = data.data.results;
|
||||||
vm.announcementList = data.data.results;
|
|
||||||
avalon.vmodels.contestListPager.totalPage = data.data.total_page;
|
avalon.vmodels.contestListPager.totalPage = data.data.total_page;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1,321 +0,0 @@
|
|||||||
require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker", "validator"], function ($, avalon, csrfTokenHeader, bsAlert, editor) {
|
|
||||||
|
|
||||||
avalon.ready(function () {
|
|
||||||
|
|
||||||
$("#edit-contest-form").validator().on('submit', function (e) {
|
|
||||||
if (!e.isDefaultPrevented()) {
|
|
||||||
e.preventDefault();
|
|
||||||
var ajaxData = {
|
|
||||||
id: vm.contestList[vm.editingContestId - 1].id,
|
|
||||||
title: vm.editTitle,
|
|
||||||
description: vm.editDescription,
|
|
||||||
mode: vm.editMode,
|
|
||||||
contest_type: 0,
|
|
||||||
real_time_rank: vm.editRealTimeRank,
|
|
||||||
show_user_submission: vm.editShowSubmission,
|
|
||||||
start_time: vm.editStartTime,
|
|
||||||
end_time: vm.editEndTime,
|
|
||||||
visible: vm.editVisible
|
|
||||||
};
|
|
||||||
|
|
||||||
var selectedGroups = [];
|
|
||||||
if (!vm.isGlobal) {
|
|
||||||
for (var i = 0; i < vm.allGroups.length; i++) {
|
|
||||||
if (vm.allGroups[i].isSelected) {
|
|
||||||
selectedGroups.push(vm.allGroups[i].id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ajaxData.groups = selectedGroups;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (vm.editPassword) {
|
|
||||||
ajaxData.password = vm.editPassword;
|
|
||||||
ajaxData.contest_type = 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ajaxData.contest_type = 1;
|
|
||||||
}
|
|
||||||
if (!vm.isGlobal && !selectedGroups.length) {
|
|
||||||
bsAlert("你没有选择参赛用户!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (vm.editDescription == "") {
|
|
||||||
bsAlert("比赛描述不能为空!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax({ // modify contest info
|
|
||||||
beforeSend: csrfTokenHeader,
|
|
||||||
url: "/api/admin/contest/",
|
|
||||||
dataType: "json",
|
|
||||||
contentType: "application/json;charset=UTF-8",
|
|
||||||
data: JSON.stringify(ajaxData),
|
|
||||||
method: "put",
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.code) {
|
|
||||||
bsAlert("修改成功!");
|
|
||||||
vm.editingContestId = 0; // Hide the editor
|
|
||||||
vm.getPage(1); // Refresh the contest list
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bsAlert(data.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (avalon.vmodels.contestList) {
|
|
||||||
// this page has been loaded before, so set the default value
|
|
||||||
var vm = avalon.vmodels.contestList;
|
|
||||||
vm.contestList = [];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var vm = avalon.define({
|
|
||||||
$id: "contestList",
|
|
||||||
contestList: [],
|
|
||||||
previousPage: 0,
|
|
||||||
nextPage: 0,
|
|
||||||
page: 1,
|
|
||||||
totalPage: 1,
|
|
||||||
showVisibleOnly: false,
|
|
||||||
keyword: "",
|
|
||||||
editingContestId: 0,
|
|
||||||
editTitle: "",
|
|
||||||
editDescription: "",
|
|
||||||
editProblemList: [],
|
|
||||||
editPassword: "",
|
|
||||||
editStartTime: "",
|
|
||||||
editEndTime: "",
|
|
||||||
editMode: "",
|
|
||||||
editShowSubmission: false,
|
|
||||||
editVisible: false,
|
|
||||||
editRealTimeRank: true,
|
|
||||||
editingProblemContestIndex: 0,
|
|
||||||
isGlobal: true,
|
|
||||||
allGroups: [],
|
|
||||||
showGlobalViewRadio: true,
|
|
||||||
admin_type: 1,
|
|
||||||
getNext: function () {
|
|
||||||
if (!vm.nextPage)
|
|
||||||
return;
|
|
||||||
getPageData(vm.page + 1);
|
|
||||||
},
|
|
||||||
getPrevious: function () {
|
|
||||||
if (!vm.previousPage)
|
|
||||||
return;
|
|
||||||
getPageData(vm.page - 1);
|
|
||||||
},
|
|
||||||
getBtnClass: function (btn) {
|
|
||||||
if (btn == "next") {
|
|
||||||
return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getPage: function (page_index) {
|
|
||||||
getPageData(page_index);
|
|
||||||
},
|
|
||||||
showEditContestArea: function (contestId) {
|
|
||||||
if (vm.editingContestId && !confirm("如果继续将丢失未保存的信息,是否继续?"))
|
|
||||||
return;
|
|
||||||
if (contestId == vm.editingContestId)
|
|
||||||
vm.editingContestId = 0;
|
|
||||||
else {
|
|
||||||
vm.editingContestId = contestId;
|
|
||||||
vm.editTitle = vm.contestList[contestId - 1].title;
|
|
||||||
vm.editPassword = vm.contestList[contestId - 1].password;
|
|
||||||
vm.editStartTime = vm.contestList[contestId - 1].start_time.substring(0, 16).replace("T", " ");
|
|
||||||
vm.editEndTime = vm.contestList[contestId - 1].end_time.substring(0, 16).replace("T", " ");
|
|
||||||
vm.editMode = vm.contestList[contestId - 1].mode;
|
|
||||||
vm.editVisible = vm.contestList[contestId - 1].visible;
|
|
||||||
vm.editRealTimeRank = vm.contestList[contestId - 1].real_time_rank;
|
|
||||||
if (vm.contestList[contestId - 1].contest_type == 0) { //contest type == 0, contest in group
|
|
||||||
vm.isGlobal = false;
|
|
||||||
for (var i = 0; i < vm.allGroups.length; i++) {
|
|
||||||
vm.allGroups[i].isSelected = false;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < vm.contestList[contestId - 1].groups.length; i++) {
|
|
||||||
var id = parseInt(vm.contestList[contestId - 1].groups[i]);
|
|
||||||
|
|
||||||
for (var index = 0; vm.allGroups[index]; index++) {
|
|
||||||
if (vm.allGroups[index].id == id) {
|
|
||||||
vm.allGroups[index].isSelected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vm.isGlobal = true;
|
|
||||||
}
|
|
||||||
vm.editShowSubmission = vm.contestList[contestId - 1].show_user_submission;
|
|
||||||
editor("#editor").setValue(vm.contestList[contestId - 1].description);
|
|
||||||
vm.editingProblemContestIndex = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showEditProblemArea: function (contestId) {
|
|
||||||
if (vm.editingProblemContestIndex == contestId) {
|
|
||||||
vm.editingProblemContestIndex = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (vm.editingContestId && !confirm("如果继续将丢失未保存的信息,是否继续?")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.ajax({ // Get the problem list of current contest
|
|
||||||
beforeSend: csrfTokenHeader,
|
|
||||||
url: "/api/admin/contest_problem/?contest_id=" + vm.contestList[contestId - 1].id,
|
|
||||||
method: "get",
|
|
||||||
dataType: "json",
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.code) {
|
|
||||||
vm.editProblemList = data.data;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bsAlert(data.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
vm.editingContestId = 0;
|
|
||||||
vm.editingProblemContestIndex = contestId;
|
|
||||||
vm.editMode = vm.contestList[contestId - 1].mode;
|
|
||||||
},
|
|
||||||
addProblem: function () {
|
|
||||||
vm.$fire("up!showContestProblemPage", 0, vm.contestList[vm.editingProblemContestIndex - 1].id, vm.editMode);
|
|
||||||
},
|
|
||||||
showProblemEditPage: function (el) {
|
|
||||||
vm.$fire("up!showContestProblemPage", el.id, vm.contestList[vm.editingProblemContestIndex - 1].id, vm.editMode);
|
|
||||||
},
|
|
||||||
showSubmissionPage: function (el) {
|
|
||||||
var problemId = 0
|
|
||||||
if (el)
|
|
||||||
problemId = el.id;
|
|
||||||
vm.$fire("up!showContestSubmissionPage", problemId, vm.contestList[vm.editingProblemContestIndex - 1].id, vm.editMode);
|
|
||||||
},
|
|
||||||
addToProblemList: function (problem) {
|
|
||||||
var ajaxData = {
|
|
||||||
title: problem.title,
|
|
||||||
description: problem.description,
|
|
||||||
time_limit: problem.time_limit,
|
|
||||||
memory_limit: problem.memory_limit,
|
|
||||||
samples: [],
|
|
||||||
test_case_id: problem.test_case_id,
|
|
||||||
hint: problem.hint,
|
|
||||||
source: problem.contest.title,
|
|
||||||
visible: false,
|
|
||||||
tags: [],
|
|
||||||
input_description: problem.input_description,
|
|
||||||
output_description: problem.output_description,
|
|
||||||
difficulty: 0
|
|
||||||
};
|
|
||||||
for (var i = 0; i < problem.samples.length; i++) {
|
|
||||||
ajaxData.samples.push({input: problem.samples[i].input, output: problem.samples[i].output})
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
beforeSend: csrfTokenHeader,
|
|
||||||
url: "/api/admin/problem/",
|
|
||||||
dataType: "json",
|
|
||||||
data: JSON.stringify(ajaxData),
|
|
||||||
method: "post",
|
|
||||||
contentType: "application/json;charset=UTF-8",
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.code) {
|
|
||||||
bsAlert("题目添加成功!题目现在处于隐藏状态,请到题目列表手动修改,并添加分类和难度信息!");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bsAlert(data.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
vm.$watch("showVisibleOnly", function () {
|
|
||||||
getPageData(1);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
getPageData(1);
|
|
||||||
|
|
||||||
//init time picker
|
|
||||||
$("#contest_start_time").datetimepicker({
|
|
||||||
format: "yyyy-mm-dd hh:ii",
|
|
||||||
minuteStep: 5,
|
|
||||||
weekStart: 1,
|
|
||||||
language: "zh-CN"
|
|
||||||
});
|
|
||||||
$("#contest_end_time").datetimepicker({
|
|
||||||
format: "yyyy-mm-dd hh:ii",
|
|
||||||
minuteStep: 5,
|
|
||||||
weekStart: 1,
|
|
||||||
language: "zh-CN"
|
|
||||||
});
|
|
||||||
|
|
||||||
function getPageData(page) {
|
|
||||||
var url = "/api/admin/contest/?paging=true&page=" + page + "&page_size=10";
|
|
||||||
if (vm.showVisibleOnly)
|
|
||||||
url += "&visible=true"
|
|
||||||
if (vm.keyword != "")
|
|
||||||
url += "&keyword=" + vm.keyword;
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
dataType: "json",
|
|
||||||
method: "get",
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.code) {
|
|
||||||
vm.contestList = data.data.results;
|
|
||||||
vm.totalPage = data.data.total_page;
|
|
||||||
vm.previousPage = data.data.previous_page;
|
|
||||||
vm.nextPage = data.data.next_page;
|
|
||||||
vm.page = page;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bsAlert(data.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get group list
|
|
||||||
$.ajax({
|
|
||||||
url: "/api/user/",
|
|
||||||
method: "get",
|
|
||||||
dataType: "json",
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.code) {
|
|
||||||
var admin_type = data.data.admin_type;
|
|
||||||
vm.admin_type = admin_type;
|
|
||||||
if (data.data.admin_type == 1) {
|
|
||||||
vm.isGlobal = false;
|
|
||||||
vm.showGlobalViewRadio = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$.ajax({
|
|
||||||
url: "/api/admin/group/",
|
|
||||||
method: "get",
|
|
||||||
dataType: "json",
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.code) {
|
|
||||||
if (!data.data.length) {
|
|
||||||
|
|
||||||
if (admin_type != 2)
|
|
||||||
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < data.data.length; i++) {
|
|
||||||
var item = data.data[i];
|
|
||||||
item["isSelected"] = false;
|
|
||||||
vm.allGroups.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bsAlert(data.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
avalon.scan();
|
|
||||||
});
|
|
64
static/src/js/app/admin/contest/contestProblemList.js
Normal file
64
static/src/js/app/admin/contest/contestProblemList.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfTokenHeader, bsAlert) {
|
||||||
|
|
||||||
|
avalon.ready(function () {
|
||||||
|
if (avalon.vmodels.contestProblemList) {
|
||||||
|
vm = avalon.vmodels.contestProblemList;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var vm = avalon.define({
|
||||||
|
$id: "contestProblemList",
|
||||||
|
problemList: [],
|
||||||
|
|
||||||
|
adminType: avalon.vmodels.admin.adminType,
|
||||||
|
|
||||||
|
showEditProblemPage: function (problemId) {
|
||||||
|
avalon.vmodels.admin.contestProblemStatus = "edit";
|
||||||
|
avalon.vmodels.admin.problemId = problemId;
|
||||||
|
avalon.vmodels.admin.template_url = "template/contest/edit_problem.html";
|
||||||
|
},
|
||||||
|
addProblem: function(){
|
||||||
|
avalon.vmodels.admin.contestProblemStatus = "add";
|
||||||
|
avalon.vmodels.admin.template_url = "template/contest/edit_problem.html";
|
||||||
|
},
|
||||||
|
goBack: function(){
|
||||||
|
avalon.vmodels.admin.template_url = "template/contest/contest_list.html"
|
||||||
|
},
|
||||||
|
|
||||||
|
makeProblemPublic: function(problem){
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/admin/contest_problem/public/",
|
||||||
|
method: "post",
|
||||||
|
dataType: "json",
|
||||||
|
data: {"problem_id": problem.id},
|
||||||
|
success: function(response){
|
||||||
|
if(response.code){
|
||||||
|
bsAlert(response.data);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
problem.is_public = true;
|
||||||
|
alert("公开题目成功,现在处于隐藏状态,请添加标签难度等信息。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/admin/contest_problem/?contest_id=" + avalon.vmodels.admin.contestId,
|
||||||
|
dataType: "json",
|
||||||
|
method: "get",
|
||||||
|
success: function (data) {
|
||||||
|
if (!data.code) {
|
||||||
|
vm.problemList = data.data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bsAlert(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
avalon.scan();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
175
static/src/js/app/admin/contest/editContest.js
Normal file
175
static/src/js/app/admin/contest/editContest.js
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "datetimePicker",
|
||||||
|
"validator", "editorComponent"],
|
||||||
|
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
|
||||||
|
|
||||||
|
$("#edit-contest-form").validator().on('submit', function (e) {
|
||||||
|
if (!e.isDefaultPrevented()) {
|
||||||
|
e.preventDefault();
|
||||||
|
var ajaxData = {
|
||||||
|
id: avalon.vmodels.admin.contestId,
|
||||||
|
title: vm.title,
|
||||||
|
description: avalon.vmodels.contestDescriptionEditor.content,
|
||||||
|
contest_type: 0,
|
||||||
|
real_time_rank: vm.realTimeRank,
|
||||||
|
start_time: vm.startTime,
|
||||||
|
end_time: vm.endTime,
|
||||||
|
visible: vm.visible
|
||||||
|
};
|
||||||
|
|
||||||
|
var selectedGroups = [];
|
||||||
|
if (!vm.isGlobal) {
|
||||||
|
for (var i = 0; i < vm.allGroups.length; i++) {
|
||||||
|
if (vm.allGroups[i].isSelected) {
|
||||||
|
selectedGroups.push(vm.allGroups[i].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxData.groups = selectedGroups;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (vm.password) {
|
||||||
|
ajaxData.password = vm.password;
|
||||||
|
ajaxData.contest_type = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ajaxData.contest_type = 1;
|
||||||
|
}
|
||||||
|
if (!vm.isGlobal && !selectedGroups.length) {
|
||||||
|
bsAlert("你没有选择参赛用户!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ajaxData.description.trim() == "") {
|
||||||
|
bsAlert("比赛描述不能为空!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/admin/contest/",
|
||||||
|
dataType: "json",
|
||||||
|
contentType: "application/json;charset=UTF-8",
|
||||||
|
data: JSON.stringify(ajaxData),
|
||||||
|
method: "put",
|
||||||
|
success: function (data) {
|
||||||
|
if (!data.code) {
|
||||||
|
bsAlert("修改成功!");
|
||||||
|
vm.showContestListPage();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bsAlert(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (avalon.vmodels.edit_contest)
|
||||||
|
var vm = avalon.vmodels.edit_contest;
|
||||||
|
else
|
||||||
|
var vm = avalon.define({
|
||||||
|
$id: "edit_contest",
|
||||||
|
title: "",
|
||||||
|
startTime: "",
|
||||||
|
endTime: "",
|
||||||
|
password: "",
|
||||||
|
isGlobal: true,
|
||||||
|
allGroups: [],
|
||||||
|
showGlobalViewRadio: true,
|
||||||
|
realTimeRank: true,
|
||||||
|
visible: false,
|
||||||
|
showContestListPage: function () {
|
||||||
|
avalon.vmodels.admin.template_url = "template/contest/contest_list.html";
|
||||||
|
},
|
||||||
|
|
||||||
|
contestDescriptionEditor: {
|
||||||
|
editorId: "contest-description-editor",
|
||||||
|
placeholder: "比赛介绍内容"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
avalon.scan();
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/user/",
|
||||||
|
method: "get",
|
||||||
|
dataType: "json",
|
||||||
|
success: function (data) {
|
||||||
|
if (!data.code) {
|
||||||
|
var admin_type = data.data.admin_type;
|
||||||
|
if (data.data.admin_type == 1) {
|
||||||
|
vm.isGlobal = false;
|
||||||
|
vm.showGlobalViewRadio = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/admin/group/",
|
||||||
|
method: "get",
|
||||||
|
dataType: "json",
|
||||||
|
success: function (data) {
|
||||||
|
if (!data.code) {
|
||||||
|
if (!data.data.length) {
|
||||||
|
if (admin_type != 2)
|
||||||
|
bsAlert("您的用户权限只能创建小组内比赛,但是您还没有创建过小组");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vm.allGroups = [];
|
||||||
|
for (var i = 0; i < data.data.length; i++) {
|
||||||
|
var item = data.data[i];
|
||||||
|
item.isSelected = false;
|
||||||
|
vm.allGroups.push(item);
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/admin/contest/?contest_id=" + avalon.vmodels.admin.contestId,
|
||||||
|
method: "get",
|
||||||
|
dataType: "json",
|
||||||
|
success: function (data) {
|
||||||
|
if (data.code) {
|
||||||
|
bsAlert(data.data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var contest = data.data;
|
||||||
|
vm.title = contest.title;
|
||||||
|
avalon.vmodels.contestDescriptionEditor.content = contest.description;
|
||||||
|
vm.visible = contest.visible;
|
||||||
|
vm.realTimeRank = contest.real_time_rank;
|
||||||
|
vm.startTime = contest.start_time.substring(0, 16).replace("T", " ");
|
||||||
|
vm.endTime = contest.end_time.substring(0, 16).replace("T", " ");
|
||||||
|
if (contest.contest_type == 0) { //contest_type == 0, 小组内比赛
|
||||||
|
vm.isGlobal = false;
|
||||||
|
for (var i = 0; i < vm.allGroups.length; i++) {
|
||||||
|
vm.allGroups[i].isSelected = false;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < contest.groups.length; i++) {
|
||||||
|
var id = contest.groups[i];
|
||||||
|
for (var index = 0; vm.allGroups[index]; index++) {
|
||||||
|
if (vm.allGroups[index].id == id) {
|
||||||
|
vm.allGroups[index].isSelected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm.isGlobal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bsAlert(data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#contest_start_time").datetimepicker({
|
||||||
|
format: "yyyy-mm-dd hh:ii",
|
||||||
|
minuteStep: 5,
|
||||||
|
weekStart: 1,
|
||||||
|
language: "zh-CN"
|
||||||
|
});
|
||||||
|
$("#contest_end_time").datetimepicker({
|
||||||
|
format: "yyyy-mm-dd hh:ii",
|
||||||
|
minuteStep: 5,
|
||||||
|
weekStart: 1,
|
||||||
|
language: "zh-CN"
|
||||||
|
});
|
||||||
|
});
|
@ -1,22 +1,22 @@
|
|||||||
require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagEditor", "validator", "jqueryUI"],
|
require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagEditor", "validator", "editorComponent"],
|
||||||
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
|
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
|
||||||
|
|
||||||
avalon.ready(function () {
|
avalon.ready(function () {
|
||||||
|
|
||||||
$("#edit-problem-form").validator()
|
$("#edit-problem-form").validator()
|
||||||
.on('submit', function (e) {
|
.on('submit', function (e) {
|
||||||
if (!e.isDefaultPrevented()){
|
if (!e.isDefaultPrevented()) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (vm.testCaseId == "") {
|
if (vm.testCaseId == "") {
|
||||||
bsAlert("你还没有上传测试数据!");
|
bsAlert("你还没有上传测试数据!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (vm.description == "") {
|
if (avalon.vmodels.contestProblemDescriptionEditor.content == "") {
|
||||||
bsAlert("题目描述不能为空!");
|
bsAlert("题目描述不能为空!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (vm.timeLimit < 1000 || vm.timeLimit > 5000) {
|
if (vm.timeLimit < 30 || vm.timeLimit > 5000) {
|
||||||
bsAlert("保证时间限制是一个1000-5000的合法整数");
|
bsAlert("保证时间限制是一个30-5000的合法整数");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (vm.samples.length == 0) {
|
if (vm.samples.length == 0) {
|
||||||
@ -31,33 +31,34 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
|
|||||||
}
|
}
|
||||||
var ajaxData = {
|
var ajaxData = {
|
||||||
title: vm.title,
|
title: vm.title,
|
||||||
description: vm.description,
|
description: avalon.vmodels.contestProblemDescriptionEditor.content,
|
||||||
time_limit: vm.timeLimit,
|
time_limit: vm.timeLimit,
|
||||||
memory_limit: vm.memoryLimit,
|
memory_limit: vm.memoryLimit,
|
||||||
samples: [],
|
samples: [],
|
||||||
test_case_id: vm.testCaseId,
|
test_case_id: vm.testCaseId,
|
||||||
hint: vm.hint,
|
hint: avalon.vmodels.contestProblemHintEditor.content,
|
||||||
visible: vm.visible,
|
visible: vm.visible,
|
||||||
contest_id: avalon.vmodels.admin.$contestId,
|
contest_id: avalon.vmodels.admin.contestId,
|
||||||
input_description: vm.inputDescription,
|
input_description: vm.inputDescription,
|
||||||
output_description: vm.outputDescription,
|
output_description: vm.outputDescription,
|
||||||
sort_index: vm.sortIndex,
|
sort_index: vm.sortIndex
|
||||||
};
|
};
|
||||||
if (vm.contestMode == '2') {
|
|
||||||
if (!vm.score) {
|
if (avalon.vmodels.admin.contestProblemStatus == "edit") {
|
||||||
bsAlert("请输入有效的分值!")
|
var method = "put";
|
||||||
return false;
|
ajaxData["id"] = avalon.vmodels.admin.problemId;
|
||||||
}
|
var alertContent = "题目编辑成功";
|
||||||
ajaxData.score = vm.score;
|
|
||||||
}
|
}
|
||||||
var method = "post";
|
else{
|
||||||
if (avalon.vmodels.admin.$problemId) {
|
var method = "post";
|
||||||
method = "put";
|
var alertContent = "题目创建成功";
|
||||||
ajaxData.id = avalon.vmodels.admin.$problemId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < vm.samples.$model.length; i++) {
|
for (var i = 0; i < vm.samples.$model.length; i++) {
|
||||||
ajaxData.samples.push({input: vm.samples.$model[i].input, output: vm.samples.$model[i].output});
|
ajaxData.samples.push({
|
||||||
|
input: vm.samples.$model[i].input,
|
||||||
|
output: vm.samples.$model[i].output
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -69,8 +70,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
|
|||||||
contentType: "application/json;charset=UTF-8",
|
contentType: "application/json;charset=UTF-8",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (!data.code) {
|
if (!data.code) {
|
||||||
bsAlert("题目编辑成功!");
|
bsAlert(alertContent);
|
||||||
vm.goBack(true);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bsAlert(data.data);
|
bsAlert(data.data);
|
||||||
@ -82,93 +82,101 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!avalon.vmodels.editProblem)
|
if (!avalon.vmodels.editProblem)
|
||||||
var vm = avalon.define({
|
var vm = avalon.define({
|
||||||
$id: "editProblem",
|
$id: "editProblem",
|
||||||
title: "",
|
title: "",
|
||||||
description: "",
|
description: "",
|
||||||
timeLimit: 0,
|
timeLimit: 1000,
|
||||||
memoryLimit: 0,
|
memoryLimit: 128,
|
||||||
samples: [],
|
samples: [],
|
||||||
hint: "",
|
hint: "",
|
||||||
sortIndex: "",
|
sortIndex: "",
|
||||||
visible: true,
|
visible: true,
|
||||||
inputDescription: "",
|
inputDescription: "",
|
||||||
outputDescription: "",
|
outputDescription: "",
|
||||||
testCaseIdd: "",
|
testCaseId: "",
|
||||||
contestMode: 0,
|
testCaseList: [],
|
||||||
score: 1,
|
uploadSuccess: false,
|
||||||
uploadSuccess: false,
|
|
||||||
testCaseList: [],
|
contestProblemDescriptionEditor: {
|
||||||
addSample: function () {
|
editorId: "contest-problem-description-editor",
|
||||||
vm.samples.push({input: "", output: "", "visible": true});
|
placeholder: "题目描述"
|
||||||
},
|
},
|
||||||
delSample: function (sample) {
|
contestProblemHintEditor: {
|
||||||
if (confirm("你确定要删除么?")) {
|
editorId: "contest-problem-hint-editor",
|
||||||
vm.samples.remove(sample);
|
placeholder: "提示"
|
||||||
}
|
},
|
||||||
},
|
|
||||||
toggleSample: function (sample) {
|
addSample: function () {
|
||||||
sample.visible = !sample.visible;
|
vm.samples.push({input: "", output: "", "visible": true});
|
||||||
},
|
},
|
||||||
getBtnContent: function (item) {
|
|
||||||
if (item.visible)
|
delSample: function (sample) {
|
||||||
return "折叠";
|
if (confirm("你确定要删除么?")) {
|
||||||
return "展开";
|
vm.samples.remove(sample);
|
||||||
},
|
}
|
||||||
goBack: function(check){
|
},
|
||||||
if (check||confirm("这将丢失所有的改动,确定要继续么?")) {
|
|
||||||
vm.$fire("up!showContestListPage");
|
toggleSample: function (sample) {
|
||||||
}
|
sample.visible = !sample.visible;
|
||||||
}
|
},
|
||||||
});
|
|
||||||
else
|
getBtnContent: function (item) {
|
||||||
vm = avalon.vmodels.editProblem;
|
if (item.visible)
|
||||||
|
return "折叠";
|
||||||
|
return "展开";
|
||||||
|
},
|
||||||
|
|
||||||
|
goBack: function (check) {
|
||||||
|
avalon.vmodels.admin.template_url = "template/contest/problem_list.html";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
else {
|
||||||
|
var vm = avalon.vmodels.editProblem;
|
||||||
|
}
|
||||||
|
|
||||||
var hintEditor = editor("#hint");
|
|
||||||
var descriptionEditor = editor("#problemDescription");
|
|
||||||
var testCaseUploader = uploader("#testCaseFile", "/api/admin/test_case_upload/", function (file, response) {
|
var testCaseUploader = uploader("#testCaseFile", "/api/admin/test_case_upload/", function (file, response) {
|
||||||
if (response.code)
|
if (response.code)
|
||||||
bsAlert(response.data);
|
bsAlert(response.data);
|
||||||
else {
|
else {
|
||||||
vm.testCaseId = response.data.test_case_id;
|
vm.testCaseId = response.data.test_case_id;
|
||||||
vm.uploadSuccess = true;
|
|
||||||
vm.testCaseList = [];
|
vm.testCaseList = [];
|
||||||
for (var i = 0; i < response.data.file_list.input.length; i++) {
|
for(var key in response.data.file_list){
|
||||||
vm.testCaseList.push({
|
vm.testCaseList.push({
|
||||||
input: response.data.file_list.input[i],
|
input: response.data.file_list[key].input_name,
|
||||||
output: response.data.file_list.output[i]
|
output: response.data.file_list[key].output_name
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
vm.uploadSuccess = true;
|
||||||
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
|
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
vm.contestMode = avalon.vmodels.admin.$contestMode;
|
if (avalon.vmodels.admin.contestProblemStatus == "edit") {
|
||||||
if (avalon.vmodels.admin.$problemId){
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/api/admin/contest_problem/?contest_problem_id=" + avalon.vmodels.admin.$problemId,
|
url: "/api/admin/contest_problem/?contest_problem_id=" + avalon.vmodels.admin.problemId,
|
||||||
method: "get",
|
method: "get",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (data.code) {
|
if (data.code) {
|
||||||
bsAlert(data.data);
|
bsAlert(data.data);
|
||||||
}
|
}
|
||||||
else { // Edit mode load the problem data
|
else {
|
||||||
var problem = data.data;
|
var problem = data.data;
|
||||||
vm.testCaseList = [];
|
vm.testCaseList = [];
|
||||||
vm.sortIndex = problem.sort_index;
|
vm.sortIndex = problem.sort_index;
|
||||||
vm.title = problem.title;
|
vm.title = problem.title;
|
||||||
vm.description = problem.description;
|
avalon.vmodels.contestProblemDescriptionEditor.content = problem.description;
|
||||||
vm.timeLimit = problem.time_limit;
|
vm.timeLimit = problem.time_limit;
|
||||||
vm.memoryLimit = problem.memory_limit;
|
vm.memoryLimit = problem.memory_limit;
|
||||||
vm.hint = problem.hint;
|
vm.hint = problem.hint;
|
||||||
vm.visible = problem.visible;
|
vm.visible = problem.visible;
|
||||||
vm.inputDescription = problem.input_description;
|
vm.inputDescription = problem.input_description;
|
||||||
vm.outputDescription = problem.output_description;
|
vm.outputDescription = problem.output_description;
|
||||||
vm.score = problem.score;
|
vm.score = problem.score;
|
||||||
vm.samples = [];
|
vm.testCaseId = problem.test_case_id;
|
||||||
vm.testCaseId = problem.test_case_id;
|
vm.samples = [];
|
||||||
for (var i = 0; i < problem.samples.length; i++) {
|
for (var i = 0; i < problem.samples.length; i++) {
|
||||||
vm.samples.push({
|
vm.samples.push({
|
||||||
input: problem.samples[i].input,
|
input: problem.samples[i].input,
|
||||||
@ -176,26 +184,32 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
|
|||||||
visible: false
|
visible: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
hintEditor.setValue(vm.hint);
|
avalon.vmodels.contestProblemHintEditor.content = problem.hint;
|
||||||
descriptionEditor.setValue(vm.description);
|
$.ajax({
|
||||||
|
url: "/api/admin/test_case_upload/?test_case_id=" + vm.testCaseId,
|
||||||
|
method: "get",
|
||||||
|
dataType: "json",
|
||||||
|
success: function(response){
|
||||||
|
if(response.code){
|
||||||
|
bsAlert(response.data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm.testCaseList = [];
|
||||||
|
for (var key in response.data.file_list) {
|
||||||
|
vm.testCaseList.push({
|
||||||
|
input: response.data.file_list[key].input_name,
|
||||||
|
output: response.data.file_list[key].output_name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
vm.uploadSuccess = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else { //Create new problem Set default values
|
|
||||||
vm.testCaseList = [];
|
|
||||||
vm.title = "";
|
|
||||||
vm.timeLimit = 1000;
|
|
||||||
vm.memoryLimit = 256;
|
|
||||||
vm.samples = [];
|
|
||||||
vm.visible = true;
|
|
||||||
vm.inputDescription = "";
|
|
||||||
vm.outputDescription = "";
|
|
||||||
vm.testCaseId = "";
|
|
||||||
vm.sortIndex = "";
|
|
||||||
vm.score = 0;
|
|
||||||
hintEditor.setValue("");
|
|
||||||
descriptionEditor.setValue("");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
avalon.scan();
|
avalon.scan();
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfTokenHeader, bsAlert) {
|
|
||||||
|
|
||||||
avalon.ready(function () {
|
|
||||||
|
|
||||||
if (avalon.vmodels.contestSubmissionList){
|
|
||||||
var vm = avalon.vmodels.contestSubmissionList;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
var vm = avalon.define({
|
|
||||||
$id: "contestSubmissionList",
|
|
||||||
submissionList: [],
|
|
||||||
previousPage: 0,
|
|
||||||
nextPage: 0,
|
|
||||||
page: 1,
|
|
||||||
totalPage: 1,
|
|
||||||
results : {
|
|
||||||
0: "Accepted",
|
|
||||||
1: "Runtime Error",
|
|
||||||
2: "Time Limit Exceeded",
|
|
||||||
3: "Memory Limit Exceeded",
|
|
||||||
4: "Compile Error",
|
|
||||||
5: "Format Error",
|
|
||||||
6: "Wrong Answer",
|
|
||||||
7: "System Error",
|
|
||||||
8: "Waiting"
|
|
||||||
},
|
|
||||||
getNext: function () {
|
|
||||||
if (!vm.nextPage)
|
|
||||||
return;
|
|
||||||
getPageData(vm.page + 1);
|
|
||||||
},
|
|
||||||
getPrevious: function () {
|
|
||||||
if (!vm.previousPage)
|
|
||||||
return;
|
|
||||||
getPageData(vm.page - 1);
|
|
||||||
},
|
|
||||||
getBtnClass: function (btn) {
|
|
||||||
if (btn == "next") {
|
|
||||||
return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getPage: function (page_index) {
|
|
||||||
if (!page_index)
|
|
||||||
var page_index = vm.page;
|
|
||||||
getPageData(page_index);
|
|
||||||
},
|
|
||||||
showSubmissionDetailPage: function (submissionId) {
|
|
||||||
|
|
||||||
},
|
|
||||||
goBack: function(check){
|
|
||||||
vm.$fire("up!showContestListPage");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getPageData(1);
|
|
||||||
|
|
||||||
function getPageData(page) {
|
|
||||||
var url = "/api/admin/contest_submission/?paging=true&page=" + page + "&page_size=10&contest_id=" + avalon.vmodels.admin.$contestId;
|
|
||||||
if (avalon.vmodels.admin.$problemId)
|
|
||||||
url += "&problem_id=" + avalon.vmodels.admin.$problemId
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
dataType: "json",
|
|
||||||
method: "get",
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.code) {
|
|
||||||
vm.submissionList = data.data.results;
|
|
||||||
vm.totalPage = data.data.total_page;
|
|
||||||
vm.previousPage = data.data.previous_page;
|
|
||||||
vm.nextPage = data.data.next_page;
|
|
||||||
vm.page = page;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bsAlert(data.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
avalon.scan();
|
|
||||||
});
|
|
@ -135,17 +135,17 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
|
|||||||
vm.testCaseId = response.data.test_case_id;
|
vm.testCaseId = response.data.test_case_id;
|
||||||
vm.uploadSuccess = true;
|
vm.uploadSuccess = true;
|
||||||
vm.testCaseList = [];
|
vm.testCaseList = [];
|
||||||
for (var i = 0; i < response.data.file_list.input.length; i++) {
|
for(var key in response.data.file_list){
|
||||||
vm.testCaseList.push({
|
vm.testCaseList.push({
|
||||||
input: response.data.file_list.input[i],
|
input: response.data.file_list[key].input_name,
|
||||||
output: response.data.file_list.output[i]
|
output: response.data.file_list[key].output_name
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
|
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (file, percentage) {
|
function (file, percentage) {
|
||||||
vm.uploadProgress = percentage;
|
vm.uploadProgress = parseInt(percentage * 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
var tagAutoCompleteList = [];
|
var tagAutoCompleteList = [];
|
||||||
|
@ -137,17 +137,17 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
|
|||||||
vm.testCaseId = response.data.test_case_id;
|
vm.testCaseId = response.data.test_case_id;
|
||||||
vm.uploadSuccess = true;
|
vm.uploadSuccess = true;
|
||||||
vm.testCaseList = [];
|
vm.testCaseList = [];
|
||||||
for (var i = 0; i < response.data.file_list.input.length; i++) {
|
for(var key in response.data.file_list){
|
||||||
vm.testCaseList.push({
|
vm.testCaseList.push({
|
||||||
input: response.data.file_list.input[i],
|
input: response.data.file_list[key].input_name,
|
||||||
output: response.data.file_list.output[i]
|
output: response.data.file_list[key].output_name
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
|
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (file, percentage) {
|
function (file, percentage) {
|
||||||
vm.uploadProgress = percentage;
|
vm.uploadProgress = parseInt(percentage * 100);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -62,17 +62,18 @@
|
|||||||
admin_8_pack: "app/admin/admin",
|
admin_8_pack: "app/admin/admin",
|
||||||
login_9_pack: "app/oj/account/login",
|
login_9_pack: "app/oj/account/login",
|
||||||
addContest_10_pack: "app/admin/contest/addContest",
|
addContest_10_pack: "app/admin/contest/addContest",
|
||||||
changePassword_11_pack: "app/oj/account/changePassword",
|
contestPassword_11_pack: "app/oj/contest/contestPassword",
|
||||||
monitor_12_pack: "app/admin/monitor/monitor",
|
changePassword_12_pack: "app/oj/account/changePassword",
|
||||||
editProblem_13_pack: "app/admin/contest/editProblem",
|
monitor_13_pack: "app/admin/monitor/monitor",
|
||||||
joinGroupRequestList_14_pack: "app/admin/group/joinGroupRequestList",
|
editProblem_14_pack: "app/admin/contest/editProblem",
|
||||||
group_15_pack: "app/oj/group/group",
|
joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList",
|
||||||
editProblem_16_pack: "app/admin/problem/editProblem",
|
group_16_pack: "app/oj/group/group",
|
||||||
register_17_pack: "app/oj/account/register",
|
contestProblemList_17_pack: "app/admin/contest/contestProblemList",
|
||||||
groupDetail_18_pack: "app/admin/group/groupDetail",
|
editProblem_18_pack: "app/admin/problem/editProblem",
|
||||||
contestPassword_19_pack: "app/oj/contest/contestPassword",
|
register_19_pack: "app/oj/account/register",
|
||||||
group_20_pack: "app/admin/group/group",
|
groupDetail_20_pack: "app/admin/group/groupDetail",
|
||||||
submissionList_21_pack: "app/admin/contest/submissionList"
|
editContest_21_pack: "app/admin/contest/editContest",
|
||||||
|
group_22_pack: "app/admin/group/group",
|
||||||
},
|
},
|
||||||
shim: {
|
shim: {
|
||||||
avalon: {
|
avalon: {
|
||||||
@ -123,38 +124,41 @@
|
|||||||
name: "addContest_10_pack"
|
name: "addContest_10_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "changePassword_11_pack"
|
name: "contestPassword_11_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "monitor_12_pack"
|
name: "changePassword_12_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "editProblem_13_pack"
|
name: "monitor_13_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "joinGroupRequestList_14_pack"
|
name: "editProblem_14_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "group_15_pack"
|
name: "joinGroupRequestList_15_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "editProblem_16_pack"
|
name: "group_16_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "register_17_pack"
|
name: "contestProblemList_17_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "groupDetail_18_pack"
|
name: "editProblem_18_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "contestPassword_19_pack"
|
name: "register_19_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "group_20_pack"
|
name: "groupDetail_20_pack"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "submissionList_21_pack"
|
name: "editContest_21_pack"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "group_22_pack"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
optimizeCss: "standard",
|
optimizeCss: "standard",
|
||||||
})
|
})
|
@ -64,17 +64,18 @@ var require = {
|
|||||||
admin_8_pack: "app/admin/admin",
|
admin_8_pack: "app/admin/admin",
|
||||||
login_9_pack: "app/oj/account/login",
|
login_9_pack: "app/oj/account/login",
|
||||||
addContest_10_pack: "app/admin/contest/addContest",
|
addContest_10_pack: "app/admin/contest/addContest",
|
||||||
changePassword_11_pack: "app/oj/account/changePassword",
|
contestPassword_11_pack: "app/oj/contest/contestPassword",
|
||||||
monitor_12_pack: "app/admin/monitor/monitor",
|
changePassword_12_pack: "app/oj/account/changePassword",
|
||||||
editProblem_13_pack: "app/admin/contest/editProblem",
|
monitor_13_pack: "app/admin/monitor/monitor",
|
||||||
joinGroupRequestList_14_pack: "app/admin/group/joinGroupRequestList",
|
editProblem_14_pack: "app/admin/contest/editProblem",
|
||||||
group_15_pack: "app/oj/group/group",
|
joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList",
|
||||||
editProblem_16_pack: "app/admin/problem/editProblem",
|
group_16_pack: "app/oj/group/group",
|
||||||
register_17_pack: "app/oj/account/register",
|
contestProblemList_17_pack: "app/admin/contest/contestProblemList",
|
||||||
groupDetail_18_pack: "app/admin/group/groupDetail",
|
editProblem_18_pack: "app/admin/problem/editProblem",
|
||||||
contestPassword_19_pack: "app/oj/contest/contestPassword",
|
register_19_pack: "app/oj/account/register",
|
||||||
group_20_pack: "app/admin/group/group",
|
groupDetail_20_pack: "app/admin/group/groupDetail",
|
||||||
submissionList_21_pack: "app/admin/contest/submissionList"
|
editContest_21_pack: "app/admin/contest/editContest",
|
||||||
|
group_22_pack: "app/admin/group/group",
|
||||||
},
|
},
|
||||||
shim: {
|
shim: {
|
||||||
avalon: {
|
avalon: {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
http://weibo.com/jslouvre/
|
http://weibo.com/jslouvre/
|
||||||
|
|
||||||
Released under the MIT license
|
Released under the MIT license
|
||||||
avalon.shim.js 1.5.4 built in 2015.10.18
|
avalon.shim.js 1.5.5 built in 2015.10.27
|
||||||
support IE6+ and other browsers
|
support IE6+ and other browsers
|
||||||
==================================================*/
|
==================================================*/
|
||||||
(function(global, factory) {
|
(function(global, factory) {
|
||||||
@ -285,7 +285,7 @@ function _number(a, len) { //用于模拟slice, splice的效果
|
|||||||
avalon.mix({
|
avalon.mix({
|
||||||
rword: rword,
|
rword: rword,
|
||||||
subscribers: subscribers,
|
subscribers: subscribers,
|
||||||
version: 1.54,
|
version: 1.55,
|
||||||
ui: {},
|
ui: {},
|
||||||
log: log,
|
log: log,
|
||||||
slice: W3C ? function (nodes, start, end) {
|
slice: W3C ? function (nodes, start, end) {
|
||||||
@ -940,6 +940,7 @@ kernel.maxRepeatSize = 100
|
|||||||
avalon.config = kernel
|
avalon.config = kernel
|
||||||
function $watch(expr, binding) {
|
function $watch(expr, binding) {
|
||||||
var $events = this.$events || (this.$events = {})
|
var $events = this.$events || (this.$events = {})
|
||||||
|
|
||||||
var queue = $events[expr] || ($events[expr] = [])
|
var queue = $events[expr] || ($events[expr] = [])
|
||||||
if (typeof binding === "function") {
|
if (typeof binding === "function") {
|
||||||
var backup = binding
|
var backup = binding
|
||||||
@ -981,31 +982,41 @@ function $watch(expr, binding) {
|
|||||||
binding.element = DOC.createElement("a")
|
binding.element = DOC.createElement("a")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function $emit(key, args) {
|
function $emit(key, args) {
|
||||||
var event = this.$events
|
var event = this.$events
|
||||||
if (event && event[key]) {
|
if (event && event[key]) {
|
||||||
if (args) {
|
if (args) {
|
||||||
args[2] = key
|
args[2] = key
|
||||||
}
|
}
|
||||||
notifySubscribers(event[key], args)
|
var arr = event[key]
|
||||||
|
notifySubscribers(arr, args)
|
||||||
var parent = this.$up
|
var parent = this.$up
|
||||||
if (parent) {
|
if (parent) {
|
||||||
if (this.$pathname) {
|
if (this.$pathname) {
|
||||||
$emit.call(parent, this.$pathname + "." + key, args)//以确切的值往上冒泡
|
$emit.call(parent, this.$pathname + "." + key, args)//以确切的值往上冒泡
|
||||||
}
|
}
|
||||||
|
|
||||||
$emit.call(parent, "*." + key, args)//以模糊的值往上冒泡
|
$emit.call(parent, "*." + key, args)//以模糊的值往上冒泡
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parent = this.$up
|
parent = this.$up
|
||||||
|
|
||||||
|
if(this.$ups ){
|
||||||
|
for(var i in this.$ups){
|
||||||
|
$emit.call(this.$ups[i], i+"."+key, args)//以确切的值往上冒泡
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
if (parent) {
|
if (parent) {
|
||||||
var path = this.$pathname + "." + key
|
var p = this.$pathname
|
||||||
var arr = path.split(".")
|
if (p === "")
|
||||||
|
p = "*"
|
||||||
|
var path = p + "." + key
|
||||||
|
arr = path.split(".")
|
||||||
if (arr.indexOf("*") === -1) {
|
if (arr.indexOf("*") === -1) {
|
||||||
$emit.call(parent, path, args)//以确切的值往上冒泡
|
$emit.call(parent, path, args)//以确切的值往上冒泡
|
||||||
arr[1] = "*"
|
arr[1] = "*"
|
||||||
$emit.call(parent, arr.join("."), args)//以确切的值往上冒泡
|
$emit.call(parent, arr.join("."), args)//以模糊的值往上冒泡
|
||||||
} else {
|
} else {
|
||||||
$emit.call(parent, path, args)//以确切的值往上冒泡
|
$emit.call(parent, path, args)//以确切的值往上冒泡
|
||||||
}
|
}
|
||||||
@ -1086,7 +1097,7 @@ avalon.define = function (source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//一些不需要被监听的属性
|
//一些不需要被监听的属性
|
||||||
var $$skipArray = oneObject("$id,$watch,$fire,$events,$model,$skipArray,$active,$pathname,$up,$track,$accessors")
|
var $$skipArray = oneObject("$id,$watch,$fire,$events,$model,$skipArray,$active,$pathname,$up,$track,$accessors,$ups")
|
||||||
var defineProperty = Object.defineProperty
|
var defineProperty = Object.defineProperty
|
||||||
var canHideOwn = true
|
var canHideOwn = true
|
||||||
//如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
|
//如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
|
||||||
@ -1212,6 +1223,7 @@ function observeObject(source, options) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/* jshint ignore:start */
|
/* jshint ignore:start */
|
||||||
|
hideProperty($vmodel, "$ups", null)
|
||||||
hideProperty($vmodel, "$id", "anonymous")
|
hideProperty($vmodel, "$id", "anonymous")
|
||||||
hideProperty($vmodel, "$up", old ? old.$up : null)
|
hideProperty($vmodel, "$up", old ? old.$up : null)
|
||||||
hideProperty($vmodel, "$track", Object.keys(hasOwn))
|
hideProperty($vmodel, "$track", Object.keys(hasOwn))
|
||||||
@ -1236,15 +1248,15 @@ function observeObject(source, options) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/* jshint ignore:end */
|
/* jshint ignore:end */
|
||||||
|
|
||||||
//必须设置了$active,$events
|
//必须设置了$active,$events
|
||||||
simple.forEach(function (name) {
|
simple.forEach(function (name) {
|
||||||
|
var oldVal = old && old[name]
|
||||||
var val = $vmodel[name] = source[name]
|
var val = $vmodel[name] = source[name]
|
||||||
if (val && typeof val === "object") {
|
if (val && typeof val === "object") {
|
||||||
val.$up = $vmodel
|
val.$up = $vmodel
|
||||||
val.$pathname = name
|
val.$pathname = name
|
||||||
}
|
}
|
||||||
$emit.call($vmodel, name)
|
$emit.call($vmodel, name, [val,oldVal])
|
||||||
})
|
})
|
||||||
for (name in computed) {
|
for (name in computed) {
|
||||||
value = $vmodel[name]
|
value = $vmodel[name]
|
||||||
@ -1316,7 +1328,7 @@ function observe(obj, old, hasReturn, watch) {
|
|||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
return observeArray(obj, old, watch)
|
return observeArray(obj, old, watch)
|
||||||
} else if (avalon.isPlainObject(obj)) {
|
} else if (avalon.isPlainObject(obj)) {
|
||||||
if (old) {
|
if (old && typeof old === 'object') {
|
||||||
var keys = getKeys(obj)
|
var keys = getKeys(obj)
|
||||||
var keys2 = getKeys(old)
|
var keys2 = getKeys(old)
|
||||||
if (keys.join(";") === keys2.join(";")) {
|
if (keys.join(";") === keys2.join(";")) {
|
||||||
@ -1356,7 +1368,6 @@ function observeArray(array, old, watch) {
|
|||||||
for (var i in newProto) {
|
for (var i in newProto) {
|
||||||
array[i] = newProto[i]
|
array[i] = newProto[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
hideProperty(array, "$up", null)
|
hideProperty(array, "$up", null)
|
||||||
hideProperty(array, "$pathname", "")
|
hideProperty(array, "$pathname", "")
|
||||||
hideProperty(array, "$track", createTrack(array.length))
|
hideProperty(array, "$track", createTrack(array.length))
|
||||||
@ -2862,7 +2873,7 @@ function parseExpr(expr, vmodels, binding) {
|
|||||||
}
|
}
|
||||||
//========
|
//========
|
||||||
|
|
||||||
function stringifyExpr(code) {
|
function normalizeExpr(code) {
|
||||||
var hasExpr = rexpr.test(code) //比如ms-class="width{{w}}"的情况
|
var hasExpr = rexpr.test(code) //比如ms-class="width{{w}}"的情况
|
||||||
if (hasExpr) {
|
if (hasExpr) {
|
||||||
var array = scanExpr(code)
|
var array = scanExpr(code)
|
||||||
@ -2877,6 +2888,7 @@ function stringifyExpr(code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avalon.normalizeExpr = normalizeExpr
|
||||||
avalon.parseExprProxy = parseExpr
|
avalon.parseExprProxy = parseExpr
|
||||||
|
|
||||||
var rthimRightParentheses = /\)\s*$/
|
var rthimRightParentheses = /\)\s*$/
|
||||||
@ -3409,7 +3421,7 @@ avalon.component = function (name, opts) {
|
|||||||
componentDefinition.$id = $id
|
componentDefinition.$id = $id
|
||||||
|
|
||||||
//==========构建VM=========
|
//==========构建VM=========
|
||||||
var keepSolt = componentDefinition.$slot
|
var keepSlot = componentDefinition.$slot
|
||||||
var keepReplace = componentDefinition.$replace
|
var keepReplace = componentDefinition.$replace
|
||||||
var keepContainer = componentDefinition.$container
|
var keepContainer = componentDefinition.$container
|
||||||
var keepTemplate = componentDefinition.$template
|
var keepTemplate = componentDefinition.$template
|
||||||
@ -3422,13 +3434,11 @@ avalon.component = function (name, opts) {
|
|||||||
elem.msResolved = 1
|
elem.msResolved = 1
|
||||||
vmodel.$init(vmodel, elem)
|
vmodel.$init(vmodel, elem)
|
||||||
global.$init(vmodel, elem)
|
global.$init(vmodel, elem)
|
||||||
console.log("init")
|
|
||||||
var nodes = elem.childNodes
|
var nodes = elem.childNodes
|
||||||
//收集插入点
|
//收集插入点
|
||||||
var slots = {}, snode
|
var slots = {}, snode
|
||||||
|
|
||||||
for (var s = 0, el; el = nodes[s++]; ) {
|
for (var s = 0, el; el = nodes[s++]; ) {
|
||||||
var type = el.nodeType === 1 && el.getAttribute("slot") || keepSolt
|
var type = el.nodeType === 1 && el.getAttribute("slot") || keepSlot
|
||||||
if (type) {
|
if (type) {
|
||||||
if (slots[type]) {
|
if (slots[type]) {
|
||||||
slots[type].push(el)
|
slots[type].push(el)
|
||||||
@ -3482,7 +3492,6 @@ avalon.component = function (name, opts) {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("dependencies "+dependencies)
|
|
||||||
if (dependencies === 0) {
|
if (dependencies === 0) {
|
||||||
var id1 = setTimeout(function () {
|
var id1 = setTimeout(function () {
|
||||||
clearTimeout(id1)
|
clearTimeout(id1)
|
||||||
@ -3512,7 +3521,6 @@ avalon.component = function (name, opts) {
|
|||||||
scanTag(elem, [vmodel].concat(host.vmodels))
|
scanTag(elem, [vmodel].concat(host.vmodels))
|
||||||
|
|
||||||
avalon.vmodels[vmodel.$id] = vmodel
|
avalon.vmodels[vmodel.$id] = vmodel
|
||||||
avalon.log("添加组件VM: "+vmodel.$id)
|
|
||||||
if (!elem.childNodes.length) {
|
if (!elem.childNodes.length) {
|
||||||
avalon.fireDom(elem, "datasetchanged", {library: library, vm: vmodel, childReady: -1})
|
avalon.fireDom(elem, "datasetchanged", {library: library, vm: vmodel, childReady: -1})
|
||||||
} else {
|
} else {
|
||||||
@ -3627,7 +3635,7 @@ var attrDir = avalon.directive("attr", {
|
|||||||
init: function (binding) {
|
init: function (binding) {
|
||||||
//{{aaa}} --> aaa
|
//{{aaa}} --> aaa
|
||||||
//{{aaa}}/bbb.html --> (aaa) + "/bbb.html"
|
//{{aaa}}/bbb.html --> (aaa) + "/bbb.html"
|
||||||
binding.expr = stringifyExpr(binding.expr.trim())
|
binding.expr = normalizeExpr(binding.expr.trim())
|
||||||
if (binding.type === "include") {
|
if (binding.type === "include") {
|
||||||
var elem = binding.element
|
var elem = binding.element
|
||||||
effectBinding(elem, binding)
|
effectBinding(elem, binding)
|
||||||
@ -3865,7 +3873,7 @@ var duplexBinding = avalon.directive("duplex", {
|
|||||||
}
|
}
|
||||||
var updateVModel = function () {
|
var updateVModel = function () {
|
||||||
var val = elem.value //防止递归调用形成死循环
|
var val = elem.value //防止递归调用形成死循环
|
||||||
if (composing || val === binding.oldValue) //处理中文输入法在minlengh下引发的BUG
|
if (composing || val === binding.oldValue || binding.pipe === null) //处理中文输入法在minlengh下引发的BUG
|
||||||
return
|
return
|
||||||
var lastValue = binding.pipe(val, binding, "get")
|
var lastValue = binding.pipe(val, binding, "get")
|
||||||
try {
|
try {
|
||||||
@ -3955,7 +3963,7 @@ var duplexBinding = avalon.directive("duplex", {
|
|||||||
var curValue = Array.isArray(value) ? value.map(String) : value + ""
|
var curValue = Array.isArray(value) ? value.map(String) : value + ""
|
||||||
avalon(elem).val(curValue)
|
avalon(elem).val(curValue)
|
||||||
elem.oldValue = curValue + ""
|
elem.oldValue = curValue + ""
|
||||||
binding.changed.call(elem, curValue)
|
callback.call(elem, curValue)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
@ -4000,15 +4008,18 @@ var duplexBinding = avalon.directive("duplex", {
|
|||||||
if (curValue !== this.oldValue) {
|
if (curValue !== this.oldValue) {
|
||||||
var fixCaret = false
|
var fixCaret = false
|
||||||
if (elem.msFocus) {
|
if (elem.msFocus) {
|
||||||
var pos = getCaret(elem)
|
try {
|
||||||
if (pos.start === pos.end) {
|
var pos = getCaret(elem)
|
||||||
pos = pos.start
|
if (pos.start === pos.end) {
|
||||||
fixCaret = true
|
pos = pos.start
|
||||||
|
fixCaret = true
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elem.value = this.oldValue = curValue
|
elem.value = this.oldValue = curValue
|
||||||
if (fixCaret) {
|
if (fixCaret) {
|
||||||
setCaret(element, pos, pos)
|
setCaret(elem, pos, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -4034,10 +4045,10 @@ var duplexBinding = avalon.directive("duplex", {
|
|||||||
case "select":
|
case "select":
|
||||||
//必须变成字符串后才能比较
|
//必须变成字符串后才能比较
|
||||||
binding._value = value
|
binding._value = value
|
||||||
if(!elem.msHasEvent){
|
if (!elem.msHasEvent) {
|
||||||
elem.msHasEvent = "selectDuplex"
|
elem.msHasEvent = "selectDuplex"
|
||||||
//必须等到其孩子准备好才触发
|
//必须等到其孩子准备好才触发
|
||||||
}else{
|
} else {
|
||||||
avalon.fireDom(elem, "datasetchanged", {
|
avalon.fireDom(elem, "datasetchanged", {
|
||||||
bubble: elem.msHasEvent
|
bubble: elem.msHasEvent
|
||||||
})
|
})
|
||||||
@ -4045,7 +4056,7 @@ var duplexBinding = avalon.directive("duplex", {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (binding.xtype !== "select") {
|
if (binding.xtype !== "select") {
|
||||||
binding.changed.call(elem, curValue)
|
binding.changed.call(elem, curValue, binding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -4178,18 +4189,19 @@ function getCaret(ctrl, start, end) {
|
|||||||
function setCaret(ctrl, begin, end) {
|
function setCaret(ctrl, begin, end) {
|
||||||
if (!ctrl.value || ctrl.readOnly)
|
if (!ctrl.value || ctrl.readOnly)
|
||||||
return
|
return
|
||||||
if (ctrl.setSelectionRange) {
|
if (ctrl.createTextRange) {//IE6-9
|
||||||
|
setTimeout(function () {
|
||||||
|
var range = ctrl.createTextRange()
|
||||||
|
range.collapse(true);
|
||||||
|
range.moveStart("character", begin)
|
||||||
|
// range.moveEnd("character", end) #1125
|
||||||
|
range.select()
|
||||||
|
}, 17)
|
||||||
|
} else {
|
||||||
ctrl.selectionStart = begin
|
ctrl.selectionStart = begin
|
||||||
ctrl.selectionEnd = end
|
ctrl.selectionEnd = end
|
||||||
} else {
|
|
||||||
var range = ctrl.createTextRange()
|
|
||||||
range.collapse(true);
|
|
||||||
range.moveStart("character", begin)
|
|
||||||
range.moveEnd("character", end - begin)
|
|
||||||
range.select()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
avalon.directive("effect", {
|
avalon.directive("effect", {
|
||||||
priority: 5,
|
priority: 5,
|
||||||
init: function (binding) {
|
init: function (binding) {
|
||||||
@ -4209,7 +4221,7 @@ avalon.directive("effect", {
|
|||||||
if (!rexpr.test(text)) {
|
if (!rexpr.test(text)) {
|
||||||
className = quote(className)
|
className = quote(className)
|
||||||
} else {
|
} else {
|
||||||
className = stringifyExpr(className)
|
className = normalizeExpr(className)
|
||||||
}
|
}
|
||||||
binding.expr = "[" + className + "," + rightExpr + "]"
|
binding.expr = "[" + className + "," + rightExpr + "]"
|
||||||
},
|
},
|
||||||
@ -4372,7 +4384,7 @@ function upperFirstChar(str) {
|
|||||||
}
|
}
|
||||||
var effectBuffer = new Buffer()
|
var effectBuffer = new Buffer()
|
||||||
function Effect() {
|
function Effect() {
|
||||||
}// 动画实例,做成类的形式,是为了共用所有原型方法
|
}// 动画实例,做成类的形式,是为了共用所有原型方法
|
||||||
|
|
||||||
Effect.prototype = {
|
Effect.prototype = {
|
||||||
contrustor: Effect,
|
contrustor: Effect,
|
||||||
@ -4395,7 +4407,7 @@ Effect.prototype = {
|
|||||||
callEffectHook(me, "abort" + upperFirstChar(oppositeName))
|
callEffectHook(me, "abort" + upperFirstChar(oppositeName))
|
||||||
callEffectHook(me, "before" + upperFirstChar(name))
|
callEffectHook(me, "before" + upperFirstChar(name))
|
||||||
if (!isLeave)
|
if (!isLeave)
|
||||||
before(el) // 这里可能做插入DOM树的操作,因此必须在修改类名前执行
|
before(el) // 这里可能做插入DOM树的操作,因此必须在修改类名前执行
|
||||||
var cssCallback = function (cancel) {
|
var cssCallback = function (cancel) {
|
||||||
el.removeEventListener(me.cssEvent, me.cssCallback)
|
el.removeEventListener(me.cssEvent, me.cssCallback)
|
||||||
if (isLeave) {
|
if (isLeave) {
|
||||||
@ -4622,7 +4634,7 @@ avalon.directive("if", {
|
|||||||
elem.required = false
|
elem.required = false
|
||||||
elem.setAttribute("_required", "true")
|
elem.setAttribute("_required", "true")
|
||||||
}
|
}
|
||||||
try {// 如果不支持querySelectorAll或:required,可以直接无视
|
try {// 如果不支持querySelectorAll或:required,可以直接无视
|
||||||
avalon.each(elem.querySelectorAll(":required"), function (el) {
|
avalon.each(elem.querySelectorAll(":required"), function (el) {
|
||||||
elem.required = false
|
elem.required = false
|
||||||
el.setAttribute("_required", "true")
|
el.setAttribute("_required", "true")
|
||||||
@ -4779,7 +4791,7 @@ avalon.directive("include", {
|
|||||||
return nodesToFrag(nodes)
|
return nodesToFrag(nodes)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
before = function () {// 新添加元素的动画
|
before = function () {// 新添加元素的动画
|
||||||
target.insertBefore(fragment, binding.end)
|
target.insertBefore(fragment, binding.end)
|
||||||
scanNodeArray(nodes, vmodels)
|
scanNodeArray(nodes, vmodels)
|
||||||
}
|
}
|
||||||
@ -4906,7 +4918,6 @@ avalon.directive("repeat", {
|
|||||||
effectBinding(elem, binding)
|
effectBinding(elem, binding)
|
||||||
binding.param = binding.param || "el"
|
binding.param = binding.param || "el"
|
||||||
binding.sortedCallback = getBindingCallback(elem, "data-with-sorted", binding.vmodels)
|
binding.sortedCallback = getBindingCallback(elem, "data-with-sorted", binding.vmodels)
|
||||||
// binding.renderedCallback =
|
|
||||||
var rendered = getBindingCallback(elem, "data-" + type + "-rendered", binding.vmodels)
|
var rendered = getBindingCallback(elem, "data-" + type + "-rendered", binding.vmodels)
|
||||||
|
|
||||||
var signature = generateID(type)
|
var signature = generateID(type)
|
||||||
@ -4984,13 +4995,18 @@ avalon.directive("repeat", {
|
|||||||
var keyOrId = track[i] //array为随机数, object 为keyName
|
var keyOrId = track[i] //array为随机数, object 为keyName
|
||||||
var proxy = retain[keyOrId]
|
var proxy = retain[keyOrId]
|
||||||
if (!proxy) {
|
if (!proxy) {
|
||||||
proxy = getProxyVM(this)
|
|
||||||
|
|
||||||
|
proxy = getProxyVM(this)
|
||||||
|
proxy.$up = null
|
||||||
if (xtype === "array") {
|
if (xtype === "array") {
|
||||||
action = "add"
|
action = "add"
|
||||||
proxy.$id = keyOrId
|
proxy.$id = keyOrId
|
||||||
|
var valueItem = value[i]
|
||||||
proxy[param] = value[i] //index
|
proxy[param] = valueItem //index
|
||||||
|
if(Object(valueItem) === valueItem){
|
||||||
|
valueItem.$ups = valueItem.$ups || {}
|
||||||
|
valueItem.$ups[param] = proxy
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
action = "append"
|
action = "append"
|
||||||
@ -5011,7 +5027,7 @@ avalon.directive("repeat", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//重写proxy
|
//重写proxy
|
||||||
if (this.enterCount === 1) {// 防止多次进入,导致位置不对
|
if (this.enterCount === 1) {// 防止多次进入,导致位置不对
|
||||||
proxy.$active = false
|
proxy.$active = false
|
||||||
proxy.$oldIndex = proxy.$index
|
proxy.$oldIndex = proxy.$index
|
||||||
proxy.$active = true
|
proxy.$active = true
|
||||||
@ -5024,7 +5040,7 @@ avalon.directive("repeat", {
|
|||||||
proxy.$last = i === length - 1
|
proxy.$last = i === length - 1
|
||||||
// proxy[param] = value[i]
|
// proxy[param] = value[i]
|
||||||
} else {
|
} else {
|
||||||
proxy.$val = toJson(value[keyOrId]) // 这里是处理vm.object = newObject的情况
|
proxy.$val = toJson(value[keyOrId]) // 这里是处理vm.object = newObject的情况
|
||||||
}
|
}
|
||||||
proxies.push(proxy)
|
proxies.push(proxy)
|
||||||
}
|
}
|
||||||
@ -5075,7 +5091,7 @@ avalon.directive("repeat", {
|
|||||||
} else if (proxy.$index !== proxy.$oldIndex) {
|
} else if (proxy.$index !== proxy.$oldIndex) {
|
||||||
(function (proxy2, preElement) {
|
(function (proxy2, preElement) {
|
||||||
staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () {
|
staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () {
|
||||||
var curNode = removeItem(proxy2.$anchor)// 如果位置被挪动了
|
var curNode = removeItem(proxy2.$anchor)// 如果位置被挪动了
|
||||||
var inserted = avalon.slice(curNode.childNodes)
|
var inserted = avalon.slice(curNode.childNodes)
|
||||||
parent.insertBefore(curNode, preElement.nextSibling)
|
parent.insertBefore(curNode, preElement.nextSibling)
|
||||||
animateRepeat(inserted, 1, binding)
|
animateRepeat(inserted, 1, binding)
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
<td>{{ el.created_by.username }}</td>
|
<td>{{ el.created_by.username }}</td>
|
||||||
<td ms-text="el.visible?'可见':'不可见'"></td>
|
<td ms-text="el.visible?'可见':'不可见'"></td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-info btn-sm" href="javascript:void(0)" ms-click="showEditContestArea($index+1)">编辑</a>
|
<a class="btn btn-info btn-sm" href="javascript:void(0)" ms-click="editContest(el.id)">编辑</a>
|
||||||
<a class="btn btn-info btn-sm" href="javascript:void(0)" ms-click="showEditProblemArea($index+1)">题目</a>
|
<a class="btn btn-info btn-sm" href="javascript:void(0)" ms-click="showContestProblems(el.id)">题目</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
107
template/src/admin/contest/edit_contest.html
Normal file
107
template/src/admin/contest/edit_contest.html
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<div ms-controller="edit_contest" class="col-md-9">
|
||||||
|
<form id="edit-contest-form">
|
||||||
|
<nav>
|
||||||
|
<ul class="pager">
|
||||||
|
<li class="previous" ms-click="showContestListPage()"><a href="javascript:void(0)"><span
|
||||||
|
aria-hidden="true">←</span> 返回</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label>比赛名称</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" name="name" class="form-control" ms-duplex="title"
|
||||||
|
data-error="请填写比赛名称(名称不能超过50个字)" required>
|
||||||
|
|
||||||
|
<div class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label>说明</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<ms:editor $id="contestDescriptionEditor" config="contestDescriptionEditor"></ms:editor>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label>开始时间</label>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" name="start_time" id="contest_start_time"
|
||||||
|
ms-duplex="startTime" data-error="请填写比赛开始时间" required>
|
||||||
|
|
||||||
|
<div class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label>结束时间</label>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" name="end_time" id="contest_end_time"
|
||||||
|
ms-duplex="endTime" data-error="请填写比赛结束时间" required>
|
||||||
|
|
||||||
|
<div class="help-block with-errors"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>比赛类型</label>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span ms-if="showGlobalViewRadio">
|
||||||
|
<label>
|
||||||
|
<small><input type="radio" value="true" name="isGlobal" ms-duplex-boolean="isGlobal">全局可见
|
||||||
|
</small>
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<label>
|
||||||
|
<small><input type="radio" value="false" name="isGlobal" ms-duplex-boolean="isGlobal">小组内可见
|
||||||
|
</small>
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6" ms-visible="isGlobal">
|
||||||
|
<label>密码保护</label>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" class="form-control" name="password" placeholder="留空就是公开赛" ms-duplex="password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-12" ms-visible="!isGlobal">
|
||||||
|
<!-- radio 的value 没有用 但是没有的话,表单验证会出错-->
|
||||||
|
<div ms-repeat="allGroups" class="col-md-4">
|
||||||
|
<input type="checkbox" value="group_id" ms-duplex-checked="el.isSelected"> {{ el.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label>实时排名</label>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="text"><input type="checkbox" ms-duplex-checked="realTimeRank">
|
||||||
|
<small>不勾选则排名不更新,且只显示自己的提交。</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label>是否可见</label>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="text"><input type="checkbox" ms-duplex-checked="visible">
|
||||||
|
<small>可见</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<input type="submit" class="btn btn-success btn-lg" value="发布比赛">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/static/js/app/admin/contest/editContest.js"></script>
|
@ -2,7 +2,7 @@
|
|||||||
<form id="edit-problem-form">
|
<form id="edit-problem-form">
|
||||||
<nav>
|
<nav>
|
||||||
<ul class="pager">
|
<ul class="pager">
|
||||||
<li class="previous" ms-click="goBack(0)"><a href="javascript:void(0)"><span
|
<li class="previous" ms-click="goBack()"><a href="javascript:void(0)"><span
|
||||||
aria-hidden="true">←</span> 返回</a></li>
|
aria-hidden="true">←</span> 返回</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
@ -22,15 +22,14 @@
|
|||||||
|
|
||||||
<div class="form-group col-md-12">
|
<div class="form-group col-md-12">
|
||||||
<label>题目描述</label>
|
<label>题目描述</label>
|
||||||
<textarea id="problemDescription" placeholder="这里输入内容(此内容不能为空)" ms-duplex="description"></textarea>
|
<ms:editor $id="contestProblemDescriptionEditor" config="contestProblemDescriptionEditor"></ms:editor>
|
||||||
<p class="error-info" ms-visible="description==''">请填写题目描述</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="form-group"><label>时间限制(ms)</label>
|
<div class="form-group"><label>时间限制(ms)</label>
|
||||||
<input type="number" name="timeLimit" class="form-control" ms-duplex="timeLimit"
|
<input type="number" name="timeLimit" class="form-control" ms-duplex="timeLimit"
|
||||||
data-error="请输入时间限制(保证是一个1000-5000的合法整数)" required>
|
data-error="请输入时间限制(保证是一个30-5000的合法整数)" required>
|
||||||
<div class="help-block with-errors"></div>
|
<div class="help-block with-errors"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -41,11 +40,6 @@
|
|||||||
<div class="help-block with-errors"></div>
|
<div class="help-block with-errors"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3" ms-visible="contestMode=='2'">
|
|
||||||
<div class="form-group"><label>分值(仅计分模式)</label>
|
|
||||||
<input type="number" name="score" class="form-control" ms-duplex="score">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3 form-group">
|
<div class="col-md-3 form-group">
|
||||||
<label>是否可见</label><br>
|
<label>是否可见</label><br>
|
||||||
<label><input type="checkbox" ms-duplex-checked="visible">
|
<label><input type="checkbox" ms-duplex-checked="visible">
|
||||||
@ -103,7 +97,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12"><br>
|
<div class="col-md-12"><br>
|
||||||
<label>测试数据(多次上传将覆盖原有测试用例)</label><br>
|
<label>测试数据<span ms-if="uploadSuccess">(当前已上传,继续上传将覆盖原有测试用例)</span></label><br>
|
||||||
<small class="text-info">请将所有测试用例打包在一个文件中上传,所有文件要在压缩包的根目录,且输入输出文件名要以从1开始连续数字标识要对应例如:<br>
|
<small class="text-info">请将所有测试用例打包在一个文件中上传,所有文件要在压缩包的根目录,且输入输出文件名要以从1开始连续数字标识要对应例如:<br>
|
||||||
1.in 1.out 2.in 2.out
|
1.in 1.out 2.in 2.out
|
||||||
</small>
|
</small>
|
||||||
@ -127,7 +121,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-12">
|
<div class="form-group col-md-12">
|
||||||
<label>提示</label>
|
<label>提示</label>
|
||||||
<textarea id="hint" placeholder="这里输入内容" ms-duplex="hint"></textarea>
|
<ms:editor $id="contestProblemHintEditor" config="contestProblemHintEditor"></ms:editor>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<button type="submit" class="btn btn-success btn-lg">发布题目</button>
|
<button type="submit" class="btn btn-success btn-lg">发布题目</button>
|
||||||
|
35
template/src/admin/contest/problem_list.html
Normal file
35
template/src/admin/contest/problem_list.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<div ms-controller="contestProblemList" class="col-md-9">
|
||||||
|
<nav>
|
||||||
|
<ul class="pager">
|
||||||
|
<li class="previous" ms-click="goBack()"><a href="javascript:void(0)">
|
||||||
|
<span aria-hidden="true">←</span> 返回</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<h1>比赛题目列表</h1>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-primary" ms-click="addProblem()">创建题目</button>
|
||||||
|
</div>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>题目</th>
|
||||||
|
<th>创建时间</th>
|
||||||
|
<th>可见</th>
|
||||||
|
<th>通过次数/提交总数</th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr ms-repeat="problemList">
|
||||||
|
<td>{{ el.sort_index }}</td>
|
||||||
|
<td>{{ el.title }}</td>
|
||||||
|
<td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
|
||||||
|
<td ms-text="el.visible?'可见':'不可见'"></td>
|
||||||
|
<td>{{ el.total_accepted_number }}/{{ el.total_submit_number }}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn-sm btn-info" ms-click="showEditProblemPage(el.id)">编辑</button>
|
||||||
|
<button class="btn-sm btn-primary" ms-if="!el.is_public && adminType == 2" ms-click="makeProblemPublic(el)">公开</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<script src="/static/js/app/admin/contest/contestProblemList.js"></script>
|
@ -1,37 +0,0 @@
|
|||||||
<div ms-controller="contestSubmissionList" class="col-md-9">
|
|
||||||
<nav>
|
|
||||||
<ul class="pager">
|
|
||||||
<li class="previous" ms-click="goBack()"><a href="javascript:void(0)"><span
|
|
||||||
aria-hidden="true">←</span> 返回</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<h1>提交列表</h1>
|
|
||||||
<a href="javascript:void(0)" class="btn btn-sm btn-primary" ms-click="getPage(1)">
|
|
||||||
<span class="glyphicon glyphicon-refresh"></span> 刷新
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<table class="table table-striped">
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>创建时间</th>
|
|
||||||
<th>作者</th>
|
|
||||||
<td>结果</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
<tr ms-repeat="submissionList">
|
|
||||||
<td>{{ el.id }}</td>
|
|
||||||
<td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
|
|
||||||
<td>{{ el.user }}</td>
|
|
||||||
<td>{{ results[el.result] }}</td>
|
|
||||||
<td>
|
|
||||||
<a class="btn btn-info" ms-attr-href="'/submission/' + el.id + '/'" target="_blank">详情</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="text-right">
|
|
||||||
页数:{{ page }}/{{ totalPage }}
|
|
||||||
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
|
|
||||||
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script src="/static/js/app/admin/contest/submissionList.js"></script>
|
|
@ -104,7 +104,7 @@
|
|||||||
<small class="text-info">请将所有测试用例打包在一个文件中上传,所有文件要在压缩包的根目录,且输入输出文件名要以从1开始连续数字标识要对应例如:<br>
|
<small class="text-info">请将所有测试用例打包在一个文件中上传,所有文件要在压缩包的根目录,且输入输出文件名要以从1开始连续数字标识要对应例如:<br>
|
||||||
1.in 1.out 2.in 2.out
|
1.in 1.out 2.in 2.out
|
||||||
</small>
|
</small>
|
||||||
<p>上传进度<span ms-text="uploadProgress * 100"></span>%</p>
|
<p>上传进度<span ms-text="uploadProgress"></span>%</p>
|
||||||
<table class="table table-striped" ms-visible="uploadSuccess">
|
<table class="table table-striped" ms-visible="uploadSuccess">
|
||||||
<tr>
|
<tr>
|
||||||
<td>编号</td>
|
<td>编号</td>
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
<small class="text-info">请将所有测试用例打包在一个文件中上传,所有文件要在压缩包的根目录,且输入输出文件名要以从1开始连续数字标识要对应例如:<br>
|
<small class="text-info">请将所有测试用例打包在一个文件中上传,所有文件要在压缩包的根目录,且输入输出文件名要以从1开始连续数字标识要对应例如:<br>
|
||||||
1.in 1.out 2.in 2.out
|
1.in 1.out 2.in 2.out
|
||||||
</small>
|
</small>
|
||||||
<p>上传进度<span ms-text="uploadProgress * 100"></span>%</p>
|
<p>上传进度<span ms-text="uploadProgress"></span>%</p>
|
||||||
<table class="table table-striped" ms-visible="uploadSuccess">
|
<table class="table table-striped" ms-visible="uploadSuccess">
|
||||||
<tr>
|
<tr>
|
||||||
<td>编号</td>
|
<td>编号</td>
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
{{ request.user.username }}
|
{{ request.user.username }}
|
||||||
<span class="caret"></span></a>
|
<span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% if request.user.admin_type == 2 %}
|
{% if request.user.admin_type > 0 %}
|
||||||
<li><a href="/admin/">后台管理</a></li>
|
<li><a href="/admin/">后台管理</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href="/submissions/">我的提交</a></li>
|
<li><a href="/submissions/">我的提交</a></li>
|
||||||
|
Loading…
Reference in New Issue
Block a user