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', { res.render('contest_edit', {
contest: contest, contest: contest,
problems: problems, problems: problems,
contest_id,
admins: admins admins: admins
}); });
} catch (e) { } 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) => { app.post('/contest/:id/edit', async (req, res) => {
try { try {
if (!res.locals.user || !res.locals.user.is_admin) throw new ErrorMessage('您没有权限进行此操作。'); 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('比赛名不能为空。'); if (!req.body.title.trim()) throw new ErrorMessage('比赛名不能为空。');
contest.title = req.body.title; contest.title = req.body.title;
contest.subtitle = req.body.subtitle; 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]; if (!Array.isArray(req.body.admins)) req.body.admins = [req.body.admins];
contest.problems = req.body.problems.join('|'); contest.problems = req.body.problems.join('|');
contest.admins = req.body.admins.join('|'); contest.admins = req.body.admins.join('|');

2
views/admin_classify.ejs

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

129
views/contest_edit.ejs

@ -1,8 +1,8 @@
<% this.title = contest.id ? '编辑比赛' : '新建比赛' %> <% this.title = contest.id ? '编辑比赛' : '新建比赛' %>
<% include header %> <% include header %>
<% include monaco-editor %> <% include monaco-editor %>
<div class="padding"> <div class="padding" id="edit_contest">
<form action="<%= syzoj.utils.makeUrl(['contest', contest.id, 'edit']) %>" method="post"> <form action="<%= syzoj.utils.makeUrl(['contest', contest.id, 'edit']) %>" method="post" id="form">
<div class="ui form"> <div class="ui form">
<div class="field"> <div class="field">
<label>比赛名称</label> <label>比赛名称</label>
@ -19,11 +19,37 @@
<div class="ui form"> <div class="ui form">
<div class="field"> <div class="field">
<label>试题列表</label> <label>试题列表</label>
<select class="ui fluid search dropdown" multiple="" id="search_problems" name="problems"> <!-- <% include problem_table %>-->
<% for (let problem of problems) { %> <input type="input" hidden name="problems" v-model="calcProblemsValue" />
<option value="<%= problem.id %>" selected>#<%= problem.id %>. <%= problem.title %></option> <el-tag @close="handleClose(item)" closable v-for="item in userselectarray" style="margin-right:5px">#{{item.id}}{{item.title}}</el-tag>
<% } %> <div class="field">
</select> <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>
<div class="field"> <div class="field">
<label>比赛管理员</label> <label>比赛管理员</label>
@ -93,6 +119,95 @@
</div> </div>
</form> </form>
<script> <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 = { var editors = {
subtitle: { defaultValue: <%- serializejs(contest.subtitle) %> }, subtitle: { defaultValue: <%- serializejs(contest.subtitle) %> },
information: { defaultValue: <%- serializejs(contest.information) %> } information: { defaultValue: <%- serializejs(contest.information) %> }

4
views/header.ejs

@ -33,6 +33,10 @@
<link href="<%- this.builtInCdnUrl %>/google-fonts/exo-2.css" rel="stylesheet"> <link href="<%- this.builtInCdnUrl %>/google-fonts/exo-2.css" rel="stylesheet">
<% } %> <% } %>
<script src="<%- lib('jquery/3.3.1/jquery.min.js') %>"></script> <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') { %> <% if (syzoj.config.google_analytics && syzoj.config.google_analytics !== 'UA-XXXXXXXX-X') { %>
<script> <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (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; font-size: 1.2em;
margin-right: 1px; margin-right: 1px;
} }
.padding{
overflow-x: auto;
}
</style> </style>
<script src="<%- lib('textfit/2.3.1/textFit.min.js') %>"></script> <script src="<%- lib('textfit/2.3.1/textFit.min.js') %>"></script>
<div class="padding"> <div class="padding">

Loading…
Cancel
Save