Browse Source

New UI for problem submit

master
Menci 8 years ago
parent
commit
141113a9f7
  1. 48
      config-example.json
  2. 24
      models/problem.js
  3. 7
      modules/contest.js
  4. 7
      modules/problem.js
  5. 81
      views/contest_problem.ejs
  6. 104
      views/problem.ejs
  7. 26
      views/submit.ejs

48
config-example.json

@ -32,51 +32,75 @@
"languages": { "languages": {
"cpp": { "cpp": {
"show": "C++", "show": "C++",
"highlight": "cpp" "highlight": "cpp",
"version": "GCC 5.4.0",
"editor": "c_cpp"
}, },
"cpp11": { "cpp11": {
"show": "C++11", "show": "C++11",
"highlight": "cpp" "highlight": "cpp",
"version": "GCC 5.4.0",
"editor": "c_cpp"
}, },
"csharp": { "csharp": {
"show": "C#", "show": "C#",
"highlight": "csharp" "highlight": "csharp",
"version": "MCS 4.6.2.0, Mono 4.6.2",
"editor": "csharp"
}, },
"c": { "c": {
"show": "C", "show": "C",
"highlight": "c" "highlight": "c",
"version": "GCC 5.4.0",
"editor": "c_cpp"
}, },
"java": { "java": {
"show": "Java", "show": "Java",
"highlight": "java" "highlight": "java",
"version": "GCC 5.4.0",
"editor": "java"
}, },
"pascal": { "pascal": {
"show": "Pascal", "show": "Pascal",
"highlight": "pascal" "highlight": "pascal",
"version": "FPC 3.0.0",
"editor": "pascal"
}, },
"python2": { "python2": {
"show": "Python 2", "show": "Python 2",
"highlight": "python" "highlight": "python",
"version": "CPython 2.7.12",
"editor": "python"
}, },
"python3": { "python3": {
"show": "Python 3", "show": "Python 3",
"highlight": "python" "highlight": "python",
"version": "CPython 3.5.2",
"editor": "python"
}, },
"nodejs": { "nodejs": {
"show": "Node.js", "show": "Node.js",
"highlight": "js" "highlight": "js",
"version": "7.2.1",
"editor": "javascript"
}, },
"ruby": { "ruby": {
"show": "Ruby", "show": "Ruby",
"highlight": "ruby" "highlight": "ruby",
"version": "2.3.1",
"editor": "ruby"
}, },
"haskell": { "haskell": {
"show": "Haskell", "show": "Haskell",
"highlight": "haskell" "highlight": "haskell",
"version": "GHC 7.10.3",
"editor": "haskell"
}, },
"vbnet": { "vbnet": {
"show": "Visual Basic", "show": "Visual Basic",
"highlight": "vbnet" "highlight": "vbnet",
"version": "VBNC 0.0.0.5943, Mono 4.6.2",
"editor": "vbscript"
} }
}, },
"notices": [ "notices": [

24
models/problem.js

@ -129,23 +129,33 @@ class Problem extends Model {
this.testdata_id = file.id; this.testdata_id = file.id;
} }
async getJudgeState(user) { async getJudgeState(user, acFirst) {
if (!user) return null; if (!user) return null;
let JudgeState = syzoj.model('judge_state'); let JudgeState = syzoj.model('judge_state');
let states = await JudgeState.query(null, { let where = {
user_id: user.id, user_id: user.id,
problem_id: this.id problem_id: this.id
}, [['submit_time', 'desc']]); };
if (!states || states.length === 0) return null; if (acFirst) {
where.status = 'Accepted';
for (let x of states) { let state = await JudgeState.findOne({
if (x.status === 'Accepted') return x; where: where,
order: [['submit_time', 'desc']]
});
if (state) return state;
} }
return states[0]; if (where.status) delete where.status;
return await JudgeState.findOne({
where: where,
order: [['submit_time', 'desc']]
});
} }
getModel() { return model; } getModel() { return model; }

7
modules/contest.js

@ -218,9 +218,12 @@ app.get('/contest/:id/:pid', async (req, res) => {
await syzoj.utils.markdown(problem, [ 'description', 'input_format', 'output_format', 'example', 'limit_and_hint' ]); await syzoj.utils.markdown(problem, [ 'description', 'input_format', 'output_format', 'example', 'limit_and_hint' ]);
res.render('contest_problem', { let state = await problem.getJudgeState(res.locals.user, false);
res.render('problem', {
contest: contest, contest: contest,
problem: problem problem: problem,
state: state
}); });
} catch (e) { } catch (e) {
syzoj.log(e); syzoj.log(e);

7
modules/problem.js

@ -31,7 +31,7 @@ app.get('/problem', async (req, res) => {
await problems.forEachAsync(async problem => { await problems.forEachAsync(async problem => {
problem.allowedEdit = await problem.isAllowedEditBy(res.locals.user); problem.allowedEdit = await problem.isAllowedEditBy(res.locals.user);
problem.judge_state = await problem.getJudgeState(res.locals.user); problem.judge_state = await problem.getJudgeState(res.locals.user, true);
}); });
res.render('problem_set', { res.render('problem_set', {
@ -64,8 +64,11 @@ app.get('/problem/:id', async (req, res) => {
throw 'Permission denied'; throw 'Permission denied';
} }
let state = await problem.getJudgeState(res.locals.user, false);
res.render('problem', { res.render('problem', {
problem: problem problem: problem,
state: state
}); });
} catch (e) { } catch (e) {
syzoj.log(e); syzoj.log(e);

81
views/contest_problem.ejs

@ -1,81 +0,0 @@
<% this.title = syzoj.utils.removeTitleTag(problem.title) + ' - ' + contest.title + ' - 比赛' %>
<% include header %>
<div class="ui center aligned grid">
<div class="row">
<h1><%= syzoj.utils.removeTitleTag(problem.title) %></h1>
</div>
<div class="row" style="margin-top: -15px">
<span class="ui label">内存限制: <%= problem.memory_limit %> MiB</span>
<span class="ui label">时间限制: <%= problem.time_limit %> ms</span>
</div>
<div class="row" style="margin-top: -23px">
<% if (problem.file_io) { %>
<span class="ui label">输入文件: <%= problem.file_io_input_name %></span>
<span class="ui label">输出文件: <%= problem.file_io_output_name %></span>
<% } else { %>
<span class="ui label">标准输入输出</span>
<% } %>
</div>
</div>
<div class="ui grid">
<div class="row">
<div class="column">
<div class="ui buttons">
<a href="#submit_form" class="ui primary button">提交</a>
<a href="<%= syzoj.utils.makeUrl(['contest', contest.id]) %>" class="ui positive button">返回比赛</a>
</div>
</div>
</div>
<div class="row">
<div class="column">
<h4 class="ui top attached block header">题目描述</h4>
<div class="ui bottom attached segment" id="description"><%- problem.description %></div>
</div>
</div>
<div class="row">
<div class="column">
<h4 class="ui top attached block header">输入格式</h4>
<div class="ui bottom attached segment" id="input"><%- problem.input_format %></div>
</div>
</div>
<div class="row">
<div class="column">
<h4 class="ui top attached block header">输出格式</h4>
<div class="ui bottom attached segment" id="output"><%- problem.output_format %></div>
</div>
</div>
<div class="row">
<div class="column">
<h4 class="ui top attached block header">测试样例</h4>
<div class="ui bottom attached segment" id="example"><%- problem.example %></div>
</div>
</div>
<div class="row">
<div class="column">
<h4 class="ui top attached block header">数据范围与提示</h4>
<div class="ui bottom attached segment" id="hint"><%- problem.limit_and_hint %></div>
</div>
</div>
</div>
<h2 class="ui header">提交代码</h2>
<form id="submit_form" class="ui form" action="<%= syzoj.utils.makeUrl(['submit', problem.id], { contest_id: contest.id }) %>" method="post">
<div class="field">
<label for="doc-select-1">选择语言</label>
<select class="ui fluid dropdown" name="language" id="doc-select-1">
<% for (lang in syzoj.config.languages) { %>
<option value="<%= lang %>"><%= syzoj.config.languages[lang].show %></option>
<% } %>
</select>
</div>
<div class="field">
<textarea rows="15" name="code" style="font-family: 'Roboto Mono', 'Bitstream Vera Sans Mono', 'Menlo', 'Consolas', 'Lucida Console', monospace; "></textarea>
</div>
<button type="submit" class="ui button">提交</button>
</form>
<script>
$(function () {
$('.ui.dropdown').dropdown();
});
</script>
<% include footer %>

104
views/problem.ejs

@ -1,8 +1,32 @@
<% this.title = problem.title + ' - 题目' %> <%
if (typeof contest === 'undefined') contest = null;
if (contest) {
this.title = syzoj.utils.removeTitleTag(problem.title) + ' - ' + contest.title + ' - 比赛';
} else {
this.title = problem.title + ' - 题目';
}
%>
<% include header %> <% include header %>
<style>
.ace_cursor {
border-left-width: 1px !important;
color: #000 !important;
}
#languages-menu::-webkit-scrollbar {
width: 0px;
background: transparent;
}
</style>
<div class="ui center aligned grid"> <div class="ui center aligned grid">
<div class="row"> <div class="row">
<h1 class="ui header"><%= problem.title %><% if (problem.allowedEdit && !problem.is_public) { %><span class="ui tiny red label">未公开</span><% } %></h1> <h1 class="ui header">
<% if (contest) { %>
<%= syzoj.utils.removeTitleTag(problem.title) %>
<% } else { %>
<%= problem.title %><% if (problem.allowedEdit && !problem.is_public) { %><span class="ui tiny red label">未公开</span><% } %>
<% } %>
</h1>
</div> </div>
<div class="row" style="margin-top: -15px"> <div class="row" style="margin-top: -15px">
<span class="ui label">内存限制: <%= problem.memory_limit %> MiB</span> <span class="ui label">内存限制: <%= problem.memory_limit %> MiB</span>
@ -21,7 +45,10 @@
<div class="row"> <div class="row">
<div class="column"> <div class="column">
<div class="ui buttons"> <div class="ui buttons">
<a class="small ui primary button" href="<%= syzoj.utils.makeUrl(['submit', problem.id]) %>">提交</a> <a class="small ui primary button" href="#submit_code">提交</a>
<% if (contest) { %>
<a href="<%= syzoj.utils.makeUrl(['contest', contest.id]) %>" class="ui positive button">返回比赛</a>
<% } else { %>
<a class="small ui positive button" href="<%= syzoj.utils.makeUrl(['judge_state'], { problem_id: problem.id }) %>">提交记录</a> <a class="small ui positive button" href="<%= syzoj.utils.makeUrl(['judge_state'], { problem_id: problem.id }) %>">提交记录</a>
<a class="small ui yellow button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'download']) %>">下载测试数据</a> <a class="small ui yellow button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'download']) %>">下载测试数据</a>
<% if (problem.allowedEdit) { %> <% if (problem.allowedEdit) { %>
@ -35,6 +62,7 @@
<button class="small ui button" id="public">公开</button> <button class="small ui button" id="public">公开</button>
<% } %> <% } %>
<% } %> <% } %>
<% } %>
</div> </div>
</div> </div>
</div> </div>
@ -68,9 +96,77 @@
<div class="ui bottom attached segment" id="hint"><%- problem.limit_and_hint %></div> <div class="ui bottom attached segment" id="hint"><%- problem.limit_and_hint %></div>
</div> </div>
</div> </div>
<div class="row">
<div class="column">
<%
let formUrl;
if (contest) formUrl = syzoj.utils.makeUrl(['submit', problem.id], { contest_id: contest.id });
else formUrl = syzoj.utils.makeUrl(['submit', problem.id]);
%>
<form class="ui form" action="<%= formUrl %>" method="post" onsubmit="return submit_code()" id="submit_code">
<input name="language" type="hidden" id="form">
<input name="code" type="hidden">
<div class="ui grid">
<div class="four wide column" style="margin-right: -25px; ">
<div class="ui attached vertical fluid pointing menu" id="languages-menu" style="max-height: 370px; overflow-y: scroll; overflow-x: hidden; ">
<%
let language = Object.getOwnPropertyNames(syzoj.config.languages).shift();
if (state) {
language = state.language;
}
%>
<% for (lang in syzoj.config.languages) { %>
<a class="item<%= lang === language ? ' active' : '' %>" data-value="<%= lang %>" data-mode="<%= syzoj.config.languages[lang].editor %>">
<%= syzoj.config.languages[lang].show %>
<div class="ui right floated" style="opacity: 0.4; margin-top: 8px; font-size: 0.7em; "><%= syzoj.config.languages[lang].version %></div>
</a>
<% } %>
</div>
</div>
<div class="twelve wide stretched column" style="padding-left: 0; margin-left: calc(-1rem - 1px); width: calc(75% + 1rem + 1px + 25px) !important; ">
<div id="editor" style="border: 1px solid #D4D4D5; "><% if (state) { %><%= state.code %><% } %></div>
</div>
</div>
<div class="ui center aligned vertical segment" style="padding-bottom: 0; "><button type="submit" class="ui button">提交</button></div>
</form>
</div>
</div>
</div> </div>
<script src="https://cdn.bootcss.com/ace/1.2.6/ace.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var editor = ace.edit("editor");
editor.setTheme("ace/theme/tomorrow");
editor.getSession().setMode("ace/mode/" + $('#languages-menu .item.active').data('mode'));
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();
function submit_code() {
$('#submit_code input[name=language]').val($('#languages-menu .item.active').data('value'));
$('#submit_code input[name=code]').val(editor.getValue());
return true;
}
$('#languages-menu')[0].scrollTop = $('#languages-menu .active')[0].offsetTop - $('#languages-menu')[0].firstElementChild.offsetTop;
$(function () {
$('#languages-menu .item').click(function() {
$(this)
.addClass('active')
.closest('.ui.menu')
.find('.item')
.not($(this))
.removeClass('active')
;
editor.getSession().setMode("ace/mode/" + $(this).data('mode'));
});
});
<% if (!contest) { %>
function public_problem() { function public_problem() {
$.ajax({ $.ajax({
url: '<%= syzoj.utils.makeUrl(['api', 'problem', problem.id, 'public']) %>', url: '<%= syzoj.utils.makeUrl(['api', 'problem', problem.id, 'public']) %>',
@ -95,6 +191,6 @@ $(document).ready(function(){
dis_public_problem(); dis_public_problem();
}); });
}); });
<% } %>
</script> </script>
<% include footer %> <% include footer %>

26
views/submit.ejs

@ -1,26 +0,0 @@
<% this.title = problem.title + ' - 提交'; %>
<% include header %>
<h1>提交 <%= problem.title %></h1>
<div class="padding">
<form class="ui form" action="<%= syzoj.utils.makeUrl(['submit', problem.id]) %>" method="post">
<div class="field">
<label for="doc-select-1">选择语言</label>
<select class="ui fluid dropdown" id="doc-select-1" name="language">
<% for (lang in syzoj.config.languages) { %>
<option value="<%= lang %>"><%= syzoj.config.languages[lang].show %></option>
<% } %>
</select>
</div>
<div class="field">
<label>代码</label>
<textarea rows="15" name="code" style="font-family: 'Roboto Mono', 'Bitstream Vera Sans Mono', 'Menlo', 'Consolas', 'Lucida Console', monospace; "></textarea>
</div>
<button type="submit" class="ui button">提交</button>
</form>
</div>
<script>
$(function () {
$('.ui.dropdown').dropdown();
});
</script>
<% include footer %>
Loading…
Cancel
Save