Files
012-kaopeilian/backend/app/api/v1/statistics.py
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

239 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
统计分析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)}"
)