All checks were successful
continuous-integration/drone/push Build is passing
- 新增数据库表: growth_path_nodes, user_growth_path_progress, user_node_completions - 新增 Model: GrowthPathNode, UserGrowthPathProgress, UserNodeCompletion - 新增 Service: GrowthPathService(管理端CRUD、学员端进度追踪) - 新增 API: 学员端获取成长路径、管理端CRUD - 前端学员端从API动态加载成长路径数据 - 更新管理端API接口定义
207 lines
6.2 KiB
Python
207 lines
6.2 KiB
Python
"""
|
|
成长路径相关数据库模型
|
|
"""
|
|
from enum import Enum
|
|
from typing import List, Optional
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
|
|
from sqlalchemy import (
|
|
String,
|
|
Text,
|
|
Integer,
|
|
Boolean,
|
|
ForeignKey,
|
|
Enum as SQLEnum,
|
|
JSON,
|
|
DateTime,
|
|
DECIMAL,
|
|
)
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.models.base import BaseModel, SoftDeleteMixin
|
|
|
|
|
|
class GrowthPathStatus(str, Enum):
|
|
"""成长路径学习状态"""
|
|
NOT_STARTED = "not_started" # 未开始
|
|
IN_PROGRESS = "in_progress" # 进行中
|
|
COMPLETED = "completed" # 已完成
|
|
|
|
|
|
class NodeStatus(str, Enum):
|
|
"""节点状态"""
|
|
LOCKED = "locked" # 锁定(前置未完成)
|
|
UNLOCKED = "unlocked" # 已解锁(可以开始)
|
|
IN_PROGRESS = "in_progress" # 学习中
|
|
COMPLETED = "completed" # 已完成
|
|
|
|
|
|
class GrowthPathNode(BaseModel, SoftDeleteMixin):
|
|
"""
|
|
成长路径节点表
|
|
每个节点对应一门课程
|
|
"""
|
|
__tablename__ = "growth_path_nodes"
|
|
|
|
# 关联
|
|
growth_path_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("growth_paths.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="成长路径ID"
|
|
)
|
|
course_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("courses.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="课程ID"
|
|
)
|
|
|
|
# 节点信息
|
|
stage_name: Mapped[Optional[str]] = mapped_column(
|
|
String(100), nullable=True, comment="所属阶段名称"
|
|
)
|
|
title: Mapped[str] = mapped_column(
|
|
String(200), nullable=False, comment="节点标题"
|
|
)
|
|
description: Mapped[Optional[str]] = mapped_column(
|
|
Text, nullable=True, comment="节点描述"
|
|
)
|
|
|
|
# 配置
|
|
order_num: Mapped[int] = mapped_column(
|
|
Integer, default=0, nullable=False, comment="排序顺序"
|
|
)
|
|
is_required: Mapped[bool] = mapped_column(
|
|
Boolean, default=True, nullable=False, comment="是否必修"
|
|
)
|
|
prerequisites: Mapped[Optional[List[int]]] = mapped_column(
|
|
JSON, nullable=True, comment="前置节点IDs"
|
|
)
|
|
estimated_days: Mapped[int] = mapped_column(
|
|
Integer, default=7, nullable=False, comment="预计学习天数"
|
|
)
|
|
|
|
# 关联关系
|
|
growth_path: Mapped["GrowthPath"] = relationship(
|
|
"GrowthPath", back_populates="nodes"
|
|
)
|
|
course: Mapped["Course"] = relationship("Course")
|
|
user_completions: Mapped[List["UserNodeCompletion"]] = relationship(
|
|
"UserNodeCompletion", back_populates="node"
|
|
)
|
|
|
|
|
|
class UserGrowthPathProgress(BaseModel):
|
|
"""
|
|
用户成长路径进度表
|
|
记录用户在某条成长路径上的整体进度
|
|
"""
|
|
__tablename__ = "user_growth_path_progress"
|
|
|
|
# 关联
|
|
user_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("users.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="用户ID"
|
|
)
|
|
growth_path_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("growth_paths.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="成长路径ID"
|
|
)
|
|
|
|
# 进度信息
|
|
current_node_id: Mapped[Optional[int]] = mapped_column(
|
|
Integer, nullable=True, comment="当前学习节点ID"
|
|
)
|
|
completed_node_ids: Mapped[Optional[List[int]]] = mapped_column(
|
|
JSON, nullable=True, comment="已完成节点IDs"
|
|
)
|
|
total_progress: Mapped[Decimal] = mapped_column(
|
|
DECIMAL(5, 2), default=0.00, nullable=False, comment="总进度百分比"
|
|
)
|
|
|
|
# 状态
|
|
status: Mapped[str] = mapped_column(
|
|
String(20),
|
|
default=GrowthPathStatus.NOT_STARTED.value,
|
|
nullable=False,
|
|
comment="状态"
|
|
)
|
|
|
|
# 时间记录
|
|
started_at: Mapped[Optional[datetime]] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, comment="开始时间"
|
|
)
|
|
completed_at: Mapped[Optional[datetime]] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, comment="完成时间"
|
|
)
|
|
last_activity_at: Mapped[Optional[datetime]] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, comment="最后活动时间"
|
|
)
|
|
|
|
# 关联关系
|
|
user: Mapped["User"] = relationship("User")
|
|
growth_path: Mapped["GrowthPath"] = relationship("GrowthPath")
|
|
|
|
|
|
class UserNodeCompletion(BaseModel):
|
|
"""
|
|
用户节点完成记录表
|
|
详细记录用户在每个节点上的学习状态
|
|
"""
|
|
__tablename__ = "user_node_completions"
|
|
|
|
# 关联
|
|
user_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("users.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="用户ID"
|
|
)
|
|
growth_path_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("growth_paths.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="成长路径ID"
|
|
)
|
|
node_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("growth_path_nodes.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="节点ID"
|
|
)
|
|
|
|
# 进度信息
|
|
course_progress: Mapped[Decimal] = mapped_column(
|
|
DECIMAL(5, 2), default=0.00, nullable=False, comment="课程学习进度"
|
|
)
|
|
status: Mapped[str] = mapped_column(
|
|
String(20),
|
|
default=NodeStatus.LOCKED.value,
|
|
nullable=False,
|
|
comment="状态"
|
|
)
|
|
|
|
# 时间记录
|
|
unlocked_at: Mapped[Optional[datetime]] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, comment="解锁时间"
|
|
)
|
|
started_at: Mapped[Optional[datetime]] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, comment="开始学习时间"
|
|
)
|
|
completed_at: Mapped[Optional[datetime]] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, comment="完成时间"
|
|
)
|
|
|
|
# 关联关系
|
|
user: Mapped["User"] = relationship("User")
|
|
node: Mapped["GrowthPathNode"] = relationship(
|
|
"GrowthPathNode", back_populates="user_completions"
|
|
)
|
|
growth_path: Mapped["GrowthPath"] = relationship("GrowthPath")
|