feat: 初始化考培练系统项目
- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
270
backend/app/models/course.py
Normal file
270
backend/app/models/course.py
Normal file
@@ -0,0 +1,270 @@
|
||||
"""
|
||||
课程相关数据库模型
|
||||
"""
|
||||
from enum import Enum
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import (
|
||||
String,
|
||||
Text,
|
||||
Integer,
|
||||
Boolean,
|
||||
ForeignKey,
|
||||
Enum as SQLEnum,
|
||||
Float,
|
||||
JSON,
|
||||
DateTime,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.models.base import BaseModel, SoftDeleteMixin, AuditMixin
|
||||
|
||||
|
||||
class CourseStatus(str, Enum):
|
||||
"""课程状态枚举"""
|
||||
|
||||
DRAFT = "draft" # 草稿
|
||||
PUBLISHED = "published" # 已发布
|
||||
ARCHIVED = "archived" # 已归档
|
||||
|
||||
|
||||
class CourseCategory(str, Enum):
|
||||
"""课程分类枚举"""
|
||||
|
||||
TECHNOLOGY = "technology" # 技术
|
||||
MANAGEMENT = "management" # 管理
|
||||
BUSINESS = "business" # 业务
|
||||
GENERAL = "general" # 通用
|
||||
|
||||
|
||||
class Course(BaseModel, SoftDeleteMixin, AuditMixin):
|
||||
"""
|
||||
课程表
|
||||
"""
|
||||
|
||||
__tablename__ = "courses"
|
||||
|
||||
# 基本信息
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False, comment="课程名称")
|
||||
description: Mapped[Optional[str]] = mapped_column(
|
||||
Text, nullable=True, comment="课程描述"
|
||||
)
|
||||
category: Mapped[CourseCategory] = mapped_column(
|
||||
SQLEnum(
|
||||
CourseCategory,
|
||||
values_callable=lambda enum_cls: [e.value for e in enum_cls],
|
||||
validate_strings=True,
|
||||
),
|
||||
default=CourseCategory.GENERAL,
|
||||
nullable=False,
|
||||
comment="课程分类",
|
||||
)
|
||||
status: Mapped[CourseStatus] = mapped_column(
|
||||
SQLEnum(
|
||||
CourseStatus,
|
||||
values_callable=lambda enum_cls: [e.value for e in enum_cls],
|
||||
validate_strings=True,
|
||||
),
|
||||
default=CourseStatus.DRAFT,
|
||||
nullable=False,
|
||||
comment="课程状态",
|
||||
)
|
||||
|
||||
# 课程详情
|
||||
cover_image: Mapped[Optional[str]] = mapped_column(
|
||||
String(500), nullable=True, comment="封面图片URL"
|
||||
)
|
||||
duration_hours: Mapped[Optional[float]] = mapped_column(
|
||||
Float, nullable=True, comment="课程时长(小时)"
|
||||
)
|
||||
difficulty_level: Mapped[Optional[int]] = mapped_column(
|
||||
Integer, nullable=True, comment="难度等级(1-5)"
|
||||
)
|
||||
tags: Mapped[Optional[List[str]]] = mapped_column(
|
||||
JSON, nullable=True, comment="标签列表"
|
||||
)
|
||||
|
||||
# 发布信息
|
||||
published_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True, comment="发布时间"
|
||||
)
|
||||
publisher_id: Mapped[Optional[int]] = mapped_column(
|
||||
Integer, nullable=True, comment="发布人ID"
|
||||
)
|
||||
|
||||
# 播课信息
|
||||
# 播课功能(Coze工作流直接写数据库)
|
||||
broadcast_audio_url: Mapped[Optional[str]] = mapped_column(
|
||||
String(500), nullable=True, comment="播课音频URL"
|
||||
)
|
||||
broadcast_generated_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True, comment="播课生成时间"
|
||||
)
|
||||
|
||||
# 排序和权重
|
||||
sort_order: Mapped[int] = mapped_column(
|
||||
Integer, default=0, nullable=False, comment="排序顺序"
|
||||
)
|
||||
is_featured: Mapped[bool] = mapped_column(
|
||||
Boolean, default=False, nullable=False, comment="是否推荐"
|
||||
)
|
||||
|
||||
# 统计信息
|
||||
student_count: Mapped[int] = mapped_column(
|
||||
Integer, default=0, nullable=False, comment="学习人数"
|
||||
)
|
||||
is_new: Mapped[bool] = mapped_column(
|
||||
Boolean, default=True, nullable=False, comment="是否新课程"
|
||||
)
|
||||
|
||||
# 资料下载设置
|
||||
allow_download: Mapped[bool] = mapped_column(
|
||||
Boolean, default=False, nullable=False, comment="是否允许下载资料"
|
||||
)
|
||||
|
||||
# 关联关系
|
||||
materials: Mapped[List["CourseMaterial"]] = relationship(
|
||||
"CourseMaterial", back_populates="course"
|
||||
)
|
||||
knowledge_points: Mapped[List["KnowledgePoint"]] = relationship(
|
||||
"KnowledgePoint", back_populates="course"
|
||||
)
|
||||
|
||||
# 岗位分配关系(通过关联表)
|
||||
position_assignments = relationship("PositionCourse", back_populates="course", cascade="all, delete-orphan")
|
||||
exams = relationship("Exam", back_populates="course")
|
||||
questions = relationship("Question", back_populates="course")
|
||||
|
||||
|
||||
class CourseMaterial(BaseModel, SoftDeleteMixin, AuditMixin):
|
||||
"""
|
||||
课程资料表
|
||||
"""
|
||||
|
||||
__tablename__ = "course_materials"
|
||||
|
||||
course_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("courses.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
comment="课程ID",
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False, comment="资料名称")
|
||||
description: Mapped[Optional[str]] = mapped_column(
|
||||
Text, nullable=True, comment="资料描述"
|
||||
)
|
||||
file_url: Mapped[str] = mapped_column(String(500), nullable=False, comment="文件URL")
|
||||
file_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="文件类型")
|
||||
file_size: Mapped[int] = mapped_column(Integer, nullable=False, comment="文件大小(字节)")
|
||||
|
||||
# 排序
|
||||
sort_order: Mapped[int] = mapped_column(
|
||||
Integer, default=0, nullable=False, comment="排序顺序"
|
||||
)
|
||||
|
||||
# 关联关系
|
||||
course: Mapped["Course"] = relationship("Course", back_populates="materials")
|
||||
# 关联的知识点(直接关联)
|
||||
knowledge_points: Mapped[List["KnowledgePoint"]] = relationship(
|
||||
"KnowledgePoint", back_populates="material"
|
||||
)
|
||||
|
||||
|
||||
class KnowledgePoint(BaseModel, SoftDeleteMixin, AuditMixin):
|
||||
"""
|
||||
知识点表
|
||||
"""
|
||||
|
||||
__tablename__ = "knowledge_points"
|
||||
|
||||
course_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("courses.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
comment="课程ID",
|
||||
)
|
||||
material_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("course_materials.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
comment="关联资料ID",
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False, comment="知识点名称")
|
||||
description: Mapped[Optional[str]] = mapped_column(
|
||||
Text, nullable=True, comment="知识点描述"
|
||||
)
|
||||
type: Mapped[str] = mapped_column(
|
||||
String(50), default="概念定义", nullable=False, comment="知识点类型"
|
||||
)
|
||||
source: Mapped[int] = mapped_column(
|
||||
Integer, default=0, nullable=False, comment="来源:0=手动,1=AI分析"
|
||||
)
|
||||
topic_relation: Mapped[Optional[str]] = mapped_column(
|
||||
String(200), nullable=True, comment="与主题的关系描述"
|
||||
)
|
||||
|
||||
# 关联关系
|
||||
course: Mapped["Course"] = relationship("Course", back_populates="knowledge_points")
|
||||
material: Mapped["CourseMaterial"] = relationship("CourseMaterial")
|
||||
|
||||
|
||||
class GrowthPath(BaseModel, SoftDeleteMixin):
|
||||
"""
|
||||
成长路径表
|
||||
"""
|
||||
|
||||
__tablename__ = "growth_paths"
|
||||
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False, comment="路径名称")
|
||||
description: Mapped[Optional[str]] = mapped_column(
|
||||
Text, nullable=True, comment="路径描述"
|
||||
)
|
||||
target_role: Mapped[Optional[str]] = mapped_column(
|
||||
String(100), nullable=True, comment="目标角色"
|
||||
)
|
||||
|
||||
# 路径配置
|
||||
courses: Mapped[Optional[List[dict]]] = mapped_column(
|
||||
JSON, nullable=True, comment="课程列表[{course_id, order, is_required}]"
|
||||
)
|
||||
|
||||
# 预计时长
|
||||
estimated_duration_days: Mapped[Optional[int]] = mapped_column(
|
||||
Integer, nullable=True, comment="预计完成天数"
|
||||
)
|
||||
|
||||
# 状态
|
||||
is_active: Mapped[bool] = mapped_column(
|
||||
Boolean, default=True, nullable=False, comment="是否启用"
|
||||
)
|
||||
sort_order: Mapped[int] = mapped_column(
|
||||
Integer, default=0, nullable=False, comment="排序顺序"
|
||||
)
|
||||
|
||||
|
||||
class MaterialKnowledgePoint(BaseModel, SoftDeleteMixin):
|
||||
"""
|
||||
资料知识点关联表
|
||||
"""
|
||||
|
||||
__tablename__ = "material_knowledge_points"
|
||||
|
||||
material_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("course_materials.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
comment="资料ID",
|
||||
)
|
||||
knowledge_point_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
ForeignKey("knowledge_points.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
comment="知识点ID",
|
||||
)
|
||||
sort_order: Mapped[int] = mapped_column(
|
||||
Integer, default=0, nullable=False, comment="排序顺序"
|
||||
)
|
||||
is_ai_generated: Mapped[bool] = mapped_column(
|
||||
Boolean, default=False, nullable=False, comment="是否AI生成"
|
||||
)
|
||||
Reference in New Issue
Block a user