feat: 问题数据迁移到数据库;学员详情页URL导航改造;侧边栏统一

- 问题从文件系统迁移到数据库 problems 表
- 移除 PROBLEMS_DIR 配置和文件读取逻辑
- student.html 完整重写:编辑/添加/删除问题,生成方案进度显示
- 学员详情页支持独立URL访问 (/student/<id>)
- 统一侧边栏到 base.html
- 更新文档:DEPLOYMENT_SOP, MODELS, STRUCTURE, FRONTEND_ARCH
- 部署到生产环境 v1.2.0
This commit is contained in:
hmo
2026-04-23 06:35:32 +08:00
parent fd593bddf4
commit 18351212e8
18 changed files with 857 additions and 488 deletions
+69 -4
View File
@@ -114,6 +114,15 @@ class Student(db.Model):
class_obj = db.relationship("Class", backref="students")
def to_dict(self):
# 获取问题列表,按严重程度排序(严重 > 中等 > 轻微)
severity_order = {"严重": 0, "中等": 1, "轻微": 2}
problems_list = sorted(
self.problems.all(),
key=lambda p: (severity_order.get(p.severity, 1), p.created_at)
)
# 通过关联获取问题名称
problem_names = [p.problem.name if p.problem else p.problem_name for p in problems_list]
return {
"id": self.id,
"name": self.name,
@@ -127,10 +136,33 @@ class Student(db.Model):
if self.created_at
else None,
"problem_count": self.problems.count(),
"problem_names": problem_names, # 问题名称列表(按严重程度排序)
"plan_count": self.plans.count(),
}
class Problem(db.Model):
"""问题表"""
__tablename__ = "problems"
id = db.Column(db.Integer, primary_key=True)
no = db.Column(db.String(10), unique=True, nullable=False) # 编号:01, 02...
name = db.Column(db.String(100), nullable=False) # 问题名称
category = db.Column(db.String(50), default="技术类") # 分类
content = db.Column(db.Text) # 问题详细内容
created_at = db.Column(db.DateTime, default=datetime.now)
updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)
def to_dict(self):
return {
"id": self.id,
"no": self.no,
"name": self.name,
"category": self.category,
}
class StudentProblem(db.Model):
"""学员问题记录表"""
@@ -138,17 +170,21 @@ class StudentProblem(db.Model):
id = db.Column(db.Integer, primary_key=True)
student_id = db.Column(db.Integer, db.ForeignKey("students.id"), nullable=False)
problem_id = db.Column(db.String(50), nullable=False) # 如 "01_手小"
problem_name = db.Column(db.String(100), nullable=False) # 如 "手小"
problem_id = db.Column(db.Integer, db.ForeignKey("problems.id"), nullable=False) # 外键
severity = db.Column(db.String(10), nullable=False) # 轻微/中等/严重
level = db.Column(db.String(20)) # 启蒙/入门/进阶/熟练/精通
created_at = db.Column(db.DateTime, default=datetime.now)
# 关联到 Problem
problem = db.relationship("Problem", foreign_keys=[problem_id])
def to_dict(self):
return {
"id": self.id,
"problem_id": self.problem_id,
"problem_name": self.problem_name,
"student_id": self.student_id,
"problem_id": self.problem_id, # 外键关联到 problems.id
"problem_name": self.problem.name if self.problem else None,
"problem_no": self.problem.no if self.problem else None,
"severity": self.severity,
"level": self.level,
}
@@ -161,14 +197,43 @@ class PracticePlan(db.Model):
id = db.Column(db.Integer, primary_key=True)
student_id = db.Column(db.Integer, db.ForeignKey("students.id"), nullable=False)
template_id = db.Column(db.Integer, db.ForeignKey("templates.id"), nullable=True) # 使用的AI提示词模板
is_typical = db.Column(db.Boolean, default=False, nullable=False) # 是否为典型方案
content = db.Column(db.Text, nullable=False) # JSON格式存储方案内容
created_at = db.Column(db.DateTime, default=datetime.now)
# 关联
template = db.relationship("Template", foreign_keys=[template_id])
def to_dict(self):
import json as json_module
content_obj = {}
try:
content_obj = json_module.loads(self.content) if self.content else {}
except:
pass
# 从 content 中提取问题列表
problems = content_obj.get("problems", [])
problem_names = [p.get("name", "") for p in problems] if problems else []
# 获取模板名称
template_name = self.template.name if self.template else None
# 获取学员班级
class_name = None
if self.student and self.student.class_obj:
class_name = self.student.class_obj.name
return {
"id": self.id,
"student_id": self.student_id,
"student_name": self.student.name if self.student else "",
"class_name": class_name,
"template_id": self.template_id,
"template_name": template_name,
"is_typical": self.is_typical,
"problem_names": problem_names,
"created_at": self.created_at.strftime("%Y-%m-%d %H:%M")
if self.created_at
else None,