""" 用户课程学习进度数据库模型 """ from enum import Enum from typing import Optional from datetime import datetime from sqlalchemy import ( String, Integer, Boolean, ForeignKey, Float, DateTime, UniqueConstraint, Index, ) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import BaseModel class ProgressStatus(str, Enum): """学习进度状态枚举""" NOT_STARTED = "not_started" # 未开始 IN_PROGRESS = "in_progress" # 学习中 COMPLETED = "completed" # 已完成 class UserCourseProgress(BaseModel): """ 用户课程进度表 记录用户对每门课程的整体学习进度 """ __tablename__ = "user_course_progress" __table_args__ = ( UniqueConstraint("user_id", "course_id", name="uq_user_course"), Index("idx_user_course_progress_user", "user_id"), Index("idx_user_course_progress_course", "course_id"), Index("idx_user_course_progress_status", "status"), ) user_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, comment="用户ID", ) course_id: Mapped[int] = mapped_column( Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, comment="课程ID", ) # 进度信息 status: Mapped[ProgressStatus] = mapped_column( String(20), default=ProgressStatus.NOT_STARTED.value, nullable=False, comment="学习状态:not_started/in_progress/completed", ) progress_percent: Mapped[float] = mapped_column( Float, default=0.0, nullable=False, comment="完成百分比(0-100)", ) completed_materials: Mapped[int] = mapped_column( Integer, default=0, nullable=False, comment="已完成资料数", ) total_materials: Mapped[int] = mapped_column( Integer, default=0, nullable=False, comment="总资料数", ) # 学习时长统计 total_study_time: Mapped[int] = mapped_column( Integer, default=0, nullable=False, comment="总学习时长(秒)", ) # 时间记录 first_accessed_at: Mapped[Optional[datetime]] = mapped_column( DateTime, nullable=True, comment="首次访问时间", ) last_accessed_at: Mapped[Optional[datetime]] = mapped_column( DateTime, nullable=True, comment="最后访问时间", ) completed_at: Mapped[Optional[datetime]] = mapped_column( DateTime, nullable=True, comment="完成时间", ) # 关联关系 user = relationship("User", backref="course_progress") course = relationship("Course", backref="user_progress") class UserMaterialProgress(BaseModel): """ 用户资料进度表 记录用户对每个课程资料的学习进度 """ __tablename__ = "user_material_progress" __table_args__ = ( UniqueConstraint("user_id", "material_id", name="uq_user_material"), Index("idx_user_material_progress_user", "user_id"), Index("idx_user_material_progress_material", "material_id"), ) user_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, comment="用户ID", ) material_id: Mapped[int] = mapped_column( Integer, ForeignKey("course_materials.id", ondelete="CASCADE"), nullable=False, comment="资料ID", ) course_id: Mapped[int] = mapped_column( Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, comment="课程ID(冗余字段,便于查询)", ) # 进度信息 is_completed: Mapped[bool] = mapped_column( Boolean, default=False, nullable=False, comment="是否已完成", ) progress_percent: Mapped[float] = mapped_column( Float, default=0.0, nullable=False, comment="阅读/播放进度百分比(0-100)", ) # 视频/音频特有字段 last_position: Mapped[int] = mapped_column( Integer, default=0, nullable=False, comment="上次播放位置(秒)", ) total_duration: Mapped[int] = mapped_column( Integer, default=0, nullable=False, comment="媒体总时长(秒)", ) # 学习时长 study_time: Mapped[int] = mapped_column( Integer, default=0, nullable=False, comment="学习时长(秒)", ) # 时间记录 first_accessed_at: Mapped[Optional[datetime]] = mapped_column( DateTime, nullable=True, comment="首次访问时间", ) last_accessed_at: Mapped[Optional[datetime]] = mapped_column( DateTime, nullable=True, comment="最后访问时间", ) completed_at: Mapped[Optional[datetime]] = mapped_column( DateTime, nullable=True, comment="完成时间", ) # 关联关系 user = relationship("User", backref="material_progress") material = relationship("CourseMaterial", backref="user_progress") course = relationship("Course", backref="material_user_progress")