Browse Source

Some UI fixes and improvement

master
Menci 6 years ago
parent
commit
488b2d6535
  1. 5
      libs/judger.js
  2. 5
      libs/submissions_process.js
  3. 10
      modules/socketio.js
  4. 7
      modules/submission.js
  5. 1
      modules/user.js
  6. 2
      package.json
  7. 10
      utility.js
  8. 12
      views/status_label.ejs
  9. 18
      views/submission.ejs
  10. 43
      views/submissions_item.ejs

5
libs/judger.js

@ -48,6 +48,11 @@ async function connect () {
judge_state.result = convertedResult.result; judge_state.result = convertedResult.result;
await judge_state.save(); await judge_state.save();
await judge_state.updateRelatedInfo(); await judge_state.updateRelatedInfo();
} else if(data.type === interface.ProgressReportType.Progress) {
if(!judge_state) return;
judge_state.score = convertedResult.score;
judge_state.total_time = convertedResult.time;
judge_state.max_memory = convertedResult.memory;
} else if(data.type == interface.ProgressReportType.Compiled) { } else if(data.type == interface.ProgressReportType.Compiled) {
if(!judge_state) return; if(!judge_state) return;
judge_state.compilation = data.progress; judge_state.compilation = data.progress;

5
libs/submissions_process.js

@ -6,7 +6,7 @@ const getSubmissionInfo = (s, displayConfig) => ({
problemName: s.problem.title, problemName: s.problem.title,
problemId: s.problem_id, problemId: s.problem_id,
language: displayConfig.showCode ? ((s.language != null && s.language !== '') ? syzoj.languages[s.language].show : null) : null, language: displayConfig.showCode ? ((s.language != null && s.language !== '') ? syzoj.languages[s.language].show : null) : null,
codeSize: displayConfig.showCode ? syzoj.utils.formatSize(s.code_length) : null, codeSize: displayConfig.showCode ? s.code_length : null,
submitTime: syzoj.utils.formatDate(s.submit_time), submitTime: syzoj.utils.formatDate(s.submit_time),
}); });
@ -18,8 +18,7 @@ const getRoughResult = (x, displayConfig) => {
return { return {
result: x.status, result: x.status,
time: displayConfig.showUsage ? x.total_time : null, time: displayConfig.showUsage ? x.total_time : null,
memory: displayConfig.showUsage ? syzoj.utils.formatSize((x.max_memory * 1024) || 0, 2) : null, memory: displayConfig.showUsage ? x.max_memory : null,
precise_memory: displayConfig.showUsage ? x.max_memory : null,
score: displayConfig.showScore ? x.score : null score: displayConfig.showScore ? x.score : null
}; };
} }

10
modules/socketio.js

