【Webman+MySQL答题系统六】用户答题流程:取卷与作答接口
果子发表于:2026-10-05 20:55:45浏览:1次
本篇目标
切到学员视角:实现取卷接口。按试卷顺序组装题目,处理好 JSON 选项,并且从返回数据里剥掉答案——这是防泄题的底线。

一、接口设计
GET /api/answer/paper?paper_id=1
返回:
{
"paper": {"id":1, "title":"Webman 基础测试卷", "total_score":6, "duration":30},
"questions": [
{"id":1, "type":1, "title":"...", "options":{"A":"...","B":"..."}, "score":2}
]
}
没有 answer、没有 analysis。前端拿到的只是"题面",判分权完全在服务端(第七篇)。
二、答题流程
整个学员端流程是一条直线:

三、控制器实现
app/controller/AnswerController.php:
<?php
namespace app\controller;
use support\Request;
use support\Db;
class AnswerController
{
public function paper(Request $request)
{
$paperId = (int)$request->get('paper_id');
$paper = Db::table('paper')
->where('id', $paperId)
->where('status', 1)
->first();
if (!$paper) {
return error('试卷不存在或已停用', 404);
}
// 按组卷时的 sort 顺序取题
$questions = Db::table('paper_question as pq')
->join('question as q', 'q.id', '=', 'pq.question_id')
->where('pq.paper_id', $paperId)
->where('q.status', 1)
->orderBy('pq.sort')
->get(['q.id', 'q.type', 'q.title', 'q.options', 'q.score']);
$items = [];
foreach ($questions as $q) {
$items[] = [
'id' => $q->id,
'type' => $q->type,
'title' => $q->title,
'options' => json_decode($q->options, true), // Db 查询不走模型 casts,手动 decode
'score' => $q->score,
// 注意:这里绝不输出 q.answer 和 q.analysis
];
}
return success([
'paper' => [
'id' => $paper->id,
'title' => $paper->title,
'total_score' => $paper->total_score,
'duration' => $paper->duration,
],
'questions' => $items,
]);
}
}
register 路由:
Route::get('/api/answer/paper', [AnswerController::class, 'paper']);
四、为什么这里用 Db 而不是 Model
- 查询是"两表 join + 指定列",Db::table 写起来最直接;
- join 结果没有模型实例,casts 不生效,所以 options 手动
json_decode; - 当初在 Question 模型里配 casts 是给管理端单表 CRUD 用的。两套写法并存是正常的:模型管单表,Db 管聚合。
五、前端作答状态
UniApp 侧把 questions 渲染成列表,作答状态存一个对象即可:
// data()
answers: {} // {questionId: 'A'} 单选/判断;多选存 'A,C'
// 单选点击
this.answers[q.id] = key
// 多选点击:切换选中再拼接
const cur = (this.answers[q.id] || '').split(',').filter(Boolean)
const i = cur.indexOf(key)
i >= 0 ? cur.splice(i, 1) : cur.push(key)
this.answers[q.id] = cur.sort().join(',')
提交时把 answers、paper_id、use_seconds(前端计时)一起 POST 给第七篇的 submit 接口。
六、验证
curl "http://127.0.0.1:8787/api/answer/paper?paper_id=1"
// 检查两点:
// 1. questions 里找不到 answer / analysis 字段
// 2. options 是对象而不是 JSON 字符串
小结
取卷完成:按 sort 组装、手动 decode、答案字段物理剥离。下一篇写整个系统的心脏——提交与自动判分。
栏目分类全部>

