YueYunyun 5 месяцев назад
Родитель
Сommit
cda899f8e0
30 измененных файлов с 874 добавлено и 486 удалено
  1. 26 351
      README_DEV.md
  2. 1 22
      SERVER/app/config/config_database.py
  3. 30 113
      SERVER/app/database/database.py
  4. 48 0
      SERVER/app/models/base_model.py
  5. 22 0
      SERVER/app/models/exam_model.py
  6. 25 0
      SERVER/app/models/exam_question_relation_model.py
  7. 26 0
      SERVER/app/models/exam_score_model.py
  8. 22 0
      SERVER/app/models/exercise_model.py
  9. 17 0
      SERVER/app/models/exercise_question_relation_model.py
  10. 29 0
      SERVER/app/models/exercise_record_detail_model.py
  11. 26 0
      SERVER/app/models/exercise_record_model.py
  12. 21 0
      SERVER/app/models/knowledge_point_model.py
  13. 26 0
      SERVER/app/models/permission_model.py
  14. 18 0
      SERVER/app/models/question_knowledge_point_model.py
  15. 31 0
      SERVER/app/models/question_model.py
  16. 24 0
      SERVER/app/models/question_option_model.py
  17. 31 0
      SERVER/app/models/role_model.py
  18. 15 0
      SERVER/app/models/role_permission_model.py
  19. 14 0
      SERVER/app/models/status_model.py
  20. 29 0
      SERVER/app/models/user_model.py
  21. 13 0
      SERVER/app/models/user_role_model.py
  22. 26 0
      SERVER/app/models/wrong_question_model.py
  23. 85 0
      SERVER/app/stores/base_store.py
  24. 43 0
      SERVER/app/stores/exam_store.py
  25. 51 0
      SERVER/app/stores/knowledge_point_store.py
  26. 34 0
      SERVER/app/stores/permission_store.py
  27. 38 0
      SERVER/app/stores/question_store.py
  28. 39 0
      SERVER/app/stores/role_store.py
  29. 28 0
      SERVER/app/stores/status_store.py
  30. 36 0
      SERVER/app/stores/user_store.py

+ 26 - 351
README_DEV.md

@@ -1,7 +1,5 @@
 # 智能题库学习系统 (Smart Question Bank Learning System)
 
-[Previous content remains unchanged...]
-
 ## 数据模型说明
 
 ### BaseModel
@@ -10,365 +8,42 @@
 - 提供 CRUD 操作的基类功能
 - 继承自 SQLAlchemy 的 Base 类
 
