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

merge...

...@@ -2,6 +2,7 @@ module.exports = { ...@@ -2,6 +2,7 @@ module.exports = {
url: '/', url: '/',
DesDir: './client-dist', DesDir: './client-dist',
apiBaseURL: 'https://learn-api.ezijing.com', apiBaseURL: 'https://learn-api.ezijing.com',
// apiBaseURL: '/',
others: { others: {
url: '/app/learn/course', url: '/app/learn/course',
loginUrl: 'https://login.ezijing.com/bluestar/login/index' loginUrl: 'https://login.ezijing.com/bluestar/login/index'
......
...@@ -2,6 +2,7 @@ module.exports = { ...@@ -2,6 +2,7 @@ module.exports = {
url: '/', url: '/',
DesDir: './client-dist', DesDir: './client-dist',
apiBaseURL: 'https://learn-api2.ezijing.com', apiBaseURL: 'https://learn-api2.ezijing.com',
// apiBaseURL: '/',
others: { others: {
url: '/app/learn/course', url: '/app/learn/course',
loginUrl: 'https://login2.ezijing.com/bluestar/login/index' loginUrl: 'https://login2.ezijing.com/bluestar/login/index'
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -29,6 +29,13 @@ ...@@ -29,6 +29,13 @@
"node": ">=8.9" "node": ">=8.9"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.11.6",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@babel/runtime-corejs3": "^7.11.2",
"acorn": "^7.1.1", "acorn": "^7.1.1",
"ali-oss": "^6.11.2", "ali-oss": "^6.11.2",
"autoprefixer": "^9.8.6", "autoprefixer": "^9.8.6",
...@@ -49,27 +56,20 @@ ...@@ -49,27 +56,20 @@
"eslint-plugin-standard": "^4.0.1", "eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.2.2", "eslint-plugin-vue": "^6.2.2",
"file-loader": "^6.1.1", "file-loader": "^6.1.1",
"html-replace-webpack-plugin": "^2.5.6",
"html-webpack-plugin": "^4.5.0", "html-webpack-plugin": "^4.5.0",
"mini-css-extract-plugin": "^0.9.0", "mini-css-extract-plugin": "^0.9.0",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"request": "^2.88.2",
"sass-loader": "^10.0.3", "sass-loader": "^10.0.3",
"semver": "^1.1.4",
"style-loader": "^2.0.0", "style-loader": "^2.0.0",
"url-loader": "^4.1.1", "url-loader": "^4.1.1",
"vconsole-webpack-plugin": "^1.5.2",
"webpack": "^4.44.2", "webpack": "^4.44.2",
"webpack-cli": "^3.3.12", "webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0", "webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2"
"html-replace-webpack-plugin": "^2.5.6",
"request": "^2.88.2",
"semver": "^1.1.4",
"vconsole-webpack-plugin": "^1.5.2",
"@babel/core": "^7.11.6",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@babel/runtime-corejs3": "^7.11.2"
}, },
"dependencies": { "dependencies": {
"@ckeditor/ckeditor5-build-classic": "^24.0.0", "@ckeditor/ckeditor5-build-classic": "^24.0.0",
......
...@@ -8,6 +8,7 @@ export default { ...@@ -8,6 +8,7 @@ export default {
}, },
data() { data() {
return { return {
loaded: false,
detail: {}, detail: {},
// 学期列表 // 学期列表
semesterList: [ semesterList: [
...@@ -33,7 +34,7 @@ export default { ...@@ -33,7 +34,7 @@ export default {
}, },
// 撤回 // 撤回
hasAbort() { hasAbort() {
return this.isEdit && this.detail.status === -1 return this.isEdit && this.detail.status === -1 && this.detail.pay !== 1
}, },
// 去支付 // 去支付
hasPay() { hasPay() {
...@@ -87,9 +88,11 @@ export default { ...@@ -87,9 +88,11 @@ export default {
}, },
// 获取详情 // 获取详情
getDetail() { getDetail() {
api.getAffair(this.pid).then(response => { this.loaded = false
return api.getAffair(this.pid).then(response => {
this.detail = response this.detail = response
this.ruleForm = response.form this.ruleForm = response.form
this.loaded = true
}) })
}, },
// 返回 // 返回
......
...@@ -122,7 +122,9 @@ export default { ...@@ -122,7 +122,9 @@ export default {
'$route.query': { '$route.query': {
immediate: true, immediate: true,
handler(query) { handler(query) {
this.payVisible = query.pay === '1' if (query.pay === '1') {
this.handlePay()
}
} }
} }
}, },
...@@ -134,15 +136,21 @@ export default { ...@@ -134,15 +136,21 @@ export default {
}, },
methods: { methods: {
handleSubmitSuccess(response) { handleSubmitSuccess(response) {
if (!this.isEdit) { if (this.isEdit) {
this.$router
.replace({ name: 'pareportEdit', params: { id: response.data.id }, query: { id: this.affairId, pay: '1' } })
.then(this.getDetail)
}
this.handlePay() this.handlePay()
} else {
this.$router.replace({
name: 'pareportEdit',
params: { id: response.data.id },
query: { id: this.affairId, pay: '1' }
})
}
}, },
// 去支付 // 去支付
handlePay() { async handlePay() {
if (!this.loaded) {
await this.getDetail()
}
this.payVisible = true this.payVisible = true
}, },
// 支付成功 // 支付成功
......
...@@ -56,7 +56,7 @@ export default { ...@@ -56,7 +56,7 @@ export default {
{ {
label: '删除', label: '删除',
isShow(row) { isShow(row) {
return row.status === -1 return row.status === -1 && row.pay !== 1
}, },
onClick: row => { onClick: row => {
this.handleRemove(row) this.handleRemove(row)
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
<template v-if="isRevised"> <template v-if="isRevised">
<div class="paper-check"> <div class="paper-check">
<p>{{ $t('viewerWork.correctionTime') }}{{ detail.checker_time }}</p> <p>{{ $t('viewerWork.correctionTime') }}{{ detail.checker_time }}</p>
<div class="paper-check-item"> <div class="paper-check-item" v-if="hasScore">
<b>{{ $t('viewerWork.score') }}</b> <b>{{ $t('viewerWork.score') }}</b>
{{ detail.score }} {{ detail.score }}
</div> </div>
...@@ -156,6 +156,10 @@ export default { ...@@ -156,6 +156,10 @@ export default {
const endTime = +new Date(this.deadline) const endTime = +new Date(this.deadline)
const currentTime = new Date().getTime() const currentTime = new Date().getTime()
return currentTime < endTime return currentTime < endTime
},
hasScore() {
// allow_score 1 显示 2隐藏
return this.detail.allow_score !== 2
} }
}, },
methods: { methods: {
......
<template> <template>
<container :title="exam.title" v-loading="!loaded"> <container :title="status.title" v-loading="loading">
<template v-slot:header-aside> <template v-slot:header-aside v-if="isStartExam">
<template v-if="isCompleted"> <template v-if="isCompleted">
{{ $t('viewerWork.fraction') }}{{ exam.score.total }}{{ $t('viewerWork.fractionUnit') }} {{ $t('viewerWork.fraction') }}{{ exam.score.total }}{{ $t('viewerWork.fractionUnit') }}
</template> </template>
<template v-else>{{ $t('viewerWork.examTime') }}{{ status.start_time }} ~ {{ status.terminate_time }}</template> <template v-else>
<div v-if="hasCountdown">倒计时:{{ countdownDurationText }}</div>
<div v-else>{{ $t('viewerWork.examTime') }}{{ status.start_time }} ~ {{ status.terminate_time }}</div>
</template>
</template> </template>
<div class="exam"> <div class="exam">
<template v-if="status.examination_status === '00'"> <template v-if="status.examination_status === '00'">
<div style="text-align: center; margin-top: 40px; margin-bottom: -60px">
{{ $t('viewerWork.examTime') }}{{ status.start_time }} ~ {{ status.terminate_time }}
</div>
<div class="no-exam">{{ $t('viewerWork.examEmpty') }}</div> <div class="no-exam">{{ $t('viewerWork.examEmpty') }}</div>
</template> </template>
<template v-else-if="isSubmited && !isCompleted && !isMultipleExams"> <template v-else-if="isSubmited && !isCompleted && !isMultipleExams">
<div class="no-exam">{{ $t('viewerWork.examSubmitedTips') }}</div> <div class="no-exam">{{ $t('viewerWork.examSubmitedTips') }}</div>
</template> </template>
<template v-else> <template v-else>
<!-- 考试期间,未开始考试 -->
<div class="exam-welcome" v-if="!isStartExam">
<div class="inner">
<div>{{ $t('viewerWork.examTime') }}{{ status.start_time }} ~ {{ status.terminate_time }}</div>
<div v-if="hasCountdown">本场考试时间:{{ durationText }}<br />时间用尽自动交卷,请您注意答题时间。</div>
</div>
<el-button type="primary" :disabled="!isExamTime" @click="onStartExam">{{ startExamButtonText }}</el-button>
</div>
<!-- 考试试题 --> <!-- 考试试题 -->
<div class="exam-form" v-if="loaded"> <div class="exam-form" v-else>
<el-form :disabled="!canEditable"> <el-form :disabled="!canEditable">
<template v-for="items in questions"> <template v-for="items in questions">
<exam-item <exam-item
...@@ -35,7 +49,7 @@ ...@@ -35,7 +49,7 @@
<template v-if="isMultipleExams"> <template v-if="isMultipleExams">
<el-button type="primary" @click="handlePrev" v-if="hasPrev">{{ $t('viewerWork.prevPapers') }}</el-button> <el-button type="primary" @click="handlePrev" v-if="hasPrev">{{ $t('viewerWork.prevPapers') }}</el-button>
<el-button type="primary" @click="handleNext" v-if="hasNext">{{ $t('viewerWork.nextPapers') }}</el-button> <el-button type="primary" @click="handleNext" v-if="hasNext">{{ $t('viewerWork.nextPapers') }}</el-button>
<el-button type="primary" @click="handleNewExam" v-if="hasResubmit"> <el-button type="primary" @click="handleNewExam" v-if="hasResubmit && isExamTime">
{{ $t('viewerWork.anotherSubmitText') }} {{ $t('viewerWork.anotherSubmitText') }}
</el-button> </el-button>
</template> </template>
...@@ -61,30 +75,21 @@ import Container from '../common/container.vue' ...@@ -61,30 +75,21 @@ import Container from '../common/container.vue'
import ExamItem from './examItem.vue' import ExamItem from './examItem.vue'
// api // api
import * as api from '../../api' import * as api from '../../api'
import tool from '@/tool/index'
// 章节测试题 // 课后考试
export default { export default {
name: 'CourseExam', name: 'CourseExam',
components: { Container, ExamItem }, components: { Container, ExamItem },
props: { props: {
// 当前选中的章节 // 当前选中的章节
chapter: { chapter: { type: Object, default: () => {} },
type: Object,
default() {
return {}
}
},
// 课程详情接口返回的数据 // 课程详情接口返回的数据
data: { data: { type: Object, default: () => {} }
type: Object,
default() {
return {}
}
}
}, },
data() { data() {
return { return {
loaded: false, loading: false,
detail: {}, detail: {},
status: {}, status: {},
questions: [], questions: [],
...@@ -95,7 +100,9 @@ export default { ...@@ -95,7 +100,9 @@ export default {
submitLoading: false, submitLoading: false,
isMultipleExams: false, // 是否可以多次考试 isMultipleExams: false, // 是否可以多次考试
maxExams: 3, // 最多考试几次 maxExams: 3, // 最多考试几次
examCount: this.data.exist_examination ? this.data.exist_examination.length : 0 // 试卷数量 countdownDuration: 0, // 倒计时剩余时间
countdownTimer: null,
isStartExam: false
} }
}, },
watch: { watch: {
...@@ -104,6 +111,12 @@ export default { ...@@ -104,6 +111,12 @@ export default {
handler() { handler() {
this.init() this.init()
} }
},
examCount: {
immediate: true,
handler(value) {
this.isStartExam = !!value
}
} }
}, },
computed: { computed: {
...@@ -124,6 +137,10 @@ export default { ...@@ -124,6 +137,10 @@ export default {
// 大于开始时间,小于结束时间 // 大于开始时间,小于结束时间
return this.status.examination_status === '20' return this.status.examination_status === '20'
}, },
// 考试按钮
startExamButtonText() {
return this.status.examination_status === '90' ? '考试结束' : '开始考试'
},
// 是否提交 // 是否提交
isSubmited() { isSubmited() {
return this.exam.type === 1 || this.exam.type === 2 return this.exam.type === 1 || this.exam.type === 2
...@@ -156,7 +173,7 @@ export default { ...@@ -156,7 +173,7 @@ export default {
}, },
// 是否显示再考一次 // 是否显示再考一次
hasResubmit() { hasResubmit() {
if (this.examList.length >= this.maxExams) { if (this.examCount >= this.maxExams) {
return false return false
} }
// 判断状态是否还有未提交的试题 // 判断状态是否还有未提交的试题
...@@ -166,11 +183,25 @@ export default { ...@@ -166,11 +183,25 @@ export default {
} }
} }
return true return true
// return this.isSubmited && this.isExamTime && this.examCount < this.maxExams
}, },
// 已存在的试题列表 // 已存在的试题列表
examList() { examList() {
return this.data.exist_examination return this.data.exist_examination
},
// 试卷数量
examCount() {
return this.examList ? this.examList.length : 0
},
// 是否有倒计时
hasCountdown() {
return !!this.status.duration && this.canEditable
},
// 倒计时文字
countdownDurationText() {
return tool.convertTime.durationToTimeString(this.countdownDuration)
},
durationText() {
return tool.convertTime.durationToTimeString2(this.status.duration)
} }
}, },
methods: { methods: {
...@@ -180,11 +211,21 @@ export default { ...@@ -180,11 +211,21 @@ export default {
// 自动获取考试状态 // 自动获取考试状态
await this.autoCheckExamStatus() await this.autoCheckExamStatus()
// 获取试题 // 获取试题
this.isStartExam && this.getExam()
},
// 开始考试
onStartExam() {
this.isStartExam = true
this.getExam() this.getExam()
}, },
// 获取考试状态 // 获取考试状态
async getExamStatus() { async getExamStatus() {
await api.getCourseExamStatus(this.sid, this.cid, this.pid).then(response => { await api.getCourseExamStatus(this.sid, this.cid, this.pid).then(response => {
// examination_status
// 00: 考场未开放,不允许进入
// 10:考场开放,允许进入
// 20:开始答题
// 90:考试已结束
this.status = response this.status = response
if (this.isSubmited || response.examination_status === '90') { if (this.isSubmited || response.examination_status === '90') {
this.checkStatusTimer && clearInterval(this.checkStatusTimer) this.checkStatusTimer && clearInterval(this.checkStatusTimer)
...@@ -196,11 +237,11 @@ export default { ...@@ -196,11 +237,11 @@ export default {
// 获取试题状态 // 获取试题状态
await this.getExamStatus() await this.getExamStatus()
this.checkStatusTimer && clearInterval(this.checkStatusTimer) this.checkStatusTimer && clearInterval(this.checkStatusTimer)
this.checkStatusTimer = setInterval(this.getExamStatus, 5000) this.checkStatusTimer = setInterval(this.getExamStatus, 1000)
}, },
// 获取试题 // 获取试题
getExam() { getExam() {
this.loaded = false this.loading = true
api api
.getCourseExamResult(this.sid, this.cid, this.pid, { offset: this.offset }) .getCourseExamResult(this.sid, this.cid, this.pid, { offset: this.offset })
.then(response => { .then(response => {
...@@ -210,9 +251,13 @@ export default { ...@@ -210,9 +251,13 @@ export default {
this.canEditable && this.autoSubmit() this.canEditable && this.autoSubmit()
// 更新菜单 // 更新菜单
this.isMultipleExams && this.$emit('update') this.isMultipleExams && this.$emit('update')
// 倒计时剩余时间
this.countdownDuration = this.status.duration - this.exam.duration
// 开始倒计时
this.hasCountdown && this.setCountdown()
}) })
.finally(() => { .finally(() => {
this.loaded = true this.loading = false
}) })
}, },
// 组装问题数据 // 组装问题数据
...@@ -293,7 +338,7 @@ export default { ...@@ -293,7 +338,7 @@ export default {
const params = { answers: JSON.stringify(answers), type: 0 } const params = { answers: JSON.stringify(answers), type: 0 }
// 请求接口 // 请求接口
this.handleSubmitRequest(params) this.handleSubmitRequest(params)
}, 3000) }, 1000)
}, },
// 处理请求接口答案数据 // 处理请求接口答案数据
handleSubmitData() { handleSubmitData() {
...@@ -340,7 +385,9 @@ export default { ...@@ -340,7 +385,9 @@ export default {
} }
}) })
.catch(error => { .catch(error => {
this.$message.error(error.message) params.type && this.$message.error(error.message)
this.autoSubmitTimer && clearInterval(this.autoSubmitTimer)
this.getExam()
}) })
.finally(() => { .finally(() => {
this.submitLoading = false this.submitLoading = false
...@@ -357,12 +404,22 @@ export default { ...@@ -357,12 +404,22 @@ export default {
}, },
handleNewExam() { handleNewExam() {
this.$router.push({ query: { offset: this.examCount } }) this.$router.push({ query: { offset: this.examCount } })
this.examCount++
}, },
// 清除定时器 // 清除定时器
clearTimer() { clearTimer() {
this.autoSubmitTimer && clearInterval(this.autoSubmitTimer) this.autoSubmitTimer && clearInterval(this.autoSubmitTimer)
this.checkStatusTimer && clearInterval(this.checkStatusTimer) this.checkStatusTimer && clearInterval(this.checkStatusTimer)
this.countdownTimer && clearInterval(this.countdownTimer)
},
// 设置倒计时
setCountdown() {
this.countdownTimer && clearInterval(this.countdownTimer)
this.countdownTimer = setInterval(() => {
this.countdownDuration--
if (this.countdownDuration <= 0) {
this.countdownTimer && clearInterval(this.countdownTimer)
}
}, 1000)
} }
}, },
beforeMount() { beforeMount() {
...@@ -392,9 +449,10 @@ export default { ...@@ -392,9 +449,10 @@ export default {
text-align: center; text-align: center;
} }
.exam-welcome { .exam-welcome {
padding: 40px; display: flex;
flex-direction: column;
align-items: center;
line-height: 30px; line-height: 30px;
text-align: center;
::v-deep .el-button { ::v-deep .el-button {
margin-top: 30px; margin-top: 30px;
} }
......
...@@ -27,8 +27,8 @@ export default { ...@@ -27,8 +27,8 @@ export default {
submitedText: '已提交', submitedText: '已提交',
fraction: '分数', fraction: '分数',
fractionUnit: '分', fractionUnit: '分',
examEmpty: '暂无考试', examEmpty: '考试暂未开始',
examTime: '考试时间', examTime: '考试有效时间',
examDeadline: '考试截止时间', examDeadline: '考试截止时间',
examSubmitedTips: '试卷批改中,请耐心等待', examSubmitedTips: '试卷批改中,请耐心等待',
examSubmitButtonTips: '提交之后就不能修改了哦', examSubmitButtonTips: '提交之后就不能修改了哦',
......
...@@ -3,15 +3,32 @@ export default class ConvertTime { ...@@ -3,15 +3,32 @@ export default class ConvertTime {
* 工具方法 - 播放时间 转化 h:m:s * 工具方法 - 播放时间 转化 h:m:s
* @param {[string]} duration 时间戳 * @param {[string]} duration 时间戳
*/ */
durationToTimeString (duration) { durationToTimeString(duration) {
const h = Math.floor(duration / 3600) const h = Math.floor(duration / 3600)
const m = Math.floor((duration - h * 3600) / 60) const m = Math.floor((duration - h * 3600) / 60)
const s = (duration - h * 3600 - m * 60) % 60 const s = (duration - h * 3600 - m * 60) % 60
function tenify (a) { function tenify(a) {
return a >= 10 ? a : '0' + a return a >= 10 ? a : '0' + a
} }
const to = { h: tenify(h), m: tenify(m), s: tenify(s) } const to = { h: tenify(h), m: tenify(m), s: tenify(s) }
const format = 'h:m:s' const format = 'h:m:s'
return format.replace(/h|m|s/g, k => to[k]).replace(/^00:/, '') return format.replace(/h|m|s/g, k => to[k]).replace(/^00:/, '')
} }
durationToTimeString2(duration) {
const h = Math.floor(duration / 3600)
const m = Math.floor((duration - h * 3600) / 60)
const s = (duration - h * 3600 - m * 60) % 60
let output = ''
if (h) {
output += `${h}小时`
}
if (m) {
output += `${m}分钟`
}
if (s) {
output += `${s}秒`
}
return output
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论