Accept Merge Request #78 : (virusdefender-dev -> dev)

Merge Request: 修改判题模块
Created By: @hohoTT
Accepted By: @hohoTT
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/78
This commit is contained in:
hohoTT
2015-08-15 17:17:12 +08:00
70 changed files with 1551 additions and 962 deletions

View File

@@ -1,5 +1,6 @@
# coding=utf-8 # coding=utf-8
import sys import sys
import os
import pymongo import pymongo
from bson.objectid import ObjectId from bson.objectid import ObjectId
@@ -8,7 +9,11 @@ from client import JudgeClient
from language import languages from language import languages
from compiler import compile_ from compiler import compile_
from result import result from result import result
from settings import judger_workspace, mongodb_config from settings import judger_workspace
sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/' + '..'))
from judger_controller.settings import celery_mongodb_config, docker_mongodb_config
# 简单的解析命令行参数 # 简单的解析命令行参数
@@ -20,7 +25,7 @@ time_limit = args[4]
memory_limit = args[6] memory_limit = args[6]
test_case_id = args[8] test_case_id = args[8]
connection = pymongo.MongoClient(host=mongodb_config["host"], port=mongodb_config["port"]) connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"])
collection = connection["oj"]["oj_submission"] collection = connection["oj"]["oj_submission"]
submission = collection.find_one({"_id": ObjectId(submission_id)}) submission = collection.find_one({"_id": ObjectId(submission_id)})
@@ -40,7 +45,7 @@ try:
exe_path = compile_(language, src_path, judger_workspace + "run/") exe_path = compile_(language, src_path, judger_workspace + "run/")
except Exception as e: except Exception as e:
print e print e
connection = pymongo.MongoClient(host=mongodb_config["host"], port=mongodb_config["port"]) connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"])
collection = connection["oj"]["oj_submission"] collection = connection["oj"]["oj_submission"]
data = {"result": result["compile_error"], "info": str(e)} data = {"result": result["compile_error"], "info": str(e)}
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data}) collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data})
@@ -72,10 +77,7 @@ except Exception as e:
print "Run successfully" print "Run successfully"
print judge_result print judge_result
connection = pymongo.MongoClient(host=mongodb_config["host"], port=mongodb_config["port"]) connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"])
collection = connection["oj"]["oj_submission"] collection = connection["oj"]["oj_submission"]
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": judge_result}) collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": judge_result})
connection.close() connection.close()

View File

@@ -14,9 +14,4 @@ lrun_gid = 1002
# judger工作目录 # judger工作目录
judger_workspace = "/var/judger/" judger_workspace = "/var/judger/"
mongodb_config = {
"host": "192.168.59.3",
"username": "root",
"password": "root",
"port": 27017
}

View File

@@ -7,4 +7,4 @@ app = Celery("judge", broker="redis://" +
redis_config["host"] + ":" + redis_config["host"] + ":" +
str(redis_config["port"]) + str(redis_config["port"]) +
"/" + str(redis_config["db"]), "/" + str(redis_config["db"]),
include=["judger_controller.tasks"]) include=["judge.judger_controller.tasks"])

View File

@@ -0,0 +1,32 @@
# coding=utf-8
redis_config = {
"host": "121.42.196.141",
"port": 6379,
"db": 0
}
docker_config = {
"image_name": "d622347336b8",
"docker_path": "docker",
"shell": True
}
test_case_dir = "/root/test_case/"
source_code_dir = "/root/"
celery_mongodb_config = {
"host": "127.0.0.1",
"username": "root",
"password": "root",
"port": 27017
}
docker_mongodb_config = {
"host": "192.168.42.1",
"username": "root",
"password": "root",
"port": 27017
}

View File

@@ -0,0 +1,31 @@
# coding=utf-8
# from __future__ import absolute_import
import pymongo
from bson import ObjectId
import subprocess32 as subprocess
from ..judger.result import result
from ..judger_controller.celery import app
from settings import docker_config, source_code_dir, test_case_dir, celery_mongodb_config
@app.task
def judge(submission_id, time_limit, memory_limit, test_case_id):
try:
command = "%s run -t -i --privileged --rm=true " \
"-v %s:/var/judger/test_case/ " \
"-v %s:/var/judger/code/ " \
"%s " \
"python judge/judger/run.py " \
"--solution_id %s --time_limit %s --memory_limit %s --test_case_id %s" % \
(docker_config["docker_path"],
test_case_dir,
source_code_dir,
docker_config["image_name"],
submission_id, str(time_limit), str(memory_limit), test_case_id)
subprocess.call(command, timeout=(time_limit / 1000.0 * 10), shell=docker_config["shell"])
except Exception as e:
connection = pymongo.MongoClient(host=celery_mongodb_config["host"], port=celery_mongodb_config["port"])
collection = connection["oj"]["oj_submission"]
data = {"result": result["system_error"], "info": str(e)}
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data})
connection.close()

View File

@@ -1,6 +0,0 @@
# coding=utf-8
redis_config = {
"host": "127.0.0.1",
"port": 6379,
"db": 0
}

View File

@@ -1,20 +0,0 @@
# coding=utf-8
from __future__ import absolute_import
from judger_controller.celery import app
import subprocess32 as subprocess
@app.task
def judge(solution_id, time_limit, memory_limit, test_case_id):
try:
subprocess.call("docker run -t -i --privileged --rm=true "
"-v /Users/virusdefender/Desktop/test_case/:/var/judger/test_case/ "
"-v /Users/virusdefender/Desktop/:/var/judger/code/ "
"judger "
"python judger/run.py "
"--solution_id %s --time_limit %s --memory_limit %s --test_case_id %s" %
(solution_id, str(time_limit), str(memory_limit), test_case_id),
# 设置最长运行时间是5倍的 cpu 时间
timeout=(time_limit / 1000.0 * 5), shell=True)
except subprocess.TimeoutExpired:
print "docker timeout"

View File

@@ -16,8 +16,9 @@ DATABASES = {
} }
} }
# 这是web 服务器连接到mongodb 的地址
MONGODB = { MONGODB = {
'HOST': '127.0.0.1', 'HOST': '121.42.196.141',
'USERNAME': 'root', 'USERNAME': 'root',
'PASSWORD': 'root', 'PASSWORD': 'root',
'PORT': 27017 'PORT': 27017
@@ -26,4 +27,4 @@ MONGODB = {
DEBUG = True DEBUG = True
# 同理 这是 web 服务器的上传路径 # 同理 这是 web 服务器的上传路径
TEST_CASE_DIR = "/Users/virusdefender/Desktop/test_case/" TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case')

View File

@@ -40,8 +40,8 @@ urlpatterns = [
url(r'^api/announcements/$', AnnouncementAPIView.as_view(), name="announcement_list_api"), url(r'^api/announcements/$', AnnouncementAPIView.as_view(), name="announcement_list_api"),
url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"), url(r'^admin/contest/$', TemplateView.as_view(template_name="admin/contest/add_contest.html"),
name="add_contest_page"), name="add_contest_page"),
url(r'^problems/$', TemplateView.as_view(template_name="oj/problem/problem_list.html"), url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
name="problem_list_page"), url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html$', AdminTemplateView.as_view(), url(r'^admin/template/(?P<template_dir>\w+)/(?P<template_name>\w+).html$', AdminTemplateView.as_view(),
name="admin_template"), name="admin_template"),
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"), url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"),

View File

@@ -33,8 +33,14 @@ class CreateProblemSerializer(serializers.Serializer):
hint = serializers.CharField(max_length=3000, required=False, default=None) hint = serializers.CharField(max_length=3000, required=False, default=None)
class ProblemTagSerializer(serializers.ModelSerializer):
class Meta:
model = ProblemTag
class ProblemSerializer(serializers.ModelSerializer): class ProblemSerializer(serializers.ModelSerializer):
samples = JSONField() samples = JSONField()
tags = ProblemTagSerializer(many=True)
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@@ -58,17 +64,11 @@ class EditProblemSerializer(serializers.Serializer):
time_limit = serializers.IntegerField() time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField()
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.IntegerField()) tags = serializers.ListField(child=serializers.CharField(max_length=20))
samples = ProblemSampleSerializer() samples = ProblemSampleSerializer()
hint = serializers.CharField(max_length=10000) hint = serializers.CharField(max_length=10000)
visible = serializers.BooleanField() visible = serializers.BooleanField()
class ProblemTagSerializer(serializers.ModelSerializer):
class Meta:
model = ProblemTag
class CreateProblemTagSerializer(serializers.Serializer): class CreateProblemTagSerializer(serializers.Serializer):
name = serializers.CharField(max_length=10) name = serializers.CharField(max_length=10)

View File

@@ -7,6 +7,7 @@ import json
from django.shortcuts import render from django.shortcuts import render
from django.db.models import Q from django.db.models import Q
from django.core.paginator import Paginator
from rest_framework.views import APIView from rest_framework.views import APIView
@@ -59,6 +60,7 @@ class ProblemAdminAPIView(APIView):
serializer = CreateProblemSerializer(data=request.data) serializer = CreateProblemSerializer(data=request.data)
if serializer.is_valid(): if serializer.is_valid():
data = serializer.data data = serializer.data
print data
problem = Problem.objects.create(title=data["title"], problem = Problem.objects.create(title=data["title"],
description=data["description"], description=data["description"],
input_description=data["input_description"], input_description=data["input_description"],
@@ -113,20 +115,30 @@ class ProblemAdminAPIView(APIView):
# 删除原有的标签的对应关系 # 删除原有的标签的对应关系
problem.tags.remove(*problem.tags.all()) problem.tags.remove(*problem.tags.all())
# 重新添加所有的标签 # 重新添加所有的标签
problem.tags.add(*ProblemTag.objects.filter(id__in=data["tags"])) for tag in data["tags"]:
try:
tag = ProblemTag.objects.get(name=tag)
except ProblemTag.DoesNotExist:
tag = ProblemTag.objects.create(name=tag)
problem.tags.add(tag)
problem.save() problem.save()
return success_response(ProblemSerializer(problem).data) return success_response(ProblemSerializer(problem).data)
else: else:
return serializer_invalid_response(serializer) return serializer_invalid_response(serializer)
class ProblemAPIView(APIView):
def get(self, request): def get(self, request):
""" """
题目分页json api接口 题目分页json api接口
--- ---
response_serializer: ProblemSerializer response_serializer: ProblemSerializer
""" """
problem_id = request.GET.get("problem_id", None)
if problem_id:
try:
problem = Problem.objects.get(id=problem_id)
return success_response(ProblemSerializer(problem).data)
except Problem.DoesNotExist:
return error_response(u"题目不存在")
problem = Problem.objects.all().order_by("-last_update_time") problem = Problem.objects.all().order_by("-last_update_time")
visible = request.GET.get("visible", None) visible = request.GET.get("visible", None)
if visible: if visible:
@@ -217,3 +229,45 @@ class TestCaseUploadAPIView(APIView):
"output": l[1::2]}}) "output": l[1::2]}})
else: else:
return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩") return error_response(u"测试用例压缩文件格式错误,请保证测试用例文件在根目录下直接压缩")
def problem_list_page(request, page=1):
# 正常情况
problems = Problem.objects.all()
# 搜索的情况
keyword = request.GET.get("keyword", None)
if keyword:
problems = problems.filter(title__contains=keyword)
# 按照标签筛选
tag_text = request.GET.get("tag", None)
if tag_text:
try:
tag = ProblemTag.objects.get(name=tag_text)
except ProblemTag.DoesNotExist:
return error_page(request, u"标签不存在")
problems = tag.problem_set.all()
paginator = Paginator(problems, 20)
try:
current_page = paginator.page(int(page))
except Exception:
return error_page(request, u"不存在的页码")
previous_page = next_page = None
try:
previous_page = current_page.previous_page_number()
except Exception:
pass
try:
next_page = current_page.next_page_number()
except Exception:
pass
return render(request, "oj/problem/problem_list.html",
{"problems": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page,
"keyword": keyword, "tag": tag_text})

View File

@@ -33,3 +33,8 @@
width: 50%; width: 50%;
float: left; float: left;
} }
.tag-editor{
border: 1px solid #d9d9d9;
border-top-color: silver;
}

View File

