3.8 *主页信息

第 28 节 / 共 46 节 课程:ThinkPHP
获取主页的右下角的错题信息:
首先修改前段的bug,在src/views/Home.vue文件,第149行代码:
改成:
let t=response.data.data;

进入主页后,前端会自动发起一个get请求,发送参数username和courseId到main,然后后台将发回的json结构如下:
{    
    "code": "200",
    "info": "",
    "data": {
        "cqcList": [
            {
                "chapterQuizStudyId": "41832",
                "score": 0,
                "datetime": "2025-03-01 21:52:53",
                "stat": "3",
                "teacherId": "system",
                "comment": "错误",
                "chapterQuizStudy": {
                    "chapterQuiz": {
                        "chapter": Object{...},
                        "code": "",
                        "codeLang": "PHP",
                        "title": "PHP是Web开发语言,可以动态生成网页内容",
                        "subjectType": {
                            "name": "判断",
                            "id": "5"
                        },
                        "content": "",
                        "valid": "1",
                        "score": 2,
                        "instruments": "",
                        "answer": "true",
                        "chapterId": "187",
                        "hint": "",
                        "typeId": "5",
                        "id": "30",
                        "keyword": "php",
                        "queue": 1
                    },
                    "studentId": "abc",
                    "stat": "0",
                    "answer": "false",
                    "quizId": "30",
                    "startTime": "2025-03-01 14:35:31",
                    "endTime": "2025-03-01 14:36:07",
                    "id": "41832",
                    "user": {
                        "role": "9",
                        "isValid": "1",
                        "nickname": "PHP",
                        "createDate": "2020-09-16 16:44:32",
                        "username": "abc"
                    }
                },
                "id": "28430",
                "user": {
                    "role": "1",
                    "isValid": "1",
                    "nickname": "系统",
                    "createDate": "2018-04-03",
                    "username": "system"
                }
            },
            //这些Object是其他错题,省略
            Object{...},
            Object{...},
            Object{...},
            Object{...}
        ],
        "courseName": "PHP程序设计",
        "code": "010200",
        "chapterName": "1.2  PHP编程环境",
        "courseId": "1",
        "percent": "0.6666666666666666"
    }
}
data部分的cqcList,实际上查询的表格是chapterQuizCorrect,这个表表示批改表,与之紧密关联的表示chapterQuizStudy,表示学生做题表,ChapterQuiz则是练习题表,最后,ChapterQuiz关联了Chapter表这四个表数据库设置了外键关联。以下表都要创建模型:
模型类说明
Chapter保存章节的表,章节的标题,内容
ChapterQuiz保存练习题的表,里面有一个Chapter的外键,记录题目是哪个章节的
ChapterQuizStudy学员完成一道练习题的记录,里面有一个chapterQuiz的外键,记录答题对应的练习
ChapterQuizCorrect系统批改一道学员答题的记录,里面有一个chapterQuizStudy的外键,记录本次批改对应的答题
SubjectType记录练习题类型,ChapterQuiz只记录一个数字id,id对于的文字在这个表里面
外键关联的表格,在ThinkPHP8中通过模型来映射关联关系,例如下面的ChapterQuiz模型,除了chapter_id字段外,还通过belongsTo定义了与Chapter模型的关联:
<?php
namespace app\model;
use think\Model;
class ChapterQuiz extends Model
{
// 关联表名(默认自动匹配,此处显式指定)
protected $table = 'chapter_quiz';
// 关联Chapter
public function chapter()
{
return $this->belongsTo(Chapter::class, 'chapter_id', 'id');
}
// 关联SubjectType
public function subjectType()
{
return $this->belongsTo(SubjectType::class, 'type_id', 'id');
}
// 关联答题记录(一对多)
public function chapterQuizStudies()
{
return $this->hasMany(ChapterQuizStudy::class, 'quiz_id', 'id');
}
}
对比下面的chapter_quiz表格的结构,可以看到每个数据库的字段都有一个属性对应,但是这里要注意:第10行代码,chapterId已经映射了chapter_id,通过模型关联方法chapter()可以自动关联查询Chapter表数据。这就是ThinkPHP模型关联的便利之处,查询ChapterQuiz时,可以同时获取关联的Chapter信息。

现在再回头去看看上面的json:
对此,我们不需要做什么,直接查询就能得到关联的表的信息,下面这个查询是本章节最核心的查询,根据用户名和课程id查询练习批改信息的函数,它应该在哪个模型里面?
// 使用模型关联查询(在ChapterQuizCorrect模型中定义)
$list = ChapterQuizCorrect::whereHas('chapterQuizStudy.student', function ($q) use ($username) {
$q->where('username', $username);
})->where('comment', '<>', '')
->whereHas('chapterQuizStudy.chapterQuiz.chapter.course', function ($q) use ($courseId) {
$q->where('id', $courseId);
})
->order('datetime', 'desc')
->select();