Merge branch 'virusdefender-dev' of git.coding.net:virusdefender/qduoj into dev-s

This commit is contained in:
sxw
2015-11-02 19:08:17 +08:00
25 changed files with 455 additions and 717 deletions

View File

@@ -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
@@ -198,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)
@@ -233,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)
@@ -273,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):

View File

@@ -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")
@@ -96,7 +96,7 @@ class MessageQueue(object):
contest_problem.add_ac_number() contest_problem.add_ac_number()
problems_status["contest_problems"][str(contest_problem.id)] = 1 problems_status["contest_problems"][str(contest_problem.id)] = 1
else: else:
problems_status["contest_problems"][str(contest_problem.id)] = 1 problems_status["contest_problems"][str(contest_problem.id)] = 0
user.problems_status = problems_status user.problems_status = problems_status
user.save() user.save()

View File

@@ -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(),

View File

@@ -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):
""" """

View File

@@ -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 () {

View File

@@ -48,7 +48,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date
method: "post", method: "post",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
bsAlert("添加成功!将转到比赛列表页以便为比赛添加问题(注意比赛当前状态为:隐藏)"); bsAlert("添加成功!接下来下需要为比赛添加问题(注意比赛当前状态为:隐藏)");
location.hash = "#contest/contest_list"; location.hash = "#contest/contest_list";
} }
else { else {
@@ -61,8 +61,19 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date
}); });
//editor("#editor"); //editor("#editor");
if (avalon.vmodels.add_contest) if (avalon.vmodels.add_contest) {
var vm = avalon.vmodels.add_contest; var vm = avalon.vmodels.add_contest;
vm.title = "";
vm.startTime = "";
vm.endTime = "";
vm.password = "";
vm.isGlobal = true;
vm.allGroups = [];
vm.showGlobalViewRadio = true;
vm.realTimeRank = true;
avalon.vmodels.contestDescriptionEditor.content = "";
}
else else
var vm = avalon.define({ var vm = avalon.define({
$id: "add_contest", $id: "add_contest",

View File

@@ -27,7 +27,8 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
avalon.vmodels.admin.template_url = "template/contest/edit_contest.html"; avalon.vmodels.admin.template_url = "template/contest/edit_contest.html";
}, },
showContestProblems: function(contestId){ showContestProblems: function(contestId){
// todo avalon.vmodels.admin.contestId = contestId;
avalon.vmodels.admin.template_url = "template/contest/problem_list.html";
} }
}) })
} }

View File

@@ -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();
});

View 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();
});
});

View File

@@ -130,6 +130,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "date
vm.realTimeRank = contest.real_time_rank; vm.realTimeRank = contest.real_time_rank;
vm.startTime = contest.start_time.substring(0, 16).replace("T", " "); vm.startTime = contest.start_time.substring(0, 16).replace("T", " ");
vm.endTime = contest.end_time.substring(0, 16).replace("T", " "); vm.endTime = contest.end_time.substring(0, 16).replace("T", " ");
vm.password = contest.password;
if (contest.contest_type == 0) { //contest_type == 0, 小组内比赛 if (contest.contest_type == 0) { //contest_type == 0, 小组内比赛
vm.isGlobal = false; vm.isGlobal = false;
for (var i = 0; i < vm.allGroups.length; i++) { for (var i = 0; i < vm.allGroups.length; i++) {

View File

@@ -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;
} }
else {
var method = "post"; var method = "post";
if (avalon.vmodels.admin.$problemId) { var alertContent = "题目创建成功";
method = "put";
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);
@@ -87,79 +87,100 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
$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,
score: 1,
uploadSuccess: false,
testCaseList: [], testCaseList: [],
uploadSuccess: false,
contestProblemDescriptionEditor: {
editorId: "contest-problem-description-editor",
placeholder: "题目描述"
},
contestProblemHintEditor: {
editorId: "contest-problem-hint-editor",
placeholder: "提示"
},
addSample: function () { addSample: function () {
vm.samples.push({input: "", output: "", "visible": true}); vm.samples.push({input: "", output: "", "visible": true});
}, },
delSample: function (sample) { delSample: function (sample) {
if (confirm("你确定要删除么?")) { if (confirm("你确定要删除么?")) {
vm.samples.remove(sample); vm.samples.remove(sample);
} }
}, },
toggleSample: function (sample) { toggleSample: function (sample) {
sample.visible = !sample.visible; sample.visible = !sample.visible;
}, },
getBtnContent: function (item) { getBtnContent: function (item) {
if (item.visible) if (item.visible)
return "折叠"; return "折叠";
return "展开"; return "展开";
}, },
goBack: function(check){
if (check||confirm("这将丢失所有的改动,确定要继续么?")) { goBack: function (check) {
vm.$fire("up!showContestListPage"); avalon.vmodels.admin.template_url = "template/contest/problem_list.html";
}
} }
}); });
else else {
vm = avalon.vmodels.editProblem; var vm = avalon.vmodels.editProblem;
title = "";
description = "";
timeLimit = 1000;
memoryLimit = 128;
samples = [];
hint = "";
sortIndex = "";
visible = true;
inputDescription = "";
outputDescription = "";
testCaseId = "";
testCaseList = [];
uploadSuccess = false;
}
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;
@@ -167,8 +188,8 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
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 +197,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();

