提交 3602241b authored 作者: 王鹏飞's avatar 王鹏飞

作业支持多道简答题

上级 506bd6c8
<template>
<div class="editor">
<textarea name="editor" :id="textareaElementId" :disabled="disabled"></textarea>
</div>
</template>
<script>
import { uniqueId } from 'lodash'
export default {
name: 'VEditor',
props: {
value: { type: String },
disabled: { type: Boolean, default: false }
},
data() {
return {
textareaElementId: uniqueId('editor_'),
ckEditor: null
}
},
methods: {
createEditor() {
const editor = (this.ckEditor = CKEDITOR.replace(this.textareaElementId, {
height: 400,
uiColor: '#eeeeee',
filebrowserImageUploadUrl: '/api/ckeditor/img/upload',
// resize_enabled: typeof this.props.resizable === 'boolean' ? this.props.resizable : true,
toolbar: [
// { name: 'document', items: ['Source', '-', 'Save', 'NewPage', 'Preview'] },
{ name: 'styles', items: ['Styles', 'Format', 'Font', 'FontSize'] },
{ name: 'colors', items: ['TextColor', 'BGColor'] },
{ name: 'tools', items: ['Maximize', 'ShowBlocks'] },
// { name: 'clipboard', items: ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo'] },
{ name: 'editing', items: ['Find', 'Replace'] },
// { name: 'forms', items: ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'] },
'/',
{
name: 'basicstyles',
items: [
'Bold',
'Italic',
'Underline',
'Strike',
'Subscript',
'Superscript',
'-',
'RemoveFormat'
]
},
{
name: 'paragraph',
items: [
'NumberedList',
'BulletedList',
'-',
'Outdent',
'Indent',
'-',
'Blockquote',
'CreateDiv',
'-',
'JustifyLeft',
'JustifyCenter',
'JustifyRight',
'JustifyBlock',
'-',
'BidiLtr',
'BidiRtl'
]
},
{ name: 'links', items: ['Link', 'Unlink', 'Anchor'] },
{ name: 'insert', items: ['Image', 'Table', 'HorizontalRule'] }
]
}))
editor.on('instanceReady', () => {
const data = this.value
editor.fire('lockSnapshot')
editor.setData(data, {
callback: () => {
this.bindEvent()
const newData = editor.getData()
// Locking the snapshot prevents the 'change' event.
// Trigger it manually to update the bound data.
if (data !== newData) {
this.$once('input', () => {
this.$emit('ready', editor)
})
this.$emit('input', newData)
} else {
this.$emit('ready', editor)
}
editor.fire('unlockSnapshot')
}
})
})
},
bindEvent() {
const editor = this.ckEditor
editor.on('change', evt => {
const data = editor.getData()
if (this.value !== data) {
this.$emit('input', data, evt, editor)
}
})
editor.on('focus', evt => {
this.$emit('focus', evt, editor)
})
editor.on('blur', evt => {
this.$emit('blur', evt, editor)
})
}
},
mounted() {
this.createEditor()
},
beforeDestroy() {
this.ckEditor && this.ckEditor.destroy()
this.ckEditor = null
}
}
</script>
<style lang="scss" scoped>
* {
margin: 0;
padding: 0;
}
</style>
<template>
<div class="upload">
<el-upload action :show-file-list="false" :http-request="httpRequest">
<slot></slot>
<el-button type="text" size="small" icon="el-icon-upload">点击上传</el-button>
<template v-slot:tip>
<div class="el-upload__tips">
<slot name="tip"></slot>
</div>
</template>
</el-upload>
<div class="file-list" v-if="value">
<div class="file-list-item">
<a :href="value" target="_blank">
<i class="el-icon-document"></i>
{{ fileName }}
</a>
<a :href="value" :download="fileName" target="_blank">
<el-tooltip effect="dark" content="下载">
<i class="el-icon-download"></i>
</el-tooltip>
</a>
</div>
</div>
</div>
</template>
<script>
import cAction from '@action'
export default {
name: 'VUpload',
props: {
value: { type: String }
},
data() {
return {}
},
computed: {
fileName() {
return this.value ? this.value.split('/').pop() : ''
}
},
methods: {
httpRequest(xhr) {
cAction.Player.uploadFile({ file: xhr.file })
.then(response => {
if (response.success) {
this.$emit('input', response.url)
}
})
.catch(error => {
console.log(error)
})
},
handleRemove() {
this.$emit('input', '')
}
}
}
</script>
<style lang="scss" scoped>
.file-list-item {
display: flex;
margin-bottom: 10px;
padding: 0 10px;
justify-content: space-between;
line-height: 30px;
background-color: #fff;
border-radius: 4px;
a {
text-decoration: none;
color: #333;
&:hover {
color: #b49441;
}
}
}
</style>
<template>
<div class="play-paper">
<div class="play-paper-body">
<div class="play-paper-title"><div><h3>{{chapterName}}</h3></div></div>
<div class="play-paper-content play-chapter-work">
<template v-if="chapterWork.questions && chapterWork.questions.length" >
<div class="play-paper">
<div class="play-paper-body">
<div class="play-paper-title">
<div>
<h3>{{chapterName}}</h3>
</div>
</div>
<div class="play-paper-content play-chapter-work">
<ul>
<template v-for="(item, index) in chapterWork.questions">
<li v-bind:key="index">
<div class="work-number">{{index + 1}}.</div>
<div class="work-title">
<div class="edit_html" v-html="item.question_content"></div>
</div>
<textarea id="editor-chapterWork"></textarea>
<div style="height: 20px;"></div>
<!-- <el-upload
ref="upFile"
class="upload-demo"
action=""
:multiple="false"
:limit="1"
:show-file-list="false"
:on-change="handleChange"
:http-request="uploadFile"
:file-list="filesArr">
请上传对应的文件附件:<el-button type="text">点击上传</el-button>
<template v-if="successFileUrl">
{{successFileUrl.replace(/.*\/([^\/]*\.docx)$/gi, '$1')}}
</template>
</el-upload> -->
<template v-if="successFileUrl">
<a :href="successFileUrl">下载已上传文件</a>
</template>
<!-- <div style="height: 20px;"></div> -->
<!-- <p class="help help-file">只支持docx格式的文件,文件小于10M</p> -->
<!-- {answer.file_url && <a style={{display: 'block', marginBottom: '20px', color: 'blue'}} href={answer.file_url} >下载附件</a> } -->
<li v-for="(item, index) in questions" :key="index">
<div class="work-number">{{index + 1}}.</div>
<div class="work-title">
<div class="edit_html" v-html="item.question_content"></div>
</div>
<!-- 文本内容 -->
<v-editor v-model="item.descreption"></v-editor>
<!-- 上传附件 -->
<v-upload v-model="item.file_url">请上传对应的文件附件:</v-upload>
</li>
</template>
</ul>
</template>
<template v-else>
<!-- <p class="no-data">暂无数据</p> -->
</template>
<!-- <p class="text-danger">{this.state.error}</p> -->
<template v-if="this.deadLine">
<p style="color: red">请于截止日期 {{this.deadLine}} 前提交</p>
</template>
<div class="area-btns">
<el-button type="primary" @click="submitWork" :disabled="!!homeData.checker_time || deadLineFlag">{{homeData.checker_time ? '已批改' : '提交'}}</el-button>
<span class="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span>
<template v-if="homeData.checker_time">
<div class="play-paper-check">
<h4>已获批改 <small>批改于{{homeData.checker_time}}</small></h4>
<div class="play-paper-check-item"><b>评分:</b>{{homeData.score}}</div>
<div class="play-paper-check-item">
<b>评语:</b>
<div class="edit_html" v-html="homeData.check_comments"></div>
</div>
</div>
</template>
<template v-else-if="homeData.created_time">
<p class="help">已于 {{homeData.created_time}} 提交,等待批改中</p>
<template v-if="deadLine">
<p style="color: red">请于截止日期 {{deadLine}} 前提交</p>
</template>
<div class="area-btns">
<el-button
type="primary"
@click="submitWork"
:disabled="!!homeData.checker_time || deadLineFlag"
>{{homeData.checker_time ? '已批改' : '提交'}}</el-button>
<span class="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span>
<template v-if="homeData.checker_time">
<div class="play-paper-check">
<h4>
已获批改
<small>批改于{{homeData.checker_time}}</small>
</h4>
<div class="play-paper-check-item">
<b>评分:</b>
{{homeData.score}}
</div>
<div class="play-paper-check-item">
<b>评语:</b>
<div class="edit_html" v-html="homeData.check_comments"></div>
</div>
</div>
</template>
<template v-else-if="homeData.created_time">
<p class="help">已于 {{homeData.created_time}} 提交,等待批改中</p>
</template>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import cAction from '@action'
import Base64 from 'Base64'
import CKEDITOR from 'CKEDITOR'
import VEditor from '@/components/editor.vue'
import VUpload from '@/components/upload.vue'
export default {
components: { VEditor, VUpload },
props: {
chapterId: { type: String, require: false },
chapterWork: { type: Object, require: false },
......@@ -83,149 +71,114 @@ export default {
cid: { type: String, require: false },
id: { type: String, require: false }
},
data () {
data() {
return {
ckeditor: null,
successFileUrl: '',
filesArr: [],
file: {
id: 'WU_FILE_0',
name: '',
type: '',
lastModifiedDate: '',
size: '',
file: ''
},
homeData: {},
/* 设置是否可以初始化 ckeditor */
setTime: null,
isInit: false,
deadLine: '',
deadLineFlag: false
deadLineFlag: false,
questions: []
}
},
/* 本组件 仅支持 单个 ckeditor 存在 */
mounted () {
this.loadAjax()
},
updated () {},
destroyed () {
/* 清空 ckeditor 需要调用方法删除 并 在DOM结构中也移除 */
this.ckeditor && this.ckeditor.destroy(true)
this.ckeditor = null
watch: {
id: {
handler() {
this.loadAjax()
}
},
chapterWork: {
handler(data) {
this.questions = data.questions.map(item => {
return Object.assign({}, item, { file_url: '', descreption: '' })
})
this.loadAjax()
}
}
},
methods: {
handleChange (file, filelist) {
this.file.name = file.raw.name
this.file.type = file.raw.type
this.file.lastModifiedDate = file.raw.lastModifiedDate
this.file.size = file.raw.size
this.file.file = file.raw
},
loadAjax () {
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.Player.getHomework(this.sid, this.cid, this.id).then(data => {
this.homeData = data
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => {
this.setTime = setInterval(() => {
if (document.querySelector('#editor-chapterWork')) {
this.initckeditor()
if (this.homeData.work_contents) {
const json = JSON.parse(this.homeData.work_contents)
if (json[0].is_encoded) {
json[0].descreption = Base64.decode(json[0].descreption)
}
this.successFileUrl = json[0].file_url
this.ckeditor.setData(json[0].descreption)
loadAjax() {
const loading = this.$loading({
lock: true,
text: '',
spinner: '',
background: 'rgba(255, 255, 255, 0.9)'
})
cAction.Player.getHomework(this.sid, this.cid, this.id)
.then(data => {
this.homeData = data
const parseAnswers = JSON.parse(data.work_contents)
this.questions = this.questions.map(item => {
const found = parseAnswers.find(
answer => answer.question_id === item.id
)
if (found) {
return Object.assign({}, item, {
file_url: found.file_url,
descreption: Base64.decode(found.descreption)
})
} else {
this.successFileUrl = ''
this.ckeditor.setData('')
return item
}
/* 滚动到头部 */
document.querySelector('.play-paper').scrollTop = 0
clearInterval(this.setTime)
}
}, 50)
loading.close()
})
})
})
.catch(e => {
this.filesArr.pop()
this.$message.error(e.message)
})
.finally(() => {
loading.close()
})
setTimeout(() => {
cAction.Player.getHomeworkStopTime(this.sid, this.cid, this.chapterId).then(data => {
this.deadLine = data.dead_line || ''
const deadLine = data.dead_line ? new Date(data.dead_line).getTime() : ''
// deadLine = new Date().getTime() - 100
this.deadLineFlag = ((new Date().getTime() > deadLine) && !!deadLine)
// console.log(this.deadLine)
}).catch(e => { this.$message.error(e.message) }).finally(() => {})
cAction.Player.getHomeworkStopTime(this.sid, this.cid, this.chapterId)
.then(data => {
this.deadLine = data.dead_line || ''
const deadLine = data.dead_line
? new Date(data.dead_line).getTime()
: ''
this.deadLineFlag = new Date().getTime() > deadLine && !!deadLine
})
.catch(e => {
this.$message.error(e.message)
})
}, 500)
},
submitWork () {
if (!this.ckeditor.getData()) {
this.$message.error('请填写内容')
return
}
/* 只能提交 单个问题 */
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
const str = JSON.stringify([{
question_id: this.chapterWork.questions[0].id,
descreption: Base64.encode(this.ckeditor.getData()),
file_url: this.successFileUrl,
is_encoded: 1
}])
submitWork() {
const loading = this.$loading({
lock: true,
text: '',
spinner: '',
background: 'rgba(255, 255, 255, 0.9)'
})
// 组装提交的数据
const answers = this.questions.map(item => {
return {
question_id: item.id,
descreption: Base64.encode(item.descreption),
file_url: item.file_url,
is_encoded: 1
}
})
cAction.Player.updateHomework({
semester_id: this.sid,
course_id: this.cid,
chapter_id: this.chapterId,
work_id: this.id,
work_contents: str,
work_contents: JSON.stringify(answers),
duration: 30 + Math.floor(Math.random() * 1000)
}).then(data => {
if (data.status) {
this.$message({ type: 'success', message: '提交成功,等待批改' })
this.loadAjax()
}
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => { loading.close() })
},
uploadFile () {
if (!/\.(docx)$/gi.test(this.file.name)) {
this.$message.error('文件格式不对,请重新上传')
this.filesArr.pop()
return
}
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.Player.uploadFile(this.file).then(data => {
this.successFileUrl = data.url
this.filesArr.pop()
}).catch(e => { this.filesArr.pop(); this.$message.error(e.message) }).finally(() => { loading.close() })
},
/* 初始化 ckeditor */
initckeditor () {
!this.ckeditor && (this.ckeditor = CKEDITOR.replace('editor-chapterWork', {
height: 300,
uiColor: '#eeeeee',
filebrowserImageUploadUrl: '/api/ckeditor/img/upload',
// resize_enabled: typeof this.props.resizable === 'boolean' ? this.props.resizable : true,
toolbar: [
// { name: 'document', items: ['Source', '-', 'Save', 'NewPage', 'Preview'] },
{ name: 'styles', items: ['Styles', 'Format', 'Font', 'FontSize'] },
{ name: 'colors', items: ['TextColor', 'BGColor'] },
{ name: 'tools', items: ['Maximize', 'ShowBlocks'] },
// { name: 'clipboard', items: ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo'] },
{ name: 'editing', items: ['Find', 'Replace'] },
// { name: 'forms', items: ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'] },
'/',
{ name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'] },
{ name: 'paragraph', items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'] },
{ name: 'links', items: ['Link', 'Unlink', 'Anchor'] },
{ name: 'insert', items: ['Image', 'Table', 'HorizontalRule'] }
]
}))
}
},
watch: {
id: {
handler () {
this.loadAjax()
}
})
.then(data => {
if (data.status) {
this.$message({ type: 'success', message: '提交成功,等待批改' })
this.loadAjax()
}
})
.catch(e => {
this.filesArr.pop()
this.$message.error(e.message)
})
.finally(() => {
loading.close()
})
}
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论