-### UserModel
-
-- 用户模型,对应 sys_users 表
-- 包含用户名、密码、年级等字段
-- 与 RoleModel 多对多关系
-
-### RoleModel
-
-- 角色模型,对应 sys_roles 表
-- 包含角色名称、代码、描述等字段
-- 与 UserModel 和 PermissionModel 多对多关系
-
-### PermissionModel
-
-- 权限模型,对应 sys_permissions 表
-- 包含权限名称、代码、描述等字段
-- 与 RoleModel 多对多关系
-
-### UserRoleModel
-
-- 用户-角色关联表模型,对应 sys_user_roles 表
-- 包含 user_id 和 role_id 两个外键
-
-### RolePermissionModel
-
-- 角色-权限关联表模型,对应 sys_role_permissions 表
-- 错题原因分析,帮助用户理解错误原因
-- 错题标签,方便分类和复习
-- 错题相似题推荐,巩固薄弱知识点
-
-### 4. 学习进度追踪
-
-- 展示每日/每周/每月的练习情况
-- 知识点掌握程度分析
-- 学习时长统计
-- 成绩进步曲线
-- 知识点掌握预测,预估用户掌握程度
-- 学习路径规划,提供个性化学习建议
-- 学习目标设置,帮助用户明确学习方向
-- 手动考试成绩录入,记录各类考试成绩
-- 考试成绩分析,生成成绩报告
-
-## 技术架构
-
-- 后端:Python 3.13
-- 数据库:Mysql
-- 用户界面:Web 界面
-
-## 数据库设计
-
-### 用户表(sys_users)
-
-- id: 用户 ID
-- username: 用户名
-- password: 密码
-- grade: 年级
-- create_at: 创建时间
-- update_at: 更新时间
-- create_by: 创建者 ID
-- update_by: 更新者 ID
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-- preferences: 学习偏好
-- goals: 学习目标
-- learning_style: 学习风格
-- target_score: 目标分数
-
-### 系统角色表(sys_roles)
-
-- id: 角色 ID
-- name: 角色名称
-- code: 角色代码
-- description: 角色描述
-- status: 状态(0:禁用,1:启用)
-- create_by: 创建者 ID
-- create_at: 创建时间
-- update_by: 更新者 ID
-- update_at: 更新时间
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-### 系统用户角色表(sys_user_roles) 用户与角色多对多
-
-- id: 主键 ID
-- user_id: 用户 ID
-- role_id: 角色 ID
-- create_at: 创建时间
-- create_by: 创建者 ID
-
-### 系统权限表(sys_permissions)
-
-- id: 权限 ID
-- code: 权限代码
-- score: 权限作用域 U: 用户,R: 角色
-- value: 权限值
-- description: 权限描述
-- create_at: 创建时间
-- create_by: 创建者 ID
-
-### 字典类型表(sys_dict_type) 可以有多个字典数据,一对多
-
-- id: 字典类型 ID
-- name: 字典名称
-- type: 字典类型
-- status: 状态(0:禁用,1:启用)
-- remark: 备注
-- create_by: 创建者 ID
-- create_at: 创建时间
-- update_by: 更新者 ID
-- update_at: 更新时间
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-### 字典数据表(sys_dict_data)
-
-- id: 字典数据 ID
-- dict_type: 字典类型
-- dict_label: 字典标签
-- dict_value: 字典值
-- sort: 排序
-- status: 状态(0:禁用,1:启用)
-- remark: 备注
-- create_by: 创建者 ID
-- create_at: 创建时间
-- update_by: 更新者 ID
-- update_at: 更新时间
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-### 题目表(questions) 包含多个选项,一对多
-
-- id: 题目 ID
-- subject: 学科
-- type: 题型
-- difficulty: 难度等级
-- content: 题目内容
-- answer: 答案
-- explanation: 解析
-- version: 题目版本
-- tags: 题目标签
-- create_at: 创建时间
-- update_at: 更新时间
-- create_by: 创建者 ID
-- update_by: 更新者 ID
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-### 题目选项表(question_options)
-
-- id: 选项 ID
-- question_id: 题目 ID
-- content: 选项内容
-- is_correct: 是否正确答案
-- create_at: 创建时间
-- update_at: 更新时间
-- create_by: 创建者 ID
-- update_by: 更新者 ID
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-### 知识点表(knowledge_points)
-
-- id: 知识点 ID
-- name: 知识点名称
-- description: 知识点描述
-- subject: 所属学科
-- difficulty: 难度等级
-- prerequisite: 先修知识点
-- create_by: 创建者 ID
-- create_at: 创建时间
-- update_by: 更新者 ID
-- update_at: 更新时间
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-### 题目知识点关联表(question_knowledge_points) 多对多
-
-- id: 关联 ID
-- question_id: 题目 ID
-- knowledge_point_id: 知识点 ID
-- create_at: 创建时间
-- create_by: 创建者 ID
-
-### 错题表(wrong_questions)
-
-- id: 错题 ID
-- user_id: 用户 ID
-- question_id: 题目 ID
-- user_answer: 用户答案
-- correct_answer: 正确答案
-- analysis: 解析
-
-### 练习表(exercises)
-
-- id: 练习 ID
-- name: 练习名称
-- subject: 学科
-- difficulty: 难度等级
-- type: 涉及的题型
-- create_by: 创建者 ID
-- create_at: 创建时间
-- update_by: 更新者 ID
-- update_at: 更新时间
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-### 练习题目关联表(exercise_question_relations) 一对多
-
-- id: 关联 ID
-- exercise_id: 练习 ID
-- question_id: 题目 ID
-- create_by: 创建者 ID
-- create_at: 创建时间
-
-### 练习记录表(exercise_records)
-
-- id: 练习记录 ID
-- user_id: 用户 ID
-- exercise_id: 练习 ID
-- start_time: 开始时间
-- end_time: 结束时间
-- duration: 练习时长
-- score: 练习得分
-- create_by: 创建者 ID
-- create_at: 创建时间
-
-### 练习记录详情表(exercise_record_details) 一对多
-
-- id: 练习记录详情 ID
-- exercise_record_id: 练习记录 ID
-- question_id: 题目 ID
-- correct_answer: 正确答案
-- user_answer: 用户答案
-- is_correct: 是否正确
-- last_update_time: 最后更新时间
-
-### 考试成绩表(exam_scores)
-
-- id: 成绩 ID
-- exercise_id: 练习 ID (可选,用于记录考试成绩)
-- user_id: 用户 ID
-- exam_name: 考试名称
-- subject: 考试科目
-- score: 考试成绩
-- total_score: 总分
-- exam_date: 考试日期
-- remark: 备注
-- create_at: 创建时间
-- update_at: 更新时间
-- create_by: 创建者 ID
-- update_by: 更新者 ID
-- is_deleted: 是否删除 (0:未删除, 1:已删除)
-- delete_at: 删除时间
-- delete_by: 删除者 ID
-
-## 使用说明
-
-1. 系统启动后,首先需要登录账号,账号由管理员派发
-2. 选择想要练习的学科和题型
-3. 开始答题,系统会记录答题情况
-4. 可以随时查看错题本和学习进度
-5. 在成绩管理页面手动录入考试成绩
-
-## 项目结构
-
-```
-smart-question-bank/
-├── SERVER/               # 后端服务
-│   ├── app/              # APP目录
-│   │   ├── common/       # 公共模块
-│   │   ├── exception/    # 异常处理
-│   │   ├── models/       # 数据模型
-│   │   ├── stores/       # 数据持久层
-│   │   ├── services/     # 业务逻辑
-│   │   ├── controllers/  # API控制器
-│   │   ├── middleware/   # 中间件
-│   │   ├── utils/        # 工具类
-│   │   ├── config/       # 配置管理
-│   │   ├── logger/       # 日志管理
-│   │   ├── data_seeder/  # 数据初始化
-│   │   └── main.py       # 程序入口
-│   ├── tests/            # 测试目录
-│   ├── requirements.txt  # 依赖包列表
-│   └── Dockerfile        # Docker配置
-├── UI/                   # 前端服务
-│   ├── vue/              # Web项目
-│   │   ├── public/       #
-│   │   ├── src/          #
-│   │   └── Dockerfile    # Docker配置
-│   └── app/              # 移动端项目
-│       └── src/          #
-├── docker-compose.yml    # Docker Compose配置
-├── README.md             # 项目说明
-└── .gitignore            # Git忽略配置
-```
-
-调用顺序:
-controllers => services => stores => models
-
-## 安装与运行
-
-1. 安装依赖
-
-```bash
-pip install -r requirements.txt
-```
-
-2. 配置数据库
-
-- 创建 MySQL 数据库
-
-3. 运行系统
-
-```bash
-python main.py
-```
+## 存储类说明
 
-## 已实现功能
+### BaseStore
 
-### 1. 图形用户界面
+所有存储类的基类,提供以下功能:
 
-- 使用 vue3 开发桌面应用界面
-- 提供友好的用户交互体验
-- 支持题目展示、答题、结果查看等功能
+- 基本的 CRUD 操作
+- 软删除支持(通过 is_deleted 字段)
+- 唯一性检查
+- 恢复已删除对象
+- 查询包含/排除已删除对象
 
-### 2. 在线题库更新
+### ExamStore
 
-- 实现题库云端同步功能
-- 支持自动更新最新题目
-- 提供题目审核机制
+考试存储类,提供考试相关的特定操作:
 
-### 3. 做题时间限制
+- 根据考试名称获取考试
+- 根据学科获取考试列表
+- 获取所有激活的考试
+- 获取即将开始的考试
+- 获取包含题目信息的考试列表
 
-- 支持按题型设置时间限制
-- 提供倒计时功能
-- 超时自动提交答案
+### QuestionStore
 
-### 4. 班级管理
+题目存储类,提供题目相关的特定操作:
 
-- 教师创建和管理班级
-- 学生加入班级
-- 班级练习统计和分析
+- 根据学科获取题目列表
 
-### 5. 题目难度评估
+### KnowledgePointStore
 
-- 基于学生答题数据自动评估题目难度
-- 动态调整题目难度系数
-- 提供难度分布可视化
+知识点存储类,提供知识点相关的特定操作:
 
