问题¶
问题是 ZJUI-Learn 的基本构建块。它们是学生将解决的个人问题,可以合并到评估(作业和考试)中。问题可以简单也可以复杂,并且可以用多种方式编写。本文档介绍了如何创建问题,包括目录结构、元数据、HTML 模板和服务器端代码。

问题组成部分¶
问题由三个主要部分组成:
info.json:有关问题的元数据,包括问题标题、主题和标签。question.html:定义问题的 HTML 模板。您可以在此处编写问题文本并定义输入元素。更多详情请参考问题模板文档。server.py:您可以在此处编写用于生成随机值、对学生响应进行评分以及任何其他服务器端代码的逻辑。该文件是可选的,但对于具有重要随机化或自定义评分行为的任何问题来说都是必需的。有关更多详细信息,请参阅服务器文档。
您还可以直接在问题目录中包含可选的 README.md 文件。 ZJUI-Learn 将其呈现为讲师 预览 页面上问题上方的 Markdown;它对学生不可见。用它来记录问题的意图、变体或维护说明。
创建问题¶
要通过 ZJUI-Learn Web 界面创建新问题:
- 导航到课程中的问题选项卡。
- 单击 添加问题 按钮。
- 输入新问题的标题和问题 ID (QID)。
- 选择一个起点:
- 空问题:仅使用基本文件(
question.html和server.py)创建一个空白问题。 - ZJUI-Learn 模板:从 ZJUI-Learn 的预构建问题模板之一开始。
- 课程模板:从课程中定义的模板开始。详情请参见自定义模板。
- 空问题:仅使用基本文件(
- 单击创建问题。
Tip
避免在问题 ID 中使用术语名称(例如 Spring20/questionName)或评估名称(例如 exam3/question12),因为这些会使在评估和术语中查找和重复使用问题变得更加困难。您可以考虑的一种潜在文件夹结构是 topic/subtopic/question。
目录结构¶
问题全部存储在课程的 questions 目录(或任何子文件夹)内。每个问题都是一个目录,其中包含该问题的所有文件。相对于 questions 的完整问题目录的名称是该问题的 QID (the "question ID")。例如,这里有三个不同的问题:
questions
|
|-- fossilFuelsRadio # first question, id is "fossilFuelsRadio"
| |
| +-- info.json # metadata for the fossilFuelsRadio question
| +-- server.py # secret server-side code (optional)
| `-- question.html # HTML template for the question
|
|-- addVectors # second question, id is "addVectors"
| |
| +-- info.json # metadata for the addVectors question
| +-- server.py
| +-- question.html
| +-- notes.docx # more files, like notes on how the question works
| +-- solution.docx # these are secret (can't be seen by students)
| |
| +-- clientFilesQuestion/ # Files accessible to the client (web browser)
| | `-- fig1.png # A client file (an image)
| |
| +-- tests/ # external grading files (see other doc)
| `-- ...
|
`-- subfolder # a subfolder we can put questions in -- this itself can't be a question
|
`-- nestedQuestion # third question, id is "subfolder/nestedQuestion"
|
+-- info.json # metadata for the "subfolder/nestedQuestion" question
`-- question.html
ZJUI-Learn 假设独立问题;没有什么可以将他们联系在一起。但是,每个问题可能有多个部分(一起验证的输入)。
Info
可以在 ZJUI-Learn 的 exampleCourse/questions 目录下找到大量示例问题库。您还可以通过本地运行ZJUI-Learn来查看这些问题。
元数据 (info.json)¶
每个问题的 info.json 文件定义问题的属性。例如:
{
"uuid": "cbf5cbf2-6458-4f13-a418-aa4d2b1093ff",
"title": "Newton's third law",
"topic": "Forces",
"tags": ["secret", "Fa18"],
"authors": [{ "name": "John Doe", "email": "doe@example.org", "orcid": "0000-0000-0000-0001" }],
"type": "v3",
"comment": "You can add comments to JSON files using this property."
}
| 物业 | 类型 | 描述 |
|---|---|---|
uuid |
字符串 | 唯一标识符。 (必需;无默认值) |
type |
枚举 | 问题的类型。对于新式问题,必须是 "v3"。 (必需;无默认值) |
title |
字符串 | 问题的标题(例如,"Addition of vectors in Cartesian coordinates")。 (必需;无默认值) |
topic |
字符串 | 问题的类别(例如,"Vectors"、"Energy")。就像教科书上的章节一样。 (必需;无默认值) |
tags |
数组 | 与问题相关的可选额外标签(例如,["secret", "concept"])。 (可选;默认:无标签) |
authors |
数组 | 问题的作者。每个作者条目可以有一个name,并且必须至少包含以下属性之一:email、orcid(ORCID标识符)或originCourse(课程共享名称;详细信息请参阅问题共享)。 (可选;默认:无作者) |
gradingMethod |
枚举 | 用于自动评分此问题的评分方法。有效值:Internal、External 或 Manual(仅适用于手动问题)。 (可选;默认:Internal) |
singleVariant |
布尔 | 问题是否不是随机的并且仅生成单个变体。 (可选;默认值:false) |
showCorrectAnswer |
布尔 | 问题是否应显示答案面板。 (可选;默认值:true) |
partialCredit |
布尔 | 问题是否会给出分数的部分分数。 (可选;默认值:true) |
externalGradingOptions |
对象 | 外部评分问题的选项。请参阅外部评分文档。 (可选;默认值:无) |
dependencies |
对象 | 要加载的外部 JavaScript 或 CSS 依赖项。见下文。 (可选;默认:{}) |
preferences |
对象 | 定义问题首选项 的模式,可以在每次评估时覆盖。 (可选;默认值:无) |
sharePublicly |
布尔 | 该问题是否应该可供任何人预览或在他们的课程中使用 |
shareSourcePublicly |
布尔 | 问题的源码是否应该可用 |
sharingSets |
数组 | 问题所属的共享集 |
!!! note 《地方发展笔记》
每当您在 ZJUI-Learn 的本地副本上编辑问题 `info.json` 文件时,都需要单击“从磁盘加载”以重新加载更改。对 HTML 或 Python 文件的大多数编辑将通过重新加载页面来获取。但是,如果您对问题生成或元素参数进行了更改,您可能还需要生成新的变体。
问题分享¶
任何标有 "shareSourcePublicly": true 的问题都将被考虑并显示为根据 CC-BY-NC 许可证免费使用。任何标有 "sharePublicly": true 的问题都将被考虑并显示为根据 CC-BY-NC-ND 许可证免费使用。问题可以使用共享集私下共享到各个课程,如共享文档 中所述。问题所属的共享集被指定为字符串列表。这些必须与课程配置 中声明的共享集匹配。
{
"sharingSets": ["python-exercises"]
}
问题作者身份¶
ZJUI-Learn 的未来版本可能会提供跟踪共享问题的使用情况的功能。为了确保问题与其原始作者(s) 和课程保持关联,我们建议在 info.json 文件中包含 authors 信息。 orcid 属性特别允许对作者进行唯一标识,即使在更改其隶属关系或电子邮件地址后也是如此。通过提供问题的共享名称,originCourse 属性可用于将问题与课程关联起来。这使得更多的课程工作人员能够被认为对问题做出了贡献,并且可能允许他们在 ZJUI-Learn 的未来版本中跟踪问题的使用情况。
问题依赖性¶
您的问题可以加载客户端资产,例如来自不同来源的脚本或样式表。将根据问题的需求和页面元素所需的任何依赖项编译完整的依赖项列表,然后将它们删除重复并加载到页面上。
这些依赖项在 info.json 文件中指定,并且可以按如下方式配置:
{
"dependencies": {
"nodeModulesScripts": ["three/build/three.min.js"],
"clientFilesQuestionScripts": ["my-question-script.js"],
"clientFilesQuestionStyles": ["my-question-style.css"],
"clientFilesCourseStyles": ["courseStylesheet1.css", "courseStylesheet2.css"]
}
}
下表总结了可用的不同类型的依赖属性:
| 物业 | 描述 |
|---|---|
nodeModulesStyles |
本题所需的样式,相对于[ZJUI-Learn directory]/node_modules。 |
nodeModulesScripts |
该问题所需的脚本,相对于[ZJUI-Learn directory]/node_modules。 |
clientFilesQuestionStyles |
此问题所需的样式相对于问题的 clientFilesQuestion 目录。 |
clientFilesQuestionScripts |
此问题所需的脚本相对于问题的 clientFilesQuestion 目录。 |
clientFilesCourseStyles |
本题要求的样式相对于[course directory]/clientFilesCourse。 |
clientFilesCourseScripts |
此问题所需的脚本与 [course directory]/clientFilesCourse 相关。 |
有关如何从 server.py 访问这些字段的其他详细信息,请参阅 clientFiles 和 serverFiles 文档。
Warning
请记住,应避免节点模块依赖项,因为它们可能会在没有警告的情况下进行更新,这在某些情况下可能会破坏您的问题。更多信息可以在元素开发者指南中找到。
非随机问题¶
虽然建议所有问题都包含随机参数,但有时这样做是不切实际的。对于其中没有有意义的随机化量的问题,info.json 文件应设置 "singleVariant": true。这具有以下效果:
- 在
Homework类型的评估中,每个学生只会得到问题的一种变体,他们可以无限制地重复尝试。正确答案永远不会显示给学生。 - 在
Exam类型的评估中,所有问题实际上都是单变量,因此singleVariant选项没有效果。
部分学分¶
默认情况下,所有问题都会授予部分学分。例如,如果问题中有两个数字答案,而其中只有一个是正确的,则学生将获得可用分数的 50%。
要禁用问题的部分计分,请在问题的 info.json 文件中设置 "partialCredit": false。这意味着问题要么给出 0%,要么给出 100%,并且只有当页面上的每个元素都完全正确时才会给出 100%。一些问题元素还提供了对部分信用更细粒度的控制。
一般来说,强烈建议对所有问题保留部分计分。
Info
请参阅 infoQuestion.json 的参考 以获取所有可用属性及其架构的详尽列表。
HTML (question.html)¶
question.html 是用于向学生呈现问题的模板。完整的 question.html 示例如下所示:
<pl-question-panel>
<p>
A particle of mass $m = {{params.m}}\rm\ kg$ is observed to have acceleration $a =
{{params.a}}\rm\ m/s^2$.
</p>
<p>What is the total force $F$ currently acting on the particle?</p>
</pl-question-panel>
<p>
<pl-number-input
answers-name="F"
comparison="sigfig"
digits="2"
label="$F =$"
suffix="$\rm m/s^2$"
></pl-number-input>
</p>
question.html 是常规 HTML,具有一些特殊功能:
- 双花括号中的任何文本(例如
{{params.m}})都将使用 Mustache 替换为变量值。这些参数通常由问题的server.py定义。 -
特殊的 HTML 元素(如
<pl-number-input>)启用输入和格式化输出。学生提交的内容由他们对问题元素提供的答案组成。请参阅ZJUI-Learn 元素列表。:警告: 所有提交元素必须具有唯一的
answers-name属性。 这是正确对问题进行评分所必需的。 -
特殊的
<markdown>标签允许您在问题中内联编写 Markdown。 - LaTeX 方程可在 HTML 中使用,方法是使用
$x^2$作为内联方程,使用$$x^2$$或\[x^2\]来显示方程。 <pl-question-panel>和<pl-answer-panel>等特殊布局元素可用于在不同上下文中向学生显示内容。
Info
有关这些功能的更多详细信息以及有关 question.html 的信息,请参阅问题模板文档。
定制生成和分级 (server.py)¶
每个问题的 server.py 文件通过生成随机参数和相应的正确答案来创建随机问题变体。最小的 server.py 可以设置随机参数并根据这些参数计算正确答案,同时使用 ZJUI-Learn 元素的内置评分功能对学生提交的内容进行评分。更复杂的问题可以使用 server.py 提供自定义解析和分级功能,或随机图像和文件。
import random
def generate(data):
# Generate random parameters
data["params"]["m"] = random.randint(1, 10)
data["params"]["a"] = random.randint(1, 10)
# Compute the correct answer
data["correct_answers"]["F"] = data["params"]["m"] * data["params"]["a"]
Info
有关 server.py、自定义分级等的更多信息可以在 server.py 文档 中找到。
对学生的答案进行评分¶
pl-multiple-choice 或 pl-checkbox 等元素(不是自由格式答案)会根据元素参数自动评分。对于其他元素,例如 pl-number-input 和 pl-string-input,让学生输入自己选择的答案,有四种不同的方法对学生答案进行自动评分:
-
使用
question.html中每个元素的正确答案属性设置正确答案。这将为每个元素使用内置的评分方法。此选项通常用于具有硬编码值的答案(即,如果info.json中的"singleVariant": true),并且预计不会在大多数随机问题中使用。 -
将
data["correct_answers"][VAR_NAME]设置为server.py。这适用于您可以根据 (randomized) 参数预先计算单个正确答案的问题。 -
在
server.py中编写一个自定义评分函数,用于检查data["submitted_answers"][VAR_NAME]并设置分数。这支持多种替代评分选项,包括拥有多个正确答案、测试提交答案的正确性属性、根据其他元素的值计算某些元素的正确答案等。 -
编写一个外部评分器,尽管这通常适用于更复杂的问题,例如编码。
如果问题使用多种评分方法,选项 3 和 4 会覆盖选项 1 和 2。如果您使用自定义评分功能(选项 3)或外部评分者(选项 4)对问题进行评分,我们仍然强烈建议您提供可能的正确答案,以便学生可以在答案面板中看到它。有关提供学生答案反馈的更多详细信息,请参阅问题模板文档 的 "answer" 面板部分。
无障碍¶
请参阅问题可访问性文档,了解有关如何确保所有学生(包括使用屏幕阅读器或其他辅助技术的学生)都能访问您的问题的更多信息。
自定义模板¶
使用以 template/ 开头的 QID 创建问题将创建一个问题,该问题将在创建问题 时作为模板选项呈现。这应该允许教师创建特定于课程的模式、惯例或评分过程,然后可以被新问题采用。