Menci
7 years ago
14 changed files with 822 additions and 29 deletions
@ -0,0 +1,347 @@
|
||||
/* |
||||
* This file is part of SYZOJ. |
||||
* |
||||
* Copyright (c) 2016 Menci <huanghaorui301@gmail.com> |
||||
* |
||||
* SYZOJ is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* SYZOJ is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public |
||||
* License along with SYZOJ. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
let Problem = syzoj.model('problem'); |
||||
let JudgeState = syzoj.model('judge_state'); |
||||
let Article = syzoj.model('article'); |
||||
let Contest = syzoj.model('contest'); |
||||
let User = syzoj.model('user'); |
||||
let UserPrivilege = syzoj.model('user_privilege'); |
||||
|
||||
let db = syzoj.db; |
||||
|
||||
app.get('/admin/info', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
let allSubmissionsCount = await JudgeState.count(); |
||||
let todaySubmissionsCount = await JudgeState.count({ submit_time: { $gte: syzoj.utils.getCurrentDate(true) } }); |
||||
let problemsCount = await Problem.count(); |
||||
let articlesCount = await Article.count(); |
||||
let contestsCount = await Contest.count(); |
||||
let usersCount = await User.count(); |
||||
|
||||
res.render('admin_info', { |
||||
allSubmissionsCount: allSubmissionsCount, |
||||
todaySubmissionsCount: todaySubmissionsCount, |
||||
problemsCount: problemsCount, |
||||
articlesCount: articlesCount, |
||||
contestsCount: contestsCount, |
||||
usersCount: usersCount |
||||
}); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
let configItems = { |
||||
'title': { name: '站点标题', type: String }, |
||||
'邮箱验证': null, |
||||
'register_mail.enabled': { name: '启用', type: Boolean }, |
||||
'register_mail.address': { name: '发件人地址', type: String }, |
||||
'register_mail.key': { name: '密钥', type: String }, |
||||
'默认参数': null, |
||||
'default.problem.time_limit': { name: '时间限制(单位:ms)', type: Number }, |
||||
'default.problem.memory_limit': { name: '空间限制(单位:MiB)', type: Number }, |
||||
'限制': null, |
||||
'limit.time_limit': { name: '最大时间限制(单位:ms)', type: Number }, |
||||
'limit.memory_limit': { name: '最大空间限制(单位:MiB)', type: Number }, |
||||
'limit.data_size': { name: '所有数据包大小(单位:byte)', type: Number }, |
||||
'limit.testdata': { name: '测试数据大小(单位:byte)', type: Number }, |
||||
'limit.submit_code': { name: '代码长度(单位:byte)', type: Number }, |
||||
'limit.submit_answer': { name: '提交答案题目答案大小(单位:byte)', type: Number }, |
||||
'limit.custom_test_input': { name: '自定义测试输入文件大小(单位:byte)', type: Number }, |
||||
'limit.testdata_filecount': { name: '测试数据文件数量(单位:byte)', type: Number }, |
||||
'每页显示数量': null, |
||||
'page.problem': { name: '题库', type: Number }, |
||||
'page.judge_state': { name: '提交记录', type: Number }, |
||||
'page.problem_statistics': { name: '题目统计', type: Number }, |
||||
'page.ranklist': { name: '排行榜', type: Number }, |
||||
'page.discussion': { name: '讨论', type: Number }, |
||||
'page.article_comment': { name: '评论', type: Number }, |
||||
'page.contest': { name: '比赛', type: Number }, |
||||
'编译器版本': null, |
||||
'languages.cpp.version': { name: 'C++', type: String }, |
||||
'languages.cpp11.version': { name: 'C++11', type: String }, |
||||
'languages.csharp.version': { name: 'C#', type: String }, |
||||
'languages.c.version': { name: 'C', type: String }, |
||||
'languages.vala.version': { name: 'Vala', type: String }, |
||||
'languages.java.version': { name: 'Java', type: String }, |
||||
'languages.pascal.version': { name: 'Pascal', type: String }, |
||||
'languages.lua.version': { name: 'Lua', type: String }, |
||||
'languages.luajit.version': { name: 'LuaJIT', type: String }, |
||||
'languages.python2.version': { name: 'Python 2', type: String }, |
||||
'languages.python3.version': { name: 'Python 3', type: String }, |
||||
'languages.nodejs.version': { name: 'Node.js', type: String }, |
||||
'languages.ruby.version': { name: 'Ruby', type: String }, |
||||
'languages.haskell.version': { name: 'Haskell', type: String }, |
||||
'languages.ocaml.version': { name: 'OCaml', type: String }, |
||||
'languages.vbnet.version': { name: 'Visual Basic', type: String } |
||||
}; |
||||
|
||||
app.get('/admin/config', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
for (let i in configItems) { |
||||
if (!configItems[i]) continue; |
||||
configItems[i].val = eval(`syzoj.config.${i}`); |
||||
} |
||||
|
||||
res.render('admin_config', { |
||||
items: configItems |
||||
}); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.post('/admin/config', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
for (let i in configItems) { |
||||
if (!configItems[i]) continue; |
||||
if (req.body[i]) { |
||||
let val; |
||||
if (configItems[i].type === Boolean) { |
||||
val = req.body[i] === 'on'; |
||||
} else { |
||||
val = req.body[i]; |
||||
} |
||||
|
||||
let f = new Function('val', `syzoj.config.${i} = val`); |
||||
f(val); |
||||
} |
||||
} |
||||
|
||||
await syzoj.utils.saveConfig(); |
||||
|
||||
res.redirect(syzoj.utils.makeUrl(['admin', 'config'])); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.get('/admin/privilege', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
let a = await UserPrivilege.query(); |
||||
let users = {}; |
||||
for (let p of a) { |
||||
if (!users[p.user_id]) { |
||||
users[p.user_id] = { |
||||
user: await User.fromID(p.user_id), |
||||
privileges: [] |
||||
}; |
||||
} |
||||
|
||||
users[p.user_id].privileges.push(p.privilege); |
||||
} |
||||
|
||||
res.render('admin_privilege', { |
||||
users: Object.values(users) |
||||
}); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.post('/admin/privilege', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
let data = JSON.parse(req.body.data); |
||||
for (let id in data) { |
||||
let user = await User.fromID(id); |
||||
if (!user) throw new ErrorMessage(`不存在 ID 为 ${id} 的用户。`); |
||||
await user.setPrivileges(data[id]); |
||||
} |
||||
|
||||
res.redirect(syzoj.utils.makeUrl(['admin', 'privilege'])); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.get('/admin/rejudge', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
res.render('admin_rejudge', { |
||||
form: {}, |
||||
count: null |
||||
}); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.post('/admin/rejudge', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
let user = await User.fromName(req.body.submitter || ''); |
||||
let where = {}; |
||||
if (user) where.user_id = user.id; |
||||
else if (req.body.submitter) where.user_id = -1; |
||||
|
||||
let minID = parseInt(req.body.min_id); |
||||
if (isNaN(minID)) minID = 0; |
||||
let maxID = parseInt(req.body.max_id); |
||||
if (isNaN(maxID)) maxID = 2147483647; |
||||
|
||||
where.id = { |
||||
$and: { |
||||
$gte: parseInt(minID), |
||||
$lte: parseInt(maxID) |
||||
} |
||||
}; |
||||
|
||||
let minScore = parseInt(req.body.min_score); |
||||
if (isNaN(minScore)) minScore = 0; |
||||
let maxScore = parseInt(req.body.max_score); |
||||
if (isNaN(maxScore)) maxScore = 100; |
||||
|
||||
where.score = { |
||||
$and: { |
||||
$gte: parseInt(minScore), |
||||
$lte: parseInt(maxScore) |
||||
} |
||||
}; |
||||
|
||||
let minTime = syzoj.utils.parseDate(req.body.min_time); |
||||
if (isNaN(minTime)) minTime = 0; |
||||
let maxTime = syzoj.utils.parseDate(req.body.max_time); |
||||
if (isNaN(maxTime)) maxTime = 2147483647; |
||||
|
||||
where.submit_time = { |
||||
$and: { |
||||
$gte: parseInt(minTime), |
||||
$lte: parseInt(maxTime) |
||||
} |
||||
}; |
||||
|
||||
if (req.body.language) { |
||||
if (req.body.language === 'submit-answer') where.language = ''; |
||||
else where.language = req.body.language; |
||||
} |
||||
if (req.body.status) where.status = { $like: req.body.status + '%' }; |
||||
if (req.body.problem_id) where.problem_id = parseInt(req.body.problem_id) || -1; |
||||
|
||||
let count = await JudgeState.count(where); |
||||
if (req.body.type === 'rejudge') { |
||||
let submissions = await JudgeState.query(null, where); |
||||
for (let submission of submissions) { |
||||
await submission.rejudge(); |
||||
} |
||||
} |
||||
|
||||
res.render('admin_rejudge', { |
||||
form: req.body, |
||||
count: count |
||||
}); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.get('/admin/links', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
res.render('admin_links', { |
||||
links: syzoj.config.links || [] |
||||
}); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.post('/admin/links', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
syzoj.config.links = JSON.parse(req.body.data); |
||||
await syzoj.utils.saveConfig(); |
||||
|
||||
res.redirect(syzoj.utils.makeUrl(['admin', 'links'])); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.get('/admin/raw', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
res.render('admin_raw', { |
||||
data: JSON.stringify(syzoj.config, null, 2) |
||||
}); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
||||
|
||||
app.post('/admin/raw', async (req, res) => { |
||||
try { |
||||
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); |
||||
|
||||
syzoj.config = JSON.parse(req.body.data); |
||||
await syzoj.utils.saveConfig(); |
||||
|
||||
res.redirect(syzoj.utils.makeUrl(['admin', 'raw'])); |
||||
} catch (e) { |
||||
syzoj.log(e); |
||||
res.render('error', { |
||||
err: e |
||||
}) |
||||
} |
||||
}); |
@ -1,25 +0,0 @@
|
||||
<% include header %> |
||||
<div class="ui grid"> |
||||
<div class="four wide column"> |
||||
<div class="ui vertical fluid tabular menu"> |
||||
<a class="item"> |
||||
; |
||||
</a> |
||||
<a class="item"> |
||||
Pics |
||||
</a> |
||||
<a class="item"> |
||||
Companies |
||||
</a> |
||||
<a class="item active"> |
||||
Links |
||||
</a> |
||||
</div> |
||||
</div> |
||||
<div class="twelve wide stretched column"> |
||||
<div class="ui segment"> |
||||
This is an stretched grid column. This segment will always match the tab height |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<% include footer %> |
@ -0,0 +1,54 @@
|
||||
<% this.adminPage = 'config'; %> |
||||
<% include admin_header %> |
||||
<form method="post" class="ui form"> |
||||
<% |
||||
function showTitle(title) { |
||||
%><h4 class="ui dividing header"><%= title %></h4><% |
||||
} |
||||
|
||||
function showStringItem(name, text, val) { |
||||
%> |
||||
<div class="ui fluid input inline field"> |
||||
<label style="line-height: 37.8px; font-weight: normal; "><%= text %></label> |
||||
<input type="text" name="<%= name %>" value="<%= val %>"> |
||||
</div> |
||||
<% |
||||
} |
||||
|
||||
function showNumberItem(name, text, val) { |
||||
%> |
||||
<div class="ui fluid input inline field"> |
||||
<label style="line-height: 37.8px; font-weight: normal; "><%= text %></label> |
||||
<input type="number" name="<%= name %>" value="<%= val %>"> |
||||
</div> |
||||
<% |
||||
} |
||||
|
||||
function showBooleanItem(name, text, val) { |
||||
%> |
||||
<div class="inline field"> |
||||
<div class="ui toggle checkbox"> |
||||
<input name="<%= name %>" type="checkbox" class=""<% if (val) { %> checked<% } %>> |
||||
<label><%= text %></label> |
||||
</div> |
||||
</div> |
||||
<% |
||||
} |
||||
|
||||
for (let item in items) { |
||||
if (items[item] === null) { |
||||
showTitle(item); |
||||
} else if (items[item].type === String) { |
||||
showStringItem(item, items[item].name, items[item].val); |
||||
} else if (items[item].type === Number) { |
||||
showNumberItem(item, items[item].name, items[item].val); |
||||
} else { |
||||
showBooleanItem(item, items[item].name, items[item].val); |
||||
} |
||||
} |
||||
%> |
||||
<div style="text-align: center; "> |
||||
<button class="ui blue button">提交</button> |
||||
</div> |
||||
</form> |
||||
<% include admin_footer %> |
@ -0,0 +1,24 @@
|
||||
<% |
||||
let items = { |
||||
info: '统计信息', |
||||
config: '系统配置', |
||||
privilege: '权限管理', |
||||
rejudge: '一键重测', |
||||
links: '友链管理', |
||||
raw: '配置文件' |
||||
}; |
||||
%> |
||||
<% this.title = items[this.adminPage] + ' - 后台管理'; %> |
||||
<% include header %> |
||||
<h1 style="text-align: center; margin-bottom: 27px; ">后台管理</h1> |
||||
<div class="ui grid"> |
||||
<div class="three wide column"> |
||||
<div class="ui vertical fluid tabular menu" style="height: 100%; "> |
||||
<% for (let x in items) { %> |
||||
<a class="item<% if (this.adminPage === x) { %> active<% } %>"<% if (this.adminPage !== x) { %> href="<%= syzoj.utils.makeUrl(['admin', x]) %>"<% } %>> |
||||
<%= items[x] %> |
||||
</a> |
||||
<% } %> |
||||
</div> |
||||
</div> |
||||
<div class="thirteen wide stretched column"> |
@ -0,0 +1,79 @@
|
||||
<% this.adminPage = 'info'; %> |
||||
<% include admin_header %> |
||||
<style> |
||||
.ui.statistics { |
||||
width: 100%; |
||||
} |
||||
|
||||
.statistic { |
||||
width: calc(100% / 3 - 3em); |
||||
} |
||||
|
||||
.statistic .icon { |
||||
font-size: 0.7em; |
||||
display: inline-block; |
||||
vertical-align: top; |
||||
padding-top: 2px; |
||||
} |
||||
|
||||
.statistic .label { |
||||
font-weight: normal !important; |
||||
} |
||||
</style> |
||||
<div class="ui statistics"> |
||||
<div class="statistic"> |
||||
<div class="value"> |
||||
<i class="tasks icon"></i> |
||||
<%= allSubmissionsCount %> |
||||
</div> |
||||
<div class="label"> |
||||
总评测量 |
||||
</div> |
||||
</div> |
||||
<div class="statistic"> |
||||
<div class="value"> |
||||
<i class="tasks icon"></i> |
||||
<%= todaySubmissionsCount %> |
||||
</div> |
||||
<div class="label"> |
||||
今日评测量 |
||||
</div> |
||||
</div> |
||||
<div class="statistic"> |
||||
<div class="value"> |
||||
<i class="list icon"></i> |
||||
<%= problemsCount %> |
||||
</div> |
||||
<div class="label"> |
||||
题目数量 |
||||
</div> |
||||
</div> |
||||
<div class="statistic"> |
||||
<div class="value"> |
||||
<i class="comments icon"></i> |
||||
<%= articlesCount %> |
||||
</div> |
||||
<div class="label"> |
||||
讨论数量 |
||||
</div> |
||||
</div> |
||||
<div class="statistic"> |
||||
<div class="value"> |
||||
<i class="calendar icon"></i> |
||||
<%= contestsCount %> |
||||
</div> |
||||
<div class="label"> |
||||
比赛数量 |
||||
</div> |
||||
</div> |
||||
<div class="statistic"> |
||||
<div class="value"> |
||||
<i class="user icon"></i> |
||||
<%= usersCount %> |
||||
</div> |
||||
<div class="label"> |
||||
用户数量 |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<% include admin_footer %> |
@ -0,0 +1,78 @@
|
||||
<% |
||||
this.adminPage = 'links'; |
||||
%> |
||||
<% include admin_header %> |
||||
<table class="ui center aligned celled table"> |
||||
<thead> |
||||
<tr> |
||||
<th>名称</th> |
||||
<th>链接</th> |
||||
<th width="50px">删除</th> |
||||
</tr> |
||||
</thead> |
||||
|
||||
<tbody> |
||||
<% for (let i = 0; i < links.length; i++) { %> |
||||
<tr> |
||||
<td><%= links[i].title %></td> |
||||
<td><a href="<%= links[i].url %>"><%= links[i].url %></a></td> |
||||
<td> |
||||
<a onclick="$('#modal-remove-<%= i %>').modal('show');" style="color: #000; " href="#"><i class="remove icon"></i></a> |
||||
<div class="ui basic modal" id="modal-remove-<%= i %>"> |
||||
<div class="ui icon header"> |
||||
<i class="remove icon"></i> |
||||
<p style="margin-top: 15px; ">删除友链</p> |
||||
</div> |
||||
<div class="content" style="text-align: center; "> |
||||
<p>确认删除该友链吗?</p> |
||||
</div> |
||||
<div class="actions"> |
||||
<div class="ui red basic cancel inverted button"> |
||||
<i class="remove icon"></i> |
||||
否 |
||||
</div> |
||||
<a class="ui green ok inverted button remove_link" data-id="<%= i %>"> |
||||
<i class="checkmark icon"></i> |
||||
是 |
||||
</a> |
||||
</div> |
||||
</div> |
||||
</td> |
||||
</tr> |
||||
<% } %> |
||||
</tbody> |
||||
</table> |
||||
|
||||
<div class="ui form"> |
||||
<div class="two fields"> |
||||
<div class="field"> |
||||
<label>名称</label> |
||||
<input type="text" id="add_title"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>链接</label> |
||||
<input type="text" id="add_url"> |
||||
</div> |
||||
</div> |
||||
<div style="text-align: center; "><div id="add_button" class="ui submit button">添加</a></div> |
||||
</div> |
||||
|
||||
<form method="post" id="submit_form"> |
||||
<input type="hidden" name="data" id="submit_data"> |
||||
</form> |
||||
|
||||
<script> |
||||
var links = <%- JSON.stringify(links) %>; |
||||
$('.remove_link').click(function () { |
||||
links.splice($(this).data('id'), 1); |
||||
$('#submit_data').val(JSON.stringify(links)); |
||||
$('#submit_form').submit(); |
||||
}); |
||||
|
||||
$('#add_button').click(function () { |
||||
links.push({ title: $('#add_title').val(), url: $('#add_url').val() }); |
||||
$('#submit_data').val(JSON.stringify(links)); |
||||
$('#submit_form').submit(); |
||||
}); |
||||
</script> |
||||
<% include admin_footer %> |
@ -0,0 +1,63 @@
|
||||
<% |
||||
this.adminPage = 'privilege'; |
||||
let privileges = { |
||||
manage_problem: '管理题目', |
||||
manage_problem_tag: '管理题目标签', |
||||
manage_user: '管理用户', |
||||
}; |
||||
%> |
||||
<% include admin_header %> |
||||
<table class="ui center aligned celled table"> |
||||
<thead> |
||||
<tr> |
||||
<th>ID</th> |
||||
<th>用户名</th> |
||||
<% for (let privilege in privileges) { %> |
||||
<th width="20%"><%= privileges[privilege] %></th> |
||||
<% } %> |
||||
</tr> |
||||
</thead> |
||||
|
||||
<tbody> |
||||
<% for (let user of users) { %> |
||||
<tr> |
||||
<td><%= user.user.id %></td> |
||||
<td><%= user.user.username %></td> |
||||
<% for (let privilege in privileges) { %> |
||||
<td> |
||||
<div class="ui fitted toggle checkbox checkbox_privilege" data-user="<%= user.user.id %>" data-name="<%= privilege %>"> |
||||
<input type="checkbox"<% if (user.privileges.includes(privilege)) { %> checked<% } %>> |
||||
<label></label> |
||||
</div> |
||||
</td> |
||||
<% } %> |
||||
</tr> |
||||
<% } %> |
||||
</tbody> |
||||
</table> |
||||
|
||||
<div style="text-align: center; "> |
||||
<button class="ui button" onclick="submit()">提交</button> |
||||
</div> |
||||
|
||||
<form method="post" id="submit_form"> |
||||
<input type="hidden" name="data" id="submit_data"> |
||||
</form> |
||||
|
||||
<script> |
||||
function submit() { |
||||
var users = {}; |
||||
$('.checkbox_privilege').each(function () { |
||||
var user = $(this).data('user'); |
||||
var name = $(this).data('name'); |
||||
if (!users[user]) users[user] = []; |
||||
if ($(this).checkbox('is checked')) { |
||||
users[user].push(name); |
||||
} |
||||
}); |
||||
|
||||
$('#submit_data').val(JSON.stringify(users)); |
||||
$('#submit_form').submit(); |
||||
} |
||||
</script> |
||||
<% include admin_footer %> |
@ -0,0 +1,34 @@
|
||||
<% this.adminPage = 'raw'; %> |
||||
<% include admin_header %> |
||||
<form method="post" class="ui form"> |
||||
|
||||
<div id="editor" style="border: 1px solid #D4D4D5; height: 500px; margin-bottom: 20px; "><%= data %></div> |
||||
<input type="hidden" name="data"> |
||||
|
||||
<script src="/libs/ace/ace.js"></script> |
||||
<script type="text/javascript"> |
||||
var editor = ace.edit("editor"); |
||||
|
||||
editor.setTheme("ace/theme/tomorrow"); |
||||
editor.getSession().setMode("ace/mode/json"); |
||||
editor.getSession().setUseSoftTabs(false); |
||||
|
||||
editor.container.name = 'data'; |
||||
editor.container.style.lineHeight = 1.6; |
||||
editor.container.style.fontSize = '14px'; |
||||
editor.container.style.fontFamily = "'Roboto Mono', 'Bitstream Vera Sans Mono', 'Menlo', 'Consolas', 'Lucida Console', monospace"; |
||||
editor.setShowPrintMargin(false); |
||||
editor.renderer.updateFontSize(); |
||||
|
||||
var input = $('[name="data"]'); |
||||
editor.getSession().on("change", function () { |
||||
input.val(editor.getSession().getValue()); |
||||
}); |
||||
</script> |
||||
|
||||
|
||||
<div style="text-align: center; "> |
||||
<button class="ui blue button">提交</button> |
||||
</div> |
||||
</form> |
||||
<% include admin_footer %> |
@ -0,0 +1,108 @@
|
||||
<% this.adminPage = 'rejudge'; %> |
||||
<% include admin_header %> |
||||
<form method="post" class="ui form"> |
||||
|
||||
<div class="four fields"> |
||||
<div class="field"> |
||||
<label>题目 ID</label> |
||||
<input type="text" name="problem_id" placeholder="题目 ID" value="<%= form.problem_id %>"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>用户名</label> |
||||
<input type="text" name="submitter" placeholder="用户名" value="<%= form.submitter %>"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>语言</label> |
||||
<div class="ui selection dropdown"> |
||||
<input type="hidden" name="language" value="<%= form.language %>"> |
||||
<i class="dropdown icon"></i> |
||||
<div class="default text"></div> |
||||
<div class="menu"> |
||||
<div class="item" data-value="">不限</div> |
||||
<div class="item" data-value="submit-answer">提交答案</div> |
||||
<% for (let lang in syzoj.config.languages) { %> |
||||
<div class="item" data-value="<%= lang %>"><%= syzoj.config.languages[lang].show %></div> |
||||
<% } %> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="field"> |
||||
<label>状态</label> |
||||
<div class="ui selection dropdown"> |
||||
<input type="hidden" name="status" value="<%= form.status %>"> |
||||
<i class="dropdown icon"></i> |
||||
<div class="default text"></div> |
||||
<div class="menu"> |
||||
<div class="item" data-value="">不限<i class="dropdown icon" style="visibility: hidden; "></i></div> |
||||
<% for (let status in this.icon) { %> |
||||
<% if (this.iconHidden.includes(status)) continue; %> |
||||
<div class="item" data-value="<%= status %>"><span class="status <%= status.toLowerCase().split(' ').join('_') %>"><i class="<%= this.icon[status] %> icon"></i> <%= status %></div> |
||||
<% } %> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="three fields"> |
||||
<div class="field"> |
||||
<label>ID(最小值)</label> |
||||
<input type="text" name="min_id" placeholder="ID(最小值)" value="<%= form.min_id %>"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>分数(最小值)</label> |
||||
<input type="text" name="min_score" placeholder="分数(最小值)" value="<%= form.min_score %>"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>提交时间(最小值)</label> |
||||
<input type="text" name="min_time" placeholder="提交时间(最小值)" value="<%= form.min_time || syzoj.utils.formatDate(0) %>"> |
||||
</div> |
||||
</div> |
||||
<div class="three fields"> |
||||
<div class="field"> |
||||
<label>ID(最大值)</label> |
||||
<input type="text" name="max_id" placeholder="ID(最大值)" value="<%= form.max_id %>"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>分数(最大值)</label> |
||||
<input type="text" name="max_score" placeholder="分数(最大值)" value="<%= form.max_score %>"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>提交时间(最大值)</label> |
||||
<input type="text" name="max_time" placeholder="提交时间(最大值)" value="<%= form.max_time || syzoj.utils.formatDate(2147483647) %>"> |
||||
</div> |
||||
</div> |
||||
|
||||
<div style="text-align: center; "> |
||||
<button class="ui button" name="type" value="query">查询</button> |
||||
<% if (form.type === 'rejudge') { %> |
||||
<button class="ui blue disabled button" name="type" value="rejudge">已重测 <%= count %> 条记录</button> |
||||
<% } else if (count !== null) { %> |
||||
<a onclick="$('#modal-rejudge').modal('show');" class="ui blue<% if (count === 0) { %> disabled<% } %> button"><% if (count === 0) { %>没有符合条件的记录<% } else { %>重测 <%= count %> 条记录<% } %></a> |
||||
<button id="submit_rejudge" name="type" value="rejudge" style="display: none; "></button> |
||||
<div class="ui basic modal" id="modal-rejudge"> |
||||
<div class="ui icon header"> |
||||
<i class="refresh icon"></i> |
||||
<p style="margin-top: 15px; ">重新评测</p> |
||||
</div> |
||||
<div class="content" style="text-align: center; "> |
||||
<p>确认重新评测 <%= count %> 条记录吗?</p> |
||||
</div> |
||||
<div class="actions"> |
||||
<div class="ui red basic cancel inverted button"> |
||||
<i class="remove icon"></i> |
||||
否 |
||||
</div> |
||||
<button class="ui green ok inverted button" onclick="$('#submit_rejudge').click()"> |
||||
<i class="checkmark icon"></i> |
||||
是 |
||||
</button> |
||||
</div> |
||||
</div> |
||||
<% } %> |
||||
</div> |
||||
</form> |
||||
<script> |
||||
$(function () { |
||||
$('.ui.dropdown').dropdown(); |
||||
}); |
||||
</script> |
||||
<% include admin_footer %> |
Loading…
Reference in new issue