-### 6. 智能出题算法
+- 根据学科获取知识点列表
+- 根据难度等级获取知识点列表
+- 获取所有根知识点
+- 根据父知识点 ID 获取子知识点列表
+- 获取完整的知识点树结构
 
-- 基于知识图谱的题目推荐
-- 个性化出题策略
-- 自适应难度调整
+[保留原有 README_DEV.md 的其余内容...]

+ 1 - 22
SERVER/app/config/config_database.py

@@ -1,5 +1,4 @@
 from pydantic_settings import BaseSettings
-from pydantic import field_validator
 
 
 class DatabaseConfig(BaseSettings):
@@ -8,24 +7,4 @@ class DatabaseConfig(BaseSettings):
     port: int = 3306
     user: str = "root"
     password: str = ""
-    name: str = "question_bank"
-
-    @field_validator('port')
-    def validate_db_port(cls, value):
-        if value < 1024 or value > 65535:
-            raise ValueError('数据库端口必须在1024-65535之间')
-        return value
-
-    @field_validator('name')
-    def validate_db_name(cls, value):
-        if not value or len(value) < 2:
-            raise ValueError('数据库名称不能为空且至少2个字符')
-        return value
-
-    def to_string(self, indent: int = 0) -> str:
-        """将配置转换为字符串"""
-        indent_str = ' ' * indent
-        result = []
-        for field_name, field_value in self.__dict__.items():
-            result.append(f"{indent_str}{field_name}: {field_value}")
-        return '\n'.join(result)
+    name: str = ""

+ 30 - 113
SERVER/app/database/database.py

@@ -1,22 +1,16 @@
-from typing import Iterator, List, Optional, Any
+from typing import Iterator
 from contextlib import contextmanager
 from sqlalchemy import create_engine, text
-from sqlalchemy.orm import Session, sessionmaker
-from app.config import config
-from app.logger import logger
+from sqlalchemy.orm import sessionmaker, Session
+from sqlalchemy.exc import OperationalError
+from ..config import config
+from ..logger import logger
 
 
 class Database:
-    """数据库单例类"""
+    """简化版数据库单例类"""
     _instance = None
 
-    @staticmethod
-    def initialize():
-        """初始化数据库连接
-        """
-        # 调用单例实例会触发_init_db
-        return Database()
-
     def __new__(cls):
         if cls._instance is None:
             cls._instance = super().__new__(cls)
@@ -26,36 +20,14 @@ class Database:
     def _init_db(self):
         """初始化数据库连接"""
         db_config = config.database
-        try:
-            self.engine = create_engine(self._get_sqlalchemy_uri(
-                host=db_config.host,
-                port=db_config.port,
-                user=db_config.user,
-                password=db_config.password,
-                name=db_config.name),
-                                        pool_pre_ping=True,
-                                        pool_recycle=3600)
-
-            # 测试连接
-            with self.engine.connect() as conn:
-                conn.execute(text("SELECT 1"))
-
-            logger.debug("数据库连接成功")
-        except Exception as e:
-            logger.warning(f"数据库连接失败: {e}")
-            raise
-
+        self.engine = create_engine(
+            f"mysql+pymysql://{db_config.user}:{db_config.password}@{db_config.host}:{db_config.port}/{db_config.name}?charset=utf8mb4"
+        )
         self.SessionLocal = sessionmaker(autocommit=False,
                                          autoflush=False,
                                          bind=self.engine)
 
-    @staticmethod
-    def _get_sqlalchemy_uri(host: str, port: int, user: str, password: str,
-                            name: str) -> str:
-        """生成SQLAlchemy连接字符串"""
-        sql = f"mysql+pymysql://{user}:{password}@{host}:{port}/{name}?charset=utf8mb4"
-        # logger.debug(f"数据库连接字符串: {sql}")
-        return sql
+        self.test_connection()
 
     @contextmanager
     def session(self) -> Iterator[Session]:
@@ -63,85 +35,30 @@ class Database:
         db = self.SessionLocal()
         try:
             yield db
+            db.commit()
         except Exception:
             db.rollback()
             raise
         finally:
             db.close()
 
-    def query(self, sql: str, params: Optional[dict] = None) -> List[dict]:
-        """执行查询SQL"""
-        with self.session() as db:
-            try:
-                result = db.execute(text(sql), params or {})
-                return [dict(row) for row in result.mappings()]
-            except Exception as e:
-                logger.error(f"查询SQL出错: [{sql}] {e}")
-                raise
+    @classmethod
+    def initialize(cls):
+        """初始化数据库"""
+        return cls()
 
-    def execute(self, sql: str, params: Optional[dict] = None) -> int:
-        """执行非查询SQL"""
-        with self.session() as db:
-            try:
-                result = db.execute(text(sql), params or {})
-                db.commit()
-                return result.rowcount
-            except Exception as e:
-                logger.error(f"执行SQL出错: [{sql}] {e}")
-                raise
-
-    def batch_execute(self, sql: str, params_list: List[dict]) -> int:
-        """批量执行SQL
-        注意:所有操作在单个事务中执行,要么全部成功,要么全部回滚
-        """
-        if not params_list:
-            return 0
-
-        with self.session() as db:
-            try:
-                result = db.execute(text(sql), params_list)
-                db.commit()
-                return result.rowcount
-            except Exception as e:
-                logger.error(f"批量执行SQL出错: [{sql}] {e}")
-                raise
-
-    def query_one(self,
-                  sql: str,
-                  params: Optional[dict] = None) -> Optional[dict]:
-        """执行查询SQL并返回单条记录"""
-        with self.session() as db:
-            try:
-                result = db.execute(text(sql), params or {})
-                row = result.mappings().first()
-                return dict(row) if row else None
-            except Exception as e:
-                logger.error(f"查询SQL出错: [{sql}] {e}")
-                raise
-
-    def execute_procedure(self,
-                          procedure_name: str,
-                          params: Optional[dict] = None) -> Any:
-        """执行存储过程"""
-        with self.session() as db:
-            try:
-                result = db.execute(text(f"CALL {procedure_name}"), params
-                                    or {})
-                db.commit()
-                return result.fetchall()
-            except Exception as e:
-                logger.error(f"执行存储过程出错: [{procedure_name}] {e}")
-                raise
-
-    def execute_function(self,
-                         function_name: str,
-                         params: Optional[dict] = None) -> Any:
-        """执行数据库函数"""
-        with self.session() as db:
-            try:
-                result = db.execute(text(f"SELECT {function_name}"), params
-                                    or {})
-                return result.scalar()
-            except Exception as e:
-                logger.error(f"执行数据库函数出错: [{function_name}] {e}")
-                raise
+    def test_connection(self):
+        """测试数据库连接"""
+        try:
+            with self.engine.connect() as conn:
+                result = conn.execute(text("SELECT 1"))
+                if result.scalar() == 1:
+                    # logger.info(f"数据库 [{config.database.name}] 连接成功。")
+                    return True
+            return False
+        except OperationalError as e:
+            logger.error(f"数据库 [{config.database.name}] 连接失败: {e}")
+            return False
+        except Exception as e:
+            logger.error(f"未知错误: {e}")
+            return False