@ -232,6 +232,13 @@ exports.updateCompileStatus = updateCompileStatus;
function updateProgress(taskId, data) { function updateProgress(taskId, data) {
winston.verbose(`Updating progress for #${taskId}`); winston.verbose(`Updating progress for #${taskId}`);
currentJudgeList[taskId] = data; currentJudgeList[taskId] = data;
const finalResult = judgeResult.convertResult(taskId, data);
const roughResult = {
result: "Running",
time: finalResult.time,
memory: finalResult.memory,
score: finalResult.score
};
forAllClients(detailProgressNamespace, taskId, (client) => { forAllClients(detailProgressNamespace, taskId, (client) => {
winston.debug(`Pushing progress update to ${client}`); winston.debug(`Pushing progress update to ${client}`);
if (clientDetailProgressList[client] && clientDisplayConfigList[client]) { if (clientDetailProgressList[client] && clientDisplayConfigList[client]) {
@ -242,7 +249,8 @@ function updateProgress(taskId, data) {
taskId: taskId, taskId: taskId,
from: version, from: version,
to: version + 1, to: version + 1,
delta: diff.diff(original, updated) delta: diff.diff(original, updated),
roughResult: roughResult
}); });
clientDetailProgressList[client].version++; clientDetailProgressList[client].version++;
} }

7
modules/submission.js

@ -97,7 +97,10 @@ app.get('/submissions', async (req, res) => {
let paginate = syzoj.utils.paginate(await JudgeState.count(where), req.query.page, syzoj.config.page.judge_state); 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); let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']], true);
await judge_state.forEachAsync(async obj => obj.loadRelationships()); await judge_state.forEachAsync(async obj => {
await obj.loadRelationships();
obj.code_length = obj.code.length;
})
res.render('submissions', { res.render('submissions', {
// judge_state: judge_state, // judge_state: judge_state,
@ -147,7 +150,7 @@ app.get('/submission/:id', async (req, res) => {
await judge.loadRelationships(); await judge.loadRelationships();
if (judge.problem.type !== 'submit-answer') { if (judge.problem.type !== 'submit-answer') {
judge.codeLength = judge.code.length; judge.code_length = judge.code.length;
let key = syzoj.utils.getFormattedCodeKey(judge.code, judge.language); let key = syzoj.utils.getFormattedCodeKey(judge.code, judge.language);
if (key) { if (key) {

1
modules/user.js

@ -187,7 +187,6 @@ app.post('/user/:id/edit', async (req, res) => {
user.information = req.body.information; user.information = req.body.information;
user.sex = req.body.sex; user.sex = req.body.sex;
user.public_email = (req.body.public_email === 'on'); user.public_email = (req.body.public_email === 'on');
console.log(req.body);
user.prefer_formatted_code = (req.body.prefer_formatted_code === 'on'); user.prefer_formatted_code = (req.body.prefer_formatted_code === 'on');
await user.save(); await user.save();

2
package.json

@ -40,7 +40,7 @@
"gravatar": "^1.8.0", "gravatar": "^1.8.0",
"javascript-time-ago": "^1.0.30", "javascript-time-ago": "^1.0.30",
"js-yaml": "^3.9.0", "js-yaml": "^3.9.0",
"jsondiffpatch": "0.3.11", "jsondiffpatch": "0.2.5",
"jsonwebtoken": "^8.4.0", "jsonwebtoken": "^8.4.0",
"katex": "^0.10.0", "katex": "^0.10.0",
"mathjax-node": "^2.1.1", "mathjax-node": "^2.1.1",

10
utility.js

@ -92,11 +92,11 @@ module.exports = {
return sgn + util.format('%s:%s:%s', toStringWithPad(x / 3600), toStringWithPad(x / 60 % 60), toStringWithPad(x % 60)); return sgn + util.format('%s:%s:%s', toStringWithPad(x / 3600), toStringWithPad(x / 60 % 60), toStringWithPad(x % 60));
}, },
formatSize(x, precision) { formatSize(x, precision) {
let res = filesize(x, { fixed: precision || 1 }).calculate(); if (typeof x !== 'number') return '0 B';
if (res.result === parseInt(res.result)) res.fixed = res.result.toString(); let unit = 'B', units = ['K', 'M', 'G', 'T'];
if (res.suffix.startsWith('Byte')) res.suffix = 'B'; for (let i in units) if (x > 1024) x /= 1024, unit = units[i];
else res.suffix = res.suffix.replace('iB', ''); var fixed = x === Math.round(x) ? x.toString() : x.toFixed(precision);
return res.fixed + ' ' + res.suffix; return fixed + ' ' + unit;
}, },
getFormattedCodeKey(code, lang) { getFormattedCodeKey(code, lang) {
if (syzoj.languages[lang].format) { if (syzoj.languages[lang].format) {

12
views/status_label.ejs

@ -10,6 +10,7 @@ const iconList = {
'File Error': 'file outline', 'File Error': 'file outline',
'Waiting': 'hourglass half', 'Waiting': 'hourglass half',
'Running': 'spinner', 'Running': 'spinner',
'Compiling': 'spinner',
'Compile Error': 'code', 'Compile Error': 'code',
'Submitted': 'checkmark', // NOI contests 'Submitted': 'checkmark', // NOI contests
'System Error': 'server', 'System Error': 'server',
@ -31,10 +32,6 @@ Vue.component('status-label', {
}, },
colorClass() { colorClass() {
return (this.indetail ? 'status_detail ' : '') + this.status.toLowerCase().split(' ').join('_'); 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;
} }
} }
}) })
@ -42,6 +39,11 @@ Vue.component('status-label', {
<script type="text/x-template" id="statusIconTemplate"> <script type="text/x-template" id="statusIconTemplate">
<span class="status" :class="colorClass"> <span class="status" :class="colorClass">
<i class="icon" :class="icon"></i> <i class="icon" :class="icon"></i>
{{ outputStatus }} <template v-if="['Running', 'Waiting'].includes(status) && progress">
<span style="display: inline-block; width: 58px; ">{{ status }}</span>{{ progress.finished }}/{{ progress.total }}
</template>
<template v-else>
{{ status }}
</template>
</span> </span>
</script> </script>

18
views/submission.ejs

@ -47,7 +47,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr is="submission-item" v-bind:data="roughData" :config="displayConfig" :show-rejudge="showRejudge" :progress="getProgress()"></tr> <tr is="submission-item" v-bind:data="roughData" :config="displayConfig" :show-rejudge="showRejudge" :progress="getProgress()" :compiling="detailResult && !detailResult.compile"></tr>
</tbody> </tbody>
</table> </table>
@ -66,7 +66,7 @@
<code-box v-if="detailResult && detailResult.compile" :escape="false" title="编译信息" v-bind:content="detailResult.compile.message"></code-box> <code-box v-if="detailResult && detailResult.compile" :escape="false" title="编译信息" v-bind:content="detailResult.compile.message"></code-box>
<code-box v-if="detailResult" title="系统信息" :escape="true" v-bind:content="detailResult.systemMessage"></code-box> <code-box v-if="detailResult" title="系统信息" :escape="true" v-bind:content="detailResult.systemMessage"></code-box>
<div class="ui styled fluid accordion" :class="singleSubtask ? 'single-subtask' : '' "v-if="detailResult && detailResult.judge && detailResult.judge.subtasks"> <div class="ui styled fluid accordion" :class="singleSubtask ? 'single-subtask' : '' " v-if="detailResult && detailResult.judge && detailResult.judge.subtasks">
<template v-for="subtask, $index in detailResult.judge.subtasks"> <template v-for="subtask, $index in detailResult.judge.subtasks">
<div class="title" :class="singleSubtask ? 'active' : ''"> <div class="title" :class="singleSubtask ? 'active' : ''">
<div class="ui grid"> <div class="ui grid">
@ -125,7 +125,7 @@
</div> </div>
</div> </div>
<script src="https://cdnjs.loli.net/ajax/libs/vue/2.5.17/vue.min.js"></script> <script src="https://cdnjs.loli.net/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script src="https://cdnjs.loli.net/ajax/libs/socket.io/2.1.1/socket.io.js"></script> <script src="https://cdnjs.loli.net/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script src="https://cdnjs.loli.net/ajax/libs/jsondiffpatch/0.2.5/jsondiffpatch.min.js"></script> <script src="https://cdnjs.loli.net/ajax/libs/jsondiffpatch/0.2.5/jsondiffpatch.min.js"></script>
<% include submissions_item %> <% include submissions_item %>
@ -308,10 +308,12 @@ if (token != null) {
vueApp.detailResult = {}; vueApp.detailResult = {};
}); });
socket.on('update', function (p) { socket.on('update', function (p) {
console.log("Delta: " + JSON.stringify(p)); console.log("Delta: ", p);
if (p.from === currentVersion) { if (p.from === currentVersion) {
currentVersion = p.to; currentVersion = p.to;
jsondiffpatch.patch(vueApp.detailResult, p.delta); jsondiffpatch.patch(vueApp.detailResult, p.delta);
vueApp.detailResult = JSON.parse(JSON.stringify(vueApp.detailResult));// WTF?
vueApp.roughData.result = p.roughResult;
} else { // Some packets are dropped. Let's reset. } else { // Some packets are dropped. Let's reset.
socket.close(); socket.close();
setTimeout(loadSocketIO, 0); setTimeout(loadSocketIO, 0);
@ -325,18 +327,18 @@ if (token != null) {
socket.close(); socket.close();
}); });
socket.emit('join', token, function (data) { socket.emit('join', token, function (data) {
console.log("join! " + JSON.stringify(data)); console.log("join! ", data);
if (data && data.ok) { if (data && data.ok) {
if (data.finished) { if (data.finished) {
vueApp.roughData.result = data.roughResult; vueApp.roughData.result = data.roughResult;
vueApp.detailResult = data.result || { if (!data.result) location.reload(true);
systemMessage: "系统出错,请刷新后重试。" vueApp.detailResult = data.result;
};
socket.close(); socket.close();
} else { } else {
if (data.running) { if (data.running) {
vueApp.roughData.running = true; vueApp.roughData.running = true;
vueApp.detailResult = data.current.content; vueApp.detailResult = data.current.content;
vueApp.roughData.result = data.roughResult;
currentVersion = data.current.version; currentVersion = data.current.version;
} }
} }

43
views/submissions_item.ejs

@ -1,37 +1,46 @@
<% include util %> <% include util %>
<% include status_label %> <% include status_label %>
<script src="https://cdnjs.loli.net/ajax/libs/textfit/2.3.1/textFit.min.js"></script>
<script> <script>
function formatSize(x, precision) {
if (typeof x !== 'number') return '0 B';
var unit = 'B', units = ['K', 'M', 'G', 'T'];
for (var i in units) if (x > 1024) x /= 1024, unit = units[i];
var fixed = x === Math.round(x) ? x.toString() : x.toFixed(precision);
return fixed + ' ' + unit;
}
const submissionUrl = <%- JSON.stringify(displayConfig.inContest ? const submissionUrl = <%- JSON.stringify(displayConfig.inContest ?
syzoj.utils.makeUrl(['contest', 'submission', 'VanDarkholme']) : syzoj.utils.makeUrl(['contest', 'submission', '20000528']) :
syzoj.utils.makeUrl(['submission', 'VanDarkholme'])) %>; syzoj.utils.makeUrl(['submission', '20000528'])) %>;
const problemUrl = <%- JSON.stringify(displayConfig.inContest ? const problemUrl = <%- JSON.stringify(displayConfig.inContest ?
syzoj.utils.makeUrl(['contest', contest.id, 'problem', 'VanDarkholme']) : syzoj.utils.makeUrl(['contest', contest.id, 'problem', '20000528']) :
syzoj.utils.makeUrl(['problem', 'VanDarkholme'])) %>; syzoj.utils.makeUrl(['problem', '20000528'])) %>;
const userUrl = <%- JSON.stringify(syzoj.utils.makeUrl(['user', 'VanDarkholme'])) %>; const userUrl = <%- JSON.stringify(syzoj.utils.makeUrl(['user', '20000528'])) %>;
Vue.component('submission-item', { Vue.component('submission-item', {
template: '#submissionItemTemplate', template: '#submissionItemTemplate',
props: ['data', 'config', 'showRejudge', 'progress'], props: ['data', 'config', 'showRejudge', 'progress', 'compiling'],
computed: { computed: {
statusString() { statusString() {
if (this.compiling) return 'Compiling';
const data = this.data; const data = this.data;
if (data.result) { if (data.result) {
return data.result.result; return data.result.result;
} else if (data.running) { } else if (data.running) {
return this.config.showResult ? 'Running' : 'Compiling'; return 'Running';
} else return 'Waiting'; } else return 'Waiting';
}, },
submissionLink() { submissionLink() {
return submissionUrl.replace('VanDarkholme', this.data.info.submissionId); return submissionUrl.replace('20000528', this.data.info.submissionId);
}, },
problemLink() { problemLink() {
return problemUrl.replace('VanDarkholme', this.data.info.problemId); return problemUrl.replace('20000528', this.data.info.problemId);
}, },
userLink() { userLink() {
return userUrl.replace('VanDarkholme', this.data.info.userId); return userUrl.replace('20000528', this.data.info.userId);
}, },
scoreClass() { scoreClass() {
return "score_" + (parseInt(this.data.result.score / 10) || 0).toString(); return "score_" + (parseInt(this.data.result.score / 10) || 0).toString();
@ -71,13 +80,15 @@ Vue.component('submission-item', {
<td v-if="config.showUsage">{{ (data.result.time || 0).toString() + ' ms' }}</td> <td v-if="config.showUsage">{{ (data.result.time || 0).toString() + ' ms' }}</td>
<% if (active === 'submissions') { %> <% if (active === 'submissions') { %>
<td v-if="config.showUsage">{{ data.result.memory }}</td> <td v-if="config.showUsage">{{ formatSize(data.result.memory * 1024, 2) }}</td>
<% } else { %> <% } else { %>
<td v-if="config.showUsage">{{ (data.result.precise_memory || 0).toString() + ' K'}}</td> <td v-if="config.showUsage">{{ (data.result.memory || 0).toString() + ' K'}}</td>
<% } %> <% } %>
</template> <template v-else> </template> <template v-else>
<td v-if="config.showScore"/> <td v-if="config.showUsage"/> <td v-if="config.showUsage"/> <td v-if="config.showScore"><a :href="submissionLink"><span class="score score_0">0</span></a></td>
<td v-if="config.showUsage">0 ms</td>
<td v-if="config.showUsage">0 B</td>
</template> </template>
<td v-if="config.showCode"> <td v-if="config.showCode">
@ -86,7 +97,7 @@ Vue.component('submission-item', {
<% } else { %> <% } else { %>
<span v-if="data.info.language"><b>{{ data.info.language }}</b> / </span> <span v-if="data.info.language"><b>{{ data.info.language }}</b> / </span>
<% } %> <% } %>
{{ data.info.codeSize }} {{ formatSize(data.info.codeSize, 1) }}
</td> </td>
<td><a :href="userLink">{{ data.info.user }}</a></td> <td><a :href="userLink">{{ data.info.user }}</a></td>
<td>{{ data.info.submitTime }}</td> <td>{{ data.info.submitTime }}</td>

Loading…
Cancel
Save