# 数据模型说明 ## 概述 本系统使用 SQLite 数据库,ORM 框架为 Flask-SQLAlchemy。 **数据库文件**: `data/piano_plans.db` --- ## 数据表 ### 0. Problem (问题定义) 系统预定义的15种常见钢琴学习问题。 | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键,自增 | | code | String(50) | 问题编号,如 "05_掌关节支撑差" | | name | String(100) | 问题名称,如 "掌关节支撑差" | | category | String(20) | 分类:技术类/认知类/节奏类/习惯类/综合类 | | created_at | DateTime | 创建时间 | > ⚠️ 问题数据已从文件系统迁移到数据库。student_problems 表通过 `problem_id` 外键关联到此表。 --- ### 1. User (用户) 系统用户,用于登录认证和权限管理。 | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键,自增 | | username | String(50) | 用户名,唯一,必填 | | password_hash | String(200) | 密码哈希值 | | role | String(20) | 角色:admin/user,默认 user | | created_at | DateTime | 创建时间 | **角色说明**: - `admin`: 管理员,拥有所有权限 - `user`: 普通用户,受限权限 **密码规则**: 8位以上,包含大小写字母、数字和特殊字符 --- ### 2. Student (学员) | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键,自增 | | name | String(100) | 学员姓名,必填 | | phone | String(20) | 手机号,可选 | | wechat_nickname | String(100) | 微信昵称,可选 | | practice_time | String(20) | 每日练习时间,默认"30分钟" | | notes | Text | 备注信息,可选 | | class_id | Integer | 外键,关联 Class,可选 | | created_at | DateTime | 创建时间 | **练习时间选项**: `15分钟`, `30分钟`, `45分钟`, `60分钟`, `90分钟`, `120分钟`, `150分钟以上` **关系**: - `problems`: 与 StudentProblem 一对多 - `plans`: 与 PracticePlan 一对多 - `class`: 与 Class 多对一 --- ### 3. StudentProblem (学员问题记录) | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键,自增 | | student_id | Integer | 外键,关联 Student | | problem_id | Integer | 外键,关联 Problem.id | | severity | String(10) | 严重程度:轻微/中等/严重 | | level | String(20) | 级别:启蒙/入门/进阶/熟练/精通 | | created_at | DateTime | 创建时间 | > ⚠️ `problem_id` 现为数字外键,关联 `Problem.id`。通过 `student_problem.problem` 关系获取问题名称。 --- ### 4. Class (班级) | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键,自增 | | name | String(100) | 班级名称,必填 | | description | Text | 班级描述,可选 | | created_at | DateTime | 创建时间 | **关系**: - `students`: 与 Student 一对多 --- ### 5. PracticePlan (练习方案) | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键,自增 | | student_id | Integer | 外键,关联 Student | | content | Text | 方案内容(JSON格式) | | created_at | DateTime | 创建时间 | **content 字段结构**: ```json { "student_name": "张三", "practice_time": "30分钟", "total_daily_minutes": 30, "problems": [ { "name": "手小", "severity": "中等", "level": "入门", "focus": {"basic": 15, "tech": 10, "piece": 20} } ], "daily_schedule": [ { "phase": "热身", "duration": "3分钟", "content": "手部放松操 + 呼吸调节", "purpose": "放松肌肉,进入状态" } ], "ai_report": "## 个性化练习方案报告\n\n..." } ``` --- ## ER 关系图 ``` ┌─────────────┐ ┌──────────────────┐ ┌───────────────┐ │ User │ │ Student │ │ Class │ ├─────────────┤ ├──────────────────┤ ├───────────────┤ │ id │ │ id │◄──────│ id │ │ username │ │ name │ │ name │ │ password │ │ phone │ │ description │ │ role │ │ wechat_nickname │ │ created_at │ │ created_at │ │ practice_time │ └───────────────┘ └─────────────┘ │ notes │ │ class_id │──┐ │ created_at │ │ └──────────────────┘ │ │ │ ▼ │ ┌──────────────────┐ │ │ StudentProblem │ │ ├──────────────────┤ │ │ id │ │ │ student_id ─────┘ │ │ problem_id │◄─┼──► Problem │ severity │ │ level │ │ created_at │ └──────────────────┘ │ ▼ ┌──────────────────┐ │ PracticePlan │ ├──────────────────┤ │ id │ │ student_id ─────┼──► Student │ content │ │ created_at │ └──────────────────┘ ``` --- ## 常用查询 ### 查询用户角色 ```python from app.models import User user = User.query.filter_by(username="admin").first() print(user.role) # "admin" or "user" ``` ### 查询学员及其问题 ```python student = Student.query.get(1) for sp in student.problems: print(sp.problem.name, sp.problem.code, sp.severity, sp.level) ``` ### 查询班级及其学员 ```python cls = Class.query.get(1) for student in cls.students: print(student.name) ``` ### 查询学员及其方案 ```python student = Student.query.get(1) for plan in student.plans: print(plan.created_at) ``` ### 获取最新方案 ```python from app.models import PracticePlan latest_plan = PracticePlan.query.order_by( PracticePlan.created_at.desc() ).first() ``` --- ## 数据库管理 ### 初始化数据库 首次运行应用时会自动创建所有表: ```python from app import create_app from app.models import db app = create_app() with app.app_context(): db.create_all() ``` ### 备份数据库 ```bash # 停止服务后复制数据库文件 copy data\piano_plans.db backup\piano_plans_backup.db ``` ### 查看数据库内容 ```bash # 使用 SQLite 命令行 sqlite3 data\piano_plans.db # 查看表 .schema # 查询数据 SELECT * FROM users; ``` --- ## 数据字典 ### User.role 取值 | 值 | 说明 | |----|------| | admin | 管理员,拥有所有权限 | | user | 普通用户,受限权限 | ### StudentProblem.severity 取值 | 值 | 说明 | |----|------| | 轻微 | 问题不明显,日常练习即可改善 | | 中等 | 需要针对性练习,建议重点关注 | | 严重 | 需要系统训练,建议额外辅导 | ### StudentProblem.level 取值 | 值 | 说明 | |----|------| | 启蒙 | 初期入门阶段 | | 入门 | 基础学习阶段 | | 进阶 | 技能提升阶段 | | 熟练 | 技术熟练阶段 | | 精通 | 高级演奏阶段 | ### Student.practice_time 取值 | 值 | 说明 | |----|------| | 15分钟 | 初级学员 | | 30分钟 | 进阶学员 | | 45分钟 | 中级学员 | | 60分钟 | 中高级学员 | | 90分钟 | 高级学员 | | 120分钟 | 专业学员 | | 150分钟以上 | 竞技水平 | --- ## 目标管理模块 ### Goal (目标表) | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键 | | name | String(100) | 目标名称 | | content | Text | 目标内容(Markdown) | | created_at | DateTime | 创建时间 | | updated_at | DateTime | 更新时间 | ### GoalRelation (目标关联表) 自关联多对多关系,用于表示目标之间的父子关系(DAG)。 | 字段 | 类型 | 说明 | |------|------|------| | parent_goal_id | Integer | 父目标ID,外键 | | child_goal_id | Integer | 子目标ID,外键 | **关系类型**:自引用多对多(一个目标可以有多个子目标,也可以有多个父目标) **约束**:通过应用层循环检测防止形成循环 ### StudentGoal (学员目标记录表) | 字段 | 类型 | 说明 | |------|------|------| | id | Integer | 主键 | | student_id | Integer | 学员ID,外键 | | goal_id | Integer | 目标ID,外键 | | status | String(20) | 状态:未开始/进行中/已完成 | | mastery_level | Integer | 掌握程度 1-5 | | deadline | DateTime | 截止日期 | | completed_at | DateTime | 完成时间 | | created_at | DateTime | 创建时间 | **关系**: - 一个学员可以分配多个目标 - 一个目标可以分配给多个学员