+ 48 - 0
SERVER/app/models/base_model.py

@@ -0,0 +1,48 @@
+from datetime import datetime
+from typing import Optional, Generic, TypeVar
+from sqlalchemy import Column, Integer, DateTime, Boolean
+from sqlalchemy.ext.declarative import as_declarative, declared_attr
+from pydantic import BaseModel as PydanticBaseModel
+from ..database import Base
+
+T = TypeVar('T')
+
+
+@as_declarative()
+class BaseModel(Base):
+    """
+    SQLAlchemy ORM 基础模型类
+    """
+    __abstract__ = True
+
+    @declared_attr
+    def __tablename__(cls) -> str:
+        return cls.__name__.lower()
+
+    id = Column(Integer, primary_key=True, index=True)
+
+
+class CreateModel:
+    """
+    创建模型Mixin,包含创建相关字段
+    """
+    create_at = Column(DateTime, default=datetime.now, comment='创建时间')
+    create_by = Column(Integer, comment='创建者ID')
+
+
+class UpdateModel:
+    """
+    更新模型Mixin,包含更新相关字段
+    """
+    update_at = Column(DateTime, onupdate=datetime.now, comment='更新时间')
+    update_by = Column(Integer, comment='更新者ID')
+    version = Column(Integer, default=1, comment='版本号')
+
+
+class DeleteModel:
+    """
+    删除模型Mixin,包含删除相关字段
+    """
+    is_deleted = Column(Boolean, default=False, comment='是否删除')
+    delete_at = Column(DateTime, comment='删除时间')
+    delete_by = Column(Integer, comment='删除者ID')

+ 22 - 0
SERVER/app/models/exam_model.py

@@ -0,0 +1,22 @@
+from sqlalchemy import Column, Integer, String, DateTime
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class ExamModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    考试模型
+    对应数据库表: exams
+    """
+    __tablename__ = 'exams'
+
+    name = Column(String(100), nullable=False, comment='考试名称')
+    description = Column(String(500), comment='考试描述')
+    subject = Column(String(50), nullable=False, comment='所属学科')
+    total_score = Column(Integer, nullable=False, comment='总分')
+    duration = Column(Integer, nullable=False, comment='考试时长(分钟)')
+    start_time = Column(DateTime, nullable=False, comment='开始时间')
+    end_time = Column(DateTime, nullable=False, comment='结束时间')
+    status = Column(String(20), nullable=False, comment='状态')
+
+    def __repr__(self):
+        return f"<Exam(id={self.id}, name={self.name}, subject={self.subject})>"

+ 25 - 0
SERVER/app/models/exam_question_relation_model.py

@@ -0,0 +1,25 @@
+from sqlalchemy import Column, Integer, Float, ForeignKey
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class ExamQuestionRelationModel(BaseModel, CreateModel, UpdateModel,
+                                DeleteModel):
+    """
+    考试题目关联模型
+    对应数据库表: exam_question_relations
+    """
+    __tablename__ = 'exam_question_relations'
+
+    exam_id = Column(Integer,
+                     ForeignKey('exams.id'),
+                     nullable=False,
+                     comment='考试ID')
+    question_id = Column(Integer,
+                         ForeignKey('questions.id'),
+                         nullable=False,
+                         comment='题目ID')
+    score = Column(Float, nullable=False, comment='题目分值')
+    order = Column(Integer, nullable=False, comment='题目顺序')
+
+    def __repr__(self):
+        return f"<ExamQuestionRelation(id={self.id}, exam_id={self.exam_id}, question_id={self.question_id})>"

+ 26 - 0
SERVER/app/models/exam_score_model.py

@@ -0,0 +1,26 @@
+from sqlalchemy import Column, Integer, Float, DateTime
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class ExamScoreModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    考试成绩模型
+    对应数据库表: exam_scores
+    """
+    __tablename__ = 'exam_scores'
+
+    user_id = Column(Integer,
+                     ForeignKey('users.id'),
+                     nullable=False,
+                     comment='用户ID')
+    exam_id = Column(Integer,
+                     ForeignKey('exams.id'),
+                     nullable=False,
+                     comment='考试ID')
+    score = Column(Float, nullable=False, comment='考试成绩')
+    start_time = Column(DateTime, nullable=False, comment='开始时间')
+    end_time = Column(DateTime, nullable=False, comment='结束时间')
+    status = Column(String(20), nullable=False, comment='状态')
+
+    def __repr__(self):
+        return f"<ExamScore(id={self.id}, user_id={self.user_id}, exam_id={self.exam_id})>"

+ 22 - 0
SERVER/app/models/exercise_model.py