View File

@@ -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();
});

View File

@@ -79,6 +79,20 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
if (avalon.vmodels.addProblem) { if (avalon.vmodels.addProblem) {
var vm = avalon.vmodels.addProblem; var vm = avalon.vmodels.addProblem;
vm.title = "";
vm.timeLimit = 1000;
vm.memoryLimit = 128;
vm.samples = [{input: "", output: "", "visible": true}];
vm.visible = true;
vm.difficulty = "1";
vm.tags = [];
vm.inputDescription = "";
vm.outputDescription = "";
vm.testCaseId = "";
vm.testCaseList = [];
vm.uploadSuccess = false;
vm.source = "";
vm.uploadProgress = 0;
} }
else else
var vm = avalon.define({ var vm = avalon.define({
@@ -135,17 +149,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 = [];

View File

@@ -137,11 +137,11 @@ 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 + "组测试数据");
} }

View File

@@ -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",
}) })

View File

@@ -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: {

View File

@@ -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,14 +982,14 @@ 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) {
@@ -999,13 +1000,23 @@ function $emit(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) {
try {
var pos = getCaret(elem) var pos = getCaret(elem)
if (pos.start === pos.end) { if (pos.start === pos.end) {
pos = pos.start pos = pos.start
fixCaret = true 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
ctrl.selectionStart = begin setTimeout(function () {
ctrl.selectionEnd = end
} else {
var range = ctrl.createTextRange() var range = ctrl.createTextRange()
range.collapse(true); range.collapse(true);
range.moveStart("character", begin) range.moveStart("character", begin)
range.moveEnd("character", end - begin) // range.moveEnd("character", end) #1125
range.select() range.select()
}, 17)
} else {
ctrl.selectionStart = begin
ctrl.selectionEnd = end
} }
} }
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)

View File

@@ -659,10 +659,10 @@
yearSingularText: 'year', yearSingularText: 'year',
monthSingularText: 'month', monthSingularText: 'month',
weekSingularText: 'week', weekSingularText: 'week',
daySingularText: 'day', daySingularText: '',
hourSingularText: 'hour', hourSingularText: '小时',
minSingularText: 'min', minSingularText: '分钟',
secSingularText: 'sec', secSingularText: '',
digits : [0,1,2,3,4,5,6,7,8,9], digits : [0,1,2,3,4,5,6,7,8,9],
isRTL: false, isRTL: false,
minus: false, minus: false,

View File

@@ -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>

View File

@@ -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">&larr;</span> 返回</a></li> aria-hidden="true">&larr;</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>

View 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">&larr;</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>

View File

@@ -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">&larr;</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 }}&nbsp;&nbsp;
<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>

View File

@@ -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>

View File

@@ -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>