一些修改
This commit is contained in:
@@ -5,10 +5,12 @@ import com.baobaot.exam.Service.makeExamService;
|
||||
import com.baobaot.exam.dao.examPaper;
|
||||
import com.baobaot.exam.dao.question;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -28,13 +30,34 @@ public class AdminController {
|
||||
|
||||
@GetMapping("/admin/exam")
|
||||
public String adminPage(Model model) {
|
||||
List<question> questions = adminService.list();
|
||||
model.addAttribute("questions", questions);
|
||||
return "admin";
|
||||
}
|
||||
|
||||
// API: 获取题目列表(支持全部、按类型、按分值)
|
||||
@GetMapping("/admin/api/questions")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> getQuestions(
|
||||
@RequestParam(required = false) Integer type,
|
||||
@RequestParam(required = false) Integer score) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
List<question> questions;
|
||||
|
||||
if (type != null) {
|
||||
questions = adminService.getQuestionsByType(type);
|
||||
} else if (score != null) {
|
||||
questions = adminService.getQuestionsByScore(score);
|
||||
} else {
|
||||
questions = adminService.list();
|
||||
}
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", questions);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@PostMapping("/admin/add/choice")
|
||||
public String addChoiceQuestion(@RequestParam String title,
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> addChoiceQuestion(@RequestParam String title,
|
||||
@RequestParam Integer type,
|
||||
@RequestParam(required = false) String answer_a,
|
||||
@RequestParam(required = false) String answer_b,
|
||||
@@ -42,40 +65,50 @@ public class AdminController {
|
||||
@RequestParam(required = false) String answer_d,
|
||||
@RequestParam String r_answer,
|
||||
@RequestParam Integer score) {
|
||||
adminService.addChoiceQuestion(title, type, answer_a, answer_b, answer_c, answer_d, r_answer, score);
|
||||
return "redirect:/admin/exam";
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
adminService.addChoiceQuestion(title, type, answer_a, answer_b, answer_c, answer_d, r_answer, score);
|
||||
result.put("success", true);
|
||||
result.put("message", "添加成功");
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("message", e.getMessage());
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@PostMapping("/admin/add/essay")
|
||||
public String addEssayQuestion(@RequestParam String title,
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> addEssayQuestion(@RequestParam String title,
|
||||
@RequestParam Integer type,
|
||||
@RequestParam(required = false) String answer,
|
||||
@RequestParam(required = false) String r_answer,
|
||||
@RequestParam Integer score) {
|
||||
adminService.addEssayQuestion(title, type, answer, r_answer, score);
|
||||
return "redirect:/admin/exam";
|
||||
}
|
||||
|
||||
@GetMapping("/admin/query/type")
|
||||
public String queryByType(@RequestParam Integer type, Model model) {
|
||||
List<question> questions = adminService.getQuestionsByType(type);
|
||||
model.addAttribute("questions", questions);
|
||||
model.addAttribute("queryType", "类型: " + type);
|
||||
return "admin";
|
||||
}
|
||||
|
||||
@GetMapping("/admin/query/score")
|
||||
public String queryByScore(@RequestParam Integer score, Model model) {
|
||||
List<question> questions = adminService.getQuestionsByScore(score);
|
||||
model.addAttribute("questions", questions);
|
||||
model.addAttribute("queryScore", "分数: " + score);
|
||||
return "admin";
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
adminService.addEssayQuestion(title, type, answer, r_answer, score);
|
||||
result.put("success", true);
|
||||
result.put("message", "添加成功");
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("message", e.getMessage());
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@PostMapping("/admin/delete")
|
||||
public String deleteByTitle(@RequestParam String title) {
|
||||
adminService.deleteQuestionByTitle(title);
|
||||
return "redirect:/admin/exam";
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> deleteByTitle(@RequestParam String title) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
adminService.deleteQuestionByTitle(title);
|
||||
result.put("success", true);
|
||||
result.put("message", "删除成功");
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("message", e.getMessage());
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@GetMapping("/admin/mkexam")
|
||||
@@ -96,10 +129,85 @@ public class AdminController {
|
||||
}
|
||||
|
||||
@GetMapping("/admin/listexam")
|
||||
public String listExamPage(@RequestParam(required = false) String title, Model model) {
|
||||
List<examPaper> examPapers = makeExamService.getExamList(title);
|
||||
model.addAttribute("examPapers", examPapers);
|
||||
model.addAttribute("searchTitle", title);
|
||||
public String listExamPage() {
|
||||
return "listexam";
|
||||
}
|
||||
|
||||
// API: 获取试卷列表
|
||||
@GetMapping("/admin/api/exams")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> getExams(@RequestParam(required = false) String title) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
List<examPaper> examPapers = makeExamService.getExamList(title);
|
||||
result.put("success", true);
|
||||
result.put("data", examPapers);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
// API: 根据ID获取题目详情
|
||||
@GetMapping("/admin/api/question/{id}")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> getQuestionById(@PathVariable Integer id) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
question q = adminService.getQuestionById(id);
|
||||
if (q != null) {
|
||||
result.put("success", true);
|
||||
result.put("data", q);
|
||||
} else {
|
||||
result.put("success", false);
|
||||
result.put("message", "题目不存在");
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
// API: 更新题目
|
||||
@PostMapping("/admin/api/question/update")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> updateQuestion(
|
||||
@RequestParam Integer id,
|
||||
@RequestParam Integer type,
|
||||
@RequestParam String title,
|
||||
@RequestParam(required = false) String answerA,
|
||||
@RequestParam(required = false) String answerB,
|
||||
@RequestParam(required = false) String answerC,
|
||||
@RequestParam(required = false) String answerD,
|
||||
@RequestParam(required = false) String answer,
|
||||
@RequestParam(required = false) String rAnswer,
|
||||
@RequestParam Integer score) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
question existing = adminService.getQuestionById(id);
|
||||
if (existing == null) {
|
||||
result.put("success", false);
|
||||
result.put("message", "题目不存在");
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
question.questionBuilder builder = question.builder()
|
||||
.id(id)
|
||||
.type(type)
|
||||
.title(title)
|
||||
.score(score)
|
||||
.rAnswer(rAnswer);
|
||||
|
||||
if (type == 1) {
|
||||
// 选择题
|
||||
builder.answerA(answerA)
|
||||
.answerB(answerB)
|
||||
.answerC(answerC)
|
||||
.answerD(answerD);
|
||||
} else {
|
||||
// 简答题
|
||||
builder.answer(answer);
|
||||
}
|
||||
|
||||
adminService.updateQuestion(builder.build());
|
||||
result.put("success", true);
|
||||
result.put("message", "修改成功");
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("message", e.getMessage());
|
||||
}
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,14 @@ public interface adminService extends IService<question> {
|
||||
* 根据标题删除题目
|
||||
*/
|
||||
boolean deleteQuestionByTitle(String title);
|
||||
|
||||
/**
|
||||
* 根据ID查询题目
|
||||
*/
|
||||
question getQuestionById(Integer id);
|
||||
|
||||
/**
|
||||
* 更新题目
|
||||
*/
|
||||
boolean updateQuestion(question q);
|
||||
}
|
||||
|
||||
@@ -126,6 +126,10 @@ public class CorrectServiceImpl implements CorrectService {
|
||||
.autoCorrect(true)
|
||||
.autoScore(score)
|
||||
.isCorrect(isCorrect)
|
||||
.answerA(q.getAnswerA())
|
||||
.answerB(q.getAnswerB())
|
||||
.answerC(q.getAnswerC())
|
||||
.answerD(q.getAnswerD())
|
||||
.build();
|
||||
detailItems.add(item);
|
||||
}
|
||||
|
||||
@@ -60,4 +60,14 @@ public class adminServiceImpl extends ServiceImpl<questionMapper, question> impl
|
||||
wrapper.eq(question::getTitle, title);
|
||||
return remove(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public question getQuestionById(Integer id) {
|
||||
return getById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateQuestion(question q) {
|
||||
return updateById(q);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,24 @@ public class CorrectDetailItem {
|
||||
* 是否正确(选择题)
|
||||
*/
|
||||
private Boolean isCorrect;
|
||||
|
||||
/**
|
||||
* 选项A(选择题)
|
||||
*/
|
||||
private String answerA;
|
||||
|
||||
/**
|
||||
* 选项B(选择题)
|
||||
*/
|
||||
private String answerB;
|
||||
|
||||
/**
|
||||
* 选项C(选择题)
|
||||
*/
|
||||
private String answerC;
|
||||
|
||||
/**
|
||||
* 选项D(选择题)
|
||||
*/
|
||||
private String answerD;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ spring:
|
||||
application:
|
||||
name: exam
|
||||
datasource:
|
||||
url: jdbc:mysql://localhost:3306/exam
|
||||
# url: jdbc:mysql://192.168.1.56:3306/exam?useSSL=true&requireSSL=true&serverTimezone=UTC
|
||||
# url: jdbc:mysql://localhost:3306/exam
|
||||
url: jdbc:mysql://192.168.1.56:3306/exam?useSSL=true&requireSSL=true&serverTimezone=UTC
|
||||
username: root
|
||||
password: 521707
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
@@ -207,39 +207,39 @@
|
||||
<div class="card">
|
||||
<h2>添加题目</h2>
|
||||
<div class="tabs">
|
||||
<button class="tab-btn active" onclick="switchTab('choice')">选择题 (Type 1)</button>
|
||||
<button class="tab-btn" onclick="switchTab('essay')">简答题 (Type 2)</button>
|
||||
<button class="tab-btn active" onclick="switchTab('choice')">选择题</button>
|
||||
<button class="tab-btn" onclick="switchTab('essay')">简答题</button>
|
||||
</div>
|
||||
|
||||
<!-- 选择题表单 -->
|
||||
<div id="choice-tab" class="tab-content active">
|
||||
<form th:action="@{/admin/add/choice}" method="post">
|
||||
<form id="choiceForm">
|
||||
<input type="hidden" name="type" value="1">
|
||||
<div class="form-group">
|
||||
<label>题目</label>
|
||||
<textarea name="title" placeholder="请输入题目内容" required></textarea>
|
||||
<textarea name="title" id="choiceTitle" placeholder="请输入题目内容" required></textarea>
|
||||
</div>
|
||||
<div class="grid-2">
|
||||
<div class="form-group">
|
||||
<label>选项 A</label>
|
||||
<input type="text" name="answer_a" placeholder="选填">
|
||||
<input type="text" name="answer_a" id="choiceA" placeholder="选填">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>选项 B</label>
|
||||
<input type="text" name="answer_b" placeholder="选填">
|
||||
<input type="text" name="answer_b" id="choiceB" placeholder="选填">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>选项 C</label>
|
||||
<input type="text" name="answer_c" placeholder="选填">
|
||||
<input type="text" name="answer_c" id="choiceC" placeholder="选填">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>选项 D</label>
|
||||
<input type="text" name="answer_d" placeholder="选填">
|
||||
<input type="text" name="answer_d" id="choiceD" placeholder="选填">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>正确答案<span class="required">*</span></label>
|
||||
<select name="r_answer" required>
|
||||
<select name="r_answer" id="choiceRAnswer" required>
|
||||
<option value="">请选择正确答案</option>
|
||||
<option value="A">A</option>
|
||||
<option value="B">B</option>
|
||||
@@ -249,7 +249,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>分值</label>
|
||||
<input type="number" name="score" placeholder="请输入分值" required min="0">
|
||||
<input type="number" name="score" id="choiceScore" placeholder="请输入分值" required min="0">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">添加选择题</button>
|
||||
</form>
|
||||
@@ -257,23 +257,19 @@
|
||||
|
||||
<!-- 简答题表单 -->
|
||||
<div id="essay-tab" class="tab-content">
|
||||
<form th:action="@{/admin/add/essay}" method="post">
|
||||
<form id="essayForm">
|
||||
<input type="hidden" name="type" value="2">
|
||||
<div class="form-group">
|
||||
<label>题目</label>
|
||||
<textarea name="title" placeholder="请输入题目内容" required></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>学生答案参考</label>
|
||||
<textarea name="answer" placeholder="选填"></textarea>
|
||||
<textarea name="title" id="essayTitle" placeholder="请输入题目内容" required></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>参考答案</label>
|
||||
<textarea name="r_answer" placeholder="选填"></textarea>
|
||||
<textarea name="r_answer" id="essayRAnswer" placeholder="选填"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>分值</label>
|
||||
<input type="number" name="score" placeholder="请输入分值" required min="0">
|
||||
<input type="number" name="score" id="essayScore" placeholder="请输入分值" required min="0">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">添加简答题</button>
|
||||
</form>
|
||||
@@ -285,29 +281,29 @@
|
||||
<h2>查询题目</h2>
|
||||
<div class="grid-2">
|
||||
<div>
|
||||
<form th:action="@{/admin/query/type}" method="get" class="query-section">
|
||||
<div class="query-section">
|
||||
<div class="form-group">
|
||||
<label>按类型查询</label>
|
||||
<select name="type" required>
|
||||
<select id="queryType" required>
|
||||
<option value="1">选择题</option>
|
||||
<option value="2">简答题</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">查询</button>
|
||||
</form>
|
||||
<button type="button" class="btn btn-success" onclick="queryByType()">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<form th:action="@{/admin/query/score}" method="get" class="query-section">
|
||||
<div class="query-section">
|
||||
<div class="form-group">
|
||||
<label>按分值查询</label>
|
||||
<input type="number" name="score" placeholder="请输入分值" required min="0">
|
||||
<input type="number" id="queryScore" placeholder="请输入分值" required min="0">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">查询</button>
|
||||
</form>
|
||||
<button type="button" class="btn btn-success" onclick="queryByScore()">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 16px; display: flex; gap: 12px;">
|
||||
<a th:href="@{/admin/exam}" class="btn btn-primary">显示全部</a>
|
||||
<button type="button" class="btn btn-primary" onclick="loadAllQuestions()">显示全部</button>
|
||||
<a th:href="@{/admin/mkexam}" class="btn btn-success">创建试卷</a>
|
||||
<a th:href="@{/admin/listexam}" class="btn btn-success">查看试卷</a>
|
||||
<a th:href="@{/admin/correct}" class="btn btn-success" style="background: #f59e0b;">批改试卷</a>
|
||||
@@ -318,64 +314,29 @@
|
||||
<div class="card">
|
||||
<h2>
|
||||
题目列表
|
||||
<span th:if="${queryType != null}" class="tag tag-choice" th:text="${queryType}" style="margin-left: 10px;"></span>
|
||||
<span th:if="${queryScore != null}" class="tag tag-essay" th:text="${queryScore}" style="margin-left: 10px;"></span>
|
||||
<span id="queryTypeTag" class="tag tag-choice" style="margin-left: 10px; display: none;"></span>
|
||||
<span id="queryScoreTag" class="tag tag-essay" style="margin-left: 10px; display: none;"></span>
|
||||
<span id="questionCount" class="tag" style="margin-left: 10px; background: #e3f2fd; color: #1976d2; display: none;">共 0 题</span>
|
||||
</h2>
|
||||
|
||||
<div th:if="${#lists.isEmpty(questions)}" class="empty-state">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<p>暂无题目数据</p>
|
||||
<div id="questionsContainer">
|
||||
<div class="empty-state">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<p>加载中...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table th:if="${!#lists.isEmpty(questions)}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>题目</th>
|
||||
<th>类型</th>
|
||||
<th>选项/学生答案</th>
|
||||
<th>正确答案</th>
|
||||
<th>分值</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="q : ${questions}">
|
||||
<td th:text="${q.id}"></td>
|
||||
<td th:text="${q.title}" style="max-width: 300px; word-wrap: break-word;"></td>
|
||||
<td>
|
||||
<span th:if="${q.type == 1}" class="tag tag-choice">选择题</span>
|
||||
<span th:if="${q.type == 2}" class="tag tag-essay">简答题</span>
|
||||
</td>
|
||||
<td>
|
||||
<div th:if="${q.type == 1}">
|
||||
<span th:if="${q.answerA != null and q.answerA != ''}" th:text="'A: ' + ${q.answerA}"></span><br th:if="${q.answerA != null and q.answerA != ''}">
|
||||
<span th:if="${q.answerB != null and q.answerB != ''}" th:text="'B: ' + ${q.answerB}"></span><br th:if="${q.answerB != null and q.answerB != ''}">
|
||||
<span th:if="${q.answerC != null and q.answerC != ''}" th:text="'C: ' + ${q.answerC}"></span><br th:if="${q.answerC != null and q.answerC != ''}">
|
||||
<span th:if="${q.answerD != null and q.answerD != ''}" th:text="'D: ' + ${q.answerD}"></span>
|
||||
</div>
|
||||
<div th:if="${q.type == 2}" th:text="${q.answer != null ? q.answer : '无答案'}"></div>
|
||||
</td>
|
||||
<td>
|
||||
<span th:if="${q.rAnswer != null and q.rAnswer != ''}" class="tag tag-answer" th:text="${q.rAnswer}"></span>
|
||||
<span th:if="${q.rAnswer == null or q.rAnswer == ''}" style="color: #999;">-</span>
|
||||
</td>
|
||||
<td><span class="score-badge" th:text="${q.score}"></span></td>
|
||||
<td>
|
||||
<form th:action="@{/admin/delete}" method="post" style="display: inline;">
|
||||
<input type="hidden" name="title" th:value="${q.title}">
|
||||
<button type="submit" class="btn btn-danger" onclick="return confirm('确定要删除这道题吗?')">删除</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 页面加载时加载全部题目
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadAllQuestions();
|
||||
});
|
||||
|
||||
// 切换标签页
|
||||
function switchTab(type) {
|
||||
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
|
||||
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
|
||||
@@ -383,6 +344,496 @@
|
||||
event.target.classList.add('active');
|
||||
document.getElementById(type + '-tab').classList.add('active');
|
||||
}
|
||||
|
||||
// 添加选择题
|
||||
document.getElementById('choiceForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(this);
|
||||
|
||||
fetch('/admin/add/choice', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showAlert('选择题添加成功!', 'success');
|
||||
this.reset();
|
||||
loadAllQuestions();
|
||||
} else {
|
||||
showAlert(data.message || '添加失败', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showAlert('添加失败,请检查网络', 'error');
|
||||
});
|
||||
});
|
||||
|
||||
// 添加简答题
|
||||
document.getElementById('essayForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(this);
|
||||
|
||||
fetch('/admin/add/essay', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showAlert('简答题添加成功!', 'success');
|
||||
this.reset();
|
||||
loadAllQuestions();
|
||||
} else {
|
||||
showAlert(data.message || '添加失败', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showAlert('添加失败,请检查网络', 'error');
|
||||
});
|
||||
});
|
||||
|
||||
// 加载全部题目
|
||||
function loadAllQuestions() {
|
||||
document.getElementById('queryTypeTag').style.display = 'none';
|
||||
document.getElementById('queryScoreTag').style.display = 'none';
|
||||
fetchQuestions('/admin/api/questions');
|
||||
}
|
||||
|
||||
// 按类型查询
|
||||
function queryByType() {
|
||||
const type = document.getElementById('queryType').value;
|
||||
const typeTag = document.getElementById('queryTypeTag');
|
||||
typeTag.textContent = type === '1' ? '选择题' : '简答题';
|
||||
typeTag.style.display = 'inline';
|
||||
document.getElementById('queryScoreTag').style.display = 'none';
|
||||
fetchQuestions('/admin/api/questions?type=' + type);
|
||||
}
|
||||
|
||||
// 按分值查询
|
||||
function queryByScore() {
|
||||
const score = document.getElementById('queryScore').value;
|
||||
if (!score && score !== '0') {
|
||||
showAlert('请输入分值', 'error');
|
||||
return;
|
||||
}
|
||||
const scoreTag = document.getElementById('queryScoreTag');
|
||||
scoreTag.textContent = score + '分';
|
||||
scoreTag.style.display = 'inline';
|
||||
document.getElementById('queryTypeTag').style.display = 'none';
|
||||
fetchQuestions('/admin/api/questions?score=' + score);
|
||||
}
|
||||
|
||||
// 获取题目列表
|
||||
function fetchQuestions(url) {
|
||||
const container = document.getElementById('questionsContainer');
|
||||
container.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<p>加载中...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
fetch(url)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
renderQuestions(data.data);
|
||||
} else {
|
||||
showAlert(data.message || '加载失败', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showAlert('加载失败,请检查网络', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染题目列表
|
||||
function renderQuestions(questions) {
|
||||
const container = document.getElementById('questionsContainer');
|
||||
const countTag = document.getElementById('questionCount');
|
||||
|
||||
// 更新计数显示
|
||||
if (countTag) {
|
||||
countTag.textContent = `共 ${questions ? questions.length : 0} 题`;
|
||||
countTag.style.display = 'inline';
|
||||
}
|
||||
|
||||
if (!questions || questions.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<p>暂无题目数据</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="60">ID</th>
|
||||
<th>题目</th>
|
||||
<th width="100">类型</th>
|
||||
<th>选项/学生答案</th>
|
||||
<th>正确答案</th>
|
||||
<th width="80">分值</th>
|
||||
<th width="150">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
questions.forEach(q => {
|
||||
const typeTag = q.type == 1 ?
|
||||
'<span class="tag tag-choice">选择题</span>' :
|
||||
'<span class="tag tag-essay">简答题</span>';
|
||||
|
||||
let optionsHtml = '';
|
||||
if (q.type == 1) {
|
||||
const parts = [];
|
||||
if (q.answerA) parts.push(`A: ${escapeHtml(q.answerA)}`);
|
||||
if (q.answerB) parts.push(`B: ${escapeHtml(q.answerB)}`);
|
||||
if (q.answerC) parts.push(`C: ${escapeHtml(q.answerC)}`);
|
||||
if (q.answerD) parts.push(`D: ${escapeHtml(q.answerD)}`);
|
||||
optionsHtml = parts.join('<br>');
|
||||
} else {
|
||||
optionsHtml = q.answer ? escapeHtml(q.answer) : '无答案';
|
||||
}
|
||||
|
||||
const rAnswerHtml = q.rAnswer ?
|
||||
`<span class="tag tag-answer">${escapeHtml(q.rAnswer)}</span>` :
|
||||
'<span style="color: #999;">-</span>';
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td>${q.id}</td>
|
||||
<td style="max-width: 300px; word-wrap: break-word;">${escapeHtml(q.title)}</td>
|
||||
<td>${typeTag}</td>
|
||||
<td>${optionsHtml}</td>
|
||||
<td>${rAnswerHtml}</td>
|
||||
<td><span class="score-badge">${q.score}</span></td>
|
||||
<td>
|
||||
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
|
||||
<button class="btn btn-primary" style="padding: 6px 12px; font-size: 12px;" onclick="editQuestion(${q.id}, ${q.type})">修改</button>
|
||||
<button class="btn btn-danger" style="padding: 6px 12px; font-size: 12px;" onclick="deleteQuestion('${escapeHtml(q.title)}')">删除</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += '</tbody></table>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
// 删除题目
|
||||
function deleteQuestion(title) {
|
||||
if (!confirm('确定要删除这道题吗?')) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('title', title);
|
||||
|
||||
fetch('/admin/delete', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showAlert('删除成功!', 'success');
|
||||
loadAllQuestions();
|
||||
} else {
|
||||
showAlert(data.message || '删除失败', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showAlert('删除失败,请检查网络', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// 转义HTML
|
||||
function escapeHtml(text) {
|
||||
if (!text) return '';
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// 显示提示
|
||||
function showAlert(message, type) {
|
||||
// 移除已有的提示
|
||||
const existingAlert = document.querySelector('.dynamic-alert');
|
||||
if (existingAlert) existingAlert.remove();
|
||||
|
||||
const alert = document.createElement('div');
|
||||
alert.className = `alert alert-${type} dynamic-alert`;
|
||||
alert.textContent = message;
|
||||
alert.style.position = 'fixed';
|
||||
alert.style.top = '20px';
|
||||
alert.style.left = '50%';
|
||||
alert.style.transform = 'translateX(-50%)';
|
||||
alert.style.zIndex = '1000';
|
||||
alert.style.minWidth = '200px';
|
||||
alert.style.textAlign = 'center';
|
||||
document.body.appendChild(alert);
|
||||
|
||||
setTimeout(() => {
|
||||
alert.remove();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 当前编辑的题目ID和类型
|
||||
let currentEditId = null;
|
||||
let currentEditType = null;
|
||||
|
||||
// 打开编辑弹窗
|
||||
function editQuestion(id, type) {
|
||||
currentEditId = id;
|
||||
currentEditType = type;
|
||||
|
||||
// 获取题目详情
|
||||
fetch('/admin/api/question/' + id)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
fillEditForm(data.data);
|
||||
document.getElementById('editModal').style.display = 'block';
|
||||
} else {
|
||||
showAlert(data.message || '加载题目失败', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showAlert('加载题目失败,请检查网络', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// 填充编辑表单
|
||||
function fillEditForm(q) {
|
||||
document.getElementById('editId').value = q.id;
|
||||
document.getElementById('editType').value = q.type;
|
||||
document.getElementById('editTitle').value = q.title || '';
|
||||
document.getElementById('editScore').value = q.score || '';
|
||||
|
||||
if (q.type == 1) {
|
||||
// 选择题表单
|
||||
document.getElementById('editChoiceForm').style.display = 'block';
|
||||
document.getElementById('editEssayForm').style.display = 'none';
|
||||
document.getElementById('editTypeLabel').textContent = '选择题';
|
||||
|
||||
document.getElementById('editAnswerA').value = q.answerA || '';
|
||||
document.getElementById('editAnswerB').value = q.answerB || '';
|
||||
document.getElementById('editAnswerC').value = q.answerC || '';
|
||||
document.getElementById('editAnswerD').value = q.answerD || '';
|
||||
document.getElementById('editRAnswer').value = q.rAnswer || '';
|
||||
} else {
|
||||
// 简答题表单
|
||||
document.getElementById('editChoiceForm').style.display = 'none';
|
||||
document.getElementById('editEssayForm').style.display = 'block';
|
||||
document.getElementById('editTypeLabel').textContent = '简答题';
|
||||
|
||||
document.getElementById('editAnswer').value = q.answer || '';
|
||||
document.getElementById('editRAnswerEssay').value = q.rAnswer || '';
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭编辑弹窗
|
||||
function closeEditModal() {
|
||||
document.getElementById('editModal').style.display = 'none';
|
||||
currentEditId = null;
|
||||
currentEditType = null;
|
||||
}
|
||||
|
||||
// 保存修改
|
||||
function saveEdit() {
|
||||
if (!currentEditId) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('id', currentEditId);
|
||||
formData.append('type', currentEditType);
|
||||
formData.append('title', document.getElementById('editTitle').value);
|
||||
formData.append('score', document.getElementById('editScore').value);
|
||||
|
||||
if (currentEditType == 1) {
|
||||
formData.append('answerA', document.getElementById('editAnswerA').value);
|
||||
formData.append('answerB', document.getElementById('editAnswerB').value);
|
||||
formData.append('answerC', document.getElementById('editAnswerC').value);
|
||||
formData.append('answerD', document.getElementById('editAnswerD').value);
|
||||
formData.append('rAnswer', document.getElementById('editRAnswer').value);
|
||||
} else {
|
||||
formData.append('answer', document.getElementById('editAnswer').value);
|
||||
formData.append('rAnswer', document.getElementById('editRAnswerEssay').value);
|
||||
}
|
||||
|
||||
fetch('/admin/api/question/update', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showAlert('修改成功!', 'success');
|
||||
closeEditModal();
|
||||
loadAllQuestions();
|
||||
} else {
|
||||
showAlert(data.message || '修改失败', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showAlert('修改失败,请检查网络', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// 点击弹窗外部关闭
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('editModal');
|
||||
if (event.target == modal) {
|
||||
closeEditModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<div id="editModal" class="modal">
|
||||
<div class="modal-content" style="max-width: 600px; max-height: 90vh; overflow-y: auto;">
|
||||
<div class="modal-header">
|
||||
<h2>修改题目 <span id="editTypeLabel" class="tag" style="margin-left: 10px;"></span></h2>
|
||||
<span class="close-btn" onclick="closeEditModal()">×</span>
|
||||
</div>
|
||||
|
||||
<input type="hidden" id="editId">
|
||||
<input type="hidden" id="editType">
|
||||
|
||||
<div class="form-group">
|
||||
<label>题目内容 <span class="required">*</span></label>
|
||||
<textarea id="editTitle" rows="3" required></textarea>
|
||||
</div>
|
||||
|
||||
<!-- 选择题表单 -->
|
||||
<div id="editChoiceForm">
|
||||
<div class="grid-2">
|
||||
<div class="form-group">
|
||||
<label>选项 A</label>
|
||||
<input type="text" id="editAnswerA">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>选项 B</label>
|
||||
<input type="text" id="editAnswerB">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>选项 C</label>
|
||||
<input type="text" id="editAnswerC">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>选项 D</label>
|
||||
<input type="text" id="editAnswerD">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>正确答案 <span class="required">*</span></label>
|
||||
<select id="editRAnswer" required>
|
||||
<option value="">请选择</option>
|
||||
<option value="A">A</option>
|
||||
<option value="B">B</option>
|
||||
<option value="C">C</option>
|
||||
<option value="D">D</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 简答题表单 -->
|
||||
<div id="editEssayForm" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>学生答案参考</label>
|
||||
<textarea id="editAnswer" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>参考答案</label>
|
||||
<textarea id="editRAnswerEssay" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>分值 <span class="required">*</span></label>
|
||||
<input type="number" id="editScore" required min="0">
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeEditModal()">取消</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveEdit()">保存修改</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 2000;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
padding-top: 50px;
|
||||
padding-bottom: 50px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.modal-content {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
position: relative;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
||||
margin: auto;
|
||||
}
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 2px solid #f59e0b;
|
||||
}
|
||||
.modal-header h2 {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
}
|
||||
.close-btn {
|
||||
font-size: 28px;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
line-height: 1;
|
||||
}
|
||||
.close-btn:hover {
|
||||
color: #f59e0b;
|
||||
}
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
margin-top: 24px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
.required {
|
||||
color: #e74c3c;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -239,42 +239,20 @@
|
||||
<h2>试卷列表</h2>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<form class="search-section" action="/admin/listexam" method="get">
|
||||
<div class="search-section">
|
||||
<div class="form-group">
|
||||
<label>试卷标题</label>
|
||||
<input type="text" name="title" th:value="${searchTitle}" placeholder="输入试卷标题进行模糊搜索...">
|
||||
<input type="text" id="searchTitle" placeholder="输入试卷标题进行模糊搜索...">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">搜索</button>
|
||||
<a href="/admin/listexam" class="btn btn-secondary">重置</a>
|
||||
</form>
|
||||
|
||||
<div th:if="${#lists.isEmpty(examPapers)}" class="empty-state">
|
||||
暂无试卷记录,点击上方"创建试卷"生成一份吧
|
||||
<button type="button" class="btn btn-primary" onclick="searchExams()">搜索</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="resetSearch()">重置</button>
|
||||
</div>
|
||||
|
||||
<table th:unless="${#lists.isEmpty(examPapers)}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="60">ID</th>
|
||||
<th width="280">UID</th>
|
||||
<th>试卷标题</th>
|
||||
<th width="220">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="paper : ${examPapers}">
|
||||
<td th:text="${paper.id}"></td>
|
||||
<td style="font-family: monospace; color: #666; font-size: 13px;" th:text="${paper.uid}"></td>
|
||||
<td th:text="${paper.title != null and paper.title != '' ? paper.title : '未命名试卷'}"></td>
|
||||
<td>
|
||||
<div class="action-btns">
|
||||
<button class="btn btn-primary btn-sm" th:attr="onclick='viewExamDetail(\'' + ${paper.uid} + '\')'">查看内容</button>
|
||||
<a th:href="'/' + ${paper.uid}" target="_blank" class="btn btn-success btn-sm">前往答题</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="examListContainer">
|
||||
<div class="empty-state">
|
||||
加载中...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -307,8 +285,124 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 页面加载时加载全部试卷
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadExams();
|
||||
});
|
||||
|
||||
// 加载试卷列表
|
||||
function loadExams(title = '') {
|
||||
const container = document.getElementById('examListContainer');
|
||||
container.innerHTML = '<div class="empty-state">加载中...</div>';
|
||||
|
||||
let url = '/admin/api/exams';
|
||||
if (title) {
|
||||
url += '?title=' + encodeURIComponent(title);
|
||||
}
|
||||
|
||||
fetch(url)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
renderExams(data.data);
|
||||
} else {
|
||||
showAlert(data.message || '加载失败', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showAlert('加载失败,请检查网络', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染试卷列表
|
||||
function renderExams(examPapers) {
|
||||
const container = document.getElementById('examListContainer');
|
||||
|
||||
if (!examPapers || examPapers.length === 0) {
|
||||
container.innerHTML = '<div class="empty-state">暂无试卷记录,点击上方"创建试卷"生成一份吧</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="60">ID</th>
|
||||
<th width="280">UID</th>
|
||||
<th>试卷标题</th>
|
||||
<th width="220">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
examPapers.forEach(paper => {
|
||||
const title = paper.title || '未命名试卷';
|
||||
html += `
|
||||
<tr>
|
||||
<td>${paper.id}</td>
|
||||
<td style="font-family: monospace; color: #666; font-size: 13px;">${paper.uid}</td>
|
||||
<td>${escapeHtml(title)}</td>
|
||||
<td>
|
||||
<div class="action-btns">
|
||||
<button class="btn btn-primary btn-sm" onclick="viewExamDetail('${paper.uid}')">查看内容</button>
|
||||
<a href="/${paper.uid}" target="_blank" class="btn btn-success btn-sm">前往答题</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += '</tbody></table>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
// 搜索试卷
|
||||
function searchExams() {
|
||||
const title = document.getElementById('searchTitle').value.trim();
|
||||
loadExams(title);
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
function resetSearch() {
|
||||
document.getElementById('searchTitle').value = '';
|
||||
loadExams();
|
||||
}
|
||||
|
||||
// 转义HTML
|
||||
function escapeHtml(text) {
|
||||
if (!text) return '';
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// 显示提示
|
||||
function showAlert(message, type) {
|
||||
const existingAlert = document.querySelector('.dynamic-alert');
|
||||
if (existingAlert) existingAlert.remove();
|
||||
|
||||
const alert = document.createElement('div');
|
||||
alert.className = `alert alert-${type} dynamic-alert`;
|
||||
alert.textContent = message;
|
||||
alert.style.cssText = 'position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 1000; min-width: 200px; text-align: center; padding: 12px 16px; border-radius: 8px;';
|
||||
if (type === 'success') {
|
||||
alert.style.background = '#d4edda';
|
||||
alert.style.color = '#155724';
|
||||
} else {
|
||||
alert.style.background = '#f8d7da';
|
||||
alert.style.color = '#721c24';
|
||||
}
|
||||
document.body.appendChild(alert);
|
||||
|
||||
setTimeout(() => {
|
||||
alert.remove();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 查看试卷详情(原有函数)
|
||||
function viewExamDetail(uid) {
|
||||
// 打开弹窗
|
||||
document.getElementById('detailModal').style.display = 'block';
|
||||
document.getElementById('modalTitle').textContent = '试卷加载中...';
|
||||
|
||||
@@ -321,22 +415,21 @@
|
||||
document.getElementById('modalChoiceCount').textContent = data.choiceCount;
|
||||
document.getElementById('modalEssayCount').textContent = data.essayCount;
|
||||
|
||||
// 渲染选择题
|
||||
let choiceHtml = '';
|
||||
if (data.choiceQuestions && data.choiceQuestions.length > 0) {
|
||||
data.choiceQuestions.forEach((q, index) => {
|
||||
choiceHtml += `
|
||||
<div class="question-item">
|
||||
<div style="margin-bottom: 12px;">
|
||||
<strong>${index + 1}. ${q.title}</strong>
|
||||
<strong>${index + 1}. ${escapeHtml(q.title)}</strong>
|
||||
<span class="question-type">选择题</span>
|
||||
<span class="question-score">${q.score}分</span>
|
||||
</div>
|
||||
<div class="answer-content">
|
||||
${q.answerA ? `<div>A. ${q.answerA}</div>` : ''}
|
||||
${q.answerB ? `<div>B. ${q.answerB}</div>` : ''}
|
||||
${q.answerC ? `<div>C. ${q.answerC}</div>` : ''}
|
||||
${q.answerD ? `<div>D. ${q.answerD}</div>` : ''}
|
||||
${q.answerA ? `<div>A. ${escapeHtml(q.answerA)}</div>` : ''}
|
||||
${q.answerB ? `<div>B. ${escapeHtml(q.answerB)}</div>` : ''}
|
||||
${q.answerC ? `<div>C. ${escapeHtml(q.answerC)}</div>` : ''}
|
||||
${q.answerD ? `<div>D. ${escapeHtml(q.answerD)}</div>` : ''}
|
||||
</div>
|
||||
<div class="correct-answer">正确答案:${q.ranswer || q.rAnswer || '-'}</div>
|
||||
</div>
|
||||
@@ -347,18 +440,17 @@
|
||||
}
|
||||
document.getElementById('choiceContainer').innerHTML = choiceHtml;
|
||||
|
||||
// 渲染简答题
|
||||
let essayHtml = '';
|
||||
if (data.essayQuestions && data.essayQuestions.length > 0) {
|
||||
data.essayQuestions.forEach((q, index) => {
|
||||
essayHtml += `
|
||||
<div class="question-item">
|
||||
<div style="margin-bottom: 12px;">
|
||||
<strong>${index + 1}. ${q.title}</strong>
|
||||
<strong>${index + 1}. ${escapeHtml(q.title)}</strong>
|
||||
<span class="question-type">简答题</span>
|
||||
<span class="question-score">${q.score}分</span>
|
||||
</div>
|
||||
<div class="correct-answer">参考答案:${q.ranswer || q.rAnswer || q.answer || '无'}</div>
|
||||
<div class="correct-answer">参考答案:${escapeHtml(q.ranswer || q.rAnswer || q.answer || '无')}</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
@@ -377,13 +469,17 @@
|
||||
document.getElementById('detailModal').style.display = 'none';
|
||||
}
|
||||
|
||||
// 点击遮罩层关闭弹窗
|
||||
window.onclick = function(event) {
|
||||
let modal = document.getElementById('detailModal');
|
||||
if (event.target == modal) {
|
||||
modal.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// 回车键搜索
|
||||
document.getElementById('searchTitle')?.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') searchExams();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -260,6 +260,25 @@
|
||||
<div class="answer-section">
|
||||
<!-- 选择题 -->
|
||||
<div th:if="${q.type == 1}">
|
||||
<!-- 选项列表 -->
|
||||
<div class="options-list" style="margin-bottom: 10px; padding-left: 10px;">
|
||||
<div class="option-item" th:if="${q.answerA != null}" style="margin: 5px 0;">
|
||||
<span style="font-weight: bold;">A.</span>
|
||||
<span th:text="${q.answerA}"></span>
|
||||
</div>
|
||||
<div class="option-item" th:if="${q.answerB != null}" style="margin: 5px 0;">
|
||||
<span style="font-weight: bold;">B.</span>
|
||||
<span th:text="${q.answerB}"></span>
|
||||
</div>
|
||||
<div class="option-item" th:if="${q.answerC != null}" style="margin: 5px 0;">
|
||||
<span style="font-weight: bold;">C.</span>
|
||||
<span th:text="${q.answerC}"></span>
|
||||
</div>
|
||||
<div class="option-item" th:if="${q.answerD != null}" style="margin: 5px 0;">
|
||||
<span style="font-weight: bold;">D.</span>
|
||||
<span th:text="${q.answerD}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="answer-row">
|
||||
<span class="answer-label">答案:</span>
|
||||
<span class="answer-content"
|
||||
|
||||
Reference in New Issue
Block a user