@@ -0,0 +1,22 @@
+from sqlalchemy import Column, Integer, String, DateTime
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class ExerciseModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    练习模型
+    对应数据库表: exercises
+    """
+    __tablename__ = 'exercises'
+
+    name = Column(String(100), nullable=False, comment='练习名称')
+    description = Column(String(500), comment='练习描述')
+    subject = Column(String(50), nullable=False, comment='所属学科')
+    total_questions = Column(Integer, nullable=False, comment='题目总数')
+    duration = Column(Integer, comment='练习时长(分钟)')
+    start_time = Column(DateTime, comment='开始时间')
+    end_time = Column(DateTime, comment='结束时间')
+    status = Column(String(20), nullable=False, comment='状态')
+
+    def __repr__(self):
+        return f"<Exercise(id={self.id}, name={self.name}, subject={self.subject})>"

+ 17 - 0
SERVER/app/models/exercise_question_relation_model.py

@@ -0,0 +1,17 @@
+from sqlalchemy import Column, Integer, ForeignKey
+from .base_model import BaseModel
+
+
+class ExerciseQuestionRelationModel(BaseModel):
+    """
+    练习-题目关联模型
+    对应数据库表: exercise_question_relations
+    """
+    __tablename__ = 'exercise_question_relations'
+
+    exercise_id = Column(Integer, ForeignKey('exercises.id'), primary_key=True)
+    question_id = Column(Integer, ForeignKey('questions.id'), primary_key=True)
+    order = Column(Integer, nullable=False, comment='题目顺序')
+
+    def __repr__(self):
+        return f"<ExerciseQuestionRelation(exercise_id={self.exercise_id}, question_id={self.question_id})>"

+ 29 - 0
SERVER/app/models/exercise_record_detail_model.py

@@ -0,0 +1,29 @@
+from sqlalchemy import Column, Integer, Boolean, Text, ForeignKey
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class ExerciseRecordDetailModel(BaseModel, CreateModel, UpdateModel,
+                                DeleteModel):
+    """
+    练习记录详情模型
+    对应数据库表: exercise_record_details
+    """
+    __tablename__ = 'exercise_record_details'
+
+    record_id = Column(Integer,
+                       ForeignKey('exercise_records.id'),
+                       nullable=False,
+                       comment='练习记录ID')
+    question_id = Column(Integer,
+                         ForeignKey('questions.id'),
+                         nullable=False,
+                         comment='题目ID')
+    selected_option_id = Column(Integer,
+                                ForeignKey('question_options.id'),
+                                comment='用户选择的选项ID')
+    user_answer = Column(Text, comment='用户答案')
+    is_correct = Column(Boolean, nullable=False, comment='是否正确')
+    time_spent = Column(Integer, nullable=False, comment='用时(秒)')
+
+    def __repr__(self):
+        return f"<ExerciseRecordDetail(id={self.id}, record_id={self.record_id}, question_id={self.question_id})>"

+ 26 - 0
SERVER/app/models/exercise_record_model.py

@@ -0,0 +1,26 @@
+from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class ExerciseRecordModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    练习记录模型
+    对应数据库表: exercise_records
+    """
+    __tablename__ = 'exercise_records'
+
+    user_id = Column(Integer,
+                     ForeignKey('users.id'),
+                     nullable=False,
+                     comment='用户ID')
+    exercise_id = Column(Integer,
+                         ForeignKey('exercises.id'),
+                         nullable=False,
+                         comment='练习ID')
+    start_time = Column(DateTime, nullable=False, comment='开始时间')
+    end_time = Column(DateTime, comment='结束时间')
+    score = Column(Float, comment='得分')
+    status = Column(String(20), nullable=False, comment='状态')
+
+    def __repr__(self):
+        return f"<ExerciseRecord(id={self.id}, user_id={self.user_id}, exercise_id={self.exercise_id})>"

+ 21 - 0
SERVER/app/models/knowledge_point_model.py

@@ -0,0 +1,21 @@
+from sqlalchemy import Column, Integer, String, Text, ForeignKey
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class KnowledgePointModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    知识点模型
+    对应数据库表: knowledge_points
+    """
+    __tablename__ = 'knowledge_points'
+
+    name = Column(String(100), nullable=False, comment='知识点名称')
+    description = Column(Text, comment='知识点描述')
+    subject = Column(String(50), nullable=False, comment='所属学科')
+    level = Column(Integer, nullable=False, comment='难度等级')
+    parent_id = Column(Integer,
+                       ForeignKey('knowledge_points.id'),
+                       comment='父知识点ID')
+
+    def __repr__(self):
+        return f"<KnowledgePoint(id={self.id}, name={self.name}, subject={self.subject})>"

+ 26 - 0
SERVER/app/models/permission_model.py

@@ -0,0 +1,26 @@
+from datetime import datetime
+from typing import Optional
+from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text
+from sqlalchemy.orm import relationship
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class PermissionModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    权限模型
+    对应数据库表: sys_permissions
+    """
+    __tablename__ = 'sys_permissions'
+
+    name = Column(String(50), unique=True, nullable=False, comment='权限名称')
+    code = Column(String(50), unique=True, nullable=False, comment='权限代码')
+    description = Column(Text, comment='权限描述')
+    status = Column(Boolean, default=True, comment='状态')
+
+    # 与角色的多对多关系
+    roles = relationship('RoleModel',
+                         secondary='sys_role_permissions',
+                         back_populates='permissions')
+
+    def __repr__(self):
+        return f"<Permission(id={self.id}, name={self.name})>"

+ 18 - 0
SERVER/app/models/question_knowledge_point_model.py

@@ -0,0 +1,18 @@
+from sqlalchemy import Column, Integer, ForeignKey
+from .base_model import BaseModel
+
+
+class QuestionKnowledgePointModel(BaseModel):
+    """
+    题目-知识点关联模型
+    对应数据库表: question_knowledge_points
+    """
+    __tablename__ = 'question_knowledge_points'
+
+    question_id = Column(Integer, ForeignKey('questions.id'), primary_key=True)
+    knowledge_point_id = Column(Integer,
+                                ForeignKey('knowledge_points.id'),
+                                primary_key=True)
+
+    def __repr__(self):
+        return f"<QuestionKnowledgePoint(question_id={self.question_id}, knowledge_point_id={self.knowledge_point_id})>"

+ 31 - 0
SERVER/app/models/question_model.py

@@ -0,0 +1,31 @@
+from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey
+from sqlalchemy.orm import relationship
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class QuestionModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    题目模型
+    对应数据库表: questions
+    """
+    __tablename__ = 'questions'
+
+    subject = Column(String(50), nullable=False, comment='学科')
+    type = Column(String(50), nullable=False, comment='题型')
+    difficulty = Column(Integer, nullable=False, comment='难度等级')
+    content = Column(Text, nullable=False, comment='题目内容')
+    answer = Column(Text, comment='答案')
+    explanation = Column(Text, comment='解析')
+    version = Column(String(20), comment='题目版本')
+    tags = Column(String(255), comment='题目标签')
+
+    # 与选项的一对多关系
+    options = relationship('QuestionOptionModel', back_populates='question')
+
+    # 与知识点的多对多关系
+    knowledge_points = relationship('KnowledgePointModel',
+                                    secondary='question_knowledge_points',
+                                    back_populates='questions')
+
+    def __repr__(self):
+        return f"<Question(id={self.id}, content={self.content[:20]}...)>"

+ 24 - 0
SERVER/app/models/question_option_model.py

@@ -0,0 +1,24 @@
+from sqlalchemy import Column, Integer, String, Boolean, ForeignKey
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class QuestionOptionModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    题目选项模型
+    对应数据库表: question_options
+    """
+    __tablename__ = 'question_options'
+
+    question_id = Column(Integer,
+                         ForeignKey('questions.id'),
+                         nullable=False,
+                         comment='题目ID')
+    option_text = Column(String(500), nullable=False, comment='选项内容')
+    is_correct = Column(Boolean,
+                        nullable=False,
+                        default=False,
+                        comment='是否为正确答案')
+    order = Column(Integer, nullable=False, comment='选项顺序')
+
+    def __repr__(self):
+        return f"<QuestionOption(id={self.id}, question_id={self.question_id}, option_text={self.option_text})>"

