diff --git a/src/main/java/com/baobaot/exam/Controller/AdminController.java b/src/main/java/com/baobaot/exam/Controller/AdminController.java index 3602261..0508266 100644 --- a/src/main/java/com/baobaot/exam/Controller/AdminController.java +++ b/src/main/java/com/baobaot/exam/Controller/AdminController.java @@ -50,19 +50,20 @@ public class AdminController { return ResponseEntity.ok(result); } - // API: 获取题目列表(支持全部、按类型、按分值、按标题模糊查询、联合查询) + // API: 获取题目列表(支持全部、按类型、按分值、按标题模糊查询、联合查询、按难度查询) @GetMapping("/admin/api/questions") @ResponseBody public ResponseEntity> getQuestions( @RequestParam(required = false) Integer type, @RequestParam(required = false) Integer score, + @RequestParam(required = false) Integer level, @RequestParam(required = false) String title) { Map result = new HashMap<>(); List questions; - if (type != null || title != null) { - // 联合查询:按类型和/或标题 - questions = adminService.getQuestionsByTypeAndTitle(type, title); + if (type != null || level != null || title != null) { + // 联合查询:按类型、难度和/或标题 + questions = adminService.getQuestionsByConditions(type, level, title); } else if (score != null) { questions = adminService.getQuestionsByScore(score); } else { @@ -83,10 +84,11 @@ public class AdminController { @RequestParam(required = false) String answer_c, @RequestParam(required = false) String answer_d, @RequestParam String r_answer, + @RequestParam Integer level, @RequestParam Integer score) { Map result = new HashMap<>(); try { - adminService.addChoiceQuestion(title, type, answer_a, answer_b, answer_c, answer_d, r_answer, score); + adminService.addChoiceQuestion(title, type, answer_a, answer_b, answer_c, answer_d, r_answer, level, score); result.put("success", true); result.put("message", "添加成功"); } catch (Exception e) { @@ -100,12 +102,12 @@ public class AdminController { @ResponseBody public ResponseEntity> addEssayQuestion(@RequestParam String title, @RequestParam Integer type, - @RequestParam(required = false) String answer, @RequestParam(required = false) String r_answer, + @RequestParam Integer level, @RequestParam Integer score) { Map result = new HashMap<>(); try { - adminService.addEssayQuestion(title, type, answer, r_answer, score); + adminService.addEssayQuestion(title, type, r_answer, level, score); result.put("success", true); result.put("message", "添加成功"); } catch (Exception e) { @@ -137,8 +139,9 @@ public class AdminController { @PostMapping("/admin/mkexam/create") @ResponseBody - public examPaper createExam(@RequestParam(required = false) String title) { - return makeExamService.createExamPaper(title); + public examPaper createExam(@RequestParam(required = false) String title, + @RequestParam(required = false, defaultValue = "1") Integer level) { + return makeExamService.createExamPaper(title, level); } @GetMapping("/admin/mkexam/detail/{uid}") @@ -191,6 +194,7 @@ public class AdminController { @RequestParam(required = false) String answerC, @RequestParam(required = false) String answerD, @RequestParam(required = false) String rAnswer, + @RequestParam Integer level, @RequestParam Integer score) { Map result = new HashMap<>(); try { @@ -205,6 +209,7 @@ public class AdminController { .id(id) .type(type) .title(title) + .level(level) .score(score) .rAnswer(rAnswer); diff --git a/src/main/java/com/baobaot/exam/Service/adminService.java b/src/main/java/com/baobaot/exam/Service/adminService.java index fd95011..9c6a83d 100644 --- a/src/main/java/com/baobaot/exam/Service/adminService.java +++ b/src/main/java/com/baobaot/exam/Service/adminService.java @@ -12,12 +12,12 @@ public interface adminService extends IService { * 添加选择题(type=1) */ boolean addChoiceQuestion(String title, Integer type, String answer_a, String answer_b, - String answer_c, String answer_d, String r_answer, Integer score); + String answer_c, String answer_d, String r_answer, Integer level, Integer score); /** * 添加简答题(type=2) */ - boolean addEssayQuestion(String title, Integer type, String answer, String r_answer, Integer score); + boolean addEssayQuestion(String title, Integer type, String r_answer, Integer level, Integer score); /** * 根据类型查询所有题目 @@ -32,6 +32,15 @@ public interface adminService extends IService { */ List getQuestionsByTypeAndTitle(Integer type, String title); + /** + * 根据条件查询题目(类型、难度、标题联合查询) + * @param type 题目类型,可为null + * @param level 题目难度,可为null + * @param title 标题关键词,可为null,支持模糊匹配 + * @return 符合条件的题目列表 + */ + List getQuestionsByConditions(Integer type, Integer level, String title); + /** * 根据分数查询所有题目 */ diff --git a/src/main/java/com/baobaot/exam/Service/impl/adminServiceImpl.java b/src/main/java/com/baobaot/exam/Service/impl/adminServiceImpl.java index f8dfae5..8a0a0a3 100644 --- a/src/main/java/com/baobaot/exam/Service/impl/adminServiceImpl.java +++ b/src/main/java/com/baobaot/exam/Service/impl/adminServiceImpl.java @@ -16,7 +16,7 @@ public class adminServiceImpl extends ServiceImpl impl @Override public boolean addChoiceQuestion(String title, Integer type, String answer_a, String answer_b, - String answer_c, String answer_d, String r_answer, Integer score) { + String answer_c, String answer_d, String r_answer, Integer level, Integer score) { question q = question.builder() .title(title) .type(type) @@ -25,17 +25,19 @@ public class adminServiceImpl extends ServiceImpl impl .answerC(answer_c) .answerD(answer_d) .rAnswer(r_answer) + .level(level) .score(score) .build(); return save(q); } @Override - public boolean addEssayQuestion(String title, Integer type, String answer, String r_answer, Integer score) { + public boolean addEssayQuestion(String title, Integer type, String r_answer, Integer level, Integer score) { question q = question.builder() .title(title) .type(type) .rAnswer(r_answer) + .level(level) .score(score) .build(); return save(q); @@ -62,6 +64,23 @@ public class adminServiceImpl extends ServiceImpl impl return list(wrapper); } + @Override + public List getQuestionsByConditions(Integer type, Integer level, String title) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + if (type != null) { + wrapper.eq(question::getType, type); + } + if (level != null) { + wrapper.eq(question::getLevel, level); + } + if (title != null && !title.trim().isEmpty()) { + wrapper.like(question::getTitle, title.trim()); + } + + return list(wrapper); + } + @Override public List getQuestionsByScore(Integer score) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -95,10 +114,12 @@ public class adminServiceImpl extends ServiceImpl impl String title = (String) qData.get("title"); Integer type = ((Number) qData.get("type")).intValue(); Integer score = ((Number) qData.get("score")).intValue(); + Integer level = qData.get("level") != null ? ((Number) qData.get("level")).intValue() : 1; question.questionBuilder builder = question.builder() .title(title) .type(type) + .level(level) .score(score); if (type == 1) { diff --git a/src/main/java/com/baobaot/exam/Service/impl/makeExamServiceImpl.java b/src/main/java/com/baobaot/exam/Service/impl/makeExamServiceImpl.java index 5784cbe..e998ef1 100644 --- a/src/main/java/com/baobaot/exam/Service/impl/makeExamServiceImpl.java +++ b/src/main/java/com/baobaot/exam/Service/impl/makeExamServiceImpl.java @@ -30,12 +30,20 @@ public class makeExamServiceImpl extends ServiceImpl @Override public examPaper createExamPaper(String title) { + return createExamPaper(title, 1); + } + + @Override + public examPaper createExamPaper(String title, Integer level) { // 生成唯一UID String uid = UidGenerator.generateUniqueUid(this::isUidExists); - // 获取所有题目 - List allChoiceQuestions = getQuestionsByType(1); - List allEssayQuestions = getQuestionsByType(2); + // 根据难度获取题目 + // level=1: 只选level=1的题目 + // level=2: 选level=1或2的题目 + // level=3: 选level=1、2、3的题目 + List allChoiceQuestions = getQuestionsByTypeAndLevel(1, level); + List allEssayQuestions = getQuestionsByTypeAndLevel(2, level); if (allChoiceQuestions.size() < 5 || allEssayQuestions.size() < 5) { throw new RuntimeException("题库题目不足(至少需要5道选择题和5道简答题)"); @@ -75,6 +83,7 @@ public class makeExamServiceImpl extends ServiceImpl examPaper paper = examPaper.builder() .uid(uid) .title(title) + .level(level) .select(selectIds) .content(contentIds) .build(); @@ -103,6 +112,16 @@ public class makeExamServiceImpl extends ServiceImpl return questionMapper.selectList(wrapper); } + private List getQuestionsByTypeAndLevel(Integer type, Integer level) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(question::getType, type); + // level=1: 只选level<=1的题目 + // level=2: 选level<=2的题目 + // level=3: 选level<=3的题目 + wrapper.le(question::getLevel, level); + return questionMapper.selectList(wrapper); + } + /** * 寻找精确100分的组合 */ @@ -289,6 +308,7 @@ public class makeExamServiceImpl extends ServiceImpl result.put("uid", paper.getUid()); result.put("title", paper.getTitle()); + result.put("level", paper.getLevel()); // 解析选择题ID列表 List choiceIds = parseIdList(paper.getSelect()); diff --git a/src/main/java/com/baobaot/exam/Service/makeExamService.java b/src/main/java/com/baobaot/exam/Service/makeExamService.java index 3417896..5c4c810 100644 --- a/src/main/java/com/baobaot/exam/Service/makeExamService.java +++ b/src/main/java/com/baobaot/exam/Service/makeExamService.java @@ -11,6 +11,13 @@ public interface makeExamService { /** * 创建试卷 * 自动生成uid,按7:3比例选择题和简答题,总分100分 + * @param title 试卷标题 + * @param level 试卷难度(1=低级只选1级题,2=中级选1-2级题,3=高级选1-3级题) + */ + examPaper createExamPaper(String title, Integer level); + + /** + * 创建试卷(默认难度1) */ examPaper createExamPaper(String title); diff --git a/src/main/java/com/baobaot/exam/dao/examPaper.java b/src/main/java/com/baobaot/exam/dao/examPaper.java index ddee5d4..0e525c6 100644 --- a/src/main/java/com/baobaot/exam/dao/examPaper.java +++ b/src/main/java/com/baobaot/exam/dao/examPaper.java @@ -15,6 +15,7 @@ public class examPaper { private Integer id; private String uid; private String title; + private Integer level; @TableField("`select`") private String select; diff --git a/src/main/java/com/baobaot/exam/dao/question.java b/src/main/java/com/baobaot/exam/dao/question.java index 86cf521..c93067f 100644 --- a/src/main/java/com/baobaot/exam/dao/question.java +++ b/src/main/java/com/baobaot/exam/dao/question.java @@ -15,6 +15,7 @@ public class question { private Integer id; private String title; private Integer type; + private Integer level; private String answerA; private String answerB; private String answerC; diff --git a/src/main/resources/templates/admin.html b/src/main/resources/templates/admin.html index 5c2968c..0e157e3 100644 --- a/src/main/resources/templates/admin.html +++ b/src/main/resources/templates/admin.html @@ -146,6 +146,18 @@ background: #fef9c3; color: #a16207; } + .tag-level-1 { + background: #dcfce7; + color: #15803d; + } + .tag-level-2 { + background: #dbeafe; + color: #1d4ed8; + } + .tag-level-3 { + background: #fce7f3; + color: #be185d; + } .score-badge { background: #f59e0b; color: white; @@ -247,9 +259,19 @@ -
- - +
+
+ + +
+
+ + +
@@ -267,9 +289,19 @@
-
- - +
+
+ + +
+
+ + +
@@ -290,6 +322,15 @@
+
+ + +
@@ -403,6 +444,7 @@ document.getElementById('queryScoreTag').style.display = 'none'; document.getElementById('queryTitleTag').style.display = 'none'; document.getElementById('queryType').value = ''; + document.getElementById('queryLevel').value = ''; document.getElementById('queryTitle').value = ''; fetchQuestions('/admin/api/questions'); } @@ -410,10 +452,11 @@ // 联合查询:按类型和/或标题 function queryQuestions() { const type = document.getElementById('queryType').value; + const level = document.getElementById('queryLevel').value; const title = document.getElementById('queryTitle').value.trim(); - // 如果类型和标题都为空,查询全部 - if (!type && !title) { + // 如果类型、难度和标题都为空,查询全部 + if (!type && !level && !title) { loadAllQuestions(); return; } @@ -440,6 +483,7 @@ let url = '/admin/api/questions?'; const params = []; if (type) params.push('type=' + encodeURIComponent(type)); + if (level) params.push('level=' + encodeURIComponent(level)); if (title) params.push('title=' + encodeURIComponent(title)); url += params.join('&'); @@ -502,7 +546,8 @@ ID 题目 - 类型 + 类型 + 难度 正确答案 分值 操作 @@ -516,6 +561,10 @@ '选择题' : '简答题'; + const levelMap = {1: '低级', 2: '中级', 3: '高级'}; + const levelClassMap = {1: 'tag-level-1', 2: 'tag-level-2', 3: 'tag-level-3'}; + const levelTag = `${levelMap[q.level] || '低级'}`; + let optionsHtml = ''; if (q.type == 1) { const parts = []; @@ -537,6 +586,7 @@ ${q.id} ${escapeHtml(q.title)} ${typeTag} + ${levelTag} ${optionsHtml} ${rAnswerHtml} ${q.score} @@ -689,6 +739,11 @@ resultDiv.style.display = 'block'; return; } + if (q.level && (q.level < 1 || q.level > 3)) { + resultDiv.innerHTML = '
第 ' + (i + 1) + ' 题难度错误,level必须是1(低级)、2(中级)或3(高级)
'; + resultDiv.style.display = 'block'; + return; + } if (!q.score || q.score < 0) { resultDiv.innerHTML = '
第 ' + (i + 1) + ' 题分值错误
'; resultDiv.style.display = 'block'; @@ -753,6 +808,7 @@ document.getElementById('editType').value = q.type; document.getElementById('editTitle').value = q.title || ''; document.getElementById('editScore').value = q.score || ''; + document.getElementById('editLevel').value = q.level || 1; if (q.type == 1) { // 选择题表单 @@ -791,6 +847,7 @@ formData.append('type', currentEditType); formData.append('title', document.getElementById('editTitle').value); formData.append('score', document.getElementById('editScore').value); + formData.append('level', document.getElementById('editLevel').value); if (currentEditType == 1) { formData.append('answerA', document.getElementById('editAnswerA').value); @@ -831,11 +888,16 @@ const title = formData.get('title'); const score = formData.get('score'); const rAnswer = formData.get('rAnswer'); + const level = formData.get('level') || 1; const typeTag = type == 1 ? '选择题' : '简答题'; + const levelMap = {1: '低级', 2: '中级', 3: '高级'}; + const levelClassMap = {1: 'tag-level-1', 2: 'tag-level-2', 3: 'tag-level-3'}; + const levelTag = `${levelMap[level] || '低级'}`; + let optionsHtml = ''; if (type == 1) { const answerA = formData.get('answerA'); @@ -861,6 +923,7 @@ ${id} ${escapeHtml(title)} ${typeTag} + ${levelTag} ${optionsHtml} ${rAnswerHtml} ${score} @@ -885,7 +948,7 @@
- 格式说明:JSON数组格式,每道题包含 title(必填), type(1=选择题,2=简答题), score(分值) 等字段 + 格式说明:JSON数组格式,每道题包含 title(必填), type(1=选择题,2=简答题), level(1=低级,2=中级,3=高级), score(分值) 等字段
@@ -894,6 +957,7 @@ { "title": "选择题示例", "type": 1, + "level": 1, "answerA": "选项A", "answerB": "选项B", "answerC": "选项C", @@ -904,6 +968,7 @@ { "title": "简答题示例", "type": 2, + "level": 2, "rAnswer": "参考答案", "score": 10 } @@ -979,9 +1044,19 @@
-
- - +
+
+ + +
+
+ + +