Files

11 KiB
Raw Permalink Blame History

数据模型说明

概述

本系统使用 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) 班级名称,必填
level String(20) 班级级别:启蒙/入门/进阶/熟练/精通
description Text 班级描述,可选
teacher_id Integer 外键,关联 User(班主任)
active Boolean 是否进行中,默认 true
created_at DateTime 创建时间

关系:

  • students: 与 Student 一对多
  • teacher: 与 User 多对一(班主任)

5. PracticePlan (练习方案)

字段 类型 说明
id Integer 主键,自增
student_id Integer 外键,关联 Student
template_id Integer 外键,关联 Template(AI提示词模板)
is_typical Boolean 是否为典型方案
content Text 方案内容(JSON格式)
created_by Integer 外键,关联 User(创建人)
created_at DateTime 创建时间
updated_by Integer 外键,关联 User(更新人,仅编辑时设置)
updated_at DateTime 更新时间(仅编辑时设置)

审计字段说明

  • created_by:创建时设置
  • updated_byupdated_at:仅在编辑更新时设置,初次创建时为空

content 字段结构:

{
  "student_name": "张三",
  "practice_time": "30分钟",
  "total_daily_minutes": 30,
  "problems": [
    {
      "name": "手小",
      "severity": "中等",
      "level": "入门",
      "focus": {"basic": 15, "tech": 10, "piece": 20}
    }
  ],
  "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       │
                      └──────────────────┘

常用查询

查询用户角色

from app.models import User
user = User.query.filter_by(username="admin").first()
print(user.role)  # "admin" or "user"

查询学员及其问题

student = Student.query.get(1)
for sp in student.problems:
    print(sp.problem.name, sp.problem.code, sp.severity, sp.level)

查询班级及其学员

cls = Class.query.get(1)
for student in cls.students:
    print(student.name)

查询学员及其方案

student = Student.query.get(1)
for plan in student.plans:
    print(plan.created_at)

获取最新方案

from app.models import PracticePlan
latest_plan = PracticePlan.query.order_by(
    PracticePlan.created_at.desc()
).first()

数据库管理

初始化数据库

首次运行应用时会自动创建所有表:

from app import create_app
from app.models import db

app = create_app()
with app.app_context():
    db.create_all()

备份数据库

# 停止服务后复制数据库文件
copy data\piano_plans.db backup\piano_plans_backup.db

查看数据库内容

# 使用 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
level String(20) 级别:启蒙/入门/进阶/熟练/精通
category String(20) 分类:综合/乐理相关/演奏能力/其他
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,外键
goal_content Text 目标内容副本(冗余存储,避免目标被删除后丢失)
start_date DateTime 开始日期
assessment_date DateTime 评估日期
mastery_level Integer 掌握程度 1-5(评估时填写)
achievement_date DateTime 达成日期
comment Text 评语
created_at DateTime 创建时间

状态计算逻辑

  • statusstart_dateassessment_date 自动计算,不存储
  • 早于 start_date → 未开始
  • start_dateassessment_date 之间 → 进行中
  • 晚于 assessment_date → 已结束

排序规则:按状态(进行中→未开始→已结束),再按评估日期倒序

关系

  • 一个学员可以分配多个目标
  • 一个目标可以分配给多个学员

操作入口

  • "调整目标":修改开始/评估日期,移除目标
  • "评估目标":填写掌握程度、达成日期、评语