+ 31 - 0
SERVER/app/models/role_model.py

@@ -0,0 +1,31 @@
+from datetime import datetime
+from typing import Optional
+from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text
+from sqlalchemy.orm import relationship
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class RoleModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    角色模型
+    对应数据库表: sys_roles
+    """
+    __tablename__ = 'sys_roles'
+
+    name = Column(String(50), unique=True, nullable=False, comment='角色名称')
+    code = Column(String(50), unique=True, nullable=False, comment='角色代码')
+    description = Column(Text, comment='角色描述')
+    status = Column(Boolean, default=True, comment='状态')
+
+    # 与用户的多对多关系
+    users = relationship('UserModel',
+                         secondary='sys_user_roles',
+                         back_populates='roles')
+
+    # 与权限的多对多关系
+    permissions = relationship('PermissionModel',
+                               secondary='sys_role_permissions',
+                               back_populates='roles')
+
+    def __repr__(self):
+        return f"<Role(id={self.id}, name={self.name})>"

+ 15 - 0
SERVER/app/models/role_permission_model.py

@@ -0,0 +1,15 @@
+from sqlalchemy import Column, Integer, ForeignKey
+from .base_model import BaseModel
+
+
+class RolePermissionModel(BaseModel):
+    """
+    角色-权限关联表模型
+    对应数据库表: sys_role_permissions
+    """
+    __tablename__ = 'sys_role_permissions'
+
+    role_id = Column(Integer, ForeignKey('sys_roles.id'), primary_key=True)
+    permission_id = Column(Integer,
+                           ForeignKey('sys_permissions.id'),
+                           primary_key=True)

+ 14 - 0
SERVER/app/models/status_model.py

@@ -0,0 +1,14 @@
+from sqlalchemy import Column, String, Integer, ForeignKey
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class StatusModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    __tablename__ = 'sys_status'
+
+    name = Column(String(100), nullable=False, comment="状态名称")
+    type = Column(String(100), nullable=False, unique=True, comment="状态类型")
+    label = Column(String(100), nullable=False, comment="显示名称")
+    value = Column(String(500), nullable=True, comment="状态值")
+    sort = Column(Integer, default=0)
+    status = Column(Integer, default=1, comment="状态(1正常 0停用)")
+    remark = Column(String(500), nullable=True, comment="备注")

+ 29 - 0
SERVER/app/models/user_model.py

@@ -0,0 +1,29 @@
+from datetime import datetime
+from typing import Optional
+from sqlalchemy import Column, Integer, String, DateTime, Boolean, JSON
+from sqlalchemy.orm import relationship
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class UserModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    用户模型
+    对应数据库表: sys_users
+    """
+    __tablename__ = 'sys_users'
+
+    username = Column(String(50), unique=True, nullable=False, comment='用户名')
+    password = Column(String(255), nullable=False, comment='密码')
+    grade = Column(String(20), comment='年级')
+    preferences = Column(JSON, comment='学习偏好')
+    goals = Column(JSON, comment='学习目标')
+    learning_style = Column(String(50), comment='学习风格')
+    target_score = Column(Integer, comment='目标分数')
+
+    # 与角色的一对多关系
+    roles = relationship('RoleModel',
+                         secondary='sys_user_roles',
+                         back_populates='users')
+
+    def __repr__(self):
+        return f"<User(id={self.id}, username={self.username})>"

+ 13 - 0
SERVER/app/models/user_role_model.py

@@ -0,0 +1,13 @@
+from sqlalchemy import Column, Integer, ForeignKey
+from .base_model import BaseModel
+
+
+class UserRoleModel(BaseModel):
+    """
+    用户-角色关联表模型
+    对应数据库表: sys_user_roles
+    """
+    __tablename__ = 'sys_user_roles'
+
+    user_id = Column(Integer, ForeignKey('sys_users.id'), primary_key=True)
+    role_id = Column(Integer, ForeignKey('sys_roles.id'), primary_key=True)

+ 26 - 0
SERVER/app/models/wrong_question_model.py

@@ -0,0 +1,26 @@
+from sqlalchemy import Column, Integer, DateTime, ForeignKey
+from .base_model import BaseModel, CreateModel, UpdateModel, DeleteModel
+
+
+class WrongQuestionModel(BaseModel, CreateModel, UpdateModel, DeleteModel):
+    """
+    错题模型
+    对应数据库表: wrong_questions
+    """
+    __tablename__ = 'wrong_questions'
+
+    user_id = Column(Integer,
+                     ForeignKey('users.id'),
+                     nullable=False,
+                     comment='用户ID')
+    question_id = Column(Integer,
+                         ForeignKey('questions.id'),
+                         nullable=False,
+                         comment='题目ID')
+    exam_id = Column(Integer, ForeignKey('exams.id'), comment='考试ID')
+    exercise_id = Column(Integer, ForeignKey('exercises.id'), comment='练习ID')
+    wrong_count = Column(Integer, nullable=False, default=1, comment='错误次数')
+    last_wrong_time = Column(DateTime, nullable=False, comment='最后错误时间')
+
+    def __repr__(self):
+        return f"<WrongQuestion(id={self.id}, user_id={self.user_id}, question_id={self.question_id})>"

+ 85 - 0
SERVER/app/stores/base_store.py

