Browse Source

Merge branch 'master' of zhaojunzhe/fair-web into master

pull/31/head
richie 5 years ago committed by Gogs
parent
commit
feee786a0b
  1. 29
      libs/submissions_process.js
  2. 14
      modules/contest.js
  3. 5
      modules/submission.js
  4. 2
      views/admin_classify.ejs
  5. 129
      views/contest_edit.ejs
  6. 4
      views/header.ejs
  7. 130
      views/problem_table.ejs
  8. 69
      views/submissions.ejs
  9. 1
      views/submissions_item.ejs

29
libs/submissions_process.js

@ -1,19 +1,22 @@
const {getCachedJudgeState} = require('./judger');
const _ = require('lodash');
const getSubmissionInfo = (s, displayConfig) => ({
submissionId: s.id,
taskId: s.task_id,
user: s.user.username,
userId: s.user_id,
problemName: s.problem.title,
problemId: s.problem_id,
language: displayConfig.showCode ? ((s.language != null && s.language !== '') ? syzoj.languages[s.language].show : null) : null,
codeSize: displayConfig.showCode ? s.code_length : null,
submitTime: syzoj.utils.formatDate(s.submit_time),
isPractice: s.is_practice,
c_id: s.c_id
});
const getSubmissionInfo = (s, displayConfig) => {
return {
submissionId: s.id,
taskId: s.task_id,
user: s.user.username,
userId: s.user_id,
problemName: s.problem.title,
problemId: s.problem_id,
language: displayConfig.showCode ? ((s.language != null && s.language !== '') ? syzoj.languages[s.language].show : null) : null,
codeSize: displayConfig.showCode ? s.code_length : null,
submitTime: syzoj.utils.formatDate(s.submit_time),
isPractice: s.is_practice,
c_id: s.c_id,
is_share: s.is_share || false
}
};
const getRoughResult = (x, displayConfig, roughOnly) => {
let max = 0;

14
modules/contest.js

@ -53,6 +53,7 @@ app.get('/contest/:id/edit', async (req, res) => {
res.render('contest_edit', {
contest: contest,
problems: problems,
contest_id,
admins: admins
});
} catch (e) {
@ -63,6 +64,17 @@ app.get('/contest/:id/edit', async (req, res) => {
}
});
app.get('/api/contest/problem/:id', async (req, res) => {
try {
const id = req.params.id;
let contest = await Contest.findById(id);
let problems = await contest.problems.split('|').mapAsync(async id => await Problem.findById(id));
res.send({ problems});
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
})
app.post('/contest/:id/edit', async (req, res) => {
try {
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。');
@ -96,7 +108,7 @@ app.post('/contest/:id/edit', async (req, res) => {
if (!req.body.title.trim()) throw new ErrorMessage('比赛名不能为空。');
contest.title = req.body.title;
contest.subtitle = req.body.subtitle;
if (!Array.isArray(req.body.problems)) req.body.problems = [req.body.problems];
if (!Array.isArray(req.body.problems) && typeof req.body.problems==='string') req.body.problems = req.body.problems.split(',');
if (!Array.isArray(req.body.admins)) req.body.admins = [req.body.admins];
contest.problems = req.body.problems.join('|');
contest.admins = req.body.admins.join('|');

5
modules/submission.js

@ -84,6 +84,11 @@ app.get('/submissions', async (req, res) => {
query.andWhere('status = :status', { status: req.query.status });
isFiltered = true;
}
if (req.query.isshare) {
query.andWhere('is_share = :status', { status: req.query.isshare });
}
if (!inContest && (!curUser || !await curUser.hasPrivilege('manage_problem'))) {
if (req.query.problem_id) {

2
views/admin_classify.ejs

@ -71,6 +71,7 @@
:total="problemCount">
</el-pagination>
</div>
<!-- <div is='problem-table' @getuserchoose="handleUserChoose" :userselectarray="multipleSelection" :disabledidarray="disabledId"></div>-->
<button class="ui button" @click="submitInfo">保存</button>
</div>
</div>
@ -112,6 +113,7 @@
<!-- 引入组件库 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<% include problem_table %>
<script>
new window.Vue({
el: '#classify',

129
views/contest_edit.ejs

@ -1,8 +1,8 @@
<% this.title = contest.id ? '编辑比赛' : '新建比赛' %>
<% include header %>
<% include monaco-editor %>
<div class="padding">
<form action="<%= syzoj.utils.makeUrl(['contest', contest.id, 'edit']) %>" method="post">
<div class="padding" id="edit_contest">
<form action="<%= syzoj.utils.makeUrl(['contest', contest.id, 'edit']) %>" method="post" id="form">
<div class="ui form">
<div class="field">
<label>比赛名称</label>
@ -19,11 +19,37 @@
<div class="ui form">
<div class="field">
<label>试题列表</label>
<select class="ui fluid search dropdown" multiple="" id="search_problems" name="problems">
<% for (let problem of problems) { %>
<option value="<%= problem.id %>" selected>#<%= problem.id %>. <%= problem.title %></option>
<% } %>
</select>
<!-- <% include problem_table %>-->
<input type="input" hidden name="problems" v-model="calcProblemsValue" />
<el-tag @close="handleClose(item)" closable v-for="item in userselectarray" style="margin-right:5px">#{{item.id}}{{item.title}}</el-tag>
<div class="field">
<el-table
ref="multipleTable"
:data="datas"
tooltip-effect="dark"
style="width: 100%"
@select="handleSelectionChange"
>
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column
prop="id"
label="题目id">
</el-table-column>
<el-table-column
prop="title"
label="题目标题">
</el-table-column>
</el-table>
<el-pagination
@current-change="handlePageChange"
layout="prev, pager, next"
:current-page.sync="currentPage"
:total="max">
</el-pagination>
</div>
</div>
<div class="field">
<label>比赛管理员</label>
@ -93,6 +119,95 @@
</div>
</form>
<script>
new window.Vue({
el:'#edit_contest',
data: {
userselectarray: [],
allproblemList:[],
datas: [],
currentPage:1,
max: 0,
arrayItem: null
},
mounted() {
this.loadProblem();
},
methods: {
loadProblem() {
fetch('/api/pagination/allproblem').then(res => res.json()).then(data => {
this.max = parseInt(data.problemInfo.length);
this.allproblemList = data.problemInfo;
this.datas = data.problemInfo.slice(0,10);
this.loadData();
})
},
loadData() {
let id = <%= contest_id %>;
fetch(`/api/contest/problem/${id}`).then(res=> res.json()).then(subitem => {
const originUserselectarray = subitem.problems.map((item) =>{
return {
id: item.id,
title: item.title
}
});
const userselectarrayId = originUserselectarray.map(item=>item.id);
const userSelectArray = this.datas.filter((item) => {
return userselectarrayId.includes(item.id);
})
this.toggleSelection(userSelectArray);
this.userselectarray = userSelectArray;
})
},
handleClose(tag) {
const deleteItem = this.userselectarray.splice(this.userselectarray.indexOf(tag), 1);
this.toggleSelection(deleteItem)
},
getProblemPagination(page) {
let that = this;
this.datas = this.allproblemList.slice((page - 1)*10, (page - 1)*10+10);
this.$nextTick(function(){
that.toggleSelection(that.userselectarray);
})
},
selectProblem: function(array) {
this.toggleSelection(array)
},
toggleSelection(rows) {
if (rows) {
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
},
handlePageChange(page){
this.selectProblem(this.userselectarray);
this.getProblemPagination(page);
},
handleSelectionChange(val, row){
const multipleSelectionId = this.userselectarray.map(item => item.id);
if (multipleSelectionId.includes(row.id)) {
this.userselectarray.splice(this.userselectarray.indexOf(row), 1)
} else {
this.userselectarray.push(row);
}
},
disableCheckbox: function(row) {
if (this.disabledidarray) {
return !this.disabledidarray.includes(row.id);
}
return true;
},
},
computed: {
calcProblemsValue:function(){
console.log(this.userselectarray.map(item=>item.id));
return this.userselectarray.map(item=>item.id);
}
}
})
var editors = {
subtitle: { defaultValue: <%- serializejs(contest.subtitle) %> },
information: { defaultValue: <%- serializejs(contest.information) %> }

4
views/header.ejs

@ -33,6 +33,10 @@
<link href="<%- this.builtInCdnUrl %>/google-fonts/exo-2.css" rel="stylesheet">
<% } %>
<script src="<%- lib('jquery/3.3.1/jquery.min.js') %>"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" />
<!-- 引入组件库 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<% if (syzoj.config.google_analytics && syzoj.config.google_analytics !== 'UA-XXXXXXXX-X') { %>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){

130
views/problem_table.ejs

@ -0,0 +1,130 @@
<% include util %>
<script>
Vue.component('problem-table', {
template: '#problemTable',
props: ['disabledidarray', 'userselectarray'],// 禁止选择的选项, 用户已经选择的选项
data() {
return {
allproblemList:[],
checkedArray: [],
datas: [],
currentPage:1,
max: 0,
arrayItem: null
}
},
watch: {
allproblemList: function(newData, olbData){
this.datas = newData.slice(0,10);
},
userselectarray: function(newData, olbData) {
console.log('更新了');
// this.checkedArray = newData;
this.toggleSelection(newData)
},
checkedArray: function(newdata, olddata){
console.log('checked更新了');
this.toggleSelection(newdata)
}
},
mounted(){
console.log('加载');
console.log(this.userselectarray);
this.getCount();
},
methods:{
getCount: function(){
let that = this;
$.ajax({
url: '/api/pagination/allproblem',
type: 'GET',
success: function (data) {
that.max = parseInt(data.problemInfo.length);
that.allproblemList = data.problemInfo;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('创建失败');
}
})
},
handleClose(tag) {
const deleteItem = this.checkedArray.splice(this.checkedArray.indexOf(tag), 1);
this.toggleSelection(deleteItem)
},
getProblemPagination(page) {
let that = this;
this.datas = this.allproblemList.slice((page - 1)*10, (page - 1)*10+10);
this.$nextTick(function(){
that.toggleSelection(that.checkedArray);
})
},
selectProblem: function(array) {
this.toggleSelection(array)
},
toggleSelection(rows) {
if (rows) {
console.log(rows);
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
},
handlePageChange(page){
this.selectProblem(this.checkedArray);
this.getProblemPagination(page);
},
handleSelectionChange(val, row){
const multipleSelectionId = this.checkedArray.map(item => item.id);
if (multipleSelectionId.includes(row.id)) {
this.checkedArray.splice(this.checkedArray.indexOf(row), 1)
} else {
this.checkedArray.push(row);
}
// this.$emit('getuserchoose', this.checkedArray)
},
disableCheckbox: function(row) {
if (this.disabledidarray) {
return !this.disabledidarray.includes(row.id);
}
return true;
},
},
});
</script>
<script id="problemTable" type="text/x-template">
<div>
<div class="field">
<label>当前练习阶段已经选择的题</label>
<el-table
ref="multipleTable"
:data="datas"
tooltip-effect="dark"
style="width: 100%"
@select="handleSelectionChange"
>
<el-table-column
type="selection"
:selectable="disableCheckbox"
width="55">
</el-table-column>
<el-table-column
prop="id"
label="题目id">
</el-table-column>
<el-table-column
prop="title"
label="题目标题">
</el-table-column>
</el-table>
<el-pagination
@current-change="handlePageChange"
layout="prev, pager, next"
:current-page.sync="currentPage"
:total="max">
</el-pagination>
</div>
</div>
</script>

69
views/submissions.ejs

@ -1,6 +1,12 @@
<% this.title = '提交记录' %>
<% include header %>
<% include util %>
<style>
.label{
font-size: 1.2em;
margin-right: 1px;
}
</style>
<script src="<%- lib('textfit/2.3.1/textFit.min.js') %>"></script>
<div class="padding">
<% if (displayConfig.inContest) { %>
@ -17,10 +23,10 @@
<form action="<%= syzoj.utils.makeUrl(displayConfig.inContest ? ['contest', contest.id, 'submissions'] : ['submissions']) %>" class="ui mini form" method="get" role="form" id="form">
<input type="hidden" name="contest" value="<%= form.contest %>" />
<div class="inline fields" style="margin-bottom: 25px; white-space: nowrap; ">
<label style="font-size: 1.2em; margin-right: 1px; ">题目:</label>
<label class="label">题目:</label>
<div class="field"><input name="problem_id" style="width: 50px; " type="text" value="<%= form.problem_id %>"></div>
<% if (displayConfig.showOthers) { %>
<label style="font-size: 1.2em; margin-right: 1px; ">提交者:</label>
<label class="label">提交者:</label>
<div class="field"><input name="submitter" style="width: 100px; " type="text" value="<%= form.submitter %>"></div>
<% } %>
<% if (displayConfig.showScore) { %>
@ -29,7 +35,7 @@
<label style="font-size: 1.2em; margin-right: 7px; ">~</label>
<div class="field"><input name="max_score" style="width: 45px; " type="text" value="<%= form.max_score || 100 %>"></div>
<% } %>
<label style="font-size: 1.2em; margin-right: 1px; ">语言:</label>
<label class="label">语言:</label>
<div class="field">
<div class="ui fluid selection dropdown" id="select_language" style="width: 110px; ">
<input type="hidden" name="language" value="<%= form.language %>">
@ -46,7 +52,7 @@
</div>
</div>
<% if (displayConfig.showResult) { %>
<label style="font-size: 1.2em; margin-right: 1px; ">状态:</label>
<label class="label">状态:</label>
<div class="field">
<div class="ui fluid selection dropdown" id="select_status" style="width: 210px; ">
<input type="hidden" name="status" value="<%= form.status %>">
@ -62,29 +68,45 @@
</div>
</div>
<% } %>
<button class="ui labeled icon mini button" type="submit">
<i class="search icon"></i>
查询
</button>
<% if (user && displayConfig.showOthers) { %>
<a class="ui mini labeled icon blue button" style="margin-left: auto; " id="my_submit">
<i class="user icon"></i>
我的提交
</a>
<script>
$(function () {
$('#my_submit').click(function () {
$('[name=submitter]').val(<%- serializejs(user.username) %>);
$('#form').submit();
});
});
</script>
<% } %>
<label class="label">代码是否分享:</label>
<div class="field">
<div class="ui fluid selection dropdown" id="select_share" style="width: 110px; ">
<input type="hidden" name="isshare" value="<%= form.isshare %>">
<i class="dropdown icon"></i>
<div class="default text"></div>
<div class="menu">
<div class="item" data-value=""><b>不限</b></div>
<div class="item" data-value="1"><b>是</b></div>
<div class="item" data-value="0"><b>否</b></div>
</div>
</div>
</div>
</div>
<div class="inline fields">
<button class="ui labeled icon mini button" type="submit">
<i class="search icon"></i>
查询
</button>
<% if (user && displayConfig.showOthers) { %>
<a class="ui mini labeled icon blue button" id="my_submit">
<i class="user icon"></i>
我的提交
</a>
<script>
$(function () {
$('#my_submit').click(function () {
$('[name=submitter]').val(<%- serializejs(user.username) %>);
$('#form').submit();
});
});
</script>
<% } %>
</div>
</form>
<table id="vueAppFuckSafari" class="ui very basic center aligned table" style="white-space: nowrap; " id="table">
<thead>
<tr>
<th>是否已经分享</th>
<th>编号</th>
<th>题目</th>
<th>状态</th>
@ -133,11 +155,14 @@
$(function () {
$('#select_language').dropdown();
$('#select_status').dropdown();
$('#select_share').dropdown();
});
const itemList = <%- serializejs(items) %>;
const socketUrl = "/rough";
const displayConfig = <%- serializejs(displayConfig) %>;
console.log(itemList);
const vueApp = new Vue({
el: '#vueAppFuckSafari',
data: {

1
views/submissions_item.ejs

@ -66,6 +66,7 @@
<script id="submissionItemTemplate" type="text/x-template">
<tr>
<td><i class="icon" :class="data.info.is_share ? 'smile': 'meh'" style="font-size: 1.5em"></i></td>
<% if (active === 'submissions') { %>
<td><a :href="submissionLink"><b>#{{ data.info.submissionId }}</b></a></td>
<% } else { %>

Loading…
Cancel
Save