diff --git a/src/main/java/io/v/nutz/question/controller/QuestionOnlineAnswerController.java b/src/main/java/io/v/nutz/question/controller/QuestionOnlineAnswerController.java new file mode 100644 index 0000000..4d1bef9 --- /dev/null +++ b/src/main/java/io/v/nutz/question/controller/QuestionOnlineAnswerController.java @@ -0,0 +1,19 @@ +package io.v.nutz.question.controller; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +@IocBean +@At("/platform/question/onlineAnswer") +@Ok("json:full") +public class QuestionOnlineAnswerController { + + @At("") + @Ok("beetl:/platform/question/onlineAnswer.html") + @RequiresPermissions("question.onlineAnswer") + public void index() { + } + +} diff --git a/src/main/resources/static/assets/platform/module/mixins/styleMixin.js b/src/main/resources/static/assets/platform/module/mixins/styleMixin.js new file mode 100644 index 0000000..ed0d274 --- /dev/null +++ b/src/main/resources/static/assets/platform/module/mixins/styleMixin.js @@ -0,0 +1,23 @@ +Vue.mixin({ + mounted() { + if (this.$options.style) { + const styleId = `style-${this._uid}` + const style = document.createElement("style") + style.id = styleId + //支持函数和字符串 + const css = typeof this.$options.style === "function" ? this.$options.style.call(this) : this.$options.style + style.textContent = css + document.head.appendChild(style) + } + }, + + beforeDestroy() { + if (this.$options.style) { + const styleId = `style-${this._uid}` + const style = document.getElementById(styleId) + if (style) { + document.head.removeChild(style) + } + } + } +}) diff --git a/src/main/resources/views/layouts/platform.html b/src/main/resources/views/layouts/platform.html index 54bcba2..3718cf9 100644 --- a/src/main/resources/views/layouts/platform.html +++ b/src/main/resources/views/layouts/platform.html @@ -72,6 +72,7 @@ + diff --git a/src/main/resources/views/platform/question/components/answer.js b/src/main/resources/views/platform/question/components/answer.js new file mode 100644 index 0000000..6f42bd7 --- /dev/null +++ b/src/main/resources/views/platform/question/components/answer.js @@ -0,0 +1,543 @@ +const BASE_URL = '/mobile/question/h5' +const onlineAnswer = { + template: + ` +
+
+
+ +

{{questionData.qtitle}}

+
+
+
+ + + + + + + + {{questionData.calcScoreMode==1 ? '今日最高成绩' : '得分'}}:{{currentScore}} + + + + + 剩余时间:{{remainder}} + + + + + + + + + +
+
+ +
+ 保存 + + 提交 + + 再答一次 + +
+
+ `, data() { + return { + questionData: { + issues: [] + }, + currentIssueIndex: 0, + replyInfo: [], + finishAnswer: false, + finishAllAnswer: false, + mLoading: true, + + //用户已答题总轮数 + randomCount: null, + currentRandomCountScore: 0, + sumScore: 0, + randomCountSheetShow: false, + randomActions: [], + currentRandomCount: null, + + //能否再次答题 + canAnswerAgain: false, + + //当前的时间(针对定时定题) + currentDate: moment().format('YYYY-MM-DD'), + + //当前分数 + currentScore: null, + + //获取用户已回答的轮数 针对单天随机 + userHasAnswerRandomNum: 0, + + //倒计时计时器 + timerInterval: null, //答题时间(使用秒) + countDownSeconds: 0, //剩余时间 + remainder: null, + + isNull(val) { + return !val + }, + } + }, + + computed: { + issueList() { + return this.questionData.issues + }, titleMsg() { + const radios = this.issueList.filter(v => v.itx === 1 && v.iisdx) + const checkBoxes = this.issueList.filter(v => v.itx === 1 && !v.iisdx) + + const radioScore = radios && radios.length > 0 ? radios[0].fraction : 0 + const checkBoxesScore = checkBoxes && checkBoxes.length > 0 ? checkBoxes[0].fraction : 0 + + const radioScoreSum = radios.map(v => v.fraction ? v.fraction : 0).reduce((a, b) => a + b, 0) + const checkBoxesScoreSum = checkBoxes.map(v => v.fraction ? v.fraction : 0).reduce((a, b) => a + b, 0) + + const sumScore = radioScoreSum + checkBoxesScoreSum + + let radiosText = '' + let checkBoxesText = '' + + if (radios && radios.length > 0) { + radiosText = "单选题" + radios.length + "题,每题" + radioScore + "分,合计" + radioScoreSum + "分;" + } + if (checkBoxes && checkBoxes.length > 0) { + checkBoxesText = "多选题" + checkBoxes.length + "题,每题" + checkBoxesScore + "分,合计" + checkBoxesScoreSum + "分;总分" + sumScore + "分。" + } + return "说明:" + radiosText + checkBoxesText + }, + + fullScore() { + return this.issueList.map(v => v.fraction ? v.fraction : 0).reduce((a, b) => a + b) + }, radioNum() { + return this.issueList.filter(v => v.idx === 1 && v.iisdx).map(v => v.fraction ? v.fraction : 0).reduce((a, b) => a + b) + }, checkBoxNum() { + + }, + + //判断是否为同一天 + isSameDay() { + if (this.questionData.startTime && this.questionData.endTime) { + return moment(this.questionData.startTime).isSame(moment(this.questionData.endTime), 'day') + } + return false + } + }, + + methods: { + openRandomCount() { + this.randomCountSheetShow = true + this.randomActions = [] + + if (this.questionData.qlx == 2 && this.questionData.ctMode == 2 && this.isSameDay) { + for (let i = 0; i < this.userHasAnswerRandomNum; i++) { + this.randomActions.push({ + name: '第' + (i + 1) + '轮', val: i + 1 + }) + } + } else if (this.questionData.qlx == 2 && (this.questionData.ctMode == 1 || (this.questionData.ctMode == 2 && !this.isSameDay))) { + const {startTime, endTime} = this.questionData + const startMoment = moment(startTime) + const endMoment = moment(endTime) + const now = moment() + // 计算两个日期之间相差的天数 + const daysDifference = endMoment.diff(startMoment, 'days') + for (let i = 0; i <= daysDifference; i++) { + this.randomActions.push({ + name: startMoment.clone().add(i, 'days').format('YYYY-MM-DD'), + val: startMoment.clone().add(i, 'days').format('YYYY-MM-DD'), + disabled: moment(startMoment.clone().add(i, 'days').format('YYYY-MM-DD')).isAfter(now) + }) + } + } + }, async randomCountSelect(val) { + if (this.questionData.qlx == 2 && this.questionData.ctMode == 2 && this.isSameDay) { + this.randomCount = val.val + } else if (this.questionData.qlx == 2 && this.questionData.ctMode == 2 && !this.isSameDay) { + this.currentDate = val.val + } else if (this.questionData.qlx == 2 && this.questionData.ctMode == 1) { + this.currentDate = val.val + } + await this.getQuestionData() + await this.checkUserFinishAnswer() + await this.checkCanAnswerAgain() + await this.getScore() + }, + + async getQuestionData() { + const resp = await $.get(BASE_URL + '/questionInfo/' + this.id, { + currentDate: this.currentDate, randomCount: this.randomCount + }) + this.questionData = resp.data + }, + + // cellToggle(issue, worId) { + // if (this.finishAnswer || this.finishAllAnswer) { + // return + // } + // this.toggle(issue, worId) + // }, + // + // toggle(issue, worId) { + // //单选 + // if (issue.iisdx) { + // this.$refs['checkboxGroup' + issue.iid][0].toggleAll(false) + // } else { + // + // } + // console.log(issue.userSelect) + // this.$refs['checkboxes' + worId][0].toggle() + // setTimeout(() => { + // console.log(issue.userSelect) + // }) + // }, + + save() { + this.$confirm('保存后下次可继续做答,您确定要保存吗?').then(async () => { + const replies = this.questionData.issues.map(v => { + return { + qid: v.iid, issueId: v.iid, userSelect: v.userSelect, + } + }) + + const {code} = await $.post(BASE_URL + '/saveAnswer', { + replies: JSON.stringify(replies), + questionId: this.questionData.qid, + isSave: true, + randomCount: this.randomCount + }) + this.$modal.closeLoading() + if (code === 0) { + this.$message.success('保存成功') + } else { + this.$message.success('保存失败') + } + }) + }, + + submit() { + const iids = this.questionData.issues.filter(v => !v.userSelect).map(v => v.iid) + + if (iids.length > 0) { + this.$toast('您还有' + iids.length + '题未作答,请答完后再提交!') + document.getElementById('issue' + iids[0]).scrollIntoView({ + behavior: 'smooth', block: 'center', 'inline': 'start' + }); + return + } + + const msg = '一旦提交不可修改,您确定要提交吗?' + + this.$modal.confirm(msg).then(async () => { + this.autoSubmit() + }) + }, + + async autoSubmit() { + const replies = this.questionData.issues.map(v => { + return { + qid: this.id, issueId: v.iid, userSelect: v.userSelect, + } + }) + + let takeTime = null + if (this.questionData.enableTimer) { + takeTime = this.questionData.timerMinute * 60 - this.countDownSeconds + } + + const {code} = await $.post(BASE_URL + '/saveAnswer', { + replies: JSON.stringify(replies), + questionId: this.questionData.qid, + isSave: false, + randomCount: this.randomCount, + takeTime: takeTime + }) + this.$modal.closeLoading() + if (code === 0) { + this.$modal.msg('提交成功') + await this.getUserHasAnswerRandomNum() + await this.checkUserFinishAnswer() + await this.getReply() + await this.assignmentAnswer() + await this.checkUserFinishAnswer() + await this.checkCanAnswerAgain() + await this.getScore() + } + }, + + //获取回答信息 + async getReply() { + const resp = await $.get(BASE_URL + '/answerInfo/' + this.id, { + randomCount: this.randomCount, currentDate: this.currentDate + }) + this.replyInfo = resp.data + }, + + //用户是否全部答完提交 + async checkUserFinishAnswer() { + this.mLoading = true + const resp = await $.get(BASE_URL + '/checkUserFinishAnswer', { + questionId: this.id, randomCount: this.randomCount, currentDate: this.currentDate + }) + this.mLoading = false + this.finishAnswer = resp.data + await this.getReply() + await this.assignmentAnswer() + }, + + //答案赋值 + assignmentAnswer() { + this.questionData.issues.forEach((issue,issueIndex) => { + const rwids = this.replyInfo.filter(v => v.issueId === issue.iid).map(v => v.rwid) + // rwids.forEach(rwid => { + // // this.toggle(issue, rwid) + // issue.userSelect = rwid + // }) + // issue.userSelect = rwids + this.$set(this.questionData.issues[issueIndex],'userSelect',rwids) + + const wids = issue.wors.filter(v => v.correct).map(v => v.wid) + const userSelects = this.replyInfo.filter(v => v.issueId === issue.iid).map(v => v.rwid) + const isEqual = wids.length === userSelects.length && wids.every(value => userSelects.includes(value)) + issue.isEqual = isEqual + }) + }, + + async answerAgain() { + if (this.questionData.ctMode === 3) { + await this.onOpen(this.id) + this.finishAnswer = false + this.questionData.issues.forEach((issue,issueIndex) => { + issue.wors.forEach(wor => { + this.$set(this.questionData.issues[issueIndex],'userSelect',[]) + }) + }) + this.checkTimer() + } else { + // this.finishAnswer = false + // setTimeout(() => { + // this.questionData.issues.forEach(issue => { + // issue.wors.forEach(wor => { + // // this.$refs['checkboxes' + wor.wid][0].toggle(false) + // wor.userSelect = [] + // }) + // }) + // }, 0) + // this.checkTimer() + } + }, + + async getUserHasAnswerRandomNum() { + const resp = await $.get(BASE_URL + '/getUserHasAnswerRandomNum', { + questionId: this.id + }) + this.userHasAnswerRandomNum = resp.data + this.randomCount = this.userHasAnswerRandomNum + }, + + async checkCanAnswerAgain() { + const resp = await $.get(BASE_URL + '/checkCanAnswerAgain', { + questionId: this.id, randomCount: this.randomCount, currentDate: this.currentDate + }) + this.canAnswerAgain = resp.data + }, + + async getScore() { + const resp = await $.get(BASE_URL + '/getScore/', { + questionId: this.id, randomCount: this.randomCount, currentDate: this.currentDate + }) + this.currentScore = resp.data + }, + + checkTimer() { + if (this.questionData.enableTimer) { + if (this.timerInterval) { + clearInterval(this.timerInterval) + } + if (!this.finishAnswer) { + this.$alert( + '本次答题时间' + this.questionData.timerMinute + '分钟,请尽快完成!', '提示' + ).then(() => { + this.countDownSeconds = this.questionData.timerMinute * 60 + this.updateCountdown() + this.timerInterval = setInterval(() => { + this.updateCountdown() + }, 1000) + }); + } + } + }, + + updateCountdown() { + // 计算剩余的分钟和秒数 + let mins = Math.floor(this.countDownSeconds / 60) + let secs = this.countDownSeconds % 60 + // 格式化时间,确保分钟和秒数始终是两位数 + mins = mins < 10 ? '0' + mins : mins; + secs = secs < 10 ? '0' + secs : secs; + this.remainder = mins + ':' + secs + // 如果倒计时结束,显示结束信息 + if (this.countDownSeconds <= 0) { + this.remainder = '时间到' + clearInterval(this.timerInterval) + this.$alert( + '答题时间到,请点击确认提交答案!', '提示' + ).then(() => { + this.autoSubmit() + }) + } else { + this.countDownSeconds = this.countDownSeconds - 1 + } + }, + + async onOpen(id) { + if (this.timerInterval) { + clearInterval(this.timerInterval) + } + this.id = id + await this.getQuestionData() + await this.checkCanAnswerAgain() + await this.getUserHasAnswerRandomNum() + await this.checkUserFinishAnswer() + await this.getScore() + await this.checkTimer() + } + + }, + + async created() { + + }, + + style: /*language=CSS*/ ` + .custom-disabled-checkbox{ + pointer-events: none; + } + ` +} diff --git a/src/main/resources/views/platform/question/onlineAnswer.html b/src/main/resources/views/platform/question/onlineAnswer.html new file mode 100644 index 0000000..81a3e09 --- /dev/null +++ b/src/main/resources/views/platform/question/onlineAnswer.html @@ -0,0 +1,154 @@ + + +
+ + +
+ + +
+
+ + + +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +