assessment-generate
约 1686 字大约 6 分钟
2025-10-09
概述
assessment-create 是一个基于 Deno 和 Supabase 的智能组卷 API。它允许学生根据特定的规则从题库中抽取题目创建测试,支持按题型、难度、知识点等多种条件进行组卷,并自动处理尝试次数限制和答案管理。
接口定义
AssessmentCreateRequest 接口
interface AssessmentCreateRequest {
question_bank_id: string; // 题库ID
title: string; // 测试标题
created_by: string; // 学生ID
rules: AssessmentRule[]; // 组卷规则数组
}AssessmentRule 接口
单条组卷规则的详细定义。
interface AssessmentRule {
type?: "single_choice" | "multiple_choice" | "true_false" | "subjective";
difficulty?: "easy" | "medium" | "hard";
knowledge_point_ids?: string[]; // 知识点ID数组
count: number; // 题目数量
}核心函数详解
validateAssessmentRequest
功能: 验证组卷请求的合法性
参数:
body: unknown- 待验证的请求体
返回值: AssessmentCreateRequest - 验证通过的请求对象
验证规则:
- 必填字段检查:
question_bank_id,title,created_by,rules - 规则数组非空检查
- 每条规则的字段完整性检查
- 数量有效性检查: 必须大于0的数字
- 题型有效性检查(如果提供):
single_choice,multiple_choice,true_false,subjective - 难度有效性检查(如果提供):
easy,medium,hard - 知识点ID数组检查(如果提供): 必须是非空数组
抛出错误:
- 缺少必填字段时抛出详细错误信息
- 规则格式错误时提供具体位置和原因
checkAttemptLimit
功能: 检查学生的测试尝试次数并返回下一次尝试编号
参数:
supabase: any- Supabase 客户端实例student_id: string- 学生IDquestion_bank_id: string- 题库ID
返回值: Promise<number> - 下一次尝试的编号
实现细节:
- 调用 Supabase RPC 函数
check_assessment_attempts - 检查学生在该题库下的尝试次数限制
- 返回下一次允许的尝试编号
数据库函数要求:
CREATE OR REPLACE FUNCTION check_assessment_attempts(
p_student_id UUID,
p_question_bank_id UUID
)
RETURNS JSONB错误处理:
- RPC调用失败时抛出错误
- 尝试次数超限时返回具体错误信息
selectQuestions
功能: 根据组卷规则从题库中抽取题目
参数:
supabase: any- Supabase 客户端实例question_bank_id: string- 题库IDrules: AssessmentRule[]- 组卷规则数组
返回值: Promise<any[]> - 抽取的题目列表
实现细节:
- 调用 Supabase RPC 函数
select_questions_by_rules - 根据规则进行智能抽题
- 返回不包含答案的题目信息
数据库函数要求:
CREATE OR REPLACE FUNCTION select_questions_by_rules(
p_question_bank_id UUID,
p_rules JSONB[]
)
RETURNS SETOF questions错误处理:
- 抽题失败时抛出错误
- 无可用题目时提供友好提示
createAssessmentRecord
功能: 创建学生测试记录
参数:
supabase: any- Supabase 客户端实例question_bank_id: string- 题库IDstudent_id: string- 学生IDtitle: string- 测试标题question_ids: string[]- 题目ID数组attempt_number: number- 尝试编号
返回值: Promise<any> - 创建的测试记录
实现细节:
- 调用 Supabase RPC 函数
create_student_assessment - 创建测试记录并关联题目
- 记录尝试编号和时间戳
数据库函数要求:
CREATE OR REPLACE FUNCTION create_student_assessment(
p_question_bank_id UUID,
p_student_id UUID,
p_title TEXT,
p_question_ids UUID[],
p_attempt_number INTEGER
)
RETURNS assessmentsgetQuestionAnswers
功能: 获取题目答案信息
参数:
supabase: any- Supabase 客户端实例question_ids: string[]- 题目ID数组requester_id: string- 请求者ID(用于权限检查)
返回值: Promise<any[]> - 题目答案列表
实现细节:
- 调用 Supabase RPC 函数
get_question_answers - 根据权限返回答案信息
- 支持答案的权限控制
数据库函数要求:
CREATE OR REPLACE FUNCTION get_question_answers(
p_question_ids UUID[],
p_requester_id UUID
)
RETURNS TABLE(id UUID, correct_answers JSONB)主处理函数
Deno.serve
功能: 处理HTTP请求的主入口点
支持的HTTP方法: POST
处理流程:
- 处理CORS预检请求
- 验证请求方法
- 解析和验证请求体
- 检查尝试次数限制
- 执行智能抽题
- 创建测试记录
- 获取题目答案
- 合并题目和答案信息
- 返回成功响应
使用示例
请求示例
curl -X POST https://your-domain.com/functions/v1/assessment-create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_SUPABASE_TOKEN" \
-d '{
"question_bank_id": "math-bank-001",
"title": "期中数学测试",
"created_by": "student-123",
"rules": [
{
"type": "single_choice",
"difficulty": "easy",
"knowledge_point_ids": ["kp-algebra-001", "kp-algebra-002"],
"count": 5
},
{
"type": "multiple_choice",
"difficulty": "medium",
"count": 3
},
{
"type": "true_false",
"difficulty": "hard",
"count": 2
}
]
}'成功响应示例
{
"success": true,
"message": "测试创建成功",
"data": {
"assessment": {
"id": "assessment-001",
"question_bank_id": "math-bank-001",
"student_id": "student-123",
"title": "期中数学测试",
"attempt_number": 1,
"created_at": "2024-01-01T00:00:00.000Z",
"status": "in_progress"
},
"questions": [
{
"id": "question-001",
"type": "single_choice",
"title": "二次函数求解",
"content": "求函数 f(x) = x² - 4x + 3 的零点",
"options": {
"A": "x=1, x=3",
"B": "x=2, x=3",
"C": "x=1, x=4",
"D": "x=2, x=4"
},
"difficulty": "easy",
"points": 1,
"correct_answers": ["A"],
"explanation": "通过因式分解可得 f(x) = (x-1)(x-3),所以零点为 x=1 和 x=3"
},
// ... 其他题目
]
}
}错误响应示例
{
"success": false,
"error": "尝试次数超限,每个学生最多允许3次尝试",
"code": "ATTEMPT_LIMIT_EXCEEDED"
}错误处理
验证错误 (400)
- 缺少必填字段
- 规则格式错误
- 无效的题型或难度
业务错误 (400)
- 尝试次数超限
- 无可用题目
- 权限不足
系统错误 (500)
- 数据库操作失败
- RPC函数调用失败
- 网络连接错误
错误代码
VALIDATION_ERROR: 请求验证失败ATTEMPT_LIMIT_EXCEEDED: 尝试次数超限NO_QUESTIONS_AVAILABLE: 无可用题目PERMISSION_DENIED: 权限不足DB_ERROR: 数据库操作失败
数据库设计
assessments 表
CREATE TABLE assessments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
question_bank_id UUID REFERENCES question_banks(id),
student_id UUID REFERENCES students(id),
title TEXT NOT NULL,
attempt_number INTEGER NOT NULL,
status TEXT DEFAULT 'in_progress',
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(question_bank_id, student_id, attempt_number)
);assessment_questions 表
CREATE TABLE assessment_questions (
assessment_id UUID REFERENCES assessments(id),
question_id UUID REFERENCES questions(id),
question_order INTEGER,
PRIMARY KEY (assessment_id, question_id)
);权限控制
答案访问控制
- 只有测试创建者可以查看答案
- 支持基于角色的答案访问控制
- 防止未授权访问正确答案
尝试次数限制
- 每个学生在每个题库下有最大尝试次数
- 防止滥用测试功能
- 支持灵活的尝试次数配置
最佳实践
前端集成示例
// 创建测试
async function createAssessment(assessmentData) {
try {
const response = await fetch('/assessment-create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getAccessToken()}`
},
body: JSON.stringify(assessmentData)
});
const result = await response.json();
if (result.success) {
return result.data;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('创建测试失败:', error);
throw error;
}
}
// 使用示例
const assessment = await createAssessment({
question_bank_id: 'math-bank-001',
title: '我的数学测试',
created_by: 'student-123',
rules: [
{
type: 'single_choice',
difficulty: 'easy',
count: 5
}
]
});错误处理
// 错误处理示例
try {
const assessment = await createAssessment(assessmentData);
} catch (error) {
if (error.message.includes('尝试次数')) {
// 处理尝试次数超限
showAlert('您已达到最大尝试次数');
} else if (error.message.includes('无可用题目')) {
// 处理无可用题目
showAlert('题库中没有足够的题目,请联系老师');
} else {
// 处理其他错误
showAlert('创建测试失败,请重试');
}
}安全考虑
- 身份验证: 依赖 Supabase JWT 认证
- 权限控制: 严格的答案访问控制
- 输入验证: 全面的请求参数验证
- 尝试限制: 防止滥用和刷题
版权所有
版权归属:Evoliant
许可证:MIT