feat: 初始化考培练系统项目
- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
316
backend/app/schemas/exam.py
Normal file
316
backend/app/schemas/exam.py
Normal file
@@ -0,0 +1,316 @@
|
||||
"""
|
||||
考试相关的Schema定义
|
||||
"""
|
||||
from typing import List, Optional, Dict, Any
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class StartExamRequest(BaseModel):
|
||||
"""开始考试请求"""
|
||||
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
count: int = Field(10, ge=1, le=100, description="题目数量")
|
||||
|
||||
|
||||
class StartExamResponse(BaseModel):
|
||||
"""开始考试响应"""
|
||||
|
||||
exam_id: int = Field(..., description="考试ID")
|
||||
|
||||
|
||||
class ExamAnswer(BaseModel):
|
||||
"""考试答案"""
|
||||
|
||||
question_id: str = Field(..., description="题目ID")
|
||||
answer: str = Field(..., description="答案")
|
||||
|
||||
|
||||
class SubmitExamRequest(BaseModel):
|
||||
"""提交考试请求"""
|
||||
|
||||
exam_id: int = Field(..., description="考试ID")
|
||||
answers: List[ExamAnswer] = Field(..., description="答案列表")
|
||||
|
||||
|
||||
class SubmitExamResponse(BaseModel):
|
||||
"""提交考试响应"""
|
||||
|
||||
exam_id: int = Field(..., description="考试ID")
|
||||
total_score: float = Field(..., description="总分")
|
||||
pass_score: float = Field(..., description="及格分")
|
||||
is_passed: bool = Field(..., description="是否通过")
|
||||
correct_count: int = Field(..., description="正确题数")
|
||||
total_count: int = Field(..., description="总题数")
|
||||
accuracy: float = Field(..., description="正确率")
|
||||
|
||||
|
||||
class QuestionInfo(BaseModel):
|
||||
"""题目信息"""
|
||||
|
||||
id: str = Field(..., description="题目ID")
|
||||
type: str = Field(..., description="题目类型")
|
||||
title: str = Field(..., description="题目标题")
|
||||
content: Optional[str] = Field(None, description="题目内容")
|
||||
options: Optional[Dict[str, Any]] = Field(None, description="选项")
|
||||
score: float = Field(..., description="分值")
|
||||
|
||||
|
||||
class ExamResultInfo(BaseModel):
|
||||
"""答题结果信息"""
|
||||
|
||||
question_id: int = Field(..., description="题目ID")
|
||||
user_answer: Optional[str] = Field(None, description="用户答案")
|
||||
is_correct: bool = Field(..., description="是否正确")
|
||||
score: float = Field(..., description="得分")
|
||||
|
||||
|
||||
class ExamDetailResponse(BaseModel):
|
||||
"""考试详情响应"""
|
||||
|
||||
id: int = Field(..., description="考试ID")
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
exam_name: str = Field(..., description="考试名称")
|
||||
question_count: int = Field(..., description="题目数量")
|
||||
total_score: float = Field(..., description="总分")
|
||||
pass_score: float = Field(..., description="及格分")
|
||||
start_time: Optional[str] = Field(None, description="开始时间")
|
||||
end_time: Optional[str] = Field(None, description="结束时间")
|
||||
duration_minutes: int = Field(..., description="考试时长(分钟)")
|
||||
status: str = Field(..., description="考试状态")
|
||||
score: Optional[float] = Field(None, description="得分")
|
||||
is_passed: Optional[bool] = Field(None, description="是否通过")
|
||||
questions: Optional[Dict[str, Any]] = Field(None, description="题目数据")
|
||||
results: Optional[List[ExamResultInfo]] = Field(None, description="答题结果")
|
||||
answers: Optional[Dict[str, Any]] = Field(None, description="用户答案")
|
||||
|
||||
|
||||
class ExamRecordInfo(BaseModel):
|
||||
"""考试记录信息"""
|
||||
|
||||
id: int = Field(..., description="考试ID")
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
exam_name: str = Field(..., description="考试名称")
|
||||
question_count: int = Field(..., description="题目数量")
|
||||
total_score: float = Field(..., description="总分")
|
||||
score: Optional[float] = Field(None, description="得分")
|
||||
is_passed: Optional[bool] = Field(None, description="是否通过")
|
||||
status: str = Field(..., description="考试状态")
|
||||
start_time: Optional[str] = Field(None, description="开始时间")
|
||||
end_time: Optional[str] = Field(None, description="结束时间")
|
||||
created_at: str = Field(..., description="创建时间")
|
||||
# 新增统计字段
|
||||
accuracy: Optional[float] = Field(None, description="正确率(%)")
|
||||
correct_count: Optional[int] = Field(None, description="正确题数")
|
||||
wrong_count: Optional[int] = Field(None, description="错题数")
|
||||
duration_seconds: Optional[int] = Field(None, description="考试用时(秒)")
|
||||
course_name: Optional[str] = Field(None, description="课程名称")
|
||||
question_type_stats: Optional[List[Dict[str, Any]]] = Field(None, description="分题型统计")
|
||||
|
||||
|
||||
class ExamRecordResponse(BaseModel):
|
||||
"""考试记录列表响应"""
|
||||
|
||||
items: List[ExamRecordInfo] = Field(..., description="考试记录列表")
|
||||
total: int = Field(..., description="总数")
|
||||
page: int = Field(..., description="当前页")
|
||||
size: int = Field(..., description="每页数量")
|
||||
pages: int = Field(..., description="总页数")
|
||||
|
||||
|
||||
# ==================== AI服务响应Schema ====================
|
||||
|
||||
class MistakeRecord(BaseModel):
|
||||
"""错题记录详情"""
|
||||
question_id: Optional[int] = Field(None, description="题目ID")
|
||||
knowledge_point_id: Optional[int] = Field(None, description="知识点ID")
|
||||
question_content: str = Field(..., description="题目内容")
|
||||
correct_answer: str = Field(..., description="正确答案")
|
||||
user_answer: str = Field(..., description="用户答案")
|
||||
|
||||
|
||||
class GenerateExamRequest(BaseModel):
|
||||
"""生成考试试题请求"""
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
position_id: Optional[int] = Field(None, description="岗位ID,如果不提供则从用户信息中自动获取")
|
||||
current_round: int = Field(1, ge=1, le=3, description="当前轮次(1/2/3)")
|
||||
exam_id: Optional[int] = Field(None, description="已存在的exam_id(第2、3轮传入)")
|
||||
mistake_records: Optional[str] = Field(None, description="错题记录JSON字符串,第一轮不传此参数,第二三轮传入上一轮错题的JSON字符串")
|
||||
single_choice_count: int = Field(4, ge=0, le=50, description="单选题数量")
|
||||
multiple_choice_count: int = Field(2, ge=0, le=30, description="多选题数量")
|
||||
true_false_count: int = Field(1, ge=0, le=20, description="判断题数量")
|
||||
fill_blank_count: int = Field(2, ge=0, le=10, description="填空题数量")
|
||||
essay_count: int = Field(1, ge=0, le=10, description="问答题数量")
|
||||
difficulty_level: int = Field(3, ge=1, le=5, description="难度系数(1-5)")
|
||||
|
||||
|
||||
class GenerateExamResponse(BaseModel):
|
||||
"""生成考试试题响应"""
|
||||
result: str = Field(..., description="试题JSON数组(字符串格式)")
|
||||
workflow_run_id: Optional[str] = Field(None, description="AI服务调用ID")
|
||||
task_id: Optional[str] = Field(None, description="任务ID")
|
||||
exam_id: int = Field(..., description="考试ID(真实的数据库ID)")
|
||||
|
||||
|
||||
class JudgeAnswerRequest(BaseModel):
|
||||
"""判断主观题答案请求"""
|
||||
question: str = Field(..., description="题目内容")
|
||||
correct_answer: str = Field(..., description="标准答案")
|
||||
user_answer: str = Field(..., description="用户提交的答案")
|
||||
analysis: str = Field(..., description="正确答案的解析(来源于试题生成器)")
|
||||
|
||||
|
||||
class JudgeAnswerResponse(BaseModel):
|
||||
"""判断主观题答案响应"""
|
||||
is_correct: bool = Field(..., description="是否正确")
|
||||
correct_answer: str = Field(..., description="标准答案")
|
||||
feedback: Optional[str] = Field(None, description="判断反馈信息")
|
||||
|
||||
|
||||
class RecordMistakeRequest(BaseModel):
|
||||
"""记录错题请求"""
|
||||
exam_id: int = Field(..., description="考试ID")
|
||||
question_id: Optional[int] = Field(None, description="题目ID(AI生成的题目可能为空)")
|
||||
knowledge_point_id: Optional[int] = Field(None, description="知识点ID")
|
||||
question_content: str = Field(..., description="题目内容")
|
||||
correct_answer: str = Field(..., description="正确答案")
|
||||
user_answer: str = Field(..., description="用户答案")
|
||||
question_type: Optional[str] = Field(None, description="题型(single/multiple/judge/blank/essay)")
|
||||
|
||||
|
||||
class RecordMistakeResponse(BaseModel):
|
||||
"""记录错题响应"""
|
||||
id: int = Field(..., description="错题记录ID")
|
||||
created_at: datetime = Field(..., description="创建时间")
|
||||
|
||||
|
||||
class MistakeRecordItem(BaseModel):
|
||||
"""错题记录项"""
|
||||
id: int = Field(..., description="错题记录ID")
|
||||
question_id: Optional[int] = Field(None, description="题目ID")
|
||||
knowledge_point_id: Optional[int] = Field(None, description="知识点ID")
|
||||
question_content: str = Field(..., description="题目内容")
|
||||
correct_answer: str = Field(..., description="正确答案")
|
||||
user_answer: str = Field(..., description="用户答案")
|
||||
created_at: datetime = Field(..., description="创建时间")
|
||||
|
||||
|
||||
class GetMistakesResponse(BaseModel):
|
||||
"""获取错题记录响应"""
|
||||
mistakes: List[MistakeRecordItem] = Field(..., description="错题列表")
|
||||
|
||||
|
||||
# ==================== 成绩报告和错题本相关Schema ====================
|
||||
|
||||
class RoundScores(BaseModel):
|
||||
"""三轮得分"""
|
||||
round1: Optional[float] = Field(None, description="第一轮得分")
|
||||
round2: Optional[float] = Field(None, description="第二轮得分")
|
||||
round3: Optional[float] = Field(None, description="第三轮得分")
|
||||
|
||||
|
||||
class ExamReportOverview(BaseModel):
|
||||
"""成绩报告概览"""
|
||||
avg_score: float = Field(..., description="平均成绩(基于round1_score)")
|
||||
total_exams: int = Field(..., description="考试总数")
|
||||
pass_rate: float = Field(..., description="及格率")
|
||||
total_questions: int = Field(..., description="答题总数")
|
||||
|
||||
|
||||
class ExamTrendItem(BaseModel):
|
||||
"""成绩趋势项"""
|
||||
date: str = Field(..., description="日期(YYYY-MM-DD)")
|
||||
avg_score: float = Field(..., description="平均分")
|
||||
|
||||
|
||||
class SubjectStatItem(BaseModel):
|
||||
"""科目统计项"""
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
course_name: str = Field(..., description="课程名称")
|
||||
avg_score: float = Field(..., description="平均分")
|
||||
exam_count: int = Field(..., description="考试次数")
|
||||
max_score: float = Field(..., description="最高分")
|
||||
min_score: float = Field(..., description="最低分")
|
||||
pass_rate: float = Field(..., description="及格率")
|
||||
|
||||
|
||||
class RecentExamItem(BaseModel):
|
||||
"""最近考试记录项"""
|
||||
id: int = Field(..., description="考试ID")
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
course_name: str = Field(..., description="课程名称")
|
||||
score: Optional[float] = Field(None, description="最终得分")
|
||||
total_score: float = Field(..., description="总分")
|
||||
is_passed: Optional[bool] = Field(None, description="是否通过")
|
||||
duration_seconds: Optional[int] = Field(None, description="考试用时(秒)")
|
||||
start_time: str = Field(..., description="开始时间")
|
||||
end_time: Optional[str] = Field(None, description="结束时间")
|
||||
round_scores: RoundScores = Field(..., description="三轮得分")
|
||||
|
||||
|
||||
class ExamReportResponse(BaseModel):
|
||||
"""成绩报告响应"""
|
||||
overview: ExamReportOverview = Field(..., description="概览数据")
|
||||
trends: List[ExamTrendItem] = Field(..., description="趋势数据")
|
||||
subjects: List[SubjectStatItem] = Field(..., description="科目分析")
|
||||
recent_exams: List[RecentExamItem] = Field(..., description="最近考试记录")
|
||||
|
||||
|
||||
class MistakeListItem(BaseModel):
|
||||
"""错题列表项"""
|
||||
id: int = Field(..., description="错题记录ID")
|
||||
exam_id: int = Field(..., description="考试ID")
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
course_name: str = Field(..., description="课程名称")
|
||||
question_content: str = Field(..., description="题目内容")
|
||||
correct_answer: str = Field(..., description="正确答案")
|
||||
user_answer: str = Field(..., description="用户答案")
|
||||
question_type: Optional[str] = Field(None, description="题型")
|
||||
knowledge_point_id: Optional[int] = Field(None, description="知识点ID")
|
||||
knowledge_point_name: Optional[str] = Field(None, description="知识点名称")
|
||||
created_at: datetime = Field(..., description="创建时间")
|
||||
|
||||
|
||||
class MistakeListResponse(BaseModel):
|
||||
"""错题列表响应"""
|
||||
items: List[MistakeListItem] = Field(..., description="错题列表")
|
||||
total: int = Field(..., description="总数")
|
||||
page: int = Field(..., description="当前页")
|
||||
size: int = Field(..., description="每页数量")
|
||||
pages: int = Field(..., description="总页数")
|
||||
|
||||
|
||||
class MistakeByCourse(BaseModel):
|
||||
"""按课程统计错题"""
|
||||
course_id: int = Field(..., description="课程ID")
|
||||
course_name: str = Field(..., description="课程名称")
|
||||
count: int = Field(..., description="错题数量")
|
||||
|
||||
|
||||
class MistakeByType(BaseModel):
|
||||
"""按题型统计错题"""
|
||||
type: str = Field(..., description="题型代码")
|
||||
type_name: str = Field(..., description="题型名称")
|
||||
count: int = Field(..., description="错题数量")
|
||||
|
||||
|
||||
class MistakeByTime(BaseModel):
|
||||
"""按时间统计错题"""
|
||||
week: int = Field(..., description="最近一周")
|
||||
month: int = Field(..., description="最近一月")
|
||||
quarter: int = Field(..., description="最近三月")
|
||||
|
||||
|
||||
class MistakesStatisticsResponse(BaseModel):
|
||||
"""错题统计响应"""
|
||||
total: int = Field(..., description="错题总数")
|
||||
by_course: List[MistakeByCourse] = Field(..., description="按课程统计")
|
||||
by_type: List[MistakeByType] = Field(..., description="按题型统计")
|
||||
by_time: MistakeByTime = Field(..., description="按时间统计")
|
||||
|
||||
|
||||
class UpdateRoundScoreRequest(BaseModel):
|
||||
"""更新轮次得分请求"""
|
||||
round: int = Field(..., ge=1, le=3, description="轮次(1/2/3)")
|
||||
score: float = Field(..., ge=0, le=100, description="得分")
|
||||
is_final: bool = Field(False, description="是否为最终轮次(如果是,则同时更新总分和状态)")
|
||||
Reference in New Issue
Block a user