@@ -0,0 +1,85 @@
+from typing import TypeVar, Generic, Optional, Dict, Any
+from sqlalchemy.orm import Session
+from sqlalchemy import and_
+from ..models.base_model import BaseModel, DeleteModel
+
+T = TypeVar('T', bound=BaseModel)
+
+
+class BaseStore(Generic[T]):
+    """
+    基础存储类,提供CRUD操作
+    """
+
+    def __init__(self, db: Session, model: type[T]):
+        self.db = db
+        self.model = model
+
+    def get(self, id: int, include_deleted: bool = False) -> Optional[T]:
+        """根据ID获取单个对象"""
+        query = self.db.query(self.model).filter(self.model.id == id)
+        if not include_deleted and issubclass(self.model, DeleteModel):
+            query = query.filter(self.model.is_deleted == False)
+        return query.first()
+
+    def get_all(self,
+                skip: int = 0,
+                limit: int = 100,
+                include_deleted: bool = False) -> list[T]:
+        """获取所有对象"""
+        query = self.db.query(self.model)
+        if not include_deleted and issubclass(self.model, DeleteModel):
+            query = query.filter(self.model.is_deleted == False)
+        return query.offset(skip).limit(limit).all()
+
+    def create(self, obj: T, unique_fields: Dict[str, Any] = None) -> T:
+        """创建新对象"""
+        if unique_fields:
+            self._check_unique_constraints(obj, unique_fields)
+        self.db.add(obj)
+        self.db.commit()
+        self.db.refresh(obj)
+        return obj
+
+    def update(self, obj: T, unique_fields: Dict[str, Any] = None) -> T:
+        """更新对象"""
+        if unique_fields:
+            self._check_unique_constraints(obj, unique_fields)
+        self.db.commit()
+        self.db.refresh(obj)
+        return obj
+
+    def delete(self, id: int, soft_delete: bool = True) -> None:
+        """删除对象"""
+        obj = self.get(id)
+        if obj:
+            if soft_delete and issubclass(self.model, DeleteModel):
+                obj.is_deleted = True
+                self.db.commit()
+            else:
+                self.db.delete(obj)
+                self.db.commit()
+
+    def _check_unique_constraints(self, obj: T,
+                                  unique_fields: Dict[str, Any]) -> None:
+        """检查唯一性约束"""
+        for field, value in unique_fields.items():
+            query = self.db.query(
+                self.model).filter(getattr(self.model, field) == value)
+            if obj.id:
+                query = query.filter(self.model.id != obj.id)
+            if issubclass(self.model, DeleteModel):
+                query = query.filter(self.model.is_deleted == False)
+            if query.first():
+                raise ValueError(f"{field} must be unique")
+
+    def restore(self, id: int) -> Optional[T]:
+        """恢复软删除的对象"""
+        if not issubclass(self.model, DeleteModel):
+            return None
+        obj = self.get(id, include_deleted=True)
+        if obj and obj.is_deleted:
+            obj.is_deleted = False
+            self.db.commit()
+            return obj
+        return None

+ 43 - 0
SERVER/app/stores/exam_store.py

@@ -0,0 +1,43 @@
+from typing import Optional, List
+from datetime import datetime
+from sqlalchemy.orm import Session, joinedload
+from ..models.exam_model import ExamModel
+from .base_store import BaseStore
+
+
+class ExamStore(BaseStore[ExamModel]):
+    """
+    考试存储类,继承自BaseStore
+    提供考试相关的特定操作
+    """
+
+    def __init__(self, db: Session):
+        super().__init__(db, ExamModel)
+
+    def get_by_name(self, name: str) -> Optional[ExamModel]:
+        """根据考试名称获取考试"""
+        return self.db.query(
+            self.model).filter(self.model.name == name).first()
+
+    def get_by_subject(self, subject: str) -> List[ExamModel]:
+        """根据学科获取考试列表"""
+        return self.db.query(
+            self.model).filter(self.model.subject == subject).all()
+
+    def get_active_exams(self) -> List[ExamModel]:
+        """获取所有激活的考试"""
+        return self.db.query(
+            self.model).filter(self.model.status == 'active').all()
+
+    def get_upcoming_exams(self) -> List[ExamModel]:
+        """获取即将开始的考试"""
+        now = datetime.now()
+        return self.db.query(self.model)\
+            .filter(self.model.start_time > now)\
+            .order_by(self.model.start_time.asc())\
+            .all()
+
+    def get_exams_with_questions(self) -> List[ExamModel]:
+        """获取包含题目信息的考试列表"""
+        return self.db.query(self.model).options(
+            joinedload(self.model.questions)).all()

+ 51 - 0
SERVER/app/stores/knowledge_point_store.py

@@ -0,0 +1,51 @@
+from typing import Optional, List
+from sqlalchemy.orm import Session
+from ..models.knowledge_point_model import KnowledgePointModel
+from .base_store import BaseStore
+
+
+class KnowledgePointStore(BaseStore[KnowledgePointModel]):
+    """
+    知识点存储类,继承自BaseStore
+    提供知识点相关的特定操作
+    """
+
+    def __init__(self, db: Session):
+        super().__init__(db, KnowledgePointModel)
+
+    def get_by_subject(self, subject: str) -> List[KnowledgePointModel]:
+        """根据学科获取知识点列表"""
+        return self.db.query(
+            self.model).filter(self.model.subject == subject).all()
+
+    def get_by_level(self, level: int) -> List[KnowledgePointModel]:
+        """根据难度等级获取知识点列表"""
+        return self.db.query(
+            self.model).filter(self.model.level == level).all()
+
+    def get_root_knowledge_points(self) -> List[KnowledgePointModel]:
+        """获取所有根知识点"""
+        return self.db.query(
+            self.model).filter(self.model.parent_id == None).all()
+
+    def get_child_knowledge_points(
+            self, parent_id: int) -> List[KnowledgePointModel]:
+        """根据父知识点ID获取子知识点列表"""
+        return self.db.query(
+            self.model).filter(self.model.parent_id == parent_id).all()
+
+    def get_knowledge_point_tree(self) -> List[KnowledgePointModel]:
+        """获取完整的知识点树结构"""
+        # 先获取所有知识点
+        all_points = self.db.query(self.model).all()
+        # 构建树结构
+        point_dict = {point.id: point for point in all_points}
+        for point in all_points:
+            if point.parent_id:
+                parent = point_dict.get(point.parent_id)
+                if parent:
+                    if not hasattr(parent, 'children'):
+                        parent.children = []
+                    parent.children.append(point)
+        # 返回根节点
+        return [point for point in all_points if not point.parent_id]

+ 34 - 0
SERVER/app/stores/permission_store.py

