Browse Source

feat: 编辑比赛选题时交互操作优化

feature/unlimited-reply
zjz1993 5 years ago
parent
commit
3118c60bed
  1. 14
      modules/contest.js
  2. 2
      views/admin_classify.ejs
  3. 129
      views/contest_edit.ejs
  4. 4
      views/header.ejs
  5. 130
      views/problem_table.ejs
  6. 3
      views/submissions.ejs

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('|');

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>

3
views/submissions.ejs

@ -6,9 +6,6 @@
font-size: 1.2em;
margin-right: 1px;
}
.padding{
overflow-x: auto;
}
</style>
<script src="<%- lib('textfit/2.3.1/textFit.min.js') %>"></script>
<div class="padding">

Loading…
Cancel
Save