Browse Source

UI improvement on submission / submissions page

pull/6/head
Menci 6 years ago
parent
commit
c90077da58
  1. 7
      modules/submission.js
  2. 19
      static/style.css
  3. 2
      views/footer.ejs
  4. 2
      views/header.ejs
  5. 8
      views/status_label.ejs
  6. 36
      views/submission.ejs
  7. 25
      views/submissions.ejs
  8. 10
      views/submissions_item.ejs

7
modules/submission.js

@ -71,9 +71,9 @@ app.get('/submissions', async (req, res) => {
if (req.query.problem_id) {
let problem_id = parseInt(req.query.problem_id);
let problem = await Problem.fromID(problem_id);
if(!problem)
if (!problem)
throw new ErrorMessage("无此题目。");
if(await problem.isAllowedUseBy(res.locals.user)) {
if (await problem.isAllowedUseBy(res.locals.user)) {
where.problem_id = {
$and: [
{ $eq: where.problem_id = problem_id }
@ -91,6 +91,8 @@ app.get('/submissions', async (req, res) => {
if (req.query.problem_id) where.problem_id = parseInt(req.query.problem_id) || -1;
}
let isFiltered = !!(where.problem_id || where.user_id || where.score || where.language || where.status);
let paginate = syzoj.utils.paginate(await JudgeState.count(where), req.query.page, syzoj.config.page.judge_state);
let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']], true);
@ -112,6 +114,7 @@ app.get('/submissions', async (req, res) => {
pushType: 'rough',
form: req.query,
displayConfig: displayConfig,
isFiltered: isFiltered
});
} catch (e) {
syzoj.log(e);

19
static/style.css

@ -21,15 +21,15 @@ h4,
h5,
body
{
font-family:
font-family:
Lato,
-apple-system,
'PingFang SC',/* Apple */
'Source Han Sans SC',
-apple-system,
'PingFang SC',/* Apple */
'Source Han Sans SC',
'Noto Sans CJK SC', /* Google */
'Microsoft Yahei',
'Lantinghei SC',
'Hiragino Sans GB',
'Microsoft Yahei',
'Lantinghei SC',
'Hiragino Sans GB',
'Microsoft Sans Serif', /* M$ */
'WenQuanYi Micro Hei', /* *nix */
sans-serif;
@ -300,3 +300,8 @@ code {
font-size: 1em;
vertical-align: initial;
}
.ui.selection.dropdown .menu>.item {
padding-left: 0.8rem !important;
padding-right: 0 !important;
}

2
views/footer.ejs

@ -1,5 +1,5 @@
</div>
<div class="ui vertical footer segment" style="margin-top: 10px; ">
<div class="ui vertical footer segment" style="margin-top: 15px; ">
<div class="ui center aligned container">
<span style="color: #999;"><%= syzoj.config.title %> Powered by <a href="https://github.com/syzoj/syzoj" target="_blank">SYZOJ</a>.</span>
</div>

2
views/header.ejs

@ -11,7 +11,7 @@
<link href="/mathjax.css?20181105" rel="stylesheet">
<link href="https://cdnjs.loli.net/ajax/libs/KaTeX/0.10.0/katex.min.css" rel="stylesheet">
<link href="https://cdnjs.loli.net/ajax/libs/morris.js/0.5.1/morris.css" rel="stylesheet">
<link href="/style.css?20181108" rel="stylesheet">
<link href="/style.css?2018110801" rel="stylesheet">
<link href="https://fonts.loli.net/css?family=Fira+Mono" rel="stylesheet">
<link href="https://fonts.loli.net/css?family=Lato:400,700,400italic,700italic&subset=latin" rel="stylesheet">
<link href="https://fonts.loli.net/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i&amp;subset=latin-ext" rel="stylesheet">

8
views/status_label.ejs

@ -20,7 +20,7 @@ const iconList = {
};
Vue.component('status-label', {
template: '#statusIconTemplate',
props: ['status', 'indetail'],
props: ['status', 'indetail', 'progress'],
computed: {
icon() {
if (this.status in iconList) {
@ -31,6 +31,10 @@ Vue.component('status-label', {
},
colorClass() {
return (this.indetail ? 'status_detail ' : '') + this.status.toLowerCase().split(' ').join('_');
},
outputStatus() {
if (this.status === 'Running' && this.progress) return 'Running ' + this.progress.finished + '/' + this.progress.total;
else return this.status;
}
}
})
@ -38,6 +42,6 @@ Vue.component('status-label', {
<script type="text/x-template" id="statusIconTemplate">
<span class="status" :class="colorClass">
<i class="icon" :class="icon"></i>
{{ status }}
{{ outputStatus }}
</span>
</script>

36
views/submission.ejs

@ -47,7 +47,7 @@
</tr>
</thead>
<tbody>
<tr is="submission-item" v-bind:data="roughData" :config="displayConfig" :show-rejudge="showRejudge"></tr>
<tr is="submission-item" v-bind:data="roughData" :config="displayConfig" :show-rejudge="showRejudge" :progress="getProgress()"></tr>
</tbody>
</table>
@ -64,7 +64,7 @@
子任务 #{{ $index + 1 }}
</div>
<div class="four wide column">
<status-label :status="getSubtaskResult(subtask)" :indetail="true"></status-label>
<status-label :status="getSubtaskResult(subtask)" :indetail="true" :progress="getProgress($index)"></status-label>
</div>
<div class="three wide column" v-if="subtask.score != null">
得分:<span style="font-weight: normal; ">{{ Math.trunc(subtask.score) }}</span>
@ -74,7 +74,7 @@
<div class="content" :class="singleSubtask ? 'active' : ''">
<div class="accordion">
<template v-for="curCase, $caseIndex in subtask.cases">
<div class="title">
<div class="title" :class="checkTestcaseOK(curCase) ? '' : 'unexpandable'">
<div class="ui grid">
<div class="three wide column">
<i class="dropdown icon"></i>
@ -234,10 +234,38 @@ const vueApp = new Vue({
},
checkTestcaseOK(c) {
return c.status === TaskStatus.Done;
},
getProgress(i) {
if (!this.detailResult || !this.detailResult.judge || !this.detailResult.judge.subtasks) return {
finished: 0,
total: 0
};
let isPending = status => [TaskStatus.Waiting, TaskStatus.Running].includes(status);
let subtaskProgress = [], allFinished = 0, allTotal = 0;
for (let i in this.detailResult.judge.subtasks) {
let subtaskFinished = 0, subtaskTotal = 0;
for (let j in this.detailResult.judge.subtasks[i].cases) {
subtaskTotal++, allTotal++;
if (!isPending(this.detailResult.judge.subtasks[i].cases[j].status)) subtaskFinished++, allFinished++;
}
subtaskProgress.push({
finished: subtaskFinished,
total: subtaskTotal
});
}
let allProgress = {
finished: allFinished,
total: allTotal
};
return typeof i === 'undefined' ? allProgress : subtaskProgress[i];
}
},
mounted() {
$(document).ready(function(){ $('.ui.accordion').accordion()});
$(document).ready(function(){ $('.ui.accordion').accordion({ selector: { trigger: '.title:not(.unexpandable)' } })});
},
updated() {
$('.ui.accordion').accordion("refresh");

25
views/submissions.ejs

@ -36,10 +36,10 @@
<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>
<div class="item" data-value=""><b>不限</b></div>
<div class="item" data-value="submit-answer"><b>提交答案</b></div>
<% for (let lang in syzoj.config.languages) { %>
<div class="item" data-value="<%= lang %>"><%= syzoj.config.languages[lang].show %></div>
<div class="item" data-value="<%= lang %>"><b><%= syzoj.config.languages[lang].show %></b></div>
<% } %>
</div>
</div>
@ -52,10 +52,10 @@
<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>
<div class="item" data-value=""><b>不限</b><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 class="item" data-value="<%= status %>"><span class="status <%= status.toLowerCase().split(' ').join('_') %>"><i class="<%= this.icon[status] %> icon"></i> <b><%= status %></b></div>
<% } %>
</div>
</div>
@ -100,8 +100,23 @@
</tr>
</tbody>
</table>
<% if (!items.length) { %>
<div style="background-color: #fff; height: 18px; margin-top: -18px; "></div>
<div class="ui placeholder segment" style="margin-top: -5px; ">
<div class="ui icon header">
<% if (isFiltered) { %>
<i class="ui search icon" style="margin-bottom: 20px; "></i>
找不到符合条件的提交
<% } else { %>
<i class="ui file icon" style="margin-bottom: 20px; "></i>
暂无提交
<% } %>
</div>
</div>
<% } else { %>
<br>
<% include page %>
<% } %>
</div>
<script src="https://cdnjs.loli.net/ajax/libs/vue/2.4.2/vue.min.js"></script>

10
views/submissions_item.ejs

@ -4,17 +4,17 @@
<script src="https://cdnjs.loli.net/ajax/libs/textfit/2.3.1/textFit.min.js"></script>
<script>
const submissionUrl = <%- JSON.stringify(displayConfig.inContest ?
const submissionUrl = <%- JSON.stringify(displayConfig.inContest ?
syzoj.utils.makeUrl(['contest', 'submission', 'VanDarkholme']) :
syzoj.utils.makeUrl(['submission', 'VanDarkholme'])) %>;
const problemUrl = <%- JSON.stringify(displayConfig.inContest ?
const problemUrl = <%- JSON.stringify(displayConfig.inContest ?
syzoj.utils.makeUrl(['contest', contest.id, 'problem', 'VanDarkholme']) :
syzoj.utils.makeUrl(['problem', 'VanDarkholme'])) %>;
const userUrl = <%- JSON.stringify(syzoj.utils.makeUrl(['user', 'VanDarkholme'])) %>;
Vue.component('submission-item', {
template: '#submissionItemTemplate',
props: ['data', 'config', 'showRejudge'],
props: ['data', 'config', 'showRejudge', 'progress'],
computed: {
statusString() {
const data = this.data;
@ -57,9 +57,9 @@ Vue.component('submission-item', {
<% } %>
<td ref="problemLabel"><a ref="problemLabelTextFit" style="width: 230px; height: 22px; display: block; margin: 0 auto; line-height: 22px;" :href="problemLink"><b>#{{ config.inContest ? alpha(data.info.problemId) : data.info.problemId }}.</b> {{ data.info.problemName }}</a></td>
<% if (active === 'submissions') { %>
<td><a :href="submissionLink"><b><status-label :status="statusString"></status-label></b></a></td>
<td><a :href="submissionLink"><b><status-label :status="statusString" :progress="progress"></status-label></b></a></td>
<% } else { %>
<td><b><status-label :status="statusString"></status-label></b></td>
<td><b><status-label :status="statusString" :progress="progress"></status-label></b></td>
<% } %>
<template v-if="data.result">

Loading…
Cancel
Save