mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2025-01-19 19:14:44 +00:00
修改 js 的命名风格
This commit is contained in:
parent
d031f14a68
commit
025335b40a
@ -33,8 +33,14 @@ class CreateProblemSerializer(serializers.Serializer):
|
||||
hint = serializers.CharField(max_length=3000, required=False, default=None)
|
||||
|
||||
|
||||
class ProblemTagSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ProblemTag
|
||||
|
||||
|
||||
class ProblemSerializer(serializers.ModelSerializer):
|
||||
samples = JSONField()
|
||||
tags = ProblemTagSerializer(many=True)
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@ -58,17 +64,11 @@ class EditProblemSerializer(serializers.Serializer):
|
||||
time_limit = serializers.IntegerField()
|
||||
memory_limit = serializers.IntegerField()
|
||||
difficulty = serializers.IntegerField()
|
||||
tags = serializers.ListField(child=serializers.IntegerField())
|
||||
tags = serializers.ListField(child=serializers.CharField(max_length=20))
|
||||
samples = ProblemSampleSerializer()
|
||||
hint = serializers.CharField(max_length=10000)
|
||||
visible = serializers.BooleanField()
|
||||
|
||||
|
||||
|
||||
class ProblemTagSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ProblemTag
|
||||
|
||||
|
||||
class CreateProblemTagSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(max_length=10)
|
||||
|
@ -60,6 +60,7 @@ class ProblemAdminAPIView(APIView):
|
||||
serializer = CreateProblemSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
data = serializer.data
|
||||
print data
|
||||
problem = Problem.objects.create(title=data["title"],
|
||||
description=data["description"],
|
||||
input_description=data["input_description"],
|
||||
@ -114,20 +115,30 @@ class ProblemAdminAPIView(APIView):
|
||||
# 删除原有的标签的对应关系
|
||||
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()
|
||||
return success_response(ProblemSerializer(problem).data)
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
|
||||
class ProblemAPIView(APIView):
|
||||
def get(self, request):
|
||||
"""
|
||||
题目分页json api接口
|
||||
---
|
||||
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")
|
||||
visible = request.GET.get("visible", None)
|
||||
if visible:
|
||||
@ -209,8 +220,7 @@ class TestCaseUploadAPIView(APIView):
|
||||
file_info["test_cases"][str(i + 1)] = {"input_name": str(i + 1) + ".in",
|
||||
"output_name": str(i + 1) + ".out",
|
||||
"output_md5": md5.hexdigest(),
|
||||
"output_size": os.path.getsize(
|
||||
test_case_dir + str(i + 1) + ".out")}
|
||||
"output_size": os.path.getsize(test_case_dir + str(i + 1) + ".out")}
|
||||
# 写入配置文件
|
||||
open(test_case_dir + "info", "w").write(json.dumps(file_info))
|
||||
|
||||
@ -222,12 +232,28 @@ class TestCaseUploadAPIView(APIView):
|
||||
|
||||
|
||||
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_response(u"不存在的页码")
|
||||
return error_page(request, u"不存在的页码")
|
||||
|
||||
previous_page = next_page = None
|
||||
|
||||
@ -241,5 +267,7 @@ def problem_list_page(request, page=1):
|
||||
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})
|
||||
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})
|
||||
|
@ -32,4 +32,9 @@
|
||||
.pie-chart-container{
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tag-editor{
|
||||
border: 1px solid #d9d9d9;
|
||||
border-top-color: silver;
|
||||
}
|
@ -28,4 +28,8 @@ label {
|
||||
|
||||
[ms-controller] {
|
||||
display: none
|
||||
}
|
||||
|
||||
.right{
|
||||
float: right;
|
||||
}
|
@ -24,17 +24,23 @@ define("admin", ["jquery", "avalon"], function ($, avalon) {
|
||||
var vm = avalon.define({
|
||||
$id: "admin",
|
||||
template_url: "template/" + hash + ".html",
|
||||
group_id: -1,
|
||||
groupId: -1,
|
||||
problemId: -1,
|
||||
hide_loading: function () {
|
||||
$("#loading-gif").hide();
|
||||
}
|
||||
});
|
||||
|
||||
vm.$watch("showGroupDetailPage", function(group_id){
|
||||
vm.group_id = group_id;
|
||||
vm.$watch("showGroupDetailPage", function(groupId){
|
||||
vm.groupId = groupId;
|
||||
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();
|
||||
|
||||
li_active("#li-" + hash.replace("/", "-"));
|
||||
|
@ -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 () {
|
||||
var announcementEditor = editor("#editor"); //创建新建公告的内容编辑器
|
||||
var editAnnouncementEditor = editor("#editAnnouncementEditor");
|
||||
avalon.ready(function () {
|
||||
avalon.vmodels.announcement = null;
|
||||
|
||||
var vm = avalon.define({
|
||||
$id: "announcement",
|
||||
//通用变量
|
||||
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 createAnnouncementEditor = editor("#create-announcement-editor");
|
||||
var editAnnouncementEditor = editor("#edit-announcement-editor");
|
||||
|
||||
},
|
||||
enEdit: function (el) { //点击编辑按钮的事件,显示/隐藏编辑区
|
||||
$("#newTitle").val(el.title);
|
||||
editAnnouncementEditor.setValue(el.content);
|
||||
vm.announcementVisible = el.visible;
|
||||
if (vm.isEditing == el.id)
|
||||
vm.isEditing = 0;
|
||||
else
|
||||
vm.isEditing = el.id;
|
||||
editAnnouncementEditor.focus();
|
||||
},
|
||||
disEdit: function () { //收起编辑框
|
||||
vm.isEditing = 0;
|
||||
},
|
||||
submitChange: function () { // 处理编辑公告提交事件,顺便验证字段为空
|
||||
var title = $("#newTitle").val(), content = editAnnouncementEditor.getValue();
|
||||
if (title != "") {
|
||||
if (content != "") {
|
||||
$.ajax({ //发送修改公告请求
|
||||
beforeSend: csrfHeader,
|
||||
var vm = avalon.define({
|
||||
$id: "announcement",
|
||||
//通用变量
|
||||
announcementList: [], // 公告列表数据项
|
||||
previousPage: 0, // 之前的页数
|
||||
nextPage: 0, // 之后的页数
|
||||
page: 1, // 当前页数
|
||||
editingAnnouncementId: 0, // 正在编辑的公告的ID, 为零说明未在编辑
|
||||
totalPage: 1, // 总页数
|
||||
showVisibleOnly: false, //仅显示可见公告
|
||||
// 编辑
|
||||
announcementVisible: 0,
|
||||
getState: function (el) { //获取公告当前状态,显示
|
||||
if (el.visible)
|
||||
return "可见";
|
||||
else
|
||||
return "隐藏";
|
||||
},
|
||||
getNext: function () {
|
||||
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/",
|
||||
dataType: "json",
|
||||
method: "put",
|
||||
data: {
|
||||
id: vm.isEditing,
|
||||
id: vm.editingAnnouncementId,
|
||||
title: title,
|
||||
content: content,
|
||||
visible: vm.announcementVisible
|
||||
},
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
bs_alert("修改成功");
|
||||
vm.isEditing = 0;
|
||||
bsAlert("修改成功");
|
||||
vm.editingAnnouncementId = 0;
|
||||
getPageData(1);
|
||||
}
|
||||
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 {
|
||||
bs_alert(data.data);
|
||||
bsAlert("标题和公告内容不得为空");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
vm.$watch("showVisibleOnly", function () {
|
||||
getPageData(1);
|
||||
});
|
||||
|
||||
//新建公告表单验证与数据提交
|
||||
$("#announcement-form")
|
||||
.formValidation({
|
||||
framework: "bootstrap",
|
||||
fields: {
|
||||
title: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写公告标题"
|
||||
getPageData(1);
|
||||
|
||||
function getPageData(page) {
|
||||
var url = "/api/announcements/?paging=true&page=" + page + "&page_size=10";
|
||||
if (vm.showVisibleOnly)
|
||||
url += "&visible=true";
|
||||
$.ajax({
|
||||
url: url,
|
||||
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) {
|
||||
e.preventDefault();
|
||||
var title = $("#title").val();
|
||||
var content = announcementEditor.getValue();
|
||||
if (content == "") {
|
||||
bs_alert("请填写公告内容");
|
||||
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);
|
||||
}
|
||||
).on('success.form.fv', function (e) {
|
||||
e.preventDefault();
|
||||
var title = $("#title").val();
|
||||
var content = createAnnouncementEditor.getValue();
|
||||
if (content == "") {
|
||||
bsAlert("请填写公告内容");
|
||||
return;
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
$.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();
|
||||
});
|
@ -1,73 +1,74 @@
|
||||
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) {
|
||||
avalon.vmodels.group = null;
|
||||
require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
|
||||
|
||||
|
||||
// avalon:定义模式 group_list
|
||||
avalon.ready(function () {
|
||||
avalon.vmodels.group = null;
|
||||
var vm = avalon.define({
|
||||
$id: "group",
|
||||
//通用变量
|
||||
group_list: [], // 用户列表数据项
|
||||
previous_page: 0, // 之前的页数
|
||||
next_page: 0, // 之后的页数
|
||||
groupList: [], // 用户列表数据项
|
||||
previousPage: 0, // 之前的页数
|
||||
nextPage: 0, // 之后的页数
|
||||
page: 1, // 当前页数
|
||||
page_count: 1, // 总页数
|
||||
totalPage: 1, // 总页数
|
||||
keyword: "",
|
||||
|
||||
getNext: function () {
|
||||
if (!vm.next_page)
|
||||
if (!vm.nextPage)
|
||||
return;
|
||||
getPageData(vm.page + 1);
|
||||
},
|
||||
getPrevious: function () {
|
||||
if (!vm.previous_page)
|
||||
if (!vm.previousPage)
|
||||
return;
|
||||
getPageData(vm.page - 1);
|
||||
},
|
||||
getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑
|
||||
if (btn) {
|
||||
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
getBtnClass: function (btnType) {
|
||||
if (btnType == "next") {
|
||||
return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
}
|
||||
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);
|
||||
search: function(){
|
||||
getPageData(1);
|
||||
},
|
||||
getGroupSettingString: function(setting){
|
||||
getGroupSettingString: function (setting) {
|
||||
return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting]
|
||||
},
|
||||
showGroupDetailPage: function(group_id){
|
||||
vm.$fire("up!showGroupDetailPage", group_id);
|
||||
showGroupDetailPage: function (groupId) {
|
||||
vm.$fire("up!showGroupDetailPage", groupId);
|
||||
}
|
||||
});
|
||||
getPageData(1);
|
||||
|
||||
avalon.scan();
|
||||
getPageData(1); //用户列表初始化
|
||||
//Ajax get数据
|
||||
function getPageData(page) {
|
||||
var url = "/api/admin/group/?paging=true&page=" + page + "&page_size=10";
|
||||
if (vm.keyword != "")
|
||||
if (vm.keyword)
|
||||
url += "&keyword=" + vm.keyword;
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
url: url,
|
||||
dataType: "json",
|
||||
method: "get",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
vm.group_list = 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.groupList = 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);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
avalon.scan();
|
||||
|
||||
});
|
@ -1,51 +1,50 @@
|
||||
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) {
|
||||
avalon.vmodels.group_detail = null;
|
||||
require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
|
||||
|
||||
|
||||
// avalon:定义模式 group_list
|
||||
avalon.ready(function () {
|
||||
avalon.vmodels.groupDetail = null;
|
||||
var vm = avalon.define({
|
||||
$id: "group_detail",
|
||||
$id: "groupDetail",
|
||||
//通用变量
|
||||
member_list: [],
|
||||
previous_page: 0,
|
||||
next_page: 0,
|
||||
memberList: [],
|
||||
previousPage: 0,
|
||||
nextPage: 0,
|
||||
page: 1,
|
||||
page_count: 1,
|
||||
totalPage: 1,
|
||||
name: "",
|
||||
description: "",
|
||||
checked_setting: "0",
|
||||
checkedSetting: "0",
|
||||
|
||||
getNext: function () {
|
||||
if (!vm.next_page)
|
||||
if (!vm.nextPage)
|
||||
return;
|
||||
getPageData(vm.page + 1);
|
||||
},
|
||||
getPrevious: function () {
|
||||
if (!vm.previous_page)
|
||||
if (!vm.previousPage)
|
||||
return;
|
||||
getPageData(vm.page - 1);
|
||||
},
|
||||
getBtnClass: function (btn) {
|
||||
if (btn) {
|
||||
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
if (btn == "next") {
|
||||
return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
}
|
||||
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) {
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/admin/group_member/",
|
||||
method: "put",
|
||||
data: JSON.stringify({group_id: relation.group, members: [relation.user.id]}),
|
||||
contentType: "application/json",
|
||||
success: function (data) {
|
||||
vm.member_list.remove(relation);
|
||||
bs_alert(data.data);
|
||||
vm.memberList.remove(relation);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -55,90 +54,90 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
|
||||
getPageData(1);
|
||||
function getPageData(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({
|
||||
url: url,
|
||||
dataType: "json",
|
||||
method: "get",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
vm.member_list = 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.memberList = 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);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/api/admin/group/?group_id=" + avalon.vmodels.admin.group_id,
|
||||
url: "/api/admin/group/?group_id=" + avalon.vmodels.admin.groupId,
|
||||
method: "get",
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
vm.name = data.data.name;
|
||||
vm.description = data.data.description;
|
||||
vm.checked_setting = data.data.join_group_setting.toString();
|
||||
vm.checkedSetting = data.data.join_group_setting.toString();
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$("#edit_group_form")
|
||||
.formValidation({
|
||||
framework: "bootstrap",
|
||||
fields: {
|
||||
name: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写小组名"
|
||||
},
|
||||
stringLength: {
|
||||
max: 20,
|
||||
message: '小组名长度必须在20位之内'
|
||||
}
|
||||
.formValidation({
|
||||
framework: "bootstrap",
|
||||
fields: {
|
||||
name: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写小组名"
|
||||
},
|
||||
stringLength: {
|
||||
max: 20,
|
||||
message: '小组名长度必须在20位之内'
|
||||
}
|
||||
},
|
||||
description: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写描述"
|
||||
},
|
||||
stringLength: {
|
||||
max: 300,
|
||||
message: '描述长度必须在300位之内'
|
||||
}
|
||||
}
|
||||
},
|
||||
description: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写描述"
|
||||
},
|
||||
stringLength: {
|
||||
max: 300,
|
||||
message: '描述长度必须在300位之内'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
).on('success.form.fv', function (e) {
|
||||
}
|
||||
).on('success.form.fv', function (e) {
|
||||
e.preventDefault();
|
||||
var data = {
|
||||
group_id: avalon.vmodels.admin.group_id,
|
||||
group_id: avalon.vmodels.admin.groupId,
|
||||
name: vm.name,
|
||||
description: vm.description,
|
||||
join_group_setting: vm.checked_setting
|
||||
join_group_setting: vm.checkedSetting
|
||||
};
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/admin/group/",
|
||||
method: "put",
|
||||
data: data,
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
bs_alert("修改成功");
|
||||
bsAlert("修改成功");
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
})
|
@ -1,46 +1,47 @@
|
||||
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) {
|
||||
avalon.vmodels.request_list = null;
|
||||
require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
|
||||
|
||||
// avalon:定义模式 group_list
|
||||
avalon.ready(function () {
|
||||
avalon.vmodels.requestList = null;
|
||||
var vm = avalon.define({
|
||||
$id: "request_list",
|
||||
$id: "requestList",
|
||||
//通用变量
|
||||
request_list: [], // 列表数据项
|
||||
previous_page: 0, // 之前的页数
|
||||
next_page: 0, // 之后的页数
|
||||
requestList: [], // 列表数据项
|
||||
previousPage: 0, // 之前的页数
|
||||
nextPage: 0, // 之后的页数
|
||||
page: 1, // 当前页数
|
||||
page_count: 1, // 总页数
|
||||
totalPage: 1, // 总页数
|
||||
|
||||
getNext: function () {
|
||||
if (!vm.next_page)
|
||||
if (!vm.nextPage)
|
||||
return;
|
||||
getPageData(vm.page + 1);
|
||||
},
|
||||
getPrevious: function () {
|
||||
if (!vm.previous_page)
|
||||
if (!vm.previousPage)
|
||||
return;
|
||||
getPageData(vm.page - 1);
|
||||
},
|
||||
getBtnClass: function (btn) { //上一页/下一页按钮启用禁用逻辑
|
||||
if (btn) {
|
||||
return vm.next_page ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
if (btn == "next") {
|
||||
return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
}
|
||||
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);
|
||||
},
|
||||
processRequest: function(request_id, status){
|
||||
processRequest: function(request, status){
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/admin/join_group_request/",
|
||||
method: "put",
|
||||
data: {request_id: request_id, status: status},
|
||||
data: {request_id: request.id, status: status},
|
||||
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) {
|
||||
var url = "/api/admin/join_group_request/?paging=true&page=" + page + "&page_size=10";
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: url,
|
||||
dataType: "json",
|
||||
method: "get",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
vm.request_list = 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.requestList = 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);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -134,11 +135,11 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
|
||||
method: "put",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
bs_alert("提交成功!");
|
||||
bsAlert("提交成功!");
|
||||
getPageData(1);
|
||||
$("#password").val("");
|
||||
} else {
|
||||
bs_alert(data.data);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
})
|
@ -1,219 +1,218 @@
|
||||
require(["jquery", "avalon", "editor", "uploader", "bs_alert", "csrf", "tagEditor", "validation", "jqueryUI"],
|
||||
function ($, avalon, editor, uploader, bs_alert, csrfHeader) {
|
||||
avalon.vmodels.add_problem = null;
|
||||
$("#add-problem-form")
|
||||
.formValidation({
|
||||
framework: "bootstrap",
|
||||
fields: {
|
||||
title: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写题目名称"
|
||||
},
|
||||
stringLength: {
|
||||
min: 1,
|
||||
max: 30,
|
||||
message: "名称不能超过30个字"
|
||||
require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagEditor", "formValidation", "jqueryUI"],
|
||||
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
|
||||
avalon.ready(function () {
|
||||
avalon.vmodels.addProblem = null;
|
||||
$("#add-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之间"
|
||||
},
|
||||
cpu: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请输入时间限制"
|
||||
},
|
||||
integer: {
|
||||
message: "请输入一个合法的数字"
|
||||
},
|
||||
between: {
|
||||
inclusive: true,
|
||||
min: 1,
|
||||
max: 5000,
|
||||
message: "只能在1-5000之间"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
memory: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请输入内存限制"
|
||||
},
|
||||
integer: {
|
||||
message: "请输入一个合法的数字"
|
||||
},
|
||||
memory: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请输入内存限制"
|
||||
},
|
||||
integer: {
|
||||
message: "请输入一个合法的数字"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
difficulty: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请输入难度"
|
||||
},
|
||||
integer: {
|
||||
message: "难度用一个整数表示"
|
||||
},
|
||||
difficulty: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请输入难度"
|
||||
},
|
||||
integer: {
|
||||
message: "难度用一个整数表示"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
input_description: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写输入描述"
|
||||
},
|
||||
input_description: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写输入描述"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
output_description: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: "请填写输出描述"
|
||||
},
|
||||
output_description: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
var problemDiscription = editor("#problemDescription");
|
||||
var testCaseUploader = uploader("#testCaseFile", "/api/admin/test_case_upload/", function (file, respond) {
|
||||
if (respond.code)
|
||||
bs_alert(respond.data);
|
||||
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);
|
||||
.on("success.form.fv", function (e) {
|
||||
e.preventDefault();
|
||||
if (vm.testCaseId == "") {
|
||||
bsAlert("你还没有上传测试数据!");
|
||||
return;
|
||||
}
|
||||
$("#tags").tagEditor({
|
||||
autocomplete: {
|
||||
delay: 0, // show suggestions immediately
|
||||
position: {collision: 'flip'}, // automatic menu position up/down
|
||||
source: completeList
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tags.length == 0) {
|
||||
bsAlert("请至少添加一个标签,这将有利于用户发现你的题目!");
|
||||
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();
|
||||
});
|
257
static/src/js/app/admin/problem/edit_problem.js
Normal file
257
static/src/js/app/admin/problem/edit_problem.js
Normal 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();
|
||||
|
||||
});
|
65
static/src/js/app/admin/problem/problem.js
Normal file
65
static/src/js/app/admin/problem/problem.js
Normal 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();
|
||||
});
|
@ -1,59 +1,58 @@
|
||||
require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, avalon, csrfHeader, bs_alert) {
|
||||
avalon.vmodels.user_list = null;
|
||||
require(["jquery", "avalon", "csrfToken", "bsAlert", "formValidation"], function ($, avalon, csrfTokenHeader, bsAlert) {
|
||||
|
||||
// avalon:定义模式 user_list
|
||||
|
||||
// avalon:定义模式 userList
|
||||
avalon.ready(function () {
|
||||
avalon.vmodels.userList = null;
|
||||
var vm = avalon.define({
|
||||
$id: "user_list",
|
||||
$id: "userList",
|
||||
//通用变量
|
||||
user_list: [], // 用户列表数据项
|
||||
previous_page: 0, // 之前的页数
|
||||
next_page: 0, // 之后的页数
|
||||
page: 1, // 当前页数
|
||||
isEditing: 0, // 正在编辑的公告的ID, 为零说明未在编辑
|
||||
page_count: 1, // 总页数
|
||||
user_type: ["一般用户", "管理员", "超级管理员"],
|
||||
key_word: "",
|
||||
userList: [],
|
||||
previousPage: 0,
|
||||
nextPage: 0,
|
||||
page: 1,
|
||||
editingUserId: 0,
|
||||
totalPage: 1,
|
||||
userType: ["一般用户", "管理员", "超级管理员"],
|
||||
keyword: "",
|
||||
showAdminOnly: false,
|
||||
//编辑区域同步变量
|
||||
username: "",
|
||||
real_name: "",
|
||||
realName: "",
|
||||
email: "",
|
||||
admin_type: 0,
|
||||
adminType: 0,
|
||||
id: 0,
|
||||
last_login: "",
|
||||
create_time: "",
|
||||
getNext: function () {
|
||||
if (!vm.next_page)
|
||||
if (!vm.nextPage)
|
||||
return;
|
||||
getPageData(vm.page + 1);
|
||||
},
|
||||
getPrevious: function () {
|
||||
if (!vm.previous_page)
|
||||
if (!vm.previousPage)
|
||||
return;
|
||||
getPageData(vm.page - 1);
|
||||
},
|
||||
getBtnClass: function (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 {
|
||||
return vm.previous_page ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
|
||||
}
|
||||
},
|
||||
enEdit: function (el) { //点击编辑按钮的事件,显示/隐藏编辑区
|
||||
vm.username = el.username;
|
||||
vm.real_name = el.real_name;
|
||||
vm.admin_type = el.admin_type;
|
||||
vm.email = el.email;
|
||||
vm.id = el.id;
|
||||
if (vm.isEditing == el.id)
|
||||
vm.isEditing = 0;
|
||||
editUser: function (user) { //点击编辑按钮的事件,显示/隐藏编辑区
|
||||
vm.username = user.username;
|
||||
vm.realName = user.real_name;
|
||||
vm.adminType = user.admin_type;
|
||||
vm.email = user.email;
|
||||
vm.id = user.id;
|
||||
if (vm.editingUserId == user.id)
|
||||
vm.editingUserId = 0;
|
||||
else
|
||||
vm.isEditing = el.id;
|
||||
vm.editingUserId = user.id;
|
||||
},
|
||||
getPage: function (page_index) {
|
||||
getPageData(page_index);
|
||||
search: function () {
|
||||
getPageData(1);
|
||||
}
|
||||
});
|
||||
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";
|
||||
if (vm.showAdminOnly == true)
|
||||
url += "&admin_type=1";
|
||||
if (vm.key_word != "")
|
||||
url += "&keyword=" + vm.key_word;
|
||||
if (vm.keyword != "")
|
||||
url += "&keyword=" + vm.keyword;
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: url,
|
||||
dataType: "json",
|
||||
method: "get",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
vm.user_list = 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.userList = 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);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -136,26 +135,26 @@ require(["jquery", "avalon", "csrf", "bs_alert", "validation"], function ($, ava
|
||||
e.preventDefault();
|
||||
var data = {
|
||||
username: vm.username,
|
||||
real_name: vm.real_name,
|
||||
real_name: vm.realName,
|
||||
email: vm.email,
|
||||
id: vm.id,
|
||||
admin_type: vm.admin_type
|
||||
admin_type: vm.adminType
|
||||
};
|
||||
if ($("#password").val() !== "")
|
||||
data.password = $("#password").val();
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/admin/user/",
|
||||
data: data,
|
||||
dataType: "json",
|
||||
method: "put",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
bs_alert("提交成功!");
|
||||
bsAlert("提交成功!");
|
||||
getPageData(1);
|
||||
$("#password").val("");
|
||||
} else {
|
||||
bs_alert(data.data);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
})
|
@ -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({
|
||||
framework: "bootstrap",
|
||||
fields: {
|
||||
@ -47,21 +47,20 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
|
||||
).on('success.form.fv', function (e) {
|
||||
e.preventDefault();
|
||||
var username = $("#username").val();
|
||||
var new_password = $("#new_password ").val();
|
||||
var newPassword = $("#new_password ").val();
|
||||
var password = $("#password").val();
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
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",
|
||||
method: "post",
|
||||
success: function (data) {
|
||||
|
||||
if (!data.code) {
|
||||
window.location.href = "/login/";
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) {
|
||||
require(["jquery", "bsAlert", "csrfToken", "formValidation"], function ($, bsAlert, csrfTokenHeader) {
|
||||
$("#login-form")
|
||||
.formValidation({
|
||||
framework: "bootstrap",
|
||||
@ -24,7 +24,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
|
||||
var username = $("#username").val();
|
||||
var password = $("#password").val();
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/login/",
|
||||
data: {username: username, password: password},
|
||||
dataType: "json",
|
||||
@ -34,7 +34,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
|
||||
window.location.href = "/";
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) {
|
||||
require(["jquery", "bsAlert", "csrfToken", "validation"], function ($, bsAlert, csrfTokenHeader) {
|
||||
$("#register-form")
|
||||
.formValidation({
|
||||
framework: "bootstrap",
|
||||
@ -73,13 +73,13 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
|
||||
).on('success.form.fv', function (e) {
|
||||
e.preventDefault();
|
||||
var username = $("#username").val();
|
||||
var real_name = $("#real_name").val();
|
||||
var realName = $("#real_name").val();
|
||||
var password = $("#password").val();
|
||||
var email = $("#email").val();
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
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",
|
||||
method: "post",
|
||||
success: function (data) {
|
||||
@ -87,7 +87,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csr
|
||||
window.location.href = "/login/";
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
bsAlert(data.data);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,12 +1,12 @@
|
||||
require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror, csrfHeader, bs_alert) {
|
||||
var code_editor = code_mirror($("#code-editor")[0], "text/x-csrc");
|
||||
require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirror, csrfTokenHeader, bsAlert) {
|
||||
var codeEditor = codeMirror($("#code-editor")[0], "text/x-csrc");
|
||||
var language = $("input[name='language'][checked]").val();
|
||||
var submission_id;
|
||||
var submissionId;
|
||||
|
||||
$("input[name='language']").change(function () {
|
||||
language = this.value;
|
||||
var language_types = {"1": "text/x-csrc", "2": "text/x-c++src", "3": "text/x-java"};
|
||||
code_editor.setOption("mode", language_types[language]);
|
||||
var languageTypes = {"1": "text/x-csrc", "2": "text/x-c++src", "3": "text/x-java"};
|
||||
codeEditor.setOption("mode", languageTypes[language]);
|
||||
});
|
||||
|
||||
$("#show-more-btn").click(function () {
|
||||
@ -14,18 +14,17 @@ require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror,
|
||||
$("#show-more-btn").hide();
|
||||
});
|
||||
|
||||
function show_loading() {
|
||||
function showLoading() {
|
||||
$("#submit-code-button").attr("disabled", "disabled");
|
||||
$("#loading-gif").show();
|
||||
}
|
||||
|
||||
function hide_loading() {
|
||||
function hideLoading() {
|
||||
$("#submit-code-button").removeAttr("disabled");
|
||||
$("#loading-gif").hide();
|
||||
}
|
||||
|
||||
|
||||
function get_result_html(data) {
|
||||
function getResultHtml(data) {
|
||||
// 0 结果正确 1 运行错误 2 超时 3 超内存 4 编译错误
|
||||
// 5 格式错误 6 结果错误 7 系统错误 8 等待判题
|
||||
var results = {
|
||||
@ -49,14 +48,14 @@ require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror,
|
||||
if (!data.result) {
|
||||
html += "CPU time: " + data.accepted_answer_info.time + "ms ";
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
function get_result() {
|
||||
function getResult() {
|
||||
$.ajax({
|
||||
url: "/api/submission/?submission_id=" + submission_id,
|
||||
url: "/api/submission/?submission_id=" + submissionId,
|
||||
method: "get",
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
@ -64,54 +63,54 @@ require(["jquery", "code_mirror", "csrf", "bs_alert"], function ($, code_mirror,
|
||||
// 8是还没有完成判题
|
||||
if (data.data.result == 8) {
|
||||
// 1秒之后重新去获取
|
||||
setTimeout(get_result, 1000);
|
||||
setTimeout(getResult, 1000);
|
||||
}
|
||||
else {
|
||||
hide_loading();
|
||||
$("#result").html(get_result_html(data.data));
|
||||
hideLoading();
|
||||
$("#result").html(getResultHtml(data.data));
|
||||
}
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
hide_loading();
|
||||
bsAlert(data.data);
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$("#submit-code-button").click(function () {
|
||||
var problem_id = window.location.pathname.split("/")[2];
|
||||
var code = code_editor.getValue();
|
||||
var problemId = window.location.pathname.split("/")[2];
|
||||
var code = codeEditor.getValue();
|
||||
|
||||
show_loading();
|
||||
showLoading();
|
||||
|
||||
if(!code.trim()){
|
||||
bs_alert("请填写代码!");
|
||||
hide_loading();
|
||||
hideLoading();
|
||||
return false;
|
||||
}
|
||||
|
||||
$("#result").html("");
|
||||
|
||||
$.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/submission/",
|
||||
method: "post",
|
||||
data: JSON.stringify({
|
||||
problem_id: window.location.pathname.split("/")[2],
|
||||
problem_id: problemId,
|
||||
language: language,
|
||||
code: code_editor.getValue()
|
||||
code: codeEditor.getValue()
|
||||
}),
|
||||
contentType: "application/json",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
submission_id = data.data.submission_id;
|
||||
submissionId = data.data.submission_id;
|
||||
// 获取到id 之后2秒去查询一下判题结果
|
||||
setTimeout(get_result, 2000);
|
||||
setTimeout(getResult, 2000);
|
||||
}
|
||||
else {
|
||||
bs_alert(data.data);
|
||||
hide_loading();
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2,24 +2,28 @@ var require = {
|
||||
// RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。
|
||||
baseUrl: "/static/js/",
|
||||
paths: {
|
||||
//百度webuploader
|
||||
webuploader: "lib/webuploader/webuploader",
|
||||
|
||||
jquery: "lib/jquery/jquery",
|
||||
avalon: "lib/avalon/avalon",
|
||||
editor: "utils/editor",
|
||||
uploader: "utils/uploader",
|
||||
validation: "utils/validation",
|
||||
code_mirror: "utils/code_mirror",
|
||||
bs_alert: "utils/bs_alert",
|
||||
formValidation: "utils/formValidation",
|
||||
codeMirror: "utils/codeMirror",
|
||||
bsAlert: "utils/bsAlert",
|
||||
problem: "app/oj/problem/problem",
|
||||
contest: "app/admin/contest/contest",
|
||||
csrf: "utils/csrf",
|
||||
csrfToken: "utils/csrfToken",
|
||||
admin: "app/admin/admin",
|
||||
chart: "lib/chart/Chart",
|
||||
tagEditor: "lib/tagEditor/jquery.tag-editor.min",
|
||||
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",
|
||||
helper: "lib/formValidation/helper",
|
||||
"language/zh_CN": "lib/formValidation/language/zh_CN",
|
||||
@ -32,26 +36,25 @@ var require = {
|
||||
"validator/confirm":"lib/formValidation/validator/confirm",
|
||||
"validator/remote":"lib/formValidation/validator/remote",
|
||||
"validator/emailAddress":"lib/formValidation/validator/emailAddress",
|
||||
//富文本编辑器 不要直接使用,而是使用上面的editor
|
||||
|
||||
//富文本编辑器simditor -> editor
|
||||
simditor: "lib/simditor/simditor",
|
||||
"simple-module": "lib/simditor/module",
|
||||
"simple-hotkeys": "lib/simditor/hotkeys",
|
||||
"simple-uploader": "lib/simditor/uploader",
|
||||
|
||||
//code mirroe 代码编辑器
|
||||
_code_mirror: "lib/codeMirror/codemirror",
|
||||
code_mirror_clang: "lib/codeMirror/language/clike",
|
||||
//code mirror 代码编辑器 ->codeMirror
|
||||
_codeMirror: "lib/codeMirror/codemirror",
|
||||
codeMirrorClang: "lib/codeMirror/language/clike",
|
||||
|
||||
//bootstrap
|
||||
bootstrap: "lib/bootstrap/bootstrap",
|
||||
//百度webuploader -> uploader
|
||||
webUploader: "lib/webuploader/webuploader",
|
||||
|
||||
//
|
||||
"_datetimepicker": "lib/datetime_picker/bootstrap-datetimepicker",
|
||||
"datetimepicker": "lib/datetime_picker/bootstrap-datetimepicker.zh-CN"
|
||||
"_datetimePicker": "lib/datetime_picker/bootstrap-datetimepicker"
|
||||
},
|
||||
shim: {
|
||||
"bootstrap": {"deps": ['jquery']},
|
||||
"_datetimepicker": {"deps": ["jquery"]},
|
||||
"datetimepicker": {"deps": ["_datetimepicker"]}
|
||||
bootstrap: {deps: ["jquery"]},
|
||||
_datetimePicker: {dep: ["jquery"]},
|
||||
datetimePicker: {deps: ["_datetimePicker"]}
|
||||
}
|
||||
};
|
@ -5,7 +5,7 @@
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["_code_mirror"], mod);
|
||||
define(["_codeMirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
|
@ -7,12 +7,12 @@
|
||||
|
||||
// AMD module is defined
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define("validator/remote", ["jquery", "base", "csrf"], factory);
|
||||
define("validator/remote", ["jquery", "base", "csrfToken"], factory);
|
||||
} else {
|
||||
// planted over the root!
|
||||
factory(root.jQuery, root.FormValidation);
|
||||
}
|
||||
}(this, function ($, FormValidation, csrfHeader) {
|
||||
}(this, function ($, FormValidation, csrfTokenHeader) {
|
||||
FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, {
|
||||
'en_US': {
|
||||
remote: {
|
||||
@ -28,7 +28,7 @@
|
||||
return true;
|
||||
var url = options.url;
|
||||
var xhr = $.ajax({
|
||||
beforeSend: csrfHeader,
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
data: ajaxData,
|
||||
|
@ -1,5 +1,5 @@
|
||||
define("bs_alert", ["jquery", "bootstrap"], function($){
|
||||
function bs_alert(content){
|
||||
define("bsAlert", ["jquery", "bootstrap"], function($){
|
||||
function bsAlert(content){
|
||||
if(!$("#alert-modal").length) {
|
||||
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"> ' +
|
||||
@ -13,5 +13,5 @@ define("bs_alert", ["jquery", "bootstrap"], function($){
|
||||
$("#modal-text").html(content);
|
||||
$("#alert-modal").modal();
|
||||
}
|
||||
return bs_alert;
|
||||
return bsAlert;
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
define("code_mirror", ["_code_mirror", "code_mirror_clang"], function(CodeMirror){
|
||||
function code_mirror(selector, language){
|
||||
define("codeMirror", ["_codeMirror", "codeMirrorClang"], function(CodeMirror){
|
||||
function codeMirror(selector, language){
|
||||
return CodeMirror.fromTextArea(selector,
|
||||
{
|
||||
indentUnit: 4,
|
||||
@ -8,5 +8,5 @@ define("code_mirror", ["_code_mirror", "code_mirror_clang"], function(CodeMirror
|
||||
mode: language
|
||||
});
|
||||
}
|
||||
return code_mirror;
|
||||
return codeMirror;
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
define("csrf",function(){
|
||||
function get_cookie(cookie_name) {
|
||||
define("csrfToken",function(){
|
||||
function getCookie(cookie_name) {
|
||||
var name = cookie_name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
@ -9,15 +9,15 @@ define("csrf",function(){
|
||||
}
|
||||
return "";
|
||||
}
|
||||
function csrfHeader(){
|
||||
function csrfTokenHeader(){
|
||||
// jquery的请求
|
||||
if(arguments.length == 2) {
|
||||
arguments[0].setRequestHeader("X-CSRFToken", get_cookie("csrftoken"));
|
||||
arguments[0].setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
|
||||
}
|
||||
// 百度webuploader 的请求
|
||||
else if(arguments.length == 3){
|
||||
arguments[2]["X-CSRFToken"] = get_cookie("csrftoken");
|
||||
arguments[2]["X-CSRFToken"] = getCookie("csrftoken");
|
||||
}
|
||||
}
|
||||
return csrfHeader;
|
||||
return csrfTokenHeader;
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
define("validation",
|
||||
define("formValidation",
|
||||
[ 'base',
|
||||
'helper',
|
||||
'framework/bootstrap',
|
4
static/src/js/utils/html5shiv.min.js
vendored
4
static/src/js/utils/html5shiv.min.js
vendored
@ -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);
|
@ -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);
|
||||
}
|
5
static/src/js/utils/respond.min.js
vendored
5
static/src/js/utils/respond.min.js
vendored
@ -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='­<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);
|
@ -1,4 +1,4 @@
|
||||
define("uploader", ["webuploader", "csrf"], function(webuploader,csrf){
|
||||
define("uploader", ["webUploader", "csrfToken"], function(webuploader,csrfTokenHeader){
|
||||
function uploader(selector, server, onSuccess, beforeUpload) {
|
||||
var Webuploader= webuploader.create({
|
||||
auto: true,
|
||||
@ -11,9 +11,9 @@ define("uploader", ["webuploader", "csrf"], function(webuploader,csrf){
|
||||
pick: selector,
|
||||
// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
|
||||
resize: false,
|
||||
uploadBeforeSend : csrf
|
||||
uploadBeforeSend : csrfTokenHeader
|
||||
});
|
||||
Webuploader.on("uploadBeforeSend",csrf);
|
||||
Webuploader.on("uploadBeforeSend",csrfTokenHeader);
|
||||
Webuploader.on("uploadSuccess", onSuccess);
|
||||
Webuploader.on("beforeFileQueued", beforeUpload);
|
||||
return Webuploader;
|
||||
|
@ -101,9 +101,6 @@
|
||||
<li class="list-group-item" id="li-user-user_list">
|
||||
<a href="#user/user_list">用户列表</a>
|
||||
</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-item" id="li-group-group">
|
||||
<a href="#group/group">小组列表</a>
|
||||
@ -124,8 +121,6 @@
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="/static/js/config.js"></script>
|
||||
<script src="/static/js/require.js"></script>
|
||||
<script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div ms-controller="announcement" class="col-md-9">
|
||||
<h1>Announcement</h1>
|
||||
<h1>公告管理</h1>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>编号</th>
|
||||
@ -8,36 +8,38 @@
|
||||
<th>更新时间</th>
|
||||
<th>创建者</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr ms-repeat="announcement">
|
||||
<td>{{el.id}}</td>
|
||||
<td>{{el.title}}</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.created_by.username}}</td>
|
||||
<td>{{getState(el)}}</td>
|
||||
<tr ms-repeat="announcementList">
|
||||
<td>{{ el.id }}</td>
|
||||
<td>{{ el.title }}</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.created_by.username }}</td>
|
||||
<td>{{ getState(el)}}</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>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="form-group">
|
||||
<label>仅显示可见 <input ms-duplex-checked="visableOnly" type="checkbox"/></label>
|
||||
<label>仅显示可见 <input ms-duplex-checked="showVisibleOnly" type="checkbox"/></label>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
页数:{{page}}/{{page_count}}
|
||||
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button>
|
||||
<div class="right">
|
||||
页数:{{ page }}/{{ totalPage }}
|
||||
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
|
||||
</div>
|
||||
|
||||
<div ms-visible="isEditing">
|
||||
<div ms-visible="editingAnnouncementId">
|
||||
<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>
|
||||
<div class="form-group">
|
||||
<label>内容</label>
|
||||
<textarea id="editAnnouncementEditor"></textarea>
|
||||
<textarea id="edit-announcement-editor"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>可见 <input ms-duplex-checked="announcementVisible" type="checkbox"/></label>
|
||||
@ -45,17 +47,17 @@
|
||||
<div class="form-group">
|
||||
<button ms-click="submitChange()" class="btn btn-primary">提交</button>
|
||||
|
||||
<button ms-click="disEdit()" class="btn btn-danger">取消</button>
|
||||
<button ms-click="cancelEdit()" class="btn btn-danger">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
<h3>添加公告</h3>
|
||||
|
||||
<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>
|
||||
<div class="form-group">
|
||||
<label>内容</label>
|
||||
<textarea id="editor" placeholder="公告内容"></textarea>
|
||||
<textarea id="create-announcement-editor" placeholder="公告内容"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
|
@ -75,13 +75,18 @@
|
||||
<div class="col-md-12">
|
||||
<label>添加题目</label>
|
||||
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="add_problem()">添加</a>
|
||||
<div class="col-md-12">
|
||||
<label>上传测试用例</label>
|
||||
<label>选择题号</label><select ms-duplex="problemNo"><option value="-1">未指定</option><option ms-repeat="problems" ms-attr-value="$index+1">{{$index+1}}</option></select>
|
||||
<div id="uploader">
|
||||
<div>选择文件</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<label>上传测试用例</label>
|
||||
<label>选择题号</label><select ms-duplex="problemNo">
|
||||
<option value="-1">未指定</option>
|
||||
<option ms-repeat="problems" ms-attr-value="$index+1">{{$index+1}}</option>
|
||||
</select>
|
||||
|
||||
<div id="uploader">
|
||||
<div>选择文件</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="problem" ms-repeat-problem="problems">
|
||||
@ -89,7 +94,7 @@
|
||||
<div class="panel-heading">
|
||||
<span class="panel-title">题目{{$index + 1}} </span>
|
||||
<a href="javascript:void(0)" class="btn btn-primary btn-sm" ms-click="toggle(problem)">
|
||||
{{getBtnContent(problem)}}
|
||||
{{ getBtnContent(problem)}}
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="btn btn-danger btn-sm" ms-click="del_problem(problem)">
|
||||
删除
|
||||
@ -97,17 +102,19 @@
|
||||
</div>
|
||||
<div class="panel-body" ms-visible="problem.visible">
|
||||
<div class="form-group col-md-12">
|
||||
<label>题目标题</label>
|
||||
<input type="text" name="problem_name[]" class="form-control" ms-duplex="problem.title">
|
||||
<label>题目标题</label>
|
||||
<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 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">
|
||||
<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 class="col-md-3 form-group">
|
||||
<label>cpu</label>
|
||||
@ -119,19 +126,24 @@
|
||||
</div>
|
||||
<div class="col-md-3 form-group">
|
||||
<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 class="col-md-12">
|
||||
<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="panel panel-default sample-panel" ms-repeat-sample="problem.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="toggle(sample)">
|
||||
{{getBtnContent(sample)}}
|
||||
<a href="javascript:void(0)" class="btn btn-primary btn-sm"
|
||||
ms-click="toggle(sample)">
|
||||
{{ getBtnContent(sample)}}
|
||||
</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>
|
||||
</div>
|
||||
@ -167,8 +179,8 @@
|
||||
</tr>
|
||||
<tr ms-repeat="problem.testCaseList">
|
||||
<td>{{$index}}</td>
|
||||
<td>{{el.input}}</td>
|
||||
<td>{{el.output}}</td>
|
||||
<td>{{ el.input }}</td>
|
||||
<td>{{ el.output }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -1,14 +1,14 @@
|
||||
<div ms-controller="group" class="col-md-9">
|
||||
<h1>小组管理</h1>
|
||||
<div class="text-right">
|
||||
|
||||
<div class="right">
|
||||
<form class="form-inline" onsubmit="return false;">
|
||||
<div class="form-group-sm">
|
||||
<label>搜索</label>
|
||||
<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>
|
||||
</form>
|
||||
<br>
|
||||
</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
@ -20,10 +20,10 @@
|
||||
<th>设置</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr ms-repeat="group_list">
|
||||
<td>{{el.id}}</td>
|
||||
<td>{{el.name}}</td>
|
||||
<td>{{el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
|
||||
<tr ms-repeat="groupList">
|
||||
<td>{{ el.id }}</td>
|
||||
<td>{{ el.name }}</td>
|
||||
<td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
|
||||
<td>{{ el.members_number }}</td>
|
||||
<td>{{ getGroupSettingString(el.join_group_setting) }}</td>
|
||||
|
||||
@ -33,10 +33,10 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="text-right">
|
||||
页数:{{page}}/{{page_count}}
|
||||
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button>
|
||||
<div class="right">
|
||||
页数:{{ page }}/{{ totalPage }}
|
||||
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div ms-controller="group_detail" class="col-md-9">
|
||||
<div ms-controller="groupDetail" class="col-md-9">
|
||||
<h1>小组成员管理</h1>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
@ -8,7 +8,7 @@
|
||||
<th>加入时间</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr ms-repeat="member_list">
|
||||
<tr ms-repeat="memberList">
|
||||
<td>{{ el.user.id }}</td>
|
||||
<td>{{ el.user.username }}</td>
|
||||
<td>{{ el.user.real_name }}</td>
|
||||
@ -21,9 +21,9 @@
|
||||
</table>
|
||||
|
||||
<div class="text-right">
|
||||
页数:{{ page }}/{{ page_count }}
|
||||
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button>
|
||||
页数:{{ page }}/{{ totalPage }}
|
||||
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
|
||||
</div>
|
||||
<h1>修改小组信息</h1>
|
||||
|
||||
@ -42,9 +42,9 @@
|
||||
<div class="form-group">
|
||||
|
||||
<label>加入小组设置</label>
|
||||
<input type="radio" name="join_group_setting" value="0" ms-duplex-string="checked_setting">允许任何人加入
|
||||
<input type="radio" name="join_group_setting" value="1" ms-duplex-string="checked_setting">提交请求后管理员审核
|
||||
<input type="radio" name="join_group_setting" value="2" 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="checkedSetting">提交请求后管理员审核
|
||||
<input type="radio" name="join_group_setting" value="2" ms-duplex-string="checkedSetting">不允许任何人加入
|
||||
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">提交</button>
|
||||
@ -52,4 +52,4 @@
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<script src="/static/js/app/admin/group/group_detail.js"></script>
|
||||
<script src="/static/js/app/admin/group/groupDetail.js"></script>
|
@ -1,31 +1,31 @@
|
||||
<div ms-controller="request_list" class="col-md-9">
|
||||
<div ms-controller="requestList" class="col-md-9">
|
||||
<h1>加入小组请求管理</h1>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>创建时间</th>
|
||||
<th>用户</th>
|
||||
<th>小组</th>
|
||||
<th>用户</th>
|
||||
<th>附加消息</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr ms-repeat="request_list">
|
||||
<td>{{el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
|
||||
<tr ms-repeat="requestList">
|
||||
<td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
|
||||
<td>{{ el.group.name }}</td>
|
||||
<td>{{ el.user.username }}</td>
|
||||
<td>{{ el.message }}</td>
|
||||
|
||||
<td>
|
||||
<button class="btn-sm btn-success" ms-click="processRequest(el.id, true)">同意</button>
|
||||
<button class="btn-sm btn-danger" ms-click="processRequest(el.id, false)">拒绝</button>
|
||||
<button class="btn-sm btn-success" ms-click="processRequest(el, true)">同意</button>
|
||||
<button class="btn-sm btn-danger" ms-click="processRequest(el, false)">拒绝</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="text-right">
|
||||
页数:{{page}}/{{page_count}}
|
||||
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button>
|
||||
页数:{{ page }}/{{ totalPage }}
|
||||
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="/static/js/app/admin/group/join_group_request_list.js"></script>
|
||||
<script src="/static/js/app/admin/group/joinGroupRequestList.js"></script>
|
@ -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">
|
||||
|
||||
<div class="form-group col-md-12">
|
||||
@ -41,27 +41,27 @@
|
||||
<div class="col-md-12 form-group">
|
||||
<label>输入描述</label><br>
|
||||
<textarea class="form-control" rows="5" name="input_description"
|
||||
ms-duplex="input_description"></textarea>
|
||||
ms-duplex="inputDescription"></textarea>
|
||||
</div>
|
||||
<div class="col-md-12 form-group">
|
||||
<label>输出描述</label><br>
|
||||
<textarea class="form-control" rows="5" name="output_description"
|
||||
ms-duplex="output_description"></textarea>
|
||||
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="add_sample()">添加</a>
|
||||
<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="toggle_sample(sample)">
|
||||
ms-click="toggleSample(sample)">
|
||||
{{ getBtnContent(sample)}}
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="btn btn-danger btn-sm"
|
||||
ms-click="del_sample(sample)">
|
||||
ms-click="delSample(sample)">
|
||||
删除
|
||||
</a>
|
||||
</div>
|
||||
|
123
template/admin/problem/edit_problem.html
Normal file
123
template/admin/problem/edit_problem.html
Normal 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>
|
40
template/admin/problem/problem_list.html
Normal file
40
template/admin/problem/problem_list.html
Normal 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 }}
|
||||
<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>
|
@ -1,11 +1,12 @@
|
||||
<div ms-controller="user_list" class="col-md-9">
|
||||
<h1>User</h1>
|
||||
<div class="text-right">
|
||||
<div ms-controller="userList" 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="key_word">
|
||||
<input type="submit" value="搜索" class="btn btn-primary" ms-click="getPage(1)">
|
||||
<input name="keyWord" class="form-control" placeholder="请输入关键词" ms-duplex="keyWord">
|
||||
<input type="submit" value="搜索" class="btn btn-primary" ms-click="search()">
|
||||
</div>
|
||||
</form>
|
||||
<br>
|
||||
@ -21,16 +22,16 @@
|
||||
<th>用户类型</th>
|
||||
<th>修改</th>
|
||||
</tr>
|
||||
<tr ms-repeat="user_list">
|
||||
<td>{{el.id}}</td>
|
||||
<td>{{el.username}}</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.real_name}}</td>
|
||||
<td>{{el.email}}</td>
|
||||
<td>{{user_type[el.admin_type]}}</td>
|
||||
<tr ms-repeat="userList">
|
||||
<td>{{ el.id }}</td>
|
||||
<td>{{ el.username }}</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.real_name }}</td>
|
||||
<td>{{ el.email }}</td>
|
||||
<td>{{ userType[el.admin_type]}}</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>
|
||||
</tr>
|
||||
</table>
|
||||
@ -38,12 +39,13 @@
|
||||
<label>仅显示管理员 <input ms-duplex-checked="showAdminOnly" type="checkbox"/></label>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
页数:{{page}}/{{page_count}}
|
||||
<button ms-attr-class="getBtnClass(0)" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass(1)" ms-click="getNext">下一页</button>
|
||||
页数:{{ page }}/{{ totalPage }}
|
||||
<button ms-attr-class="getBtnClass('pre')" ms-click="getPrevious">上一页</button>
|
||||
<button ms-attr-class="getBtnClass('next')" ms-click="getNext">下一页</button>
|
||||
</div>
|
||||
<div ms-visible="isEditing">
|
||||
<div ms-visible="editingUserId">
|
||||
<h3>修改用户信息</h3>
|
||||
|
||||
<form id="edit_user-form">
|
||||
<div class="row">
|
||||
<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">
|
||||
</div>
|
||||
<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 class="row">
|
||||
@ -65,8 +67,8 @@
|
||||
<input name="email" type="email" class="form-control" ms-duplex="email">
|
||||
</div>
|
||||
<div class="form-group col-md-4"><label>用户类型</label>
|
||||
<select name="admin_type" class="form-control" ms-duplex="admin_type">
|
||||
<option ms-repeat="user_type" ms-attr-value="$index">{{el}}</option>
|
||||
<select name="admin_type" class="form-control" ms-duplex="adminType">
|
||||
<option ms-repeat="userType" ms-attr-value="$index">{{ el }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -76,4 +78,4 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/js/app/admin/user/user_list.js"></script>
|
||||
<script src="/static/js/app/admin/user/userList.js"></script>
|
@ -1,34 +1,36 @@
|
||||
{% extends "oj_base.html" %}
|
||||
{% block body %}
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">修改密码</h2>
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">修改密码</h2>
|
||||
|
||||
<form id="change_password-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
|
||||
autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">旧密码</label>
|
||||
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password">新密码</label>
|
||||
<input type="password" class="form-control input-lg" id="new_password" name="new_password" placeholder="新密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password" placeholder="确认密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
<form id="change_password-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
|
||||
autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">旧密码</label>
|
||||
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password">新密码</label>
|
||||
<input type="password" class="form-control input-lg" id="new_password" name="new_password"
|
||||
placeholder="新密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password"
|
||||
placeholder="确认密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% 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 %}
|
@ -1,26 +1,26 @@
|
||||
{% extends "oj_base.html" %}
|
||||
{% block body %}
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">用户登录</h2>
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">用户登录</h2>
|
||||
|
||||
<form id="login-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
|
||||
autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">密码</label>
|
||||
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
<form id="login-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
|
||||
autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">密码</label>
|
||||
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js_block %}
|
||||
<script src="/static/js/app/oj/account/login.js"></script>
|
||||
<script src="/static/js/app/oj/account/login.js"></script>
|
||||
{% endblock %}
|
@ -1,38 +1,39 @@
|
||||
{% extends "oj_base.html" %}
|
||||
{% block body %}
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">用户注册</h2>
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">用户注册</h2>
|
||||
|
||||
<form id="register-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
|
||||
autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="real_name">真实姓名</label>
|
||||
<input type="text" class="form-control input-lg" id="real_name" name="real_name" placeholder="真实姓名">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">邮箱地址</label>
|
||||
<input type="email" class="form-control input-lg" id="email" name="email" placeholder="邮箱地址">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">密码</label>
|
||||
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password" placeholder="确认密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
<form id="register-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control input-lg" id="username" name="username" placeholder="用户名"
|
||||
autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="real_name">真实姓名</label>
|
||||
<input type="text" class="form-control input-lg" id="real_name" name="real_name" placeholder="真实姓名">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">邮箱地址</label>
|
||||
<input type="email" class="form-control input-lg" id="email" name="email" placeholder="邮箱地址">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">密码</label>
|
||||
<input type="password" class="form-control input-lg" id="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password"
|
||||
placeholder="确认密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js_block %}
|
||||
<script src="/static/js/app/oj/account/register.js"></script>
|
||||
<script src="/static/js/app/oj/account/register.js"></script>
|
||||
{% endblock %}
|
@ -1,22 +1,22 @@
|
||||
{% extends "oj_base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container main">
|
||||
<h1 class="text-center">{{ announcement.title }}</h1>
|
||||
<div class="container main">
|
||||
<h1 class="text-center">{{ announcement.title }}</h1>
|
||||
|
||||
<p class="text-muted text-center">
|
||||
作者:{{ announcement.created_by }}
|
||||
|
||||
创建时间:{{ announcement.create_time }}
|
||||
{% ifequal announcement.create_time announcement.last_update_time %}
|
||||
{% else %}
|
||||
|
||||
最后更新:{{ announcement.last_update_time }}
|
||||
{% endifequal %}
|
||||
</p>
|
||||
<p class="text-muted text-center">
|
||||
作者:{{ announcement.created_by }}
|
||||
|
||||
创建时间:{{ announcement.create_time }}
|
||||
{% ifequal announcement.create_time announcement.last_update_time %}
|
||||
{% else %}
|
||||
|
||||
最后更新:{{ announcement.last_update_time }}
|
||||
{% endifequal %}
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<p>{{ announcement.content|safe }}</p>
|
||||
<div>
|
||||
<p>{{ announcement.content|safe }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,15 +1,15 @@
|
||||
{% extends "oj_base.html" %}
|
||||
{% block body %}
|
||||
<div class="container main">
|
||||
<ul class="nav nav-tabs nav-tabs-google">
|
||||
<li role="presentation" class="active">
|
||||
<a href="problem.html">题目</a></li>
|
||||
<li role="presentation"><a href="my_solutions_list.html">我的提交</a></li>
|
||||
<li role="presentation"><a href="#">排名</a></li>
|
||||
</ul>
|
||||
<h2 class="text-center">第一次比赛</h2>
|
||||
<div class="container main">
|
||||
<ul class="nav nav-tabs nav-tabs-google">
|
||||
<li role="presentation" class="active">
|
||||
<a href="problem.html">题目</a></li>
|
||||
<li role="presentation"><a href="my_solutions_list.html">我的提交</a></li>
|
||||
<li role="presentation"><a href="#">排名</a></li>
|
||||
</ul>
|
||||
<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 %}
|
@ -1,37 +1,39 @@
|
||||
{% extends "oj_base.html" %}
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
|
||||
<div class="jumbotron">
|
||||
<h1>青岛大学在线评测平台</h1>
|
||||
<div class="jumbotron">
|
||||
<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>
|
||||
|
||||
<!-- 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>
|
||||
{% endblock %}
|
@ -1,4 +1,3 @@
|
||||
|
||||
<h2 class="text-center">{{ problem.title }}</h2>
|
||||
|
||||
<p class="text-muted text-center">发布时间 : {{ problem.create_time }}
|
||||
|
@ -1,9 +1,9 @@
|
||||
{% extends 'oj_base.html' %}
|
||||
{% block css_block %}
|
||||
<style>
|
||||
.CodeMirror{
|
||||
height: auto;
|
||||
}
|
||||
.CodeMirror {
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
@ -29,7 +29,7 @@
|
||||
{% ifequal submission.result 4 %}
|
||||
<p>{{ submission.info }}</p>
|
||||
{% endifequal %}
|
||||
<p>提交时间 : {{ submission.create_time }}</p>
|
||||
<p>提交时间 : {{ submission.create_time }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="code-field">
|
||||
@ -40,7 +40,7 @@
|
||||
{% endblock %}
|
||||
{% block js_block %}
|
||||
<script>
|
||||
require(["jquery", "code_mirror"], function ($, code_mirror) {
|
||||
require(["jquery", "codeMirror"], function ($, codeMirror) {
|
||||
{% ifequal submission.language 1 %}
|
||||
var language = "text/x-csrc";
|
||||
{% else %}
|
||||
@ -50,8 +50,8 @@
|
||||
var language = "text/x-java";
|
||||
{% endifequal %}
|
||||
{% endifequal %}
|
||||
var code_editor = code_mirror($("#code-editor")[0], language);
|
||||
code_editor.setOption("readOnly", true);
|
||||
var codeEditor = codeMirror($("#code-editor")[0], language);
|
||||
codeEditor.setOption("readOnly", true);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
@ -5,7 +5,7 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-9">
|
||||
<div class="row">
|
||||
<div style="float: right;">
|
||||
<div class="search-box">
|
||||
<form class="form-inline" onsubmit="return false;">
|
||||
<div class="form-group-sm">
|
||||
<input name="keyWord" class="form-control" placeholder="请输入关键词" ms-duplex="key_word">
|
||||
@ -28,7 +28,7 @@
|
||||
{% for item in problems %}
|
||||
<tr>
|
||||
<th scope="row"><a href="/problem/{{ item.id }}/">{{ item.id }}</a></th>
|
||||
<td><a href="/problem/1/">{{ item.title }}</a></td>
|
||||
<td><a href="/problem/{{ item.id }}/">{{ item.title }}</a></td>
|
||||
<td>{{ item.difficulty }}</td>
|
||||
<td>{{ item|accepted_radio }}</td>
|
||||
</tr>
|
||||
@ -38,11 +38,13 @@
|
||||
<nav>
|
||||
<ul class="pager">
|
||||
{% if previous_page %}
|
||||
<li class="previous"><a href="/problems/{{ previous_page }}/"><span
|
||||
aria-hidden="true">←</span> 上一页</a></li>
|
||||
<li class="previous"><a
|
||||
href="/problems/{{ previous_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">
|
||||
<span aria-hidden="true">←</span> 上一页</a></li>
|
||||
{% endif %}
|
||||
{% if next_page %}
|
||||
<li class="next"><a href="/problems/{{ next_page }}/">下一页 <span
|
||||
<li class="next"><a
|
||||
href="/problems/{{ next_page }}/{% if keyword %}?keyword={{ keyword }}{% endif %}{% if tag %}?tag={{ tag }}{% endif %}">下一页 <span
|
||||
aria-hidden="true">→</span></a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
@ -48,28 +48,28 @@
|
||||
<li><a href="/about/">关于</a></li>
|
||||
</ul>
|
||||
{% if request.user.is_authenticated %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
李扬
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#">我的提交</a></li>
|
||||
<li><a href="#">我的资料</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="#">退出</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
李扬
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#">我的提交</a></li>
|
||||
<li><a href="#">我的资料</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="#">退出</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{% else %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="/login/" class="dropdown-toggle">
|
||||
登录
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<li class="dropdown">
|
||||
<a href="/login/" class="dropdown-toggle">
|
||||
登录
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user