@@ -29,3 +29,7 @@ label {
[ms-controller] { [ms-controller] {
display: none display: none
} }
.right{
float: right;
}

View File

@@ -24,17 +24,23 @@ define("admin", ["jquery", "avalon"], function ($, avalon) {
var vm = avalon.define({ var vm = avalon.define({
$id: "admin", $id: "admin",
template_url: "template/" + hash + ".html", template_url: "template/" + hash + ".html",
group_id: -1, groupId: -1,
problemId: -1,
hide_loading: function () { hide_loading: function () {
$("#loading-gif").hide(); $("#loading-gif").hide();
} }
}); });
vm.$watch("showGroupDetailPage", function(group_id){ vm.$watch("showGroupDetailPage", function(groupId){
vm.group_id = group_id; vm.groupId = groupId;
vm.template_url = "template/group/group_detail.html"; vm.template_url = "template/group/group_detail.html";
}); });
vm.$watch("showEditProblemPage", function(problemId){
vm.problemId = problemId;
vm.template_url = "template/problem/edit_problem.html";
});
avalon.scan(); avalon.scan();
li_active("#li-" + hash.replace("/", "-")); li_active("#li-" + hash.replace("/", "-"));

View File

@@ -1,171 +1,166 @@
require(["jquery", "avalon", "csrf", "bs_alert", "editor", "validation"], function ($, avalon, csrfHeader, bs_alert, editor) { require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "formValidation"],
function ($, avalon, csrfTokenHeader, bsAlert, editor) {
avalon.vmodels.announcement = null;
// avalon:定义模式 announcement avalon.ready(function () {
avalon.ready(function () { avalon.vmodels.announcement = null;
var announcementEditor = editor("#editor"); //创建新建公告的内容编辑器
var editAnnouncementEditor = editor("#editAnnouncementEditor");
var vm = avalon.define({ var createAnnouncementEditor = editor("#create-announcement-editor");
$id: "announcement", var editAnnouncementEditor = editor("#edit-announcement-editor");
//通用变量
announcement: [], // 公告列表数据项
previous_page: 0, // 之前的页数
next_page: 0, // 之后的页数
page: 1, // 当前页数
isEditing: 0, // 正在编辑的公告的ID 为零说明未在编辑
page_count: 1, // 总页数
visableOnly: false, //仅显示可见公告
// 编辑
announcementVisible: 0,
getState: function (el) { //获取公告当前状态,显示
if (el.visible)
return "可见";
else
return "隐藏";
},
getNext: function () {
if (!vm.next_page)
return;
getPageData(vm.page + 1);
},
getPrevious: function () {
if (!vm.previous_page)
return;
getPageData(vm.page - 1);
},
getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑
if (btn) {
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled";
}
else {
return vm.previous_page ? "btn btn-primary" : "btn btn-primary disabled";
}
}, var vm = avalon.define({
enEdit: function (el) { //点击编辑按钮的事件,显示/隐藏编辑区 $id: "announcement",
$("#newTitle").val(el.title); //通用变量
editAnnouncementEditor.setValue(el.content); announcementList: [], // 公告列表数据项
vm.announcementVisible = el.visible; previousPage: 0, // 之前的页数
if (vm.isEditing == el.id) nextPage: 0, // 之后的页数
vm.isEditing = 0; page: 1, // 当前页数
else editingAnnouncementId: 0, // 正在编辑的公告的ID 为零说明未在编辑
vm.isEditing = el.id; totalPage: 1, // 总页数
editAnnouncementEditor.focus(); showVisibleOnly: false, //仅显示可见公告
}, // 编辑
disEdit: function () { //收起编辑框 announcementVisible: 0,
vm.isEditing = 0; getState: function (el) { //获取公告当前状态,显示
}, if (el.visible)
submitChange: function () { // 处理编辑公告提交事件,顺便验证字段为空 return "可见";
var title = $("#newTitle").val(), content = editAnnouncementEditor.getValue(); else
if (title != "") { return "隐藏";
if (content != "") { },
$.ajax({ //发送修改公告请求 getNext: function () {
beforeSend: csrfHeader, if (!vm.nextPage)
return;
getPageData(vm.page + 1);
},
getPrevious: function () {
if (!vm.previousPage)
return;
getPageData(vm.page - 1);
},
getBtnClass: function (btnType) {
if (btnType == "next") {
return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
}
else {
return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
}
},
editAnnouncement: function (announcement) {
$("#newTitle").val(announcement.title);
editAnnouncementEditor.setValue(announcement.content);
vm.announcementVisible = announcement.visible;
if (vm.editingAnnouncementId == announcement.id)
vm.editingAnnouncementId = 0;
else
vm.editingAnnouncementId = announcement.id;
editAnnouncementEditor.focus();
},
cancelEdit: function () {
vm.editingAnnouncementId = 0;
},
submitChange: function () {
var title = $("#newTitle").val();
var content = editAnnouncementEditor.getValue();
if (content && title) {
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/admin/announcement/", url: "/api/admin/announcement/",
dataType: "json", dataType: "json",
method: "put", method: "put",
data: { data: {
id: vm.isEditing, id: vm.editingAnnouncementId,
title: title, title: title,
content: content, content: content,
visible: vm.announcementVisible visible: vm.announcementVisible
}, },
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
bs_alert("修改成功"); bsAlert("修改成功");
vm.isEditing = 0; vm.editingAnnouncementId = 0;
getPageData(1); getPageData(1);
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}); });
} }
else
bs_alert("公告内容不得为空");
}
else
bs_alert("公告标题不能为空");
}
});
vm.$watch("visableOnly", function () {
getPageData(1);
});
avalon.scan();
getPageData(1); //公告列表初始化
//Ajax get数据
function getPageData(page) {
var visible = '';
if (vm.visableOnly == true)
visible = "&visible=true";
$.ajax({
beforeSend: csrfHeader,
url: "/api/announcements/?paging=true&page=" + page + "&page_size=10" + visible,
dataType: "json",
method: "get",
success: function (data) {
if (!data.code) {
vm.announcement = data.data.results;
vm.page_count = data.data.total_page;
vm.previous_page = data.data.previous_page;
vm.next_page = data.data.next_page;
vm.page = page;
}
else { else {
bs_alert(data.data); bsAlert("标题和公告内容不得为空");
} }
} }
}); });
} vm.$watch("showVisibleOnly", function () {
getPageData(1);
});
//新建公告表单验证与数据提交 getPageData(1);
$("#announcement-form")
.formValidation({ function getPageData(page) {
framework: "bootstrap", var url = "/api/announcements/?paging=true&page=" + page + "&page_size=10";
fields: { if (vm.showVisibleOnly)
title: { url += "&visible=true";
validators: { $.ajax({
notEmpty: { url: url,
message: "请填写公告标题" dataType: "json",
method: "get",
success: function (data) {
if (!data.code) {
vm.announcementList = 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 {
bs_alert(data.data);
}
}
});
}
//新建公告表单验证与数据提交
$("#announcement-form")
.formValidation({
framework: "bootstrap",
fields: {
title: {
validators: {
notEmpty: {
message: "请填写公告标题"
}
} }
} }
} }
} }
} ).on('success.form.fv', function (e) {
).on('success.form.fv', function (e) { e.preventDefault();
e.preventDefault(); var title = $("#title").val();
var title = $("#title").val(); var content = createAnnouncementEditor.getValue();
var content = announcementEditor.getValue(); if (content == "") {
if (content == "") { bsAlert("请填写公告内容");
bs_alert("请填写公告内容"); return;
return;
}
$.ajax({
beforeSend: csrfHeader,
url: "/api/admin/announcement/",
data: {title: title, content: content},
dataType: "json",
method: "post",
success: function (data) {
if (!data.code) {
bs_alert("提交成功!");
$("#title").val("");
announcementEditor.setValue("");
getPageData(1);
} else {
bs_alert(data.data);
}
} }
}) $.ajax({
}); beforeSend: csrfTokenHeader,
url: "/api/admin/announcement/",
data: {title: title, content: content},
dataType: "json",
method: "post",
success: function (data) {
if (!data.code) {
bsAlert("提交成功!");
$("#title").val("");
createAnnouncementEditor.setValue("");
getPageData(1);
} else {
bs_alert(data.data);
}
}
})
});
});
avalon.scan();
}); });
});

View File

@@ -1,73 +1,74 @@
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) { require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
avalon.vmodels.group = null;
// avalon:定义模式 group_list
avalon.ready(function () { avalon.ready(function () {
avalon.vmodels.group = null;
var vm = avalon.define({ var vm = avalon.define({
$id: "group", $id: "group",
//通用变量 //通用变量
group_list: [], // 用户列表数据项 groupList: [], // 用户列表数据项
previous_page: 0, // 之前的页数 previousPage: 0, // 之前的页数
next_page: 0, // 之后的页数 nextPage: 0, // 之后的页数
page: 1, // 当前页数 page: 1, // 当前页数
page_count: 1, // 总页数 totalPage: 1, // 总页数
keyword: "", keyword: "",
getNext: function () { getNext: function () {
if (!vm.next_page) if (!vm.nextPage)
return; return;
getPageData(vm.page + 1); getPageData(vm.page + 1);
}, },
getPrevious: function () { getPrevious: function () {
if (!vm.previous_page) if (!vm.previousPage)
return; return;
getPageData(vm.page - 1); getPageData(vm.page - 1);
}, },
getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑 getBtnClass: function (btnType) {
if (btn) { if (btnType == "next") {
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
else { else {
return vm.previous_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
}, },
getPage: function (page_index) { search: function(){
getPageData(page_index); getPageData(1);
}, },
getGroupSettingString: function(setting){ getGroupSettingString: function (setting) {
return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting] return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting]
}, },
showGroupDetailPage: function(group_id){ showGroupDetailPage: function (groupId) {
vm.$fire("up!showGroupDetailPage", group_id); vm.$fire("up!showGroupDetailPage", groupId);
} }
}); });
getPageData(1);
avalon.scan();
getPageData(1); //用户列表初始化
//Ajax get数据
function getPageData(page) { function getPageData(page) {
var url = "/api/admin/group/?paging=true&page=" + page + "&page_size=10"; var url = "/api/admin/group/?paging=true&page=" + page + "&page_size=10";
if (vm.keyword != "") if (vm.keyword)
url += "&keyword=" + vm.keyword; url += "&keyword=" + vm.keyword;
$.ajax({ $.ajax({
beforeSend: csrfHeader,
url: url, url: url,
dataType: "json", dataType: "json",
method: "get", method: "get",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
vm.group_list = data.data.results; vm.groupList = data.data.results;
vm.page_count = data.data.total_page; vm.totalPage = data.data.total_page;
vm.previous_page = data.data.previous_page; vm.previousPage = data.data.previous_page;
vm.next_page = data.data.next_page; vm.nextPage = data.data.next_page;
vm.page = page; vm.page = page;
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}); });
} }
}); });
avalon.scan();
}); });

View File

