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}}
+
+
+
+
+
+
+
+
+
+ 第{{randomCount}}轮
+
+
+ 第{{i}}轮
+
+
+
+
+
+
+
+
+
+
+ {{questionData.calcScoreMode==1 ? '今日最高成绩' : '得分'}}:{{currentScore}}
+
+
+
+
+ 剩余时间:{{remainder}}
+
+
+
+
+
+
+
+
+ *
+ {{issue.$index+1}}.
+
+
+
+
+ ({{issue.row.fraction}}分)
+
+
+
+
+ ({{issue.row.iisdx ? '单选' : '多选'}})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{wor.wtxt}}
+
+
+
+
+ *
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{issue.row.isEqual ? '回答正确' : '回答错误'}}
+
+
+ 正确答案:{{issue.row.wors.filter(v=>v.correct).map(v=>v.wtxt).join('')}}
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+ 提交
+
+ 再答一次
+
+
+
+ `, 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 @@
+
+
+
+
+
+
+
+
+
+
+
+ 标题
+
+
+
+
+
+
+
+
+
+
+
+ {{scope.$index+(pageForm.pageNumber - 1) * pageForm.pageSize + 1}}
+
+
+
+
+
+
+ {{scope.row.qsm}}
+
+ 暂无
+
+
+
+
+ {{moment(scope.row.startTime).format('YYYY-MM-DD HH:mm')}}
+
+
+
+
+ {{moment(scope.row.endTime).format('YYYY-MM-DD HH:mm')}}
+
+
+
+
+ 调查
+ 答题
+
+ 意向选择
+
+
+
+
+ 未开启
+ 已开启
+ 已关闭
+
+
+
+
+
+ 开始答题
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+