- 教育
- 后端
- 前端
【免费下载链接】rsschool-app
An application for the RS School education process
导读
本文面向 RS School 平台的教练(trainers)与管理员(admins),完整讲解如何在 RS School App 中为课程添加"RS School App Test"类型的自测任务(Self-Education Test):包括创建全局任务、挂载到课程、通过 Auto-Test 菜单验证的完整操作流程,以及决定测试评分逻辑的核心配置 JSON Attributes 中每个参数的含义与取值规则。读完本文,你将能够独立配置一套带严格尝试次数、超时限流与阈值判定等规则的课程自测题,并理解其在前端渲染与后端判分中的底层实现。
一、功能定位:什么是 RS School App 的 Auto-Test 自测任务
在 RS School 的教学流程中,除了自动代码检查(Cross-Check / 代码仓库测试),平台还内置了一套题库式自测任务(Self-Education):教练以 JSON 形式录入题目与答案,学生在前端作答后由后端即时判分并写入课程成绩。该功能在仓库中对应两套实现:
- 后端判分核心:nestjs/src/courses/task-verifications/self-education.service.ts,负责校验答案、计算正确率与得分、执行尝试次数与限流规则;
- 前端作答页面:client/src/modules/AutoTest/components/SelfEducation/SelfEducation.tsx,负责把题目渲染为单选(Radio)或多选(Checkbox)表单。
后端通过TaskType.SelfEducation识别这类任务(见 auto-test.service.ts),并将其统一暴露给"Auto-Test"页面。下面按官方流程逐步说明配置方法。
二、创建全局测试任务(Manage Tasks 页面)
2.1 进入任务管理页并新建任务
- 在平台导航中进入"Manage Tasks"页面,这是所有课程的全局任务库,见下图:
- 点击"Add Task"按钮开始新建:
2.2 填写任务表单
在弹出的表单中依次填写以下字段:
| 字段 | 说明 |
|---|---|
| Name | 任务标题,会展示在课程任务列表与 Auto-Test 页面中 |
| Task Type | 必须选择"RS School App Test",后端据此以TaskType.SelfEducation存储(见 task.ts 的枚举定义) |
| Discipline | 选择与课程相关的学科(Discipline),用于归类和筛选 |
| Tags | 可选。设置标签以标明该题与课程的哪个知识点相关,例如javascript、html/css等 |
| Description URL | 任务描述的外部链接 |
| JSON Attributes | 核心配置:把包含测试设置、题目与答案的 JSON 内容整体粘贴进来(完整格式见下文"四、JSON Attributes 详解") |
提示:JSON Attributes 中的题目结构直接决定了学生端作答表单的渲染方式。前端组件会按
multiple字段选择渲染单选还是多选(见 SelfEducation.tsx),因此务必保证 JSON 结构合法、字段完整。
三、将测试任务挂载到具体课程(Course Tasks 页面)
全局任务创建完成后,还需要把它挂载到目标课程上,学生才会看到该任务:
- 在课程菜单中进入"Course Tasks"页面:
- 同样点击"Add Task"按钮:
- 再次填写课程维度的任务配置并保存:
| 字段 | 说明 |
|---|---|
| Task | 选择上一步刚创建的全局任务 |
| Task Type | 选择"RS School App Test" |
| Checker | 选择"Auto-Test",表示由平台自动判分而非人工检查 |
| Task Owner | 该任务的负责人 |
| Start Date – End Date | 任务下发时间与截止时间(Deadline) |
| Score | 学生可获得的该任务最高分(后端以此作为maxScore参与计算) |
| Score Weight | 任务权重,默认1。此值由课程管理者后续统一修正,教练在创建任务时请勿修改 |
说明:
Score Weight属于课程管理层面的调分手段,教练创建任务时保留默认值即可,避免干扰课程统一的评分口径。
四、验证任务是否配置成功(Auto-Test 菜单)
- 任务添加完成后,回到课程菜单,进入"Auto-Test"页面,即可看到当前课程下所有 Self-Education 类型任务(后端 AutoTestService.getAll 会按
TaskType.SelfEducation过滤并关联课程信息返回):
- 在 Auto-Test 页面的下拉列表中选择刚创建的测试,检查题目渲染、得分与尝试次数提示是否正常:
前端 Auto-Test 页面由 client/src/modules/AutoTest/pages/AutoTests/AutoTests.tsx 承载,任务卡片通过 TaskCard 展示阈值与得分信息,例如当学生分数未达到tresholdPercentage时卡片会标记为未通过(见 TaskCard.tsx)。
五、JSON Attributes 详解:决定测试评分规则的核心配置
JSON Attributes 是整个自测功能的关键。它分为public(对学生可见/参与判分的公开配置)与answers(标准答案)两大块。
5.1 参数说明
| 参数 | 含义与取值规则 |
|---|---|
| strictAttemptsMode | 严格模式开关,默认开启(true)。为false时关闭严格模式。严格模式下,达到最大尝试次数后学生不得再提交(得 0);非严格模式下,学生可以无限次提交,但超过最大次数后最终得分减半 |
| maxAttemptsNumber | 最大尝试次数。严格模式下提交次数达到该值后学生本次任务直接得 0;非严格模式下超过该次数后每轮得分除以 2 |
| numberOfQuestions | 题目数量,必须等于answers数组长度,也等于public.questions数组长度(否则后端计算的正确率基数会出错) |
| tresholdPercentage | 通过阈值百分比(原文拼写即如此)。学生正确率需达到该百分比,任务才算通过;否则得 0 并消耗一次尝试机会 |
| oneAttemptPerNumberOfHours | 提交限流:设为正整数时,限制为每 N 小时仅可提交 1 次;默认 0 表示关闭该限制 |
| public.questions | 题目与选项数组。每道题含question(题干)、answers(选项数组)、multiple(是否多选,设为true渲染为复选框) |
| answers | 标准答案数组,元素为正确选项的下标(单选为单个数字,多选为数字数组),顺序必须与public.questions一一对应 |
注意:学生重新提交后,最终得分为最后一次提交获得的分数——也就是说,即使之前的提交拿了高分,最后一次提交也可能得 0,最终成绩按最后一次记录。
5.2 完整示例
以下是一个包含单选、多选的标准 JSON 配置:
{ "public": { "tresholdPercentage": 70, "numberOfQuestions": 10, "maxAttemptsNumber": 2, "strictAttemptsMode": false, "questions": [ { "question": "Do you like html?", "answers": ["Yes", "No", "Maybe"], "multiple": false }, { "question": "What is css?", "answers": ["Cascade style sheets", "cosmic super solutions", "cool super stuff"], "multiple": true }, { "question": "What is not a css selector?", "answers": ["<div>", "div", "a.a", "p<div>"], "multiple": true } ] }, "answers": [ [0], [0, 2], [0, 3] ] }示例中的判分逻辑:
- 第 1 题为单选,正确选项下标为
0("Yes"); - 第 2 题为多选,正确选项为
[0, 2](即第 0 项和第 2 项); - 第 3 题为多选,正确选项为
[0, 3]; numberOfQuestions在示例中填了10,但只列了 3 道题——实际使用时必须把该值改为与题目数量一致的数值,否则正确率基数(100 / numberOfQuestions)会与真实题数不符。
5.3 判分算法与参数如何被后端消费
后端 verifySelfEducationAnswers 完整实现了上述参数的全部逻辑:
- 提交合法性校验:答案数量不能超过题目总数且不能为空;所有答案值必须是非负整数;题目下标必须在
answers范围内且不能重复(self-education.service.ts)。 - 次数与限流判定:
oneAttemptPerNumberOfHours通过对比上次提交时间与当前时间的小时差实现(isNextSubmitAllowed);严格模式下attempt >= maxAttemptsNumber直接抛出ForbiddenException,禁止再提交(self-education.service.ts)。 - 答案比对:多选答案先排序再以
|连接成字符串进行比较(serializeAnswers),保证选择顺序不影响正确性判定。 - 得分计算:
correctAnswersPercent = round(100 / numberOfQuestions * correctAnswersCount);若正确率低于tresholdPercentage则得 0 分;否则score = floor(maxScore * correctAnswersPercent * 0.01);非严格模式下若attempt >= maxAttemptsNumber,得分再floor(score / 2)(self-education.service.ts)。 - 写库与计分:保存
TaskVerification记录(含答案明细),并调用WriteScoreService.saveScore把最终得分写入课程成绩(self-education.service.ts)。该流程在 task-verifications.service.ts 中对TaskType.SelfEducation分支触发。
以上规则均有对应的单元测试覆盖,可参见 self-education.service.test.ts(如严格模式达到上限抛异常、非严格模式减半得分、oneAttemptPerNumberOfHours为 0 时不限流等用例)。
5.4 前端如何解释这些参数(学生体验侧)
- 学生作答页会先对题目做随机打乱,再按
numberOfQuestions截取展示(SelfEducation.tsx),因此同一任务每次进入题目顺序可能不同; - 每道题按
multiple渲染为单选(Radio.Group)或多选(Checkbox.Group),答案以选项下标为提交值(SelfEducation.tsx); - 提示文案(剩余尝试次数、通过阈值、限流倒计时)由 useAttemptsMessage.ts 统一生成:例如非严格模式下提示"After limit attempts is over you can get only half of a score.",设置了
oneAttemptPerNumberOfHours时会额外提示"only one attempt per N hours",其测试用例见 useAttemptsMessage.test.ts; - 任务卡片会展示最大尝试次数、严格模式开关与阈值达成状态(AutoTestTaskCard.tsx)。
5.5 进阶:带图片的题目
题目与选项均支持图片形式(仓库中对应的功能扩展,见 PR #798 描述):
- 题干图片:在题目对象中添加
questionImage字段,值为图片 URL,渲染时显示在题干下方(SelfEducation.tsx); - 选项图片:将
answersType设为"image",并把answers数组中的元素替换为图片 URL,选项会以图片形式展示(SelfEducation.tsx)。
类型定义可参考 client/src/services/course.ts 中的SelfEducationQuestion(questionImage?: string; answersType?: 'image'),对应渲染测试见 SelfEducation.test.tsx。
六、功能演进参考(PR / Issue)
以下历史改动展示了该功能能力的扩展脉络,可帮助你判断当前实例支持的配置范围:
- 基础示例:首个支持"RS School App Test"任务类型与 JSON Attributes 的 PR,包含上述判分逻辑的雏形(对应本文 5.2 节示例);
- 题目/选项图片支持:为题目与选项增加图片展示能力(对应 5.5 节);
- 按小时限制提交次数:引入
oneAttemptPerNumberOfHours参数,用于限制每小时提交次数(对应 5.1 节参数表)。
七、常见问题与排错建议
| 现象 | 可能原因与处理 |
|---|---|
| 学生端题目数量与预期不符 | numberOfQuestions与public.questions数组长度不一致,或前端按numberOfQuestions截取了随机题目,请核对 JSON 中两者数值 |
| 学生提交后被拒绝(Forbidden) | 严格模式下尝试次数已达上限,或oneAttemptPerNumberOfHours限流未到期(见 useAttemptsMessage.ts 中allowStartTask的判定) |
| 得分低于预期 | 检查tresholdPercentage是否过高;非严格模式下超过maxAttemptsNumber后得分强制减半;Score字段决定任务最高分 |
| 多选答案判错 | 确认answers中多选的下标数组与public.questions中该题的选项顺序一致(下标从 0 开始) |
| 创建任务后 Auto-Test 页面看不到 | 确认该任务Task Type为 "RS School App Test" 且已挂载到当前课程(Course Tasks),后端仅返回TaskType.SelfEducation且有关联课程的任务 |
- 教育
- 后端
- 前端
【免费下载链接】rsschool-app
An application for the RS School education process
相关推荐
speed-test高级配置指南:自定义服务器和测试参数详解
speed test高级配置指南:自定义服务器和测试参数详解 speed test是一款强大的命令行工具,能够帮助用户通过speedtest.net测试互联网连
开发工具miniblink49 内置 Google Test 示例详解:从 TEST 宏到参数化测试与监听器 API(v8_6_7 测试套件)
miniblink49 内置 Google Test 示例详解:从 TEST 宏到参数化测试与监听器 API(v8_6_7 测试套件) 在 miniblink4
前端桌面应用Gcovr深度解析:现代C/C++代码覆盖率报告的架构设计与实战指南
Gcovr深度解析:现代C/C++代码覆盖率报告的架构设计与实战指南 在持续集成和代码质量保障体系中,代码覆盖率分析是不可或缺的一环。对于C/C++项目而言,传
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考