@@ -1,51 +1,50 @@
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) { require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
avalon.vmodels.group_detail = null;
// avalon:定义模式 group_list // avalon:定义模式 group_list
avalon.ready(function () { avalon.ready(function () {
avalon.vmodels.groupDetail = null;
var vm = avalon.define({ var vm = avalon.define({
$id: "group_detail", $id: "groupDetail",
//通用变量 //通用变量
member_list: [], memberList: [],
previous_page: 0, previousPage: 0,
next_page: 0, nextPage: 0,
page: 1, page: 1,
page_count: 1, totalPage: 1,
name: "", name: "",
description: "", description: "",
checked_setting: "0", checkedSetting: "0",
getNext: function () { getNext: function () {
if (!vm.next_page) if (!vm.nextPage)
return; return;
getPageData(vm.page + 1); getPageData(vm.page + 1);
}, },
getPrevious: function () { getPrevious: function () {
if (!vm.previous_page) if (!vm.previousPage)
return; return;
getPageData(vm.page - 1); getPageData(vm.page - 1);
}, },
getBtnClass: function (btn) { getBtnClass: function (btn) {
if (btn) { if (btn == "next") {
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
else { else {
return vm.previous_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
}, },
getPage: function (page_index) {
getPageData(page_index);
},
removeMember: function (relation) { removeMember: function (relation) {
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: "/api/admin/group_member/", url: "/api/admin/group_member/",
method: "put", method: "put",
data: JSON.stringify({group_id: relation.group, members: [relation.user.id]}), data: JSON.stringify({group_id: relation.group, members: [relation.user.id]}),
contentType: "application/json", contentType: "application/json",
success: function (data) { success: function (data) {
vm.member_list.remove(relation); vm.memberList.remove(relation);
bs_alert(data.data); bsAlert(data.data);
} }
}) })
} }
@@ -55,90 +54,90 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
getPageData(1); getPageData(1);
function getPageData(page) { function getPageData(page) {
var url = "/api/admin/group_member/?paging=true&page=" + page + var url = "/api/admin/group_member/?paging=true&page=" + page +
"&page_size=10&group_id=" + avalon.vmodels.admin.group_id; "&page_size=10&group_id=" + avalon.vmodels.admin.groupId;
$.ajax({ $.ajax({
url: url, url: url,
dataType: "json", dataType: "json",
method: "get", method: "get",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
vm.member_list = data.data.results; vm.memberList = data.data.results;
vm.page_count = data.data.total_page; vm.totalPage = data.data.total_page;
vm.previous_page = data.data.previous_page; vm.previousPage = data.data.previous_page;
vm.next_page = data.data.next_page; vm.nextPage = data.data.next_page;
vm.page = page; vm.page = page;
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}); });
} }
$.ajax({ $.ajax({
url: "/api/admin/group/?group_id=" + avalon.vmodels.admin.group_id, url: "/api/admin/group/?group_id=" + avalon.vmodels.admin.groupId,
method: "get", method: "get",
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
vm.name = data.data.name; vm.name = data.data.name;
vm.description = data.data.description; vm.description = data.data.description;
vm.checked_setting = data.data.join_group_setting.toString(); vm.checkedSetting = data.data.join_group_setting.toString();
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}) });
$("#edit_group_form") $("#edit_group_form")
.formValidation({ .formValidation({
framework: "bootstrap", framework: "bootstrap",
fields: { fields: {
name: { name: {
validators: { validators: {
notEmpty: { notEmpty: {
message: "请填写小组名" message: "请填写小组名"
}, },
stringLength: { stringLength: {
max: 20, max: 20,
message: '小组名长度必须在20位之内' message: '小组名长度必须在20位之内'
}
} }
}, }
description: { },
validators: { description: {
notEmpty: { validators: {
message: "请填写描述" notEmpty: {
}, message: "请填写描述"
stringLength: { },
max: 300, stringLength: {
message: '描述长度必须在300位之内' max: 300,
} message: '描述长度必须在300位之内'
} }
} }
} }
} }
).on('success.form.fv', function (e) { }
).on('success.form.fv', function (e) {
e.preventDefault(); e.preventDefault();
var data = { var data = {
group_id: avalon.vmodels.admin.group_id, group_id: avalon.vmodels.admin.groupId,
name: vm.name, name: vm.name,
description: vm.description, description: vm.description,
join_group_setting: vm.checked_setting join_group_setting: vm.checkedSetting
}; };
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: "/api/admin/group/", url: "/api/admin/group/",
method: "put", method: "put",
data: data, data: data,
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
bs_alert("修改成功"); bsAlert("修改成功");
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}) })

View File

@@ -1,46 +1,47 @@
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) { require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
avalon.vmodels.request_list = null;
// avalon:定义模式 group_list // avalon:定义模式 group_list
avalon.ready(function () { avalon.ready(function () {
avalon.vmodels.requestList = null;
var vm = avalon.define({ var vm = avalon.define({
$id: "request_list", $id: "requestList",
//通用变量 //通用变量
request_list: [], // 列表数据项 requestList: [], // 列表数据项
previous_page: 0, // 之前的页数 previousPage: 0, // 之前的页数
next_page: 0, // 之后的页数 nextPage: 0, // 之后的页数
page: 1, // 当前页数 page: 1, // 当前页数
page_count: 1, // 总页数 totalPage: 1, // 总页数
getNext: function () { getNext: function () {
if (!vm.next_page) if (!vm.nextPage)
return; return;
getPageData(vm.page + 1); getPageData(vm.page + 1);
}, },
getPrevious: function () { getPrevious: function () {
if (!vm.previous_page) if (!vm.previousPage)
return; return;
getPageData(vm.page - 1); getPageData(vm.page - 1);
}, },
getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑 getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑
if (btn) { if (btn == "next") {
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
else { else {
return vm.previous_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
}, },
getPage: function (page_index) { getPage: function (page_index) {
getPageData(page_index); getPageData(page_index);
}, },
processRequest: function(request_id, status){ processRequest: function(request, status){
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: "/api/admin/join_group_request/", url: "/api/admin/join_group_request/",
method: "put", method: "put",
data: {request_id: request_id, status: status}, data: {request_id: request.id, status: status},
success: function(data){ success: function(data){
bs_alert(data.data); vm.requestList.remove(request);
bsAlert(data.data);
} }
}) })
} }
@@ -52,20 +53,20 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
function getPageData(page) { function getPageData(page) {
var url = "/api/admin/join_group_request/?paging=true&page=" + page + "&page_size=10"; var url = "/api/admin/join_group_request/?paging=true&page=" + page + "&page_size=10";
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: url, url: url,
dataType: "json", dataType: "json",
method: "get", method: "get",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
vm.request_list = data.data.results; vm.requestList = data.data.results;
vm.page_count = data.data.total_page; vm.totalPage = data.data.total_page;
vm.previous_page = data.data.previous_page; vm.previousPage = data.data.previous_page;
vm.next_page = data.data.next_page; vm.nextPage = data.data.next_page;
vm.page = page; vm.page = page;
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}); });
@@ -134,11 +135,11 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
method: "put", method: "put",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
bs_alert("提交成功!"); bsAlert("提交成功!");
getPageData(1); getPageData(1);
$("#password").val(""); $("#password").val("");
} else { } else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}) })

View File

@@ -1,219 +1,218 @@
require(["jquery", "avalon", "editor", "uploader", "bs_alert", "csrf", "tagEditor", "validation", "jqueryUI"], require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagEditor", "formValidation", "jqueryUI"],
function ($, avalon, editor, uploader, bs_alert, csrfHeader) { function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
avalon.vmodels.add_problem = null; avalon.ready(function () {
$("#add-problem-form") avalon.vmodels.addProblem = null;
.formValidation({ $("#add-problem-form")
framework: "bootstrap", .formValidation({
fields: { framework: "bootstrap",
title: { fields: {
validators: { title: {
notEmpty: { validators: {
message: "请填写题目名称" notEmpty: {
}, message: "请填写题目名称"
stringLength: { },
min: 1, stringLength: {
max: 30, min: 1,
message: "名称不能超过30个字" max: 30,
message: "名称不能超过30个字"
}
} }
} },
}, cpu: {
cpu: { validators: {
validators: { notEmpty: {
notEmpty: { message: "请输入时间限制"
message: "请输入时间限制" },
}, integer: {
integer: { message: "请输入一个合法的数字"
message: "请输入一个合法的数字" },
}, between: {
between: { inclusive: true,
inclusive: true, min: 1,
min: 1, max: 5000,
max: 5000, message: "只能在1-5000之间"
message: "只能在1-5000之间" }
} }
} },
}, memory: {
memory: { validators: {
validators: { notEmpty: {
notEmpty: { message: "请输入内存限制"
message: "请输入内存限制" },
}, integer: {
integer: { message: "请输入一个合法的数字"
message: "请输入一个合法的数字" }
} }
} },
}, difficulty: {
difficulty: { validators: {
validators: { notEmpty: {
notEmpty: { message: "请输入难度"
message: "请输入难度" },
}, integer: {
integer: { message: "难度用一个整数表示"
message: "难度用一个整数表示" }
} }
} },
}, input_description: {
input_description: { validators: {
validators: { notEmpty: {
notEmpty: { message: "请填写输入描述"
message: "请填写输入描述" }
} }
} },
}, output_description: {
output_description: { validators: {
validators: { notEmpty: {
notEmpty: { message: "请填写输出描述"
message: "请填写输出描述" }
} }
} }
} }
}
})
.on("success.form.fv", function (e) {
e.preventDefault();
if (vm.test_case_id == '') {
bs_alert("你还没有上传测试数据!");
return;
}
if (vm.description == '') {
bs_alert("题目描述不能为空!");
return;
}
var ajaxData = {
title: vm.title,
description: vm.description,
time_limit: vm.cpu,
memory_limit: vm.memory,
samples: [],
test_case_id: vm.test_case_id,
hint: vm.hint,
source: vm.source,
tags: $("#tags").tagEditor("getTags")[0].tags,
input_description: vm.input_description,
output_description: vm.output_description,
difficulty: vm.difficulty
};
if (vm.samples.length == 0) {
bs_alert("请至少添加一组样例!");
return;
}
for(var i = 0; i < vm.samples.length; i++){
if (vm.samples[i].input == "" || vm.samples[i].output == ""){
bs_alert("样例输入与样例输出不能为空!");
return;
}
}
if (tags.length == 0) {
bs_alert("请至少添加一个标签,这将有利于用户发现你的题目!");
return;
}
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});
}
$.ajax({
beforeSend: csrfHeader,
url: "/api/admin/problem/",
dataType: "json",
data: JSON.stringify(ajaxData),
method: "post",
contentType: "application/json",
success: function (data) {
if (!data.code) {
bs_alert("successful!");
console.log(data);
}
else {
bs_alert(data.data);
}
}
}) })
}); .on("success.form.fv", function (e) {
var problemDiscription = editor("#problemDescription"); e.preventDefault();
var testCaseUploader = uploader("#testCaseFile", "/api/admin/test_case_upload/", function (file, respond) { if (vm.testCaseId == "") {
if (respond.code) bsAlert("你还没有上传测试数据!");
bs_alert(respond.data); return;
else {
vm.test_case_id = respond.data.test_case_id;
vm.uploadSuccess = true;
vm.testCaseList = [];
for (var i = 0; i < respond.data.file_list.input.length; i++) {
vm.testCaseList.push({
input: respond.data.file_list.input[i],
output: respond.data.file_list.output[i]
});
}
bs_alert("测试数据添加成功!共添加"+vm.testCaseList.length +"组测试数据");
}
});
var hinteditor = editor("#hint");
var tagList = [], completeList = [];
var vm = avalon.define({
$id: "add_problem",
title: "",
description: "",
cpu: 1000,
memory: 256,
samples: [{input: "", output: "", "visible": true}],
hint: "",
visible: true,
difficulty: 0,
tags: [],
tag: "",
input_description: "",
output_description: "",
test_case_id: "",
testCaseList: [],
uploadSuccess: false,
source: "",
add_sample: function () {
vm.samples.push({input: "", output: "", "visible": true});
},
del_sample: function (sample) {
if (confirm("你确定要删除么?")) {
vm.samples.remove(sample);
}
},
toggle_sample: function (sample) {
sample.visible = !sample.visible;
},
getBtnContent: function (item) {
if (item.visible)
return "折叠";
return "展开";
}
});
$.ajax({
beforeSend: csrfHeader,
url: "/api/admin/tag/",
dataType: "json",
method: "get",
success: function (data) {
if (!data.code) {
tagList = data.data;
completeList = [];
for (var i = 0; i < tagList.length; i++) {
completeList.push(tagList[i].name);
} }
$("#tags").tagEditor({ if (vm.description == "") {
autocomplete: { bsAlert("题目描述不能为空!");
delay: 0, // show suggestions immediately return;
position: {collision: 'flip'}, // automatic menu position up/down }
source: completeList if (vm.samples.length == 0) {
bsAlert("请至少添加一组样例!");
return;
}
for (var i = 0; i < vm.samples.length; i++) {
if (vm.samples[i].input == "" || vm.samples[i].output == "") {
bsAlert("样例输入与样例输出不能为空!");
return;
} }
}); }
} if (tags.length == 0) {
else { bsAlert("请至少添加一个标签,这将有利于用户发现你的题目!");
bs_alert(data.data); return;
} }
} var ajaxData = {
title: vm.title,
description: vm.description,
time_limit: vm.timeLimit,
memory_limit: vm.memoryLimit,
samples: [],
test_case_id: vm.testCaseId,
hint: vm.hint,
source: vm.source,
tags: $("#tags").tagEditor("getTags")[0].tags,
input_description: vm.inputDescription,
output_description: vm.outputDescription,
difficulty: vm.difficulty
};
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});
}
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/admin/problem/",
dataType: "json",
data: JSON.stringify(ajaxData),
method: "post",
contentType: "application/json",
success: function (data) {
if (!data.code) {
bsAlert("题目添加成功!");
}
else {
bsAlert(data.data);
}
}
})
});
var testCaseUploader = uploader("#testCaseFile", "/api/admin/test_case_upload/", function (file, response) {
if (response.code)
bsAlert(response.data);
else {
vm.testCaseId = response.data.test_case_id;
vm.uploadSuccess = true;
vm.testCaseList = [];
for (var i = 0; i < response.data.file_list.input.length; i++) {
vm.testCaseList.push({
input: response.data.file_list.input[i],
output: response.data.file_list.output[i]
});
}
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
}
});
var hintEditor = editor("#hint");
var problemDescription = editor("#problemDescription");
var vm = avalon.define({
$id: "addProblem",
title: "",
description: "",
cpu: 1000,
memory: 256,
samples: [{input: "", output: "", "visible": true}],
hint: "",
visible: true,
difficulty: 0,
tags: [],
inputDescription: "",
outputDescription: "",
testCaseId: "",
testCaseList: [],
uploadSuccess: false,
source: "",
addSample: function () {
vm.samples.push({input: "", output: "", "visible": true});
},
delSample: function (sample) {
if (confirm("你确定要删除么?")) {
vm.samples.remove(sample);
}
},
toggleSample: function (sample) {
sample.visible = !sample.visible;
},
getBtnContent: function (item) {
if (item.visible)
return "折叠";
return "展开";
}
});
var tagAutoCompleteList = [];
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/admin/tag/",
dataType: "json",
method: "get",
success: function (data) {
if (!data.code) {
for (var i = 0; i < data.data.length; i++) {
tagAutoCompleteList.push(data.data[i].name);
}
$("#tags").tagEditor({
autocomplete: {
delay: 0, // show suggestions immediately
position: {collision: 'flip'}, // automatic menu position up/down
source: tagAutoCompleteList
}
});
}
else {
bsAlert(data.data);
}
}
});
}); });
avalon.scan(); avalon.scan();
}); });

View File

