Files
2026-09-20 15:46:34 +08:00

544 lines
25 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const BASE_URL = '/mobile/question/h5'
const onlineAnswer = {
template:
`
<div style="height: 100%">
<div style="max-height: 700px;overflow-y: scroll">
<div class="btDiv mb10" title="">
<el-row style="text-align: center">
<h2>{{questionData.qtitle}}</h2>
</el-row>
</div>
<div class="survey-container" v-if="!mLoading">
<!-- 顶部信息区 -->
<el-card class="survey-head-top" shadow="never">
<!-- 轮次/日期选择 -->
<template v-if="questionData.qlx==2">
<el-dropdown @command="randomCountSelect"
v-if="questionData.ctMode==2 && isSameDay && randomCount > 0">
<el-button>
第{{randomCount}}轮<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="i in userHasAnswerRandomNum" :key="i"
:command="{val: i}">第{{i}}轮
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-date-picker
v-else-if="questionData.ctMode==1 || (questionData.ctMode==2 && !isSameDay)"
v-model="currentDate"
type="date"
:disabled-date="disabledDate"
@change="dateChange">
</el-date-picker>
</template>
<!-- 分数显示 -->
<span class="score" v-if="finishAnswer && (currentScore || currentScore===0)">
{{questionData.calcScoreMode==1 ? '今日最高成绩' : '得分'}}:{{currentScore}}
</span>
<!-- 计时器 -->
<span v-if="questionData.enableTimer && !finishAnswer">
剩余时间:{{remainder}}
</span>
</el-card>
<!-- 题目列表 -->
<el-table :data="issueList"
class="issueList mt10"
default-expand-all="true"
highlight-current-row="true"
style="width: 100%">
<el-table-column align="left" header-align="left" label="">
<template scope="issue">
<el-col :span="1">
<span style="color: red" v-if="issue.row.iisbd">*</span>
<span style="font-weight: bolder">{{issue.$index+1}}.</span>
</el-col>
<el-col :span="23">
<el-row>
<el-col :span="1" v-if="issue.row.fraction">
<span>({{issue.row.fraction}}分)</span>
</el-col>
<el-col :span="23" style="display: flex">
<span v-html="issue.row.iname"></span>
<span v-if="issue.row.itx===1" size="mini" style="font-weight: bold">
({{issue.row.iisdx ? '单选' : '多选'}})
</span>
</el-col>
</el-row>
<el-row>
<div style="color: rgb(160,160,160)" v-html="issue.row.its"
v-if="!isNull(issue.row.its)"></div>
</el-row>
<el-row>
<el-row v-for="wor,idx in issue.row.wors">
<el-row style="margin-top: 5px" v-if="wor.wimg">
<el-image
:src="FILE_STREAM_PREVIEW_ADDRESS + '?id=' +wor.wimg"
fit="fill"
style="max-width: 100px;max-height: 100px"></el-image>
</el-row>
<el-row style="margin-top: 5px"
v-if="!isNull(wor.wimg)">
<div style="color: rgb(160,160,160);text-align: left">
<div v-html="wor.wsm"></div>
</div>
</el-row>
<!-- <el-radio v-if="issue.row.iisdx==true"-->
<!-- :label="idx"-->
<!-- v-model="issue.row.userSelect"-->
<!-- border-->
<!-- style="margin-bottom: 5px;"-->
<!-- :disabled="finishAnswer || finishAllAnswer"-->
<!-- size="small">-->
<!-- <span>{{wor.wtxt}}</span>-->
<!-- </el-radio>-->
<!-- :disabled="finishAnswer || finishAllAnswer"-->
<el-checkbox style="margin-bottom: 5px;"
class="custom-disabled-checkbox"
border
size="small"
v-model="issue.row.userSelect"
:key="idx"
:label="wor.wid">
<span>{{wor.wtxt}}</span>
</el-checkbox>
<span v-else-if="wor.wistk==true" class="inputParent">
<el-input
size="mini"
style="border-top: none"
disabled
v-model="wor.tktxt"></el-input>
<span style="color:red;"
v-if="wor.wisbt==true">*</span>
</span>
<el-row style="margin-top: 5px"
v-if="isNull(wor.wimg)&&!isNull(wor.wsm)">
<div style="color: rgb(160,160,160)">
<div v-html="wor.wsm"></div>
</div>
</el-row>
</el-row>
</el-row>
<el-row v-if="issue.row.itx==2">
<el-input size="small" style="width: 50%"
v-for="wor in issue.row.wors"
v-model="issue.row.tktxt"></el-input>
</el-row>
<div v-if="finishAnswer" class="question-result">
<span :class="issue.row.isEqual ? 'text-success' : 'text-danger'">
{{issue.row.isEqual ? '回答正确' : '回答错误'}}
</span>
<span>
正确答案:{{issue.row.wors.filter(v=>v.correct).map(v=>v.wtxt).join('')}}
</span>
</div>
</el-col>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="page-control" style="display: flex;justify-content: center;margin-top: 10px">
<el-button v-if="!finishAnswer && !questionData.enableTimer"
type="primary"
@click="save">保存
</el-button>
<el-button v-if="!finishAnswer"
type="primary"
@click="submit">提交
</el-button>
<el-button v-if="canAnswerAgain && finishAnswer"
type="primary"
@click="answerAgain">再答一次
</el-button>
</div>
</div>
`, 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;
}
`
}