@@ -0,0 +1,34 @@
+from typing import Optional, List
+from sqlalchemy.orm import Session, joinedload
+from ..models.permission_model import PermissionModel
+from .base_store import BaseStore
+
+
+class PermissionStore(BaseStore[PermissionModel]):
+    """
+    权限存储类,继承自BaseStore
+    提供权限相关的特定操作
+    """
+
+    def __init__(self, db: Session):
+        super().__init__(db, PermissionModel)
+
+    def get_by_name(self, name: str) -> Optional[PermissionModel]:
+        """根据权限名称获取权限"""
+        return self.db.query(
+            self.model).filter(self.model.name == name).first()
+
+    def get_by_code(self, code: str) -> Optional[PermissionModel]:
+        """根据权限代码获取权限"""
+        return self.db.query(
+            self.model).filter(self.model.code == code).first()
+
+    def get_active_permissions(self) -> List[PermissionModel]:
+        """获取所有激活的权限"""
+        return self.db.query(
+            self.model).filter(self.model.status == True).all()
+
+    def get_permissions_with_roles(self) -> List[PermissionModel]:
+        """获取包含角色信息的权限列表"""
+        return self.db.query(self.model).options(joinedload(
+            self.model.roles)).all()

+ 38 - 0
SERVER/app/stores/question_store.py

@@ -0,0 +1,38 @@
+from typing import Optional, List
+from sqlalchemy.orm import Session, joinedload
+from ..models.question_model import QuestionModel
+from .base_store import BaseStore
+
+
+class QuestionStore(BaseStore[QuestionModel]):
+    """
+    题目存储类,继承自BaseStore
+    提供题目相关的特定操作
+    """
+
+    def __init__(self, db: Session):
+        super().__init__(db, QuestionModel)
+
+    def get_by_subject(self, subject: str) -> List[QuestionModel]:
+        """根据学科获取题目列表"""
+        return self.db.query(
+            self.model).filter(self.model.subject == subject).all()
+
+    def get_by_type(self, type: str) -> List[QuestionModel]:
+        """根据题型获取题目列表"""
+        return self.db.query(self.model).filter(self.model.type == type).all()
+
+    def get_by_difficulty(self, difficulty: int) -> List[QuestionModel]:
+        """根据难度获取题目列表"""
+        return self.db.query(
+            self.model).filter(self.model.difficulty == difficulty).all()
+
+    def get_questions_with_options(self) -> List[QuestionModel]:
+        """获取包含选项信息的题目列表"""
+        return self.db.query(self.model).options(joinedload(
+            self.model.options)).all()
+
+    def get_questions_with_knowledge_points(self) -> List[QuestionModel]:
+        """获取包含知识点信息的题目列表"""
+        return self.db.query(self.model).options(
+            joinedload(self.model.knowledge_points)).all()

+ 39 - 0
SERVER/app/stores/role_store.py

@@ -0,0 +1,39 @@
+from typing import Optional, List
+from sqlalchemy.orm import Session, joinedload
+from ..models.role_model import RoleModel
+from .base_store import BaseStore
+
+
+class RoleStore(BaseStore[RoleModel]):
+    """
+    角色存储类,继承自BaseStore
+    提供角色相关的特定操作
+    """
+
+    def __init__(self, db: Session):
+        super().__init__(db, RoleModel)
+
+    def get_by_name(self, name: str) -> Optional[RoleModel]:
+        """根据角色名称获取角色"""
+        return self.db.query(
+            self.model).filter(self.model.name == name).first()
+
+    def get_by_code(self, code: str) -> Optional[RoleModel]:
+        """根据角色代码获取角色"""
+        return self.db.query(
+            self.model).filter(self.model.code == code).first()
+
+    def get_active_roles(self) -> List[RoleModel]:
+        """获取所有激活的角色"""
+        return self.db.query(
+            self.model).filter(self.model.status == True).all()
+
+    def get_roles_with_users(self) -> List[RoleModel]:
+        """获取包含用户信息的角色列表"""
+        return self.db.query(self.model).options(joinedload(
+            self.model.users)).all()
+
+    def get_roles_with_permissions(self) -> List[RoleModel]:
+        """获取包含权限信息的角色列表"""
+        return self.db.query(self.model).options(
+            joinedload(self.model.permissions)).all()

+ 28 - 0
SERVER/app/stores/status_store.py

@@ -0,0 +1,28 @@
+from typing import Optional
+from sqlalchemy.orm import Session
+from ..models.status_model import StatusModel
+from .base_store import BaseStore
+
+
+class StatusStore(BaseStore[StatusModel]):
+    """
+    状态存储类,继承自BaseStore
+    提供状态相关的特定操作
+    """
+
+    def __init__(self, db: Session):
+        super().__init__(db, StatusModel)
+
+    def get_by_type(self, type: str) -> Optional[StatusModel]:
+        """根据类型获取状态"""
+        return self.db.query(
+            self.model).filter(self.model.type == type).first()
+
+    def get_all_by_status(self, status: int) -> list[StatusModel]:
+        """根据状态值获取所有状态"""
+        return self.db.query(
+            self.model).filter(self.model.status == status).all()
+
+    def get_all_by_sort(self) -> list[StatusModel]:
+        """根据排序获取所有状态"""
+        return self.db.query(self.model).order_by(self.model.sort).all()

+ 36 - 0
SERVER/app/stores/user_store.py

@@ -0,0 +1,36 @@
+from typing import Optional, List
+from sqlalchemy.orm import Session
+from ..models.user_model import UserModel
+from .base_store import BaseStore
+
+
+class UserStore(BaseStore[UserModel]):
+    """
+    用户存储类,继承自BaseStore
+    提供用户相关的特定操作
+    """
+
+    def __init__(self, db: Session):
+        super().__init__(db, UserModel)
+
+    def get_by_username(self, username: str) -> Optional[UserModel]:
+        """根据用户名获取用户"""
+        return self.db.query(
+            self.model).filter(self.model.username == username).first()
+
+    def get_by_grade(self, grade: str) -> List[UserModel]:
+        """根据年级获取用户"""
+        return self.db.query(
+            self.model).filter(self.model.grade == grade).all()
+
+    def get_by_target_score(self, min_score: int,
+                            max_score: int) -> List[UserModel]:
+        """根据目标分数范围获取用户"""
+        return self.db.query(self.model).filter(
+            self.model.target_score >= min_score, self.model.target_score
+            <= max_score).all()
+
+    def get_by_learning_style(self, learning_style: str) -> List[UserModel]:
+        """根据学习风格获取用户"""
+        return self.db.query(self.model).filter(
+            self.model.learning_style == learning_style).all()