@@ -0,0 +1,257 @@
require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagEditor", "formValidation", "jqueryUI"],
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
avalon.ready(function () {
avalon.vmodels.editProblem = null;
$("#edit-problem-form")
.formValidation({
framework: "bootstrap",
fields: {
title: {
validators: {
notEmpty: {
message: "请填写题目名称"
},
stringLength: {
min: 1,
max: 30,
message: "名称不能超过30个字"
}
}
},
cpu: {
validators: {
notEmpty: {
message: "请输入时间限制"
},
integer: {
message: "请输入一个合法的数字"
},
between: {
inclusive: true,
min: 1,
max: 5000,
message: "只能在1-5000之间"
}
}
},
memory: {
validators: {
notEmpty: {
message: "请输入内存限制"
},
integer: {
message: "请输入一个合法的数字"
}
}
},
difficulty: {
validators: {
notEmpty: {
message: "请输入难度"
},
integer: {
message: "难度用一个整数表示"
}
}
},
input_description: {
validators: {
notEmpty: {
message: "请填写输入描述"
}
}
},
output_description: {
validators: {
notEmpty: {
message: "请填写输出描述"
}
}
}
}
})
.on("success.form.fv", function (e) {
e.preventDefault();
if (vm.testCaseId == "") {
bsAlert("你还没有上传测试数据!");
return;
}
if (vm.description == "") {
bsAlert("题目描述不能为空!");
return;
}
if (vm.samples.length == 0) {
bsAlert("请至少添加一组样例!");
return;
}
for (var i = 0; i < vm.samples.length; i++) {
if (vm.samples[i].input == "" || vm.samples[i].output == "") {
bsAlert("样例输入与样例输出不能为空!");
return;
}
}
if (tags.length == 0) {
bsAlert("请至少添加一个标签,这将有利于用户发现你的题目!");
return;
}
var ajaxData = {
id: avalon.vmodels.admin.problemId,
title: vm.title,
description: vm.description,
time_limit: vm.timeLimit,
memory_limit: vm.memoryLimit,
samples: [],
test_case_id: vm.testCaseId,
hint: vm.hint,
source: vm.source,
visible: vm.visible,
tags: $("#tags").tagEditor("getTags")[0].tags,
input_description: vm.inputDescription,
output_description: vm.outputDescription,
difficulty: vm.difficulty
};
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});
}
$.ajax({
beforeSend: csrfTokenHeader,
url: "/api/admin/problem/",
dataType: "json",
data: JSON.stringify(ajaxData),
method: "put",
contentType: "application/json",
success: function (data) {
if (!data.code) {
bsAlert("题目编辑成功!");
}
else {
bsAlert(data.data);
}
}
})
});
var vm = avalon.define({
$id: "editProblem",
title: "",
description: "",
timeLimit: -1,
memoryLimit: -1,
samples: [],
hint: "",
visible: true,
difficulty: 0,
inputDescription: "",
outputDescription: "",
testCaseIdd: "",
uploadSuccess: false,
source: "",
testCaseList: [],
addSample: function () {
vm.samples.push({input: "", output: "", "visible": true});
},
delSample: function (sample) {
if (confirm("你确定要删除么?")) {
vm.samples.remove(sample);
}
},
toggleSample: function (sample) {
sample.visible = !sample.visible;
},
getBtnContent: function (item) {
if (item.visible)
return "折叠";
return "展开";
}
});
var hintEditor = editor("#hint");
var descriptionEditor = editor("#problemDescription");
var testCaseUploader = uploader("#testCaseFile", "/api/admin/test_case_upload/", function (file, response) {
if (response.code)
bsAlert(response.data);
else {
vm.testCaseId = response.data.test_case_id;
vm.uploadSuccess = true;
vm.testCaseList = [];
for (var i = 0; i < response.data.file_list.input.length; i++) {
vm.testCaseList.push({
input: response.data.file_list.input[i],
output: response.data.file_list.output[i]
});
}
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据");
}
});
$.ajax({
url: "/api/admin/problem/?problem_id=" + avalon.vmodels.admin.problemId,
method: "get",
dataType: "json",
success: function (data) {
if (data.code) {
bsAlert(data.data);
}
else {
var problem = data.data;
console.log(problem);
vm.title = problem.title;
vm.description = problem.description;
vm.timeLimit = problem.time_limit;
vm.memoryLimit = problem.memory_limit;
for (var i = 0; i < problem.samples.length; i++) {
vm.samples.push({
input: problem.samples[i].input,
output: problem.samples[i].output,
visible: false
})
}
vm.hint = problem.hint;
vm.visible = problem.visible;
vm.difficulty = problem.difficulty;
vm.inputDescription = problem.input_description;
vm.outputDescription = problem.output_description;
vm.testCaseId = problem.test_case_id;
vm.source = problem.source;
var problemTags = problem.tags;
hintEditor.setValue(vm.hint);
descriptionEditor.setValue(vm.description);
$.ajax({
url: "/api/admin/tag/",
dataType: "json",
method: "get",
success: function (data) {
if (!data.code) {
var tagAutoCompleteList = [], tags = [];
for (var i = 0; i < data.data.length; i++) {
tagAutoCompleteList.push(data.data[i].name);
}
for (var j = 0; j < problem.tags.length; j++) {
tags.push(problemTags[j].name);
}
$("#tags").tagEditor({
initialTags: tags,
autocomplete: {
delay: 0,
position: {collision: 'flip'},
source: tagAutoCompleteList
}
});
}
else {
bsAlert(data.data);
}
}
});
}
}
});
});
avalon.scan();
});

View File

@@ -0,0 +1,65 @@
require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
avalon.ready(function () {
avalon.vmodels.problemList = null;
var vm = avalon.define({
$id: "problemList",
problemList: [],
previousPage: 0,
nextPage: 0,
page: 1,
totalPage: 1,
keyword: "",
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);
},
showEditProblemPage: function (problem_id) {
vm.$fire("up!showEditProblemPage", problem_id);
}
});
function getPageData(page) {
var url = "/api/admin/problem/?paging=true&page=" + page + "&page_size=10";
if (vm.keyword != "")
url += "&keyword=" + vm.keyword;
$.ajax({
url: url,
dataType: "json",
method: "get",
success: function (data) {
if (!data.code) {
vm.problemList = 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);
}
}
});
}
getPageData(1);
});
avalon.scan();
});

View File

@@ -1,59 +1,58 @@
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) { require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
avalon.vmodels.user_list = null;
// avalon:定义模式 user_list
// avalon:定义模式 userList
avalon.ready(function () { avalon.ready(function () {
avalon.vmodels.userList = null;
var vm = avalon.define({ var vm = avalon.define({
$id: "user_list", $id: "userList",
//通用变量 //通用变量
user_list: [], // 用户列表数据项 userList: [],
previous_page: 0, // 之前的页数 previousPage: 0,
next_page: 0, // 之后的页数 nextPage: 0,
page: 1, // 当前页数 page: 1,
isEditing: 0, // 正在编辑的公告的ID 为零说明未在编辑 editingUserId: 0,
page_count: 1, // 总页数 totalPage: 1,
user_type: ["一般用户", "管理员", "超级管理员"], userType: ["一般用户", "管理员", "超级管理员"],
key_word: "", keyword: "",
showAdminOnly: false, showAdminOnly: false,
//编辑区域同步变量 //编辑区域同步变量
username: "", username: "",
real_name: "", realName: "",
email: "", email: "",
admin_type: 0, adminType: 0,
id: 0, id: 0,
last_login: "",
create_time: "",
getNext: function () { getNext: function () {
if (!vm.next_page) if (!vm.nextPage)
return; return;
getPageData(vm.page + 1); getPageData(vm.page + 1);
}, },
getPrevious: function () { getPrevious: function () {
if (!vm.previous_page) if (!vm.previousPage)
return; return;
getPageData(vm.page - 1); getPageData(vm.page - 1);
}, },
getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑 getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑
if (btn) { if (btn) {
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
else { else {
return vm.previous_page ? "btn btn-primary" : "btn btn-primary disabled"; return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
} }
}, },
enEdit: function (el) { //点击编辑按钮的事件,显示/隐藏编辑区 editUser: function (user) { //点击编辑按钮的事件,显示/隐藏编辑区
vm.username = el.username; vm.username = user.username;
vm.real_name = el.real_name; vm.realName = user.real_name;
vm.admin_type = el.admin_type; vm.adminType = user.admin_type;
vm.email = el.email; vm.email = user.email;
vm.id = el.id; vm.id = user.id;
if (vm.isEditing == el.id) if (vm.editingUserId == user.id)
vm.isEditing = 0; vm.editingUserId = 0;
else else
vm.isEditing = el.id; vm.editingUserId = user.id;
}, },
getPage: function (page_index) { search: function () {
getPageData(page_index); getPageData(1);
} }
}); });
vm.$watch("showAdminOnly", function () { vm.$watch("showAdminOnly", function () {
@@ -66,23 +65,23 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
var url = "/api/admin/user/?paging=true&page=" + page + "&page_size=10"; var url = "/api/admin/user/?paging=true&page=" + page + "&page_size=10";
if (vm.showAdminOnly == true) if (vm.showAdminOnly == true)
url += "&admin_type=1"; url += "&admin_type=1";
if (vm.key_word != "") if (vm.keyword != "")
url += "&keyword=" + vm.key_word; url += "&keyword=" + vm.keyword;
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: url, url: url,
dataType: "json", dataType: "json",
method: "get", method: "get",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
vm.user_list = data.data.results; vm.userList = data.data.results;
vm.page_count = data.data.total_page; vm.totalPage = data.data.total_page;
vm.previous_page = data.data.previous_page; vm.previousPage = data.data.previous_page;
vm.next_page = data.data.next_page; vm.nextPage = data.data.next_page;
vm.page = page; vm.page = page;
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}); });
@@ -136,26 +135,26 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
e.preventDefault(); e.preventDefault();
var data = { var data = {
username: vm.username, username: vm.username,
real_name: vm.real_name, real_name: vm.realName,
email: vm.email, email: vm.email,
id: vm.id, id: vm.id,
admin_type: vm.admin_type admin_type: vm.adminType
}; };
if ($("#password").val() !== "") if ($("#password").val() !== "")
data.password = $("#password").val(); data.password = $("#password").val();
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: "/api/admin/user/", url: "/api/admin/user/",
data: data, data: data,
dataType: "json", dataType: "json",
method: "put", method: "put",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
bs_alert("提交成功!"); bsAlert("提交成功!");
getPageData(1); getPageData(1);
$("#password").val(""); $("#password").val("");
} else { } else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}) })

View File

