feat: 初始化考培练系统项目
- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
238
backend/app/api/v1/statistics.py
Normal file
238
backend/app/api/v1/statistics.py
Normal file
@@ -0,0 +1,238 @@
|
||||
"""
|
||||
统计分析API路由
|
||||
"""
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import get_db, get_current_user
|
||||
from app.models.user import User
|
||||
from app.schemas.base import ResponseModel
|
||||
from app.services.statistics_service import StatisticsService
|
||||
from app.core.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
router = APIRouter(prefix="/statistics", tags=["statistics"])
|
||||
|
||||
|
||||
@router.get("/key-metrics", response_model=ResponseModel)
|
||||
async def get_key_metrics(
|
||||
course_id: Optional[int] = Query(None, description="课程ID,不传则统计全部课程"),
|
||||
period: str = Query("month", description="时间范围: week/month/quarter/halfYear/year"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
获取关键指标
|
||||
|
||||
返回:
|
||||
- learningEfficiency: 学习效率
|
||||
- knowledgeCoverage: 知识覆盖率
|
||||
- avgTimePerQuestion: 平均用时
|
||||
- progressSpeed: 进步速度
|
||||
"""
|
||||
try:
|
||||
metrics = await StatisticsService.get_key_metrics(
|
||||
db=db,
|
||||
user_id=current_user.id,
|
||||
course_id=course_id,
|
||||
period=period
|
||||
)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="获取关键指标成功",
|
||||
data=metrics
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"获取关键指标失败: {e}", exc_info=True)
|
||||
return ResponseModel(
|
||||
code=500,
|
||||
message=f"获取关键指标失败: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/score-distribution", response_model=ResponseModel)
|
||||
async def get_score_distribution(
|
||||
course_id: Optional[int] = Query(None, description="课程ID,不传则统计全部课程"),
|
||||
period: str = Query("month", description="时间范围: week/month/quarter/halfYear/year"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
获取成绩分布统计
|
||||
|
||||
返回各分数段的考试数量:
|
||||
- excellent: 优秀(90-100)
|
||||
- good: 良好(80-89)
|
||||
- medium: 中等(70-79)
|
||||
- pass: 及格(60-69)
|
||||
- fail: 不及格(<60)
|
||||
"""
|
||||
try:
|
||||
distribution = await StatisticsService.get_score_distribution(
|
||||
db=db,
|
||||
user_id=current_user.id,
|
||||
course_id=course_id,
|
||||
period=period
|
||||
)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="获取成绩分布成功",
|
||||
data=distribution
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"获取成绩分布失败: {e}", exc_info=True)
|
||||
return ResponseModel(
|
||||
code=500,
|
||||
message=f"获取成绩分布失败: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/difficulty-analysis", response_model=ResponseModel)
|
||||
async def get_difficulty_analysis(
|
||||
course_id: Optional[int] = Query(None, description="课程ID,不传则统计全部课程"),
|
||||
period: str = Query("month", description="时间范围: week/month/quarter/halfYear/year"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
获取题目难度分析
|
||||
|
||||
返回各难度题目的正确率:
|
||||
- 简单题
|
||||
- 中等题
|
||||
- 困难题
|
||||
- 综合题
|
||||
- 应用题
|
||||
"""
|
||||
try:
|
||||
analysis = await StatisticsService.get_difficulty_analysis(
|
||||
db=db,
|
||||
user_id=current_user.id,
|
||||
course_id=course_id,
|
||||
period=period
|
||||
)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="获取难度分析成功",
|
||||
data=analysis
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"获取难度分析失败: {e}", exc_info=True)
|
||||
return ResponseModel(
|
||||
code=500,
|
||||
message=f"获取难度分析失败: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/knowledge-mastery", response_model=ResponseModel)
|
||||
async def get_knowledge_mastery(
|
||||
course_id: Optional[int] = Query(None, description="课程ID,不传则统计全部课程"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
获取知识点掌握度
|
||||
|
||||
返回知识点列表及其掌握度:
|
||||
- name: 知识点名称
|
||||
- mastery: 掌握度(0-100)
|
||||
"""
|
||||
try:
|
||||
mastery = await StatisticsService.get_knowledge_mastery(
|
||||
db=db,
|
||||
user_id=current_user.id,
|
||||
course_id=course_id
|
||||
)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="获取知识点掌握度成功",
|
||||
data=mastery
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"获取知识点掌握度失败: {e}", exc_info=True)
|
||||
return ResponseModel(
|
||||
code=500,
|
||||
message=f"获取知识点掌握度失败: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/study-time", response_model=ResponseModel)
|
||||
async def get_study_time_stats(
|
||||
course_id: Optional[int] = Query(None, description="课程ID,不传则统计全部课程"),
|
||||
period: str = Query("month", description="时间范围: week/month/quarter/halfYear/year"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
获取学习时长统计
|
||||
|
||||
返回学习时长和练习时长的日期分布:
|
||||
- labels: 日期标签列表
|
||||
- studyTime: 学习时长列表(小时)
|
||||
- practiceTime: 练习时长列表(小时)
|
||||
"""
|
||||
try:
|
||||
time_stats = await StatisticsService.get_study_time_stats(
|
||||
db=db,
|
||||
user_id=current_user.id,
|
||||
course_id=course_id,
|
||||
period=period
|
||||
)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="获取学习时长统计成功",
|
||||
data=time_stats
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"获取学习时长统计失败: {e}", exc_info=True)
|
||||
return ResponseModel(
|
||||
code=500,
|
||||
message=f"获取学习时长统计失败: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/detail", response_model=ResponseModel)
|
||||
async def get_detail_data(
|
||||
course_id: Optional[int] = Query(None, description="课程ID,不传则统计全部课程"),
|
||||
period: str = Query("month", description="时间范围: week/month/quarter/halfYear/year"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
获取详细统计数据(按日期)
|
||||
|
||||
返回每日详细统计数据:
|
||||
- date: 日期
|
||||
- examCount: 考试次数
|
||||
- avgScore: 平均分
|
||||
- studyTime: 学习时长(小时)
|
||||
- questionCount: 练习题数
|
||||
- accuracy: 正确率
|
||||
- improvement: 进步指数
|
||||
"""
|
||||
try:
|
||||
detail = await StatisticsService.get_detail_data(
|
||||
db=db,
|
||||
user_id=current_user.id,
|
||||
course_id=course_id,
|
||||
period=period
|
||||
)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="获取详细数据成功",
|
||||
data=detail
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"获取详细数据失败: {e}", exc_info=True)
|
||||
return ResponseModel(
|
||||
code=500,
|
||||
message=f"获取详细数据失败: {str(e)}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user