diff --git a/src/main/java/io/v/nutz/question/controller/QuestionH5Controller.java b/src/main/java/io/v/nutz/question/controller/QuestionH5Controller.java index 69c23d5..2539f6e 100644 --- a/src/main/java/io/v/nutz/question/controller/QuestionH5Controller.java +++ b/src/main/java/io/v/nutz/question/controller/QuestionH5Controller.java @@ -2,6 +2,7 @@ package io.v.nutz.question.controller; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; import cn.wizzer.framework.base.Result; import cn.wizzer.framework.page.Pagination; import io.v.nutz.activity.models.ActivityUserScope; @@ -15,6 +16,7 @@ import org.nutz.dao.Dao; import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.dao.util.Daos; +import org.nutz.dao.util.cri.Static; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.lang.Lang; @@ -282,10 +284,39 @@ public class QuestionH5Controller { } else if (ctMode == 3) { //常规模式 //判断是否将题目加进去了 - QuestionRandomIssue randomIssue = dao.fetch(QuestionRandomIssue.class, Cnd.where("questionId", "=", question.getQid()).and("userId", "=", ShiroUtil.getUserId())); - if (Lang.isEmpty(randomIssue)) { - Sql issueSql = Sqls.create(" SELECT iid FROM `question_issue` where iqid = @qid"); - issueSql.setParam("qid", id); + + Sql issueSql = Sqls.create(" SELECT iid FROM `question_issue` $condition"); + Cnd commonIssueCnd = Cnd.NEW(); + commonIssueCnd.and("iqid", "=", id); + + //判断是否要随机 + Integer ranDomSum = question.getRanDomSum(); + Integer ranDomSingleIssueNum = question.getRanDomSingleIssueNum(); + + //已经回答最大次数 + int maxAnswer = 0; + + boolean needFor = true; + + List randomIssues = dao.query(QuestionRandomIssue.class, Cnd.where("questionId", "=", question.getQid()).and("userId", "=", ShiroUtil.getUserId())); + if (Lang.isNotEmpty(randomIssues)) { + maxAnswer = randomIssues.stream().mapToInt(QuestionRandomIssue::getNum).max().orElse(0); + int finalMaxAnswer = maxAnswer; + QuestionRandomIssue maxQuestionRandomIssue = randomIssues.stream().filter(randomIssue -> randomIssue.getNum() == finalMaxAnswer).findFirst().orElse(null); + if (randomIssues.size() < ranDomSum && Lang.isNotEmpty(maxQuestionRandomIssue) && maxQuestionRandomIssue.getIsFinish()) { + List allIssueIds = randomIssues.stream().flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList()); + commonIssueCnd.andEX("iid", "not in", allIssueIds); + }else{ + needFor = false; + } + } + + if (ObjectUtil.isAllNotEmpty(ranDomSum, ranDomSingleIssueNum)) { + commonIssueCnd.and(new Static("1=1 order by rand() limit " + ranDomSingleIssueNum)); + } + + if(needFor){ + issueSql.setCondition(commonIssueCnd); issueSql.setCallback(Sqls.callback.strList()); dao.execute(issueSql); List randomIssueIds = (List) issueSql.getResult(); @@ -294,13 +325,40 @@ public class QuestionH5Controller { questionRandomIssue.setQuestionId(id); questionRandomIssue.setUserId(ShiroUtil.getUserId()); questionRandomIssue.setIssueIds(randomIssueIds); - questionRandomIssue.setNum(null); + questionRandomIssue.setNum(maxAnswer + 1); questionRandomIssue.setIsFinish(false); dao.insert(questionRandomIssue); issueCnd.and("iid", "in", randomIssueIds); - } else { - issueCnd.and("iid", "in", randomIssue.getIssueIds()); + }else{ +// List allIssueIds = randomIssues.stream().flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList()); + int finalMaxAnswer1 = maxAnswer; + List allIssueIds = randomIssues.stream().filter(randomIssue -> randomIssue.getNum() == finalMaxAnswer1).flatMap(randomIssue -> randomIssue.getIssueIds().stream()).collect(Collectors.toList()); + issueCnd.and("iid", "in", allIssueIds); } + +// if (Lang.isEmpty(randomIssue)) { +// +// Sql issueSql = Sqls.create(" SELECT iid FROM `question_issue` where iqid = @qid $randLimit"); +// issueSql.setParam("qid", id); +// if (ranDomSingleIssueNum != null && ranDomSingleIssueNum > 0) { +// issueSql.setVar("randLimit", " order by rand() limit " + ranDomSingleIssueNum); +// } +// +// issueSql.setCallback(Sqls.callback.strList()); +// dao.execute(issueSql); +// List randomIssueIds = (List) issueSql.getResult(); +// Collections.shuffle(randomIssueIds); +// QuestionRandomIssue questionRandomIssue = new QuestionRandomIssue(); +// questionRandomIssue.setQuestionId(id); +// questionRandomIssue.setUserId(ShiroUtil.getUserId()); +// questionRandomIssue.setIssueIds(randomIssueIds); +// questionRandomIssue.setNum(null); +// questionRandomIssue.setIsFinish(false); +// dao.insert(questionRandomIssue); +// issueCnd.and("iid", "in", randomIssueIds); +// } else { +// issueCnd.and("iid", "in", randomIssue.getIssueIds()); +// } } // issueCnd.asc("ipxbh"); diff --git a/src/main/java/io/v/nutz/question/controller/QuestionMangeController.java b/src/main/java/io/v/nutz/question/controller/QuestionMangeController.java index d4468c6..7b47cbb 100644 --- a/src/main/java/io/v/nutz/question/controller/QuestionMangeController.java +++ b/src/main/java/io/v/nutz/question/controller/QuestionMangeController.java @@ -225,12 +225,13 @@ public class QuestionMangeController { List newIssueIds = issues.stream().map(v -> v.getIid()).collect(Collectors.toList()); List deleteIssues = oldIssues.stream().filter(v -> !newIssueIds.contains(v.getIid())).collect(Collectors.toList()); + List deleteIssueIds = deleteIssues.stream().map(v -> v.getIid()).collect(Collectors.toList()); //题目删掉 - dao.clear(Question_issue.class, Cnd.where("iid", "in", deleteIssues)); + dao.clear(Question_issue.class, Cnd.where("iid", "in", deleteIssueIds)); //选项删掉 - dao.clear(Question_wor.class, Cnd.where("wiid", "in", deleteIssues)); + dao.clear(Question_wor.class, Cnd.where("wiid", "in", deleteIssueIds)); //回答记录删掉 - dao.clear(Question_reply.class, Cnd.where("issueId", "in", deleteIssues)); + dao.clear(Question_reply.class, Cnd.where("issueId", "in", deleteIssueIds)); for (Question_issue oldIssue : oldIssues) { diff --git a/src/main/java/io/v/nutz/question/model/Question_issue.java b/src/main/java/io/v/nutz/question/model/Question_issue.java index aafc1e5..22d87c8 100644 --- a/src/main/java/io/v/nutz/question/model/Question_issue.java +++ b/src/main/java/io/v/nutz/question/model/Question_issue.java @@ -51,7 +51,7 @@ public class Question_issue implements Serializable { private Boolean iisbd; @Column - @Comment("题型 (1 选择题 2 填空题)") + @Comment("题型 (1 选择题 2 填空题 3 判断题)") @J4EIgnore @ColDefine(type = ColType.INT, width = 2) private Integer itx; diff --git a/src/main/java/io/v/nutz/question/model/Question_wor.java b/src/main/java/io/v/nutz/question/model/Question_wor.java index db14f46..e0e7f5f 100644 --- a/src/main/java/io/v/nutz/question/model/Question_wor.java +++ b/src/main/java/io/v/nutz/question/model/Question_wor.java @@ -33,7 +33,7 @@ public class Question_wor implements Serializable { @Column @Comment("选项文字") @J4EIgnore - @ColDefine(type = ColType.VARCHAR, width = 100) + @ColDefine(type = ColType.VARCHAR, width = 500) private String wtxt; @Column diff --git a/src/main/resources/views/mobile/question/answer.html b/src/main/resources/views/mobile/question/answer.html index c36941a..7a7fd12 100644 --- a/src/main/resources/views/mobile/question/answer.html +++ b/src/main/resources/views/mobile/question/answer.html @@ -250,7 +250,7 @@ layout("/mobile/platform.html"){ 提交
+ v-if="canAnswerAgain && finishAnswer && moment().format('YYYY-MM-DD') === currentDate"> 再答一次 @@ -572,14 +572,19 @@ layout("/mobile/platform.html"){ }, answerAgain() { - this.finishAnswer = false - setTimeout(() => { - this.questionData.issues.forEach(issue => { - issue.wors.forEach(wor => { - this.$refs['checkboxes' + wor.wid][0].toggle(false) + if(this.questionData.ctMode===3){ + location.reload() + }else{ + this.finishAnswer = false + setTimeout(() => { + this.questionData.issues.forEach(issue => { + issue.wors.forEach(wor => { + this.$refs['checkboxes' + wor.wid][0].toggle(false) + }) }) - }) - }, 0) + }, 0) + this.checkTimer() + } }, async getUserHasAnswerRandomNum() { @@ -608,19 +613,22 @@ layout("/mobile/platform.html"){ this.currentScore = resp.data }, checkTimer() { - if (this.timerInterval) { - clearInterval(this.timerInterval) - } - if (!this.finishAnswer) { - this.$dialog.alert({ - title: '提示', - message: '本次答题时间' + this.questionData.timerMinute + '分钟,请尽快完成!' - }).then(() => { - this.countDownSeconds = this.questionData.timerMinute * 60 - this.timerInterval = setInterval(() => { + if(this.questionData.enableTimer){ + if (this.timerInterval) { + clearInterval(this.timerInterval) + } + if (!this.finishAnswer) { + this.$dialog.alert({ + title: '提示', + message: '本次答题时间' + this.questionData.timerMinute + '分钟,请尽快完成!' + }).then(() => { + this.countDownSeconds = this.questionData.timerMinute * 60 this.updateCountdown() - }, 1000) - }); + this.timerInterval = setInterval(() => { + this.updateCountdown() + }, 1000) + }); + } } }, diff --git a/src/main/resources/views/platform/question/components/batchInsert.js b/src/main/resources/views/platform/question/components/batchInsert.js new file mode 100644 index 0000000..ec04e3f --- /dev/null +++ b/src/main/resources/views/platform/question/components/batchInsert.js @@ -0,0 +1,156 @@ +const batchInsert = { + template: ` + +
+

1、题目的识别基于标题前的题型说明,放在标题的前面,格式为“[题型]标题内容((描述))“
2、题干与选项,及各选项之间需回车换行

+ 清空文本 +
+ {{errorMsg}} +
+
+ +
+
+ +
+
+
+
+
{{index+1}}、
+
{{issue.iname}}
+
+
+ +
+ {{wor.wtxt}} +
+
+ + {{wor.wtxt}} + +
+
+
+
+ +
+ `, + data() { + return { + visible: false, + txt: null, + errorMsg: null + } + }, + computed: { + issues() { + if (!this.txt) { + return [] + } + let errorMsg = '' + + // 使用正则表达式分割文本为单独的问题 + // const questionTexts = this.txt.split('\n').map(line => line.trim()).join(); // 每个问题之间用换行符分隔 + const questionTexts = this.txt.split('\n').map(v => v.trim()).join('\n').split("\n\n") + // 初始化问题数组 + const questions = []; + // 遍历每个问题文本 + questionTexts.forEach((questionText, index) => { + // 提取问题编号和题干 + const match = questionText.trim().split('\n').slice(0, 1).join('').match(/^(?:\d+\.|\d+、)?\s*(.*?)\s*\[(.*题)\]\s*(?:\((\d+)分\)|\((\d+)分\))?$/); + if (match) { + const questionContent = match[1].trim(); + const questionType = match[2]; + const scoreChinese = match[3]; + const scoreEnglish = match[4]; + const score = scoreChinese || scoreEnglish; + + // 题型合法性校验 + const validTypes = ['多选题', '单选题']; + if (!validTypes.includes(questionType)) { + console.warn('问题' + (index + 1) + '的题型不合法: ' + questionType); + errorMsg += '\n问题' + (index + 1) + '的题型不合法: ' + questionType; + return; + } + + // 分数格式校验 + if (score) { + const scoreNumber = parseInt(score, 10); + if (isNaN(scoreNumber)) { + console.warn('问题' + (index + 1) + '的分数格式无效: ' + score); + errorMsg += '\n问题' + (index + 1) + '的分数格式无效: ' + score; + return; + } + } + + // 提取选项 + const optionTexts = questionText.replaceAll(match.input, "").split('\n').slice(1).filter(line => line.trim()); // 假设选项从第二行开始 + const options = []; + + optionTexts.forEach(optionText => { + // 使用正则表达式提取选项名称和是否正确 + const optionMatch = optionText.match(/^([A-Z])\.?(.+?)\((正确答案|错误答案)\)/); + if (optionMatch) { + const optionName = optionMatch[1] + optionMatch[2].trim(); + const isCorrect = optionMatch[3] === '正确答案'; + options.push({wtxt: optionName, correct: isCorrect}); + } else { + options.push({wtxt: optionText.trim(), correct: false}); + } + }); + + // 构建问题对象 + const question = { + //是否必答 + iisbd: true, + //单选还是多选 + iisdx: questionType === '单选题', + //是否随机选项??? + iisrandom: false, + //题干 + iname: questionContent, + //排列方式 没用 + iplfs: 1, + //提示 + its: null, + //题型 (1 选择题 2 填空题 3 判断题) + itx: (questionType === '单选题' || questionType === '多选题') ? 1 : 3, + //分数 + fraction: score, + //选项 + wors: options + }; + // 添加到问题数组中 + questions.push(question); + } + }); + this.errorMsg = errorMsg + console.log(questions) + return questions + } + }, + methods: { + onOpen() { + debugger + this.txt = null + this.visible = true + }, + async confirm() { + if (this.errorMsg) { + this.$message.warning('存在不合法的题目,请调整后再提交') + return + } + this.$emit('confirm', this.issues) + this.visible = false + }, + } +} diff --git a/src/main/resources/views/platform/question/question.html b/src/main/resources/views/platform/question/question.html index 5d7fcd4..0b478b9 100644 --- a/src/main/resources/views/platform/question/question.html +++ b/src/main/resources/views/platform/question/question.html @@ -302,7 +302,7 @@ layout("/layouts/platform.html"){ - + @@ -323,6 +323,7 @@ layout("/layouts/platform.html"){ + @@ -457,7 +458,8 @@ layout("/layouts/platform.html"){ - + 是 否 @@ -471,7 +473,6 @@ layout("/layouts/platform.html"){ - @@ -622,8 +623,9 @@ layout("/layouts/platform.html"){ + 批量添加 添加题目 @@ -1066,8 +1068,12 @@ layout("/layouts/platform.html"){ + +