@@ -1,4 +1,4 @@
require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) { require(["jquery", "bsAlert", "csrfToken", "formValidation"], function ($, bsAlert, csrfTokenHeader) {
$("#change_password-form").formValidation({ $("#change_password-form").formValidation({
framework: "bootstrap", framework: "bootstrap",
fields: { fields: {
@@ -47,21 +47,20 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
).on('success.form.fv', function (e) { ).on('success.form.fv', function (e) {
e.preventDefault(); e.preventDefault();
var username = $("#username").val(); var username = $("#username").val();
var new_password = $("#new_password ").val(); var newPassword = $("#new_password ").val();
var password = $("#password").val(); var password = $("#password").val();
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: "/api/change_password/", url: "/api/change_password/",
data: {username: username, new_password: new_password, old_password: password}, data: {username: username, new_password: newPassword, old_password: password},
dataType: "json", dataType: "json",
method: "post", method: "post",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
window.location.href = "/login/"; window.location.href = "/login/";
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}) })

View File

@@ -1,4 +1,4 @@
require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) { require(["jquery", "bsAlert", "csrfToken", "formValidation"], function ($, bsAlert, csrfTokenHeader) {
$("#login-form") $("#login-form")
.formValidation({ .formValidation({
framework: "bootstrap", framework: "bootstrap",
@@ -24,7 +24,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
var username = $("#username").val(); var username = $("#username").val();
var password = $("#password").val(); var password = $("#password").val();
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: "/api/login/", url: "/api/login/",
data: {username: username, password: password}, data: {username: username, password: password},
dataType: "json", dataType: "json",
@@ -34,7 +34,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
window.location.href = "/"; window.location.href = "/";
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }

View File

@@ -1,4 +1,4 @@
require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) { require(["jquery", "bsAlert", "csrfToken", "validation"], function ($, bsAlert, csrfTokenHeader) {
$("#register-form") $("#register-form")
.formValidation({ .formValidation({
framework: "bootstrap", framework: "bootstrap",
@@ -73,13 +73,13 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
).on('success.form.fv', function (e) { ).on('success.form.fv', function (e) {
e.preventDefault(); e.preventDefault();
var username = $("#username").val(); var username = $("#username").val();
var real_name = $("#real_name").val(); var realName = $("#real_name").val();
var password = $("#password").val(); var password = $("#password").val();
var email = $("#email").val(); var email = $("#email").val();
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfHeader,
url: "/api/register/", url: "/api/register/",
data: {username: username, real_name: real_name, password: password, email: email}, data: {username: username, real_name: realName, password: password, email: email},
dataType: "json", dataType: "json",
method: "post", method: "post",
success: function (data) { success: function (data) {
@@ -87,7 +87,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
window.location.href = "/login/"; window.location.href = "/login/";
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
} }
} }
}) })

View File

@@ -1,12 +1,12 @@
require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror, csrfHeader, bs_alert) { require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirror, csrfTokenHeader, bsAlert) {
var code_editor = code_mirror($("#code-editor")[0], "text/x-csrc"); var codeEditor = codeMirror($("#code-editor")[0], "text/x-csrc");
var language = $("input[name='language'][checked]").val(); var language = $("input[name='language'][checked]").val();
var submission_id; var submissionId;
$("input[name='language']").change(function () { $("input[name='language']").change(function () {
language = this.value; language = this.value;
var language_types = {"1": "text/x-csrc", "2": "text/x-c++src", "3": "text/x-java"}; var languageTypes = {"1": "text/x-csrc", "2": "text/x-c++src", "3": "text/x-java"};
code_editor.setOption("mode", language_types[language]); codeEditor.setOption("mode", languageTypes[language]);
}); });
$("#show-more-btn").click(function () { $("#show-more-btn").click(function () {
@@ -14,18 +14,17 @@ require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror,
$("#show-more-btn").hide(); $("#show-more-btn").hide();
}); });
function show_loading() { function showLoading() {
$("#submit-code-button").attr("disabled", "disabled"); $("#submit-code-button").attr("disabled", "disabled");
$("#loading-gif").show(); $("#loading-gif").show();
} }
function hide_loading() { function hideLoading() {
$("#submit-code-button").removeAttr("disabled"); $("#submit-code-button").removeAttr("disabled");
$("#loading-gif").hide(); $("#loading-gif").hide();
} }
function getResultHtml(data) {
function get_result_html(data) {
// 0 结果正确 1 运行错误 2 超时 3 超内存 4 编译错误 // 0 结果正确 1 运行错误 2 超时 3 超内存 4 编译错误
// 5 格式错误 6 结果错误 7 系统错误 8 等待判题 // 5 格式错误 6 结果错误 7 系统错误 8 等待判题
var results = { var results = {
@@ -49,14 +48,14 @@ require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror,
if (!data.result) { if (!data.result) {
html += "CPU time: " + data.accepted_answer_info.time + "ms &nbsp;&nbsp;"; html += "CPU time: " + data.accepted_answer_info.time + "ms &nbsp;&nbsp;";
} }
html += ('<a href="/my_submission/' + submission_id + '/" target="_blank">查看详情</a></div> </div>'); html += ('<a href="/my_submission/' + submissionId + '/" target="_blank">查看详情</a></div> </div>');
return html; return html;
} }
function get_result() { function getResult() {
$.ajax({ $.ajax({
url: "/api/submission/?submission_id=" + submission_id, url: "/api/submission/?submission_id=" + submissionId,
method: "get", method: "get",
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
@@ -64,54 +63,54 @@ require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror,
// 8是还没有完成判题 // 8是还没有完成判题
if (data.data.result == 8) { if (data.data.result == 8) {
// 1秒之后重新去获取 // 1秒之后重新去获取
setTimeout(get_result, 1000); setTimeout(getResult, 1000);
} }
else { else {
hide_loading(); hideLoading();
$("#result").html(get_result_html(data.data)); $("#result").html(getResultHtml(data.data));
} }
} }
else { else {
bs_alert(data.data); bsAlert(data.data);
hide_loading(); hideLoading();
} }
} }
}) })
} }
$("#submit-code-button").click(function () { $("#submit-code-button").click(function () {
var problem_id = window.location.pathname.split("/")[2]; var problemId = window.location.pathname.split("/")[2];
var code = code_editor.getValue(); var code = codeEditor.getValue();
show_loading(); showLoading();
if(!code.trim()){ if(!code.trim()){
bs_alert("请填写代码!"); bs_alert("请填写代码!");
hide_loading(); hideLoading();
return false; return false;
} }
$("#result").html(""); $("#result").html("");
$.ajax({ $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: "/api/submission/", url: "/api/submission/",
method: "post", method: "post",
data: JSON.stringify({ data: JSON.stringify({
problem_id: window.location.pathname.split("/")[2], problem_id: problemId,
language: language, language: language,
code: code_editor.getValue() code: codeEditor.getValue()
}), }),
contentType: "application/json", contentType: "application/json",
success: function (data) { success: function (data) {
if (!data.code) { if (!data.code) {
submission_id = data.data.submission_id; submissionId = data.data.submission_id;
// 获取到id 之后2秒去查询一下判题结果 // 获取到id 之后2秒去查询一下判题结果
setTimeout(get_result, 2000); setTimeout(getResult, 2000);
} }
else { else {
bs_alert(data.data); bs_alert(data.data);
hide_loading(); hideLoading();
} }
} }
}); });

View File

@@ -2,24 +2,28 @@ var require = {
// RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。 // RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。
baseUrl: "/static/js/", baseUrl: "/static/js/",
paths: { paths: {
//百度webuploader
webuploader: "lib/webuploader/webuploader",
jquery: "lib/jquery/jquery", jquery: "lib/jquery/jquery",
avalon: "lib/avalon/avalon", avalon: "lib/avalon/avalon",
editor: "utils/editor", editor: "utils/editor",
uploader: "utils/uploader", uploader: "utils/uploader",
validation: "utils/validation", formValidation: "utils/formValidation",
code_mirror: "utils/code_mirror", codeMirror: "utils/codeMirror",
bs_alert: "utils/bs_alert", bsAlert: "utils/bsAlert",
problem: "app/oj/problem/problem", problem: "app/oj/problem/problem",
contest: "app/admin/contest/contest", contest: "app/admin/contest/contest",
csrf: "utils/csrf", csrfToken: "utils/csrfToken",
admin: "app/admin/admin", admin: "app/admin/admin",
chart: "lib/chart/Chart", chart: "lib/chart/Chart",
tagEditor: "lib/tagEditor/jquery.tag-editor.min", tagEditor: "lib/tagEditor/jquery.tag-editor.min",
jqueryUI: "lib/jqueryUI/jquery-ui", jqueryUI: "lib/jqueryUI/jquery-ui",
//formValidation 不要在代码中单独使用而是使用和修改utils/validation bootstrap: "lib/bootstrap/bootstrap",
datetimePicker: "lib/datetime_picker/bootstrap-datetimepicker.zh-CN",
// ------ 下面写的都不要直接用,而是使用上面的封装版本 ------
//formValidation -> utils/validation
base: "lib/formValidation/base", base: "lib/formValidation/base",
helper: "lib/formValidation/helper", helper: "lib/formValidation/helper",
"language/zh_CN": "lib/formValidation/language/zh_CN", "language/zh_CN": "lib/formValidation/language/zh_CN",
@@ -32,26 +36,25 @@ var require = {
"validator/confirm":"lib/formValidation/validator/confirm", "validator/confirm":"lib/formValidation/validator/confirm",
"validator/remote":"lib/formValidation/validator/remote", "validator/remote":"lib/formValidation/validator/remote",
"validator/emailAddress":"lib/formValidation/validator/emailAddress", "validator/emailAddress":"lib/formValidation/validator/emailAddress",
//富文本编辑器 不要直接使用而是使用上面的editor
//富文本编辑器simditor -> editor
simditor: "lib/simditor/simditor", simditor: "lib/simditor/simditor",
"simple-module": "lib/simditor/module", "simple-module": "lib/simditor/module",
"simple-hotkeys": "lib/simditor/hotkeys", "simple-hotkeys": "lib/simditor/hotkeys",
"simple-uploader": "lib/simditor/uploader", "simple-uploader": "lib/simditor/uploader",
//code mirroe 代码编辑器 //code mirror 代码编辑器 ->codeMirror
_code_mirror: "lib/codeMirror/codemirror", _codeMirror: "lib/codeMirror/codemirror",
code_mirror_clang: "lib/codeMirror/language/clike", codeMirrorClang: "lib/codeMirror/language/clike",
//bootstrap //百度webuploader -> uploader
bootstrap: "lib/bootstrap/bootstrap", webUploader: "lib/webuploader/webuploader",
// "_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker"
"_datetimepicker": "lib/datetime_picker/bootstrap-datetimepicker",
"datetimepicker": "lib/datetime_picker/bootstrap-datetimepicker.zh-CN"
}, },
shim: { shim: {
"bootstrap": {"deps": ['jquery']}, bootstrap: {deps: ["jquery"]},
"_datetimepicker": {"deps": ["jquery"]}, _datetimePicker: {dep: ["jquery"]},
"datetimepicker": {"deps": ["_datetimepicker"]} datetimePicker: {deps: ["_datetimePicker"]}
} }
}; };

View File

@@ -5,7 +5,7 @@
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["_code_mirror"], mod); define(["_codeMirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {

View File

@@ -7,12 +7,12 @@
// AMD module is defined // AMD module is defined
if (typeof define === "function" && define.amd) { if (typeof define === "function" && define.amd) {
define("validator/remote", ["jquery", "base", "csrf"], factory); define("validator/remote", ["jquery", "base", "csrfToken"], factory);
} else { } else {
// planted over the root! // planted over the root!
factory(root.jQuery, root.FormValidation); factory(root.jQuery, root.FormValidation);
} }
}(this, function ($, FormValidation, csrfHeader) { }(this, function ($, FormValidation, csrfTokenHeader) {
FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, {
'en_US': { 'en_US': {
remote: { remote: {
@@ -28,7 +28,7 @@
return true; return true;
var url = options.url; var url = options.url;
var xhr = $.ajax({ var xhr = $.ajax({
beforeSend: csrfHeader, beforeSend: csrfTokenHeader,
url: url, url: url,
dataType: 'json', dataType: 'json',
data: ajaxData, data: ajaxData,

View File

@@ -1,5 +1,5 @@
define("bs_alert", ["jquery", "bootstrap"], function($){ define("bsAlert", ["jquery", "bootstrap"], function($){
function bs_alert(content){ function bsAlert(content){
if(!$("#alert-modal").length) { if(!$("#alert-modal").length) {
var html = '<div class="modal fade" id="alert-modal" tabindex="-1" role="dialog"> ' + var html = '<div class="modal fade" id="alert-modal" tabindex="-1" role="dialog"> ' +
'<div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-header"> ' + '<div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-header"> ' +
@@ -13,5 +13,5 @@ define("bs_alert", ["jquery", "bootstrap"], function($){
$("#modal-text").html(content); $("#modal-text").html(content);
$("#alert-modal").modal(); $("#alert-modal").modal();
} }
return bs_alert; return bsAlert;
}); });

View File

@@ -1,5 +1,5 @@
define("code_mirror", ["_code_mirror", "code_mirror_clang"], function(CodeMirror){ define("codeMirror", ["_codeMirror", "codeMirrorClang"], function(CodeMirror){
function code_mirror(selector, language){ function codeMirror(selector, language){
return CodeMirror.fromTextArea(selector, return CodeMirror.fromTextArea(selector,
{ {
indentUnit: 4, indentUnit: 4,
@@ -8,5 +8,5 @@ define("code_mirror", ["_code_mirror", "code_mirror_clang"], function(CodeMirror
mode: language mode: language
}); });
} }
return code_mirror; return codeMirror;
}); });

View File

@@ -1,5 +1,5 @@
define("csrf",function(){ define("csrfToken",function(){
function get_cookie(cookie_name) { function getCookie(cookie_name) {
var name = cookie_name + "="; var name = cookie_name + "=";
var ca = document.cookie.split(';'); var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) { for (var i = 0; i < ca.length; i++) {
@@ -9,15 +9,15 @@ define("csrf",function(){
} }
return ""; return "";
} }
function csrfHeader(){ function csrfTokenHeader(){
// jquery的请求 // jquery的请求
if(arguments.length == 2) { if(arguments.length == 2) {
arguments[0].setRequestHeader("X-CSRFToken", get_cookie("csrftoken")); arguments[0].setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
} }
// 百度webuploader 的请求 // 百度webuploader 的请求
else if(arguments.length == 3){ else if(arguments.length == 3){
arguments[2]["X-CSRFToken"] = get_cookie("csrftoken"); arguments[2]["X-CSRFToken"] = getCookie("csrftoken");
} }
} }
return csrfHeader; return csrfTokenHeader;
}); });

View File

@@ -1,4 +1,4 @@
define("validation", define("formValidation",
[ 'base', [ 'base',
'helper', 'helper',
'framework/bootstrap', 'framework/bootstrap',

View File

@@ -1,4 +0,0 @@
/**
* @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);

View File

@@ -1,24 +0,0 @@
function _notify(notify_type, title, content){
$.notify({
title: title,
message: content
}, {
type: notify_type,
placement: {
from: "top",
align: "center"
},
offset: {
y: 50
},
delay: 3000,
timer: 1000
});
}
function show_info(title, content) {
_notify("info", title, content);
}
function show_warning(title, content) {
_notify("warning", title, content);
}

View File

@@ -1,5 +0,0 @@
/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
* Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
* */
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmValue=t,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);

View File

@@ -1,4 +1,4 @@
define("uploader", ["webuploader", "csrf"], function(webuploader,csrf){ define("uploader", ["webUploader", "csrfToken"], function(webuploader,csrfTokenHeader){
function uploader(selector, server, onSuccess, beforeUpload) { function uploader(selector, server, onSuccess, beforeUpload) {
var Webuploader= webuploader.create({ var Webuploader= webuploader.create({
auto: true, auto: true,
@@ -11,9 +11,9 @@ define("uploader", ["webuploader", "csrf"], function(webuploader,csrf){
pick: selector, pick: selector,
// 不压缩image, 默认如果是jpeg文件上传前会压缩一把再上传 // 不压缩image, 默认如果是jpeg文件上传前会压缩一把再上传
resize: false, resize: false,
uploadBeforeSend : csrf uploadBeforeSend : csrfTokenHeader
}); });
Webuploader.on("uploadBeforeSend",csrf); Webuploader.on("uploadBeforeSend",csrfTokenHeader);
Webuploader.on("uploadSuccess", onSuccess); Webuploader.on("uploadSuccess", onSuccess);
Webuploader.on("beforeFileQueued", beforeUpload); Webuploader.on("beforeFileQueued", beforeUpload);
return Webuploader; return Webuploader;

View File

@@ -9,15 +9,15 @@ from rest_framework.views import APIView
from django.conf import settings from django.conf import settings
from judger.result import result from judge.judger.result import result
from judger_controller.tasks import judge from judge.judger_controller.tasks import judge
from account.decorators import login_required from account.decorators import login_required
from problem.models import Problem from problem.models import Problem
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page
from .serializers import CreateSubmissionSerializer from .serializers import CreateSubmissionSerializer
def _create_mondodb_connection(): def _create_mongodb_connection():
mongodb_setting = settings.MONGODB mongodb_setting = settings.MONGODB
connection = pymongo.MongoClient(host=mongodb_setting["HOST"], port=mongodb_setting["PORT"]) connection = pymongo.MongoClient(host=mongodb_setting["HOST"], port=mongodb_setting["PORT"])
return connection["oj"]["oj_submission"] return connection["oj"]["oj_submission"]
@@ -42,9 +42,7 @@ class SubmissionAPIView(APIView):
problem = Problem.objects.get(id=data["problem_id"]) problem = Problem.objects.get(id=data["problem_id"])
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_response(u"题目不存在") return error_response(u"题目不存在")
mongodb_setting = settings.DATABASES["mongodb"] collection = _create_mongodb_connection()
connection = pymongo.MongoClient(host=mongodb_setting["HOST"], port=mongodb_setting["PORT"])
collection = connection["oj"]["oj_submission"]
submission_id = str(collection.insert_one(data).inserted_id) submission_id = str(collection.insert_one(data).inserted_id)
judge.delay(submission_id, problem.time_limit, problem.memory_limit, problem.test_case_id) judge.delay(submission_id, problem.time_limit, problem.memory_limit, problem.test_case_id)
return success_response({"submission_id": submission_id}) return success_response({"submission_id": submission_id})
@@ -56,7 +54,7 @@ class SubmissionAPIView(APIView):
submission_id = request.GET.get("submission_id", None) submission_id = request.GET.get("submission_id", None)
if not submission_id: if not submission_id:
return error_response(u"参数错误") return error_response(u"参数错误")
submission = _create_mondodb_connection().find_one({"_id": ObjectId(submission_id), "user_id": request.user.id}) submission = _create_mongodb_connection().find_one({"_id": ObjectId(submission_id), "user_id": request.user.id})
if submission: if submission:
response_data = {"result": submission["result"]} response_data = {"result": submission["result"]}
if submission["result"] == 0: if submission["result"] == 0:
@@ -68,7 +66,7 @@ class SubmissionAPIView(APIView):
@login_required @login_required
def problem_my_submissions_list_page(request, problem_id): def problem_my_submissions_list_page(request, problem_id):
collection = _create_mondodb_connection() collection = _create_mongodb_connection()
submissions = collection.find({"problem_id": int(problem_id), "user_id": request.user.id}, submissions = collection.find({"problem_id": int(problem_id), "user_id": request.user.id},
projection=["result", "accepted_answer_info", "create_time", "language"], projection=["result", "accepted_answer_info", "create_time", "language"],
sort=[["create_time", -pymongo.ASCENDING]]) sort=[["create_time", -pymongo.ASCENDING]])
@@ -82,7 +80,7 @@ def problem_my_submissions_list_page(request, problem_id):
@login_required @login_required
def my_submission(request, submission_id): def my_submission(request, submission_id):
collection = _create_mondodb_connection() collection = _create_mongodb_connection()
submission = collection.find_one({"user_id": request.user.id, "_id": ObjectId(submission_id)}, submission = collection.find_one({"user_id": request.user.id, "_id": ObjectId(submission_id)},
projection=["result", "accepted_answer_info", "create_time", projection=["result", "accepted_answer_info", "create_time",
"language", "code", "problem_id", "info"]) "language", "code", "problem_id", "info"])

View File

@@ -101,9 +101,6 @@
<li class="list-group-item" id="li-user-user_list"> <li class="list-group-item" id="li-user-user_list">
<a href="#user/user_list">用户列表</a> <a href="#user/user_list">用户列表</a>
</li> </li>
<li class="list-group-item" id="li-user-user_group">
<a href="#user/user_group">用户分组</a>
</li>
<li class="list-group-header">小组管理</li> <li class="list-group-header">小组管理</li>
<li class="list-group-item" id="li-group-group"> <li class="list-group-item" id="li-group-group">
<a href="#group/group">小组列表</a> <a href="#group/group">小组列表</a>
@@ -124,8 +121,6 @@
</div> </div>
<script src="/static/js/config.js"></script> <script src="/static/js/config.js"></script>
<script src="/static/js/require.js"></script> <script src="/static/js/require.js"></script>
<script> <script>

View File

@@ -1,5 +1,5 @@
<div ms-controller="announcement" class="col-md-9"> <div ms-controller="announcement" class="col-md-9">
<h1>Announcement</h1> <h1>公告管理</h1>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>编号</th> <th>编号</th>
@@ -8,36 +8,38 @@
<th>更新时间</th> <th>更新时间</th>
<th>创建者</th> <th>创建者</th>
<th>状态</th> <th>状态</th>
<th>操作</th> <th></th>
</tr> </tr>
<tr ms-repeat="announcement"> <tr ms-repeat="announcementList">
<td>{{el.id}}</td> <td>{{ el.id }}</td>
<td>{{el.title}}</td> <td>{{ el.title }}</td>
<td>{{el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td> <td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{el.last_update_time|date("yyyy-MM-dd HH:mm:ss")}}</td> <td>{{ el.last_update_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{el.created_by.username}}</td> <td>{{ el.created_by.username }}</td>
<td>{{getState(el)}}</td> <td>{{ getState(el)}}</td>
<td> <td>
<button class="btn-sm btn-info" ms-click="enEdit(el)">编辑</button> <button class="btn-sm btn-info" ms-click="editAnnouncement(el)">编辑</button>
</td> </td>
</tr> </tr>
</table> </table>
<div class="form-group"> <div class="form-group">
<label>仅显示可见 <input ms-duplex-checked="visableOnly" type="checkbox"/></label> <label>仅显示可见 <input ms-duplex-checked="showVisibleOnly" type="checkbox"/></label>
</div> </div>
<div class="text-right"> <div class="right">
页数:{{page}}/{{page_count}}&nbsp;&nbsp; 页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp;
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button> <button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button> <button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div> </div>
<div ms-visible="isEditing"> <div ms-visible="editingAnnouncementId">
<h3>编辑公告</h3> <h3>编辑公告</h3>
<div class="form-group"><label for="title">标题</label>
<div class="form-group">
<label>标题</label>
<input name="title" type="text" class="form-control" id="newTitle" placeholder="公告标题" value=""></div> <input name="title" type="text" class="form-control" id="newTitle" placeholder="公告标题" value=""></div>
<div class="form-group"> <div class="form-group">
<label>内容</label> <label>内容</label>
<textarea id="editAnnouncementEditor"></textarea> <textarea id="edit-announcement-editor"></textarea>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>可见 <input ms-duplex-checked="announcementVisible" type="checkbox"/></label> <label>可见 <input ms-duplex-checked="announcementVisible" type="checkbox"/></label>
@@ -45,17 +47,17 @@
<div class="form-group"> <div class="form-group">
<button ms-click="submitChange()" class="btn btn-primary">提交</button> <button ms-click="submitChange()" class="btn btn-primary">提交</button>
&nbsp;&nbsp; &nbsp;&nbsp;
<button ms-click="disEdit()" class="btn btn-danger">取消</button> <button ms-click="cancelEdit()" class="btn btn-danger">取消</button>
</div> </div>
</div> </div>
<h3>添加公告</h3> <h3>添加公告</h3>
<form id="announcement-form"> <form id="announcement-form">
<div class="form-group"><label for="title">标题</label> <div class="form-group"><label>标题</label>
<input name="title" type="text" class="form-control" id="title" placeholder="公告标题"></div> <input name="title" type="text" class="form-control" id="title" placeholder="公告标题"></div>
<div class="form-group"> <div class="form-group">
<label>内容</label> <label>内容</label>
<textarea id="editor" placeholder="公告内容"></textarea> <textarea id="create-announcement-editor" placeholder="公告内容"></textarea>
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="submit" class="btn btn-primary">提交</button> <button type="submit" class="btn btn-primary">提交</button>

View File

@@ -75,13 +75,18 @@
<div class="col-md-12"> <div class="col-md-12">
<label>添加题目</label> <label>添加题目</label>
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="add_problem()">添加</a> <a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="add_problem()">添加</a>
<div class="col-md-12">
<label>上传测试用例</label> <div class="col-md-12">
<label>选择题号</label><select ms-duplex="problemNo"><option value="-1">未指定</option><option ms-repeat="problems" ms-attr-value="$index+1">{{$index+1}}</option></select> <label>上传测试用例</label>
<div id="uploader"> <label>选择题号</label><select ms-duplex="problemNo">
<div>选择文件</div> <option value="-1">未指定</option>
</div> <option ms-repeat="problems" ms-attr-value="$index+1">{{$index+1}}</option>
</div> </select>
<div id="uploader">
<div>选择文件</div>
</div>
</div>
</div> </div>
<div class="col-md-12"> <div class="col-md-12">
<div class="problem" ms-repeat-problem="problems"> <div class="problem" ms-repeat-problem="problems">
@@ -89,7 +94,7 @@
<div class="panel-heading"> <div class="panel-heading">
<span class="panel-title">题目{{$index + 1}} </span> <span class="panel-title">题目{{$index + 1}} </span>
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="toggle(problem)"> <a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="toggle(problem)">
{{getBtnContent(problem)}} {{ getBtnContent(problem)}}
</a> </a>
<a href="javascript:void(0)" class="btn btn-danger btn-sm" ms-click="del_problem(problem)"> <a href="javascript:void(0)" class="btn btn-danger btn-sm" ms-click="del_problem(problem)">
删除 删除
@@ -97,17 +102,19 @@
</div> </div>
<div class="panel-body" ms-visible="problem.visible"> <div class="panel-body" ms-visible="problem.visible">
<div class="form-group col-md-12"> <div class="form-group col-md-12">
<label>题目标题</label> <label>题目标题</label>
<input type="text" name="problem_name[]" class="form-control" ms-duplex="problem.title"> <input type="text" name="problem_name[]" class="form-control" ms-duplex="problem.title">
</div>
<div class="form-group col-md-12">
<label>题目描述</label>
<textarea ms-attr-id="problem-{{ problem.id }}-description" placeholder="这里输入内容"
ms-duplex="problem.description"></textarea>
<small ms-visible="problem.description==''" style="color:red">请填写题目描述</small>
</div> </div>
<div class="form-group col-md-12">
<label>题目描述</label>
<textarea ms-attr-id="problem-{{ problem.id }}-description" placeholder="这里输入内容" ms-duplex="problem.description"></textarea>
<small ms-visible="problem.description==''" style="color:red">请填写题目描述</small>
</div>
<div class="form-group col-md-12"> <div class="form-group col-md-12">
<label>提示</label> <label>提示</label>
<textarea ms-attr-id="problem-{{ problem.id }}-hint" placeholder="这里输入内容" ms-duplex="problem.hint"></textarea> <textarea ms-attr-id="problem-{{ problem.id }}-hint" placeholder="这里输入内容"
ms-duplex="problem.hint"></textarea>
</div> </div>
<div class="col-md-3 form-group"> <div class="col-md-3 form-group">
<label>cpu</label> <label>cpu</label>
@@ -119,19 +126,24 @@
</div> </div>
<div class="col-md-3 form-group"> <div class="col-md-3 form-group">
<label>难度</label> <label>难度</label>
<input type="number" name="difficulty[]" class="form-control" ms-duplex="problem.difficulty"> <input type="number" name="difficulty[]" class="form-control"
ms-duplex="problem.difficulty">
</div> </div>
<div class="col-md-12"> <div class="col-md-12">
<label>样例</label> <label>样例</label>
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="add_sample(problem)">添加</a> <a href="javascript:void(0)" class="btn btn-primary btn-sm"
ms-click="add_sample(problem)">添加</a>
<div class="sample"> <div class="sample">
<div class="panel panel-default sample-panel" ms-repeat-sample="problem.samples"> <div class="panel panel-default sample-panel" ms-repeat-sample="problem.samples">
<div class="panel-heading"> <div class="panel-heading">
<span class="panel-title">样例{{$index + 1}}</span> <span class="panel-title">样例{{$index + 1}}</span>
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="toggle(sample)"> <a href="javascript:void(0)" class="btn btn-primary btn-sm"
{{getBtnContent(sample)}} ms-click="toggle(sample)">
{{ getBtnContent(sample)}}
</a> </a>
<a href="javascript:void(0)" class="btn btn-danger btn-sm" ms-click="del_sample(problem, sample)"> <a href="javascript:void(0)" class="btn btn-danger btn-sm"
ms-click="del_sample(problem, sample)">
删除 删除
</a> </a>
</div> </div>
@@ -167,8 +179,8 @@
</tr> </tr>
<tr ms-repeat="problem.testCaseList"> <tr ms-repeat="problem.testCaseList">
<td>{{$index}}</td> <td>{{$index}}</td>
<td>{{el.input}}</td> <td>{{ el.input }}</td>
<td>{{el.output}}</td> <td>{{ el.output }}</td>
</tr> </tr>
</table> </table>
</div> </div>

View File

@@ -1,14 +1,14 @@
<div ms-controller="group" class="col-md-9"> <div ms-controller="group" class="col-md-9">
<h1>小组管理</h1> <h1>小组管理</h1>
<div class="text-right">
<div class="right">
<form class="form-inline" onsubmit="return false;"> <form class="form-inline" onsubmit="return false;">
<div class="form-group-sm"> <div class="form-group-sm">
<label>搜索</label> <label>搜索</label>
<input class="form-control" placeholder="请输入关键词" ms-duplex="keyword"> <input class="form-control" placeholder="请输入关键词" ms-duplex="keyword">
<input type="submit" value="搜索" class="btn btn-primary" ms-click="getPage(1)"> <input type="submit" value="搜索" class="btn btn-primary" ms-click="search()">
</div> </div>
</form> </form>
<br>
</div> </div>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
@@ -20,10 +20,10 @@
<th>设置</th> <th>设置</th>
<th></th> <th></th>
</tr> </tr>
<tr ms-repeat="group_list"> <tr ms-repeat="groupList">
<td>{{el.id}}</td> <td>{{ el.id }}</td>
<td>{{el.name}}</td> <td>{{ el.name }}</td>
<td>{{el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td> <td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{ el.members_number }}</td> <td>{{ el.members_number }}</td>
<td>{{ getGroupSettingString(el.join_group_setting) }}</td> <td>{{ getGroupSettingString(el.join_group_setting) }}</td>
@@ -33,10 +33,10 @@
</tr> </tr>
</table> </table>
<div class="text-right"> <div class="right">
页数:{{page}}/{{page_count}}&nbsp;&nbsp; 页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp;
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button> <button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button> <button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
<div ms-controller="group_detail" class="col-md-9"> <div ms-controller="groupDetail" class="col-md-9">
<h1>小组成员管理</h1> <h1>小组成员管理</h1>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
@@ -8,7 +8,7 @@
<th>加入时间</th> <th>加入时间</th>
<th></th> <th></th>
</tr> </tr>
<tr ms-repeat="member_list"> <tr ms-repeat="memberList">
<td>{{ el.user.id }}</td> <td>{{ el.user.id }}</td>
<td>{{ el.user.username }}</td> <td>{{ el.user.username }}</td>
<td>{{ el.user.real_name }}</td> <td>{{ el.user.real_name }}</td>
@@ -21,9 +21,9 @@
</table> </table>
<div class="text-right"> <div class="text-right">
页数:{{ page }}/{{ page_count }}&nbsp;&nbsp; 页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp;
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button> <button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button> <button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div> </div>
<h1>修改小组信息</h1> <h1>修改小组信息</h1>
@@ -42,9 +42,9 @@
<div class="form-group"> <div class="form-group">
<label>加入小组设置</label> <label>加入小组设置</label>
<input type="radio" name="join_group_setting" value="0" ms-duplex-string="checked_setting">允许任何人加入 <input type="radio" name="join_group_setting" value="0" ms-duplex-string="checkedSetting">允许任何人加入
<input type="radio" name="join_group_setting" value="1" ms-duplex-string="checked_setting">提交请求后管理员审核 <input type="radio" name="join_group_setting" value="1" ms-duplex-string="checkedSetting">提交请求后管理员审核
<input type="radio" name="join_group_setting" value="2" ms-duplex-string="checked_setting">不允许任何人加入 <input type="radio" name="join_group_setting" value="2" ms-duplex-string="checkedSetting">不允许任何人加入
</div> </div>
<button class="btn btn-primary" type="submit">提交</button> <button class="btn btn-primary" type="submit">提交</button>
@@ -52,4 +52,4 @@
</form> </form>
</div> </div>
<script src="/static/js/app/admin/group/group_detail.js"></script> <script src="/static/js/app/admin/group/groupDetail.js"></script>

View File

@@ -1,31 +1,31 @@
<div ms-controller="request_list" class="col-md-9"> <div ms-controller="requestList" class="col-md-9">
<h1>加入小组请求管理</h1> <h1>加入小组请求管理</h1>
<table class="table table-striped"> <table class="table table-striped">
<tr> <tr>
<th>创建时间</th> <th>创建时间</th>
<th>用户</th>
<th>小组</th> <th>小组</th>
<th>用户</th>
<th>附加消息</th> <th>附加消息</th>
<th></th> <th></th>
</tr> </tr>
<tr ms-repeat="request_list"> <tr ms-repeat="requestList">
<td>{{el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td> <td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{ el.group.name }}</td> <td>{{ el.group.name }}</td>
<td>{{ el.user.username }}</td> <td>{{ el.user.username }}</td>
<td>{{ el.message }}</td> <td>{{ el.message }}</td>
<td> <td>
<button class="btn-sm btn-success" ms-click="processRequest(el.id, true)">同意</button> <button class="btn-sm btn-success" ms-click="processRequest(el, true)">同意</button>
<button class="btn-sm btn-danger" ms-click="processRequest(el.id, false)">拒绝</button> <button class="btn-sm btn-danger" ms-click="processRequest(el, false)">拒绝</button>
</td> </td>
</tr> </tr>
</table> </table>
<div class="text-right"> <div class="text-right">
页数:{{page}}/{{page_count}}&nbsp;&nbsp; 页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp;
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button> <button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button> <button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div> </div>
</div> </div>
<script src="/static/js/app/admin/group/join_group_request_list.js"></script> <script src="/static/js/app/admin/group/joinGroupRequestList.js"></script>

View File

@@ -1,4 +1,4 @@
<div ms-controller="add_problem" class="col-md-9"> <div ms-controller="addProblem" class="col-md-9">
<form id="add-problem-form"> <form id="add-problem-form">
<div class="form-group col-md-12"> <div class="form-group col-md-12">
@@ -41,27 +41,27 @@
<div class="col-md-12 form-group"> <div class="col-md-12 form-group">
<label>输入描述</label><br> <label>输入描述</label><br>
<textarea class="form-control" rows="5" name="input_description" <textarea class="form-control" rows="5" name="input_description"
ms-duplex="input_description"></textarea> ms-duplex="inputDescription"></textarea>
</div> </div>
<div class="col-md-12 form-group"> <div class="col-md-12 form-group">
<label>输出描述</label><br> <label>输出描述</label><br>
<textarea class="form-control" rows="5" name="output_description" <textarea class="form-control" rows="5" name="output_description"
ms-duplex="output_description"></textarea> ms-duplex="outputDescription"></textarea>
</div> </div>
<div class="col-md-12"><br> <div class="col-md-12"><br>
<label>样例</label> <label>样例</label>
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="add_sample()">添加</a> <a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="addSample()">添加</a>
<div class="sample"> <div class="sample">
<div class="panel panel-default sample-panel" ms-repeat-sample="samples"> <div class="panel panel-default sample-panel" ms-repeat-sample="samples">
<div class="panel-heading"> <div class="panel-heading">
<span class="panel-title">样例{{$index + 1}}</span> <span class="panel-title">样例{{$index + 1}}</span>
<a href="javascript:void(0)" class="btn btn-primary btn-sm" <a href="javascript:void(0)" class="btn btn-primary btn-sm"
ms-click="toggle_sample(sample)"> ms-click="toggleSample(sample)">
{{ getBtnContent(sample)}} {{ getBtnContent(sample)}}
</a> </a>
<a href="javascript:void(0)" class="btn btn-danger btn-sm" <a href="javascript:void(0)" class="btn btn-danger btn-sm"
ms-click="del_sample(sample)"> ms-click="delSample(sample)">
删除 删除
</a> </a>
</div> </div>

View File

@@ -0,0 +1,123 @@
<div ms-controller="editProblem" class="col-md-9">
<form id="edit-problem-form">
<div class="form-group col-md-12">
<label>题目标题</label>
<input type="text" name="title" autofocus class="form-control" ms-duplex="title">
</div>
<div class="form-group col-md-12">
<label>题目描述</label>
<textarea id="problemDescription" placeholder="这里输入内容(此内容不能为空)" ms-duplex="description"></textarea>
<small ms-visible="description==''" style="color:red">请填写题目描述</small>
</div>
<div class="col-md-3">
<div class="form-group"><label>时间限制(ms)</label>
<input type="number" name="cpu" class="form-control" ms-duplex="timeLimit">
</div>
</div>
<div class="col-md-3">
<div class="form-group"><label>内存限制(MB)</label>
<input type="number" name="memory" class="form-control" ms-duplex="memoryLimit">
</div>
</div>
<div class="col-md-3">
<div class="form-group"><label>难度</label>
<input type="number" name="difficulty" class="form-control" ms-duplex="difficulty">
</div>
</div>
<div class="col-md-3 form-group">
<label>前台是否可见</label><br>
<label><input type="checkbox" ms-duplex-checked="visible">
<small> 可见</small>
</label>
</div>
<div id="tag" class="col-md-12">
<label>标签</label><br>
<input type="text" id="tags">
</div>
<div class="col-md-12 form-group">
<label>输入描述</label><br>
<textarea class="form-control" rows="5" name="input_description"
ms-duplex="inputDescription"></textarea>
</div>
<div class="col-md-12 form-group">
<label>输出描述</label><br>
<textarea class="form-control" rows="5" name="output_escription"
ms-duplex="outputDescription"></textarea>
</div>
<div class="col-md-12"><br>
<label>样例</label>
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="addSample()">添加</a>
<div class="sample">
<div class="panel panel-default sample-panel" ms-repeat-sample="samples">
<div class="panel-heading">
<span class="panel-title">样例{{$index + 1}}</span>
<a href="javascript:void(0)" class="btn btn-primary btn-sm"
ms-click="toggleSample(sample)">
{{ getBtnContent(sample)}}
</a>
<a href="javascript:void(0)" class="btn btn-danger btn-sm"
ms-click="delSample(sample)">
删除
</a>
</div>
<div class="panel-body row" ms-visible="sample.visible">
<div class="col-md-6">
<div class="form-group">
<label>样例输入</label>
<textarea class="form-control" rows="5" ms-duplex="sample.input"></textarea>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>样例输出</label>
<textarea class="form-control" rows="5" ms-duplex="sample.output"></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12"><br>
<label>测试数据(当前已上传,继续上传将覆盖原有测试用例)</label><br>
<small class="text-info">请将所有测试用例打包在一个文件中上传所有文件要在压缩包的根目录且输入输出文件名要以从1开始连续数字标识要对应例如<br>
1.in 1.out 2.in 2.out
</small>
<table class="table table-striped" ms-visible="uploadSuccess">
<tr>
<td>编号</td>
<td>输入文件名</td>
<td>输出文件名</td>
</tr>
<tr ms-repeat="testCaseList">
<td>{{ $index + 1 }}</td>
<td>{{ el.input }}</td>
<td>{{ el.output }}</td>
</tr>
</table>
</div>
<div class="col-md-12">
<div class="form-group">
<div id="testCaseFile">选择文件</div>
</div>
</div>
<div class="form-group col-md-12">
<label>提示</label>
<textarea id="hint" placeholder="这里输入内容" ms-duplex="hint"></textarea>
</div>
<div class="form-group col-md-12">
<label>来源</label>
<input type="text" name="source" class="form-control" ms-duplex="source">
</div>
<div class="col-md-12">
<input type="submit" class="btn btn-success btn-lg" value="发布题目" id="submitBtn">
</div>
</form>
</div>
<script src="/static/js/app/admin/problem/edit_problem.js"></script>

View File

@@ -0,0 +1,40 @@
<div ms-controller="problemList" class="col-md-9">
<h1>题目列表</h1>
<div class="right">
<form class="form-inline" onsubmit="return false;">
<div class="form-group-sm">
<label>搜索</label>
<input name="keyWord" class="form-control" placeholder="请输入关键词" ms-duplex="keyword">
<input type="submit" value="搜索" class="btn btn-primary" ms-click="getPage(1)">
</div>
</form>
<br>
</div>
<table class="table table-striped">
<tr>
<th>ID</th>
<th>题目</th>
<th>创建时间</th>
<th>作者</th>
<td>通过次数/提交总数</td>
<td></td>
</tr>
<tr ms-repeat="problemList">
<td>{{ el.id }}</td>
<td>{{ el.title }}</td>
<td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{ el.created_by.username }}</td>
<td>{{ el.total_accepted_number }}/{{ el.total_submit_number }}</td>
<td>
<button class="btn-sm btn-info" ms-click="showEditProblemPage(el.id)">编辑</button>
</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/problem/problem.js"></script>

View File

@@ -1,11 +1,12 @@
<div ms-controller="user_list" class="col-md-9"> <div ms-controller="userList" class="col-md-9">
<h1>User</h1> <h1>用户管理</h1>
<div class="text-right">
<div class="right">
<form class="form-inline" onsubmit="return false;"> <form class="form-inline" onsubmit="return false;">
<div class="form-group-sm"> <div class="form-group-sm">
<label>搜索</label> <label>搜索</label>
<input name="keyWord" class="form-control" placeholder="请输入关键词" ms-duplex="key_word"> <input name="keyWord" class="form-control" placeholder="请输入关键词" ms-duplex="keyWord">
<input type="submit" value="搜索" class="btn btn-primary" ms-click="getPage(1)"> <input type="submit" value="搜索" class="btn btn-primary" ms-click="search()">
</div> </div>
</form> </form>
<br> <br>
@@ -21,16 +22,16 @@
<th>用户类型</th> <th>用户类型</th>
<th>修改</th> <th>修改</th>
</tr> </tr>
<tr ms-repeat="user_list"> <tr ms-repeat="userList">
<td>{{el.id}}</td> <td>{{ el.id }}</td>
<td>{{el.username}}</td> <td>{{ el.username }}</td>
<td>{{el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td> <td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{el.last_login|date("yyyy-MM-dd HH:mm:ss")}}</td> <td>{{ el.last_login|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td>{{el.real_name}}</td> <td>{{ el.real_name }}</td>
<td>{{el.email}}</td> <td>{{ el.email }}</td>
<td>{{user_type[el.admin_type]}}</td> <td>{{ userType[el.admin_type]}}</td>
<td> <td>
<button class="btn-sm btn-info" ms-click="enEdit(el)">编辑</button> <button class="btn-sm btn-info" ms-click="editUser(el)">编辑</button>
</td> </td>
</tr> </tr>
</table> </table>
@@ -38,12 +39,13 @@
<label>仅显示管理员 <input ms-duplex-checked="showAdminOnly" type="checkbox"/></label> <label>仅显示管理员 <input ms-duplex-checked="showAdminOnly" type="checkbox"/></label>
</div> </div>
<div class="text-right"> <div class="text-right">
页数:{{page}}/{{page_count}}&nbsp;&nbsp; 页数:{{ page }}/{{ totalPage }}&nbsp;&nbsp;
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button> <button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button> <button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
</div> </div>
<div ms-visible="isEditing"> <div ms-visible="editingUserId">
<h3>修改用户信息</h3> <h3>修改用户信息</h3>
<form id="edit_user-form"> <form id="edit_user-form">
<div class="row"> <div class="row">
<div class="form-group col-md-4"><label>ID</label> <div class="form-group col-md-4"><label>ID</label>
@@ -53,7 +55,7 @@
<input name="username" type="text" class="form-control" ms-duplex="username"> <input name="username" type="text" class="form-control" ms-duplex="username">
</div> </div>
<div class="form-group col-md-4"><label>真实姓名</label> <div class="form-group col-md-4"><label>真实姓名</label>
<input name="real_name" type="text" class="form-control" ms-duplex="real_name"> <input name="real_name" type="text" class="form-control" ms-duplex="realName">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -65,8 +67,8 @@
<input name="email" type="email" class="form-control" ms-duplex="email"> <input name="email" type="email" class="form-control" ms-duplex="email">
</div> </div>
<div class="form-group col-md-4"><label>用户类型</label> <div class="form-group col-md-4"><label>用户类型</label>
<select name="admin_type" class="form-control" ms-duplex="admin_type"> <select name="admin_type" class="form-control" ms-duplex="adminType">
<option ms-repeat="user_type" ms-attr-value="$index">{{el}}</option> <option ms-repeat="userType" ms-attr-value="$index">{{ el }}</option>
</select> </select>
</div> </div>
</div> </div>
@@ -76,4 +78,4 @@
</form> </form>
</div> </div>
</div> </div>
<script src="/static/js/app/admin/user/user_list.js"></script> <script src="/static/js/app/admin/user/userList.js"></script>

View File

@@ -1,34 +1,36 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
<div class="container main"> <div class="container main">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
<h2 class="text-center">修改密码</h2> <h2 class="text-center">修改密码</h2>
<form id="change_password-form"> <form id="change_password-form">
<div class="form-group"> <div class="form-group">
<label for="username">用户名</label> <label for="username">用户名</label>
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名" <input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
autofocus> autofocus>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password">旧密码</label> <label for="password">旧密码</label>
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码"> <input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="new_password">新密码</label> <label for="new_password">新密码</label>
<input type="password" class="form-control input-lg" id="new_password" name="new_password" placeholder="新密码"> <input type="password" class="form-control input-lg" id="new_password" name="new_password"
</div> placeholder="新密码">
<div class="form-group"> </div>
<label for="confirm_password">确认密码</label> <div class="form-group">
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password" placeholder="确认密码"> <label for="confirm_password">确认密码</label>
</div> <input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password"
<div class="form-group"> placeholder="确认密码">
<button type="submit" class="btn btn-primary">提交</button> </div>
</div> <div class="form-group">
</form> <button type="submit" class="btn btn-primary">提交</button>
</div>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block js_block %} {% block js_block %}
<script src="/static/js/app/oj/account/change_password.js"></script> <script src="/static/js/app/oj/account/change_password.js"></script>
{% endblock %} {% endblock %}

View File

@@ -1,26 +1,26 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
<div class="container main"> <div class="container main">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
<h2 class="text-center">用户登录</h2> <h2 class="text-center">用户登录</h2>
<form id="login-form"> <form id="login-form">
<div class="form-group"> <div class="form-group">
<label for="username">用户名</label> <label for="username">用户名</label>
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名" <input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
autofocus> autofocus>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password">密码</label> <label for="password">密码</label>
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码"> <input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="submit" class="btn btn-primary">提交</button> <button type="submit" class="btn btn-primary">提交</button>
</div> </div>
</form> </form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block js_block %} {% block js_block %}
<script src="/static/js/app/oj/account/login.js"></script> <script src="/static/js/app/oj/account/login.js"></script>
{% endblock %} {% endblock %}

View File

@@ -1,38 +1,39 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
<div class="container main"> <div class="container main">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
<h2 class="text-center">用户注册</h2> <h2 class="text-center">用户注册</h2>
<form id="register-form"> <form id="register-form">
<div class="form-group"> <div class="form-group">
<label for="username">用户名</label> <label for="username">用户名</label>
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名" <input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
autofocus> autofocus>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="real_name">真实姓名</label> <label for="real_name">真实姓名</label>
<input type="text" class="form-control input-lg" id="real_name" name="real_name" placeholder="真实姓名"> <input type="text" class="form-control input-lg" id="real_name" name="real_name" placeholder="真实姓名">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="email">邮箱地址</label> <label for="email">邮箱地址</label>
<input type="email" class="form-control input-lg" id="email" name="email" placeholder="邮箱地址"> <input type="email" class="form-control input-lg" id="email" name="email" placeholder="邮箱地址">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password">密码</label> <label for="password">密码</label>
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码"> <input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="confirm_password">确认密码</label> <label for="confirm_password">确认密码</label>
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password" placeholder="确认密码"> <input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password"
</div> placeholder="确认密码">
<div class="form-group"> </div>
<button type="submit" class="btn btn-primary">提交</button> <div class="form-group">
</div> <button type="submit" class="btn btn-primary">提交</button>
</form> </div>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block js_block %} {% block js_block %}
<script src="/static/js/app/oj/account/register.js"></script> <script src="/static/js/app/oj/account/register.js"></script>
{% endblock %} {% endblock %}

View File

@@ -1,22 +1,22 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
<div class="container main"> <div class="container main">
<h1 class="text-center">{{ announcement.title }}</h1> <h1 class="text-center">{{ announcement.title }}</h1>
<p class="text-muted text-center"> <p class="text-muted text-center">
作者:{{ announcement.created_by }} 作者:{{ announcement.created_by }}
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
创建时间:{{ announcement.create_time }} 创建时间:{{ announcement.create_time }}
{% ifequal announcement.create_time announcement.last_update_time %} {% ifequal announcement.create_time announcement.last_update_time %}
{% else %} {% else %}
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
最后更新:{{ announcement.last_update_time }} 最后更新:{{ announcement.last_update_time }}
{% endifequal %} {% endifequal %}
</p> </p>
<div> <div>
<p>{{ announcement.content|safe }}</p> <p>{{ announcement.content|safe }}</p>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@@ -1,15 +1,15 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
<div class="container main"> <div class="container main">
<ul class="nav nav-tabs nav-tabs-google"> <ul class="nav nav-tabs nav-tabs-google">
<li role="presentation" class="active"> <li role="presentation" class="active">
<a href="problem.html">题目</a></li> <a href="problem.html">题目</a></li>
<li role="presentation"><a href="my_solutions_list.html">我的提交</a></li> <li role="presentation"><a href="my_solutions_list.html">我的提交</a></li>
<li role="presentation"><a href="#">排名</a></li> <li role="presentation"><a href="#">排名</a></li>
</ul> </ul>
<h2 class="text-center">第一次比赛</h2> <h2 class="text-center">第一次比赛</h2>
<p class="text-muted text-center"><b>开始时间:</b> 2015-6-8 19:00 <b>结束时间:</b> 2015-9-1 12:00</p> <p class="text-muted text-center"><b>开始时间:</b> 2015-6-8 19:00 <b>结束时间:</b> 2015-9-1 12:00</p>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -1,37 +1,39 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
<div class="container">
<div class="container"> <div class="container">
<div class="container">
<div class="jumbotron"> <div class="jumbotron">
<h1>青岛大学在线评测平台</h1> <h1>青岛大学在线评测平台</h1>
<p class="lead">走心的在线评测平台和算法交流社区,全新登场~</p> <p class="lead">走心的在线评测平台和算法交流社区,全新登场~</p>
<p><a class="btn btn-lg btn-primary" href="/problems/" role="button">开始刷题!</a></p>
</div>
<!-- Example row of columns -->
<div class="row">
<div class="col-lg-4">
<h2>全新UI 全新设计</h2>
<p>精心设计的UI和交互让你。。。编不下去了 </p>
</div>
<div class="col-lg-4">
<h2>分布式评测</h2>
<p>技术领先的高性能分布式评测机制,根据提交数量自动伸缩判题机器实例。</p>
</div>
<div class="col-lg-4">
<h2>高质量原创题目</h2>
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id
ligula
porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum
nibh,
ut fermentum massa.</p>
</div>
</div>
<p><a class="btn btn-lg btn-primary" href="/problems/" role="button">开始刷题!</a></p>
</div> </div>
<!-- Example row of columns -->
<div class="row">
<div class="col-lg-4">
<h2>全新UI 全新设计</h2>
<p>精心设计的UI和交互让你。。。编不下去了 </p>
</div>
<div class="col-lg-4">
<h2>分布式评测</h2>
<p>技术领先的高性能分布式评测机制,根据提交数量自动伸缩判题机器实例。</p>
</div>
<div class="col-lg-4">
<h2>高质量原创题目</h2>
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula
porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh,
ut fermentum massa.</p>
</div>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@@ -1,4 +1,3 @@
<h2 class="text-center">{{ problem.title }}</h2> <h2 class="text-center">{{ problem.title }}</h2>
<p class="text-muted text-center">发布时间 : {{ problem.create_time }}&nbsp;&nbsp; <p class="text-muted text-center">发布时间 : {{ problem.create_time }}&nbsp;&nbsp;

View File

@@ -1,9 +1,9 @@
{% extends 'oj_base.html' %} {% extends 'oj_base.html' %}
{% block css_block %} {% block css_block %}
<style> <style>
.CodeMirror{ .CodeMirror {
height: auto; height: auto;
} }
</style> </style>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
@@ -29,7 +29,7 @@
{% ifequal submission.result 4 %} {% ifequal submission.result 4 %}
<p>{{ submission.info }}</p> <p>{{ submission.info }}</p>
{% endifequal %} {% endifequal %}
<p>提交时间 : {{ submission.create_time }}</p> <p>提交时间 : {{ submission.create_time }}</p>
</div> </div>
</div> </div>
<div id="code-field"> <div id="code-field">
@@ -40,7 +40,7 @@
{% endblock %} {% endblock %}
{% block js_block %} {% block js_block %}
<script> <script>
require(["jquery", "code_mirror"], function ($, code_mirror) { require(["jquery", "codeMirror"], function ($, codeMirror) {
{% ifequal submission.language 1 %} {% ifequal submission.language 1 %}
var language = "text/x-csrc"; var language = "text/x-csrc";
{% else %} {% else %}
@@ -50,8 +50,8 @@
var language = "text/x-java"; var language = "text/x-java";
{% endifequal %} {% endifequal %}
{% endifequal %} {% endifequal %}
var code_editor = code_mirror($("#code-editor")[0], language); var codeEditor = codeMirror($("#code-editor")[0], language);
code_editor.setOption("readOnly", true); codeEditor.setOption("readOnly", true);
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -1,11 +1,17 @@
{% extends "oj_base.html" %} {% extends "oj_base.html" %}
{% block body %} {% block body %}
{% load problem %}
<div class="container main" ms-controller="problem_list"> <div class="container main" ms-controller="problem_list">
<div class="row"> <div class="row">
<div class="col-lg-9"> <div class="col-lg-9">
<div class="row"> <div class="row">
<div class="col-lg-3 col-lg-offset-9"> <div class="search-box">
<input type="text" class="form-control" placeholder="搜索题号,标题"> <form class="form-inline" onsubmit="return false;">
<div class="form-group-sm">
<input name="keyWord" class="form-control" placeholder="请输入关键词" ms-duplex="key_word">
<input type="submit" value="搜索" class="btn btn-primary" ms-click="getPage(1)">
</div>
</form>
</div> </div>
</div> </div>
<div> <div>
@@ -19,28 +25,33 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> {% for item in problems %}
<th scope="row"><a href="/problem/1/">1</a></th> <tr>
<td><a href="/problem/1/">Mark</a></td> <th scope="row"><a href="/problem/{{ item.id }}/">{{ item.id }}</a></th>
<td>Otto</td> <td><a href="/problem/{{ item.id }}/">{{ item.title }}</a></td>
<td>@mdo</td> <td>{{ item.difficulty }}</td>
</tr> <td>{{ item|accepted_radio }}</td>
<tr> </tr>
<th scope="row">2</th> {% endfor %}
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td>Larry</td>
<td>the Bird</td>
<td>@twitter</td>
</tr>
</tbody> </tbody>
</table> </table>
<nav>
<ul class="pager">
{% if previous_page %}
<li class="previous"><a
href="/problems/{{ previous_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">
<span aria-hidden="true">&larr;</span> 上一页</a></li>
{% endif %}
{% if next_page %}
<li class="next"><a
href="/problems/{{ next_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">下一页 <span
aria-hidden="true">&rarr;</span></a></li>
{% endif %}
</ul>
</nav>
</div> </div>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<div class="panel panel-info"> <div class="panel panel-info">
<div class="panel-heading"> <div class="panel-heading">
@@ -87,5 +98,5 @@
{% endblock %} {% endblock %}
{% block js_block %} {% block js_block %}
<script src="/static/js/app/oj/problem/problem_list.js"></script> <script src="/static/js/app/oj/problem/problem_list.js"></script>
{% endblock %} {% endblock %}

View File

@@ -48,28 +48,28 @@
<li><a href="/about/">关于</a></li> <li><a href="/about/">关于</a></li>
</ul> </ul>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
李扬 李扬
<span class="caret"></span></a> <span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#">我的提交</a></li> <li><a href="#">我的提交</a></li>
<li><a href="#">我的资料</a></li> <li><a href="#">我的资料</a></li>
<li role="separator" class="divider"></li> <li role="separator" class="divider"></li>
<li><a href="#">退出</a></li> <li><a href="#">退出</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
{% else %} {% else %}
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li class="dropdown"> <li class="dropdown">
<a href="/login/" class="dropdown-toggle"> <a href="/login/" class="dropdown-toggle">
登录 登录
</a> </a>
</li> </li>
</ul> </ul>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@@ -0,0 +1,14 @@
# coding=utf-8
def get_problem_accepted_radio(problem):
if problem.total_accepted_number:
return int((problem.total_accepted_number * 100) / problem.total_submit_number)
return 0
from django import template
register = template.Library()
register.filter("accepted_radio", get_problem_accepted_radio)