数据库课设

数据库课程设计:学生成绩管理系统

任务要求

  1. 设计系统,包括系统的功能、需要存储数据的模块等

  2. 画E-R图并分解成各关系模型

  3. 数据库系统的搭建,根据E-R图和关系模型进行编写

  4. 用高级语言编译器连接数据库,实现GUI界面,体现相应的功能

    • 用python+vscode编写后端功能逻辑,将每个功能封装成function

    • 搭建前端界面,并链接数据库文件插入excel表格

  5. 及时维护和更新博客的内容攥写

  6. 完善课设报告



任务分配

板块成员具体任务
系统分析(√)成员1总体需求分析功能模块划分
成员2信息需求分析数据流图
系统设计(√)成员1概念结构+逻辑结构设计视图设计函数设计
成员2物理结构设计存储过程触发器设计
系统实现(√)成员1main.py+管理员登入.py 代码与前端实现管理员登入类+学生信息类+教师信息类+评分类数据库的连接
成员2学生登入.py+教师登入.py 代码与用户交互实现学生登入类+教师登入类+成绩类+课程类交互界面的完善
共同作业:excel表格的插入和导出工作代码适应文件和配置excel表格
系统测试(√)成员1数据库对正确、错误、边界数据的系统处理正确且符合需求分析的数据框架准备和测试
成员2交互界面在错误数据情况是否正常交互界面插入数据和excel导入数据是否合理报错
文稿答辩(√)成员1markdown文件的编写,博客编写完善PPT的修改完善
成员2PPT的制作图片表格的整理


文章目录

一、系统分析

1.1 项目背景

随着高等教育信息化建设的加速推进,高校管理正面临学生规模扩大、数据维度多元化和管理实时性要求的挑战。传统基于手工操作和离散文件的学生信息管理模式已显露出数据冗余、更新滞后和查询效率低下等系统性缺陷,严重制约了教学管理质量的提升。

用户角色:学生信息管理系统共包括三类用户,分别为管理员学生教师

甲方需求:需要以管理员的视角总体查看管理,可以实现在前端平台对老师和学生信息的修改和完善,且只有管理员身份可以修改终端数据库,管理员可以批量导入excel文件以插入数据

​核心需求教学评分表,交互界面和操作系统excel文件的导入,并且想要快速的在每个表中查找数据(前端查找功能)

1.2 需求分析

1、总体需求分析

使用学生管理系统的学校有若干个专业
学生表,学生自己的信息,一个学生只能在一个专业中,只能有一个邮箱注册
教师表,一个老师可以授课多个专业,但只能授课一个课程
课程表,一个课程对应多个学生+多个老师,以及学分等其他属性
成绩表,供学生查看,老师填写,管理员修改(甲方核心需求)
评分表,学生填写,老师查看,管理员监控违规评价(甲方核心需求)
该系统通过输入正确的用户名和密码进行登录


2、信息需求分析

1. 实体与属性设计

实体核心属性关联关系核心外键字段
学生学号(主码)、姓名、性别、专业编号(外键)、邮箱(登录名)、密码、入学年份1. 学生 ∈ 专业(多对一) 2. 学生 N:M 课程(通过成绩表关联)major_id
教师教师工号(主码)、姓名、性别、职称、邮箱(登录名)、密码、所属专业编号(外键)1. 教师 ∈ 专业(多对一) 2. 教师 N:M 课程(一对多)major_id
课程课程编号(主码)、课程名、学分、授课教师工号(外键)、上课时间地点、考试时间、所属专业编号(外键)1. 课程 ∈ 教师(一对一) 2. 课程 ∈ 专业(多对一) 3. 课程 N:M 学生(通过成绩表关联)teacher_id major_id
专业专业编号(主码)、专业名称、所属院系、专业负责人工号(外键,关联教师表)1. 专业 1:N 学生(一对多) 2. 专业 1:N 课程(一对多) 3. 专业 1:N 教师(多对一)dean_id

2. 数据关联说明

学生 - 专业

  • 关联方式:学生表通过 major_id 直接关联专业表,形成 学生 → 专业 的多对一关系(一个学生只能属于一个专业,一个专业包含多个学生)。
  • 示例:查询 “计算机科学与技术专业” 的所有学生时,直接通过学生表的 major_id 过滤数据,无需经过班级表。

课程 - 专业

  • 关联方式:课程表通过 major_id 关联专业表,形成 课程 → 专业 的多对一关系(一门课程属于一个专业,一个专业包含多门课程)。
  • 示例:为 “计算机专业” 开设 “操作系统” 课程时,通过课程表的 major_id 绑定专业编号,明确课程归属。

教师 - 专业

  • 关联方式:教师表通过专业表的 dean_id(专业负责人)或新增字段(如 affiliated_major_id)关联专业表,形成 教师 → 专业 的多对一关系(一个教师可隶属于一个专业,一个专业有多个教师)。
  • 场景:
  • dean_id:专业负责人(如 “计算机专业” 的负责人为 “张三老师”)。
  • affiliated_major_id:教师所属专业(如 “李四老师属于软件工程专业”)。

学生 - 课程

关联方式

:通过成绩表和评价表间接关联,形成学生 ↔ 课程的多对多关系(一个学生可选多门课程,一门课程可被多个学生选择)。

  • 成绩表student_id(学生)+ course_id(课程)记录选课成绩。
  • 评价表student_id(学生)+ course_id(课程)记录选课评价。

教师 - 课程

  • 关联方式:课程表通过 teacher_id 关联教师表,形成 教师 ↔ 课程 的一对多关系(一个教师可授多门课程,一门课程由一个教师授课)。
  • 示例:“张三老师” 教授 “数据结构” 和 “计算机网络” 两门课程,通过课程表的 teacher_id 关联教师工号。


3、功能模块划分

1. 用户登录与权限管理

  • 登录验证:学生 / 教师 / 管理员通过邮箱 + 密码登录,系统根据用户表(学生表 / 教师表 / 管理员表)验证身份并分配权限。
  • 权限控制:
  • 学生:查看个人信息(含专业)、成绩、已选课程的评价。
  • 教师:管理授课课程、录入成绩、查看本人授课课程的评价。
  • 管理员:管理学生 / 教师 / 课程信息、按专业统计成绩、系统设置。

2.学生信息管理

  • 学生视角:
  • 查看个人信息(学号、姓名、性别、专业、邮箱),修改邮箱和密码。
  • 管理员视角:
  • 专业管理:
  • 维护专业基础信息(专业名称、所属院系、专业负责人)。
  • 按院系筛选专业,导出专业列表。
  • 学生 - 专业关联:
  • 修改学生所属专业(支持批量调整,如 “将学生从计算机专业调整到软件工程专业”)。
  • 批量导入专业学生名单(通过专业编号关联)。

3. 课程信息管理

  • 管理员功能:
  • 维护课程基础信息(课程编号、名称、学分、上课时间地点、考试时间)。
  • 按专业分配课程(如为 “计算机专业” 添加 “数据结构” 课程)。
  • 标记专业核心课(通过课程表is_core字段),支持按专业查询核心课程。
  • 分配 / 修改课程的授课教师(通过教师工号关联)。
  • 教师功能:
  • 查看所授课程的详细信息,申请新增课程或调整上课时间。
  • 查看所授课程的所属专业,申请跨专业授课(需管理员审批)。

4. 成绩管理

  • 学生功能:按学期查询课程成绩(自动过滤所属专业的课程),下载成绩报告单。
  • 教师功能:
  • 录入 / 修改学生成绩(支持批量导入 Excel,按课程筛选学生)。
  • 查看所授课程的成绩分布(如平均分、及格率)。
  • 管理员功能:
  • 专业统计成绩(如专业排名、挂科率、各专业平均分对比)。
  • 生成成绩报表并打印(如某专业期末成绩单)。

5. 课程评价管理

  • 学生功能:对已选课程(所属专业内的课程)的教师和课程质量进行评价(内容 + 评分 1~5 星),每个课程仅限评价一次。
  • 教师功能:查看所授课程的评价详情,统计平均评分。
  • 管理员功能:
  • 监控违规评价(如敏感内容),导出课程评价报告。
  • 按专业汇总课程评价(如 “计算机专业所有课程的平均评分”),辅助优化专业课程设置。

6. 密码管理

  • 自主修改:学生 / 教师登录后可自行修改密码,需验证原密码。
  • 管理员重置:为忘记密码的用户重置密码(默认密码为学号 / 工号),支持邮件通知。

7. 专业管理

  • 功能描述:管理学校专业信息,明确专业与院系、教师、课程的关联关系。
  • 专业信息维护:
  • 新增专业(输入专业名称、所属院系、专业负责人)。
  • 修改专业负责人(如 “更换计算机专业的负责人”)。
  • 专业关联管理:
  • 查看专业下的所有课程和学生。
  • 统计专业教师数量、核心课程数量、学生总人数。

4、数据流图分析

在这里插入图片描述

外部实体与系统交互说明分析

  • 学生:向系统发送 “选课申请”“成绩查询” 请求,从系统接收 “选课结果”“成绩通知”。体现学生在系统中选课及获取成绩相关信息的流程。
  • 教师:向系统进行 “成绩录入” 和 “课程管理” 操作,接收系统反馈的 “录入确认” 及 “统计报表”,反映教师在系统中对成绩和课程的管理职能。
  • 管理员:对系统执行 “账户管理”“数据审核” 操作,接收系统的 “操作反馈”,并将相关数据 “归档系统”,表明管理员对系统整体数据和账户的管理工作。

详细说明

流程参与主体输入处理模块输出说明
学生信息管理学生、管理员、系统学生信息、专业选择、信息更新请求学生信息管理模块学生信息表更新学生或管理员维护学生基本信息(如姓名、专业、邮箱),直接关联专业表。
成绩管理学生、教师、管理员、系统学生考试信息、教师录入的成绩成绩录入与统计模块成绩表更新、统计报表教师通过课程表关联专业,录入学生成绩;学生按专业和课程查询成绩。
教师信息管理教师、管理员、系统教师信息、授课课程更新请求教师信息管理模块教师信息表更新管理员维护教师所属专业及授课课程,教师查看个人授课记录(关联课程表)。
课程管理教师、管理员、系统课程信息、专业分配请求课程信息管理模块课程表更新管理员按专业创建课程并分配教师;教师申请调整课程时间或跨专业授课(需审批)。
课程评价管理学生、教师、管理员、系统学生对课程 / 教师的评价内容评价管理模块评价表更新、违规记录学生对已选课程(关联专业)的教师进行评价,管理员审核违规内容并统计分析。
专业管理管理员、系统专业信息、院系分配、负责人调整专业信息管理模块专业表更新管理员维护专业基础信息(如院系、负责人),关联学生表和课程表。

数据库总体可视化分析:

数据库总体可视化

E-R图片分析

E-R图片分析

二、系统设计

2.1 数据库功能设计

2.1.1. 用户登录与权限管理
  • 登录验证:

    支持学生、教师和管理员三种角色通过邮箱和密码进行登录。数据库中为每种角色的用户表(学生表、教师表、管理员表)设置了唯一的邮箱字段(student_emailteacher_emailadmin_email)和加密后的密码字段(student_password_hashteacher_password_hashadmin_password_hash),并对邮箱字段创建了索引(idx_student_emailidx_teacher_emailidx_admin_email),以加速登录查询。

  • 权限控制:

    • 学生:可以查看个人信息(从学生表获取)、成绩(从成绩表获取)以及已选课程的评价(从评价表获取)。
    • 教师:能够管理授课课程(课程表)、录入和修改学生成绩(成绩表),并查看本人授课课程的评价(评价表)。
    • 管理员:负责管理学生、教师和课程信息(分别对应学生表、教师表和课程表),进行成绩统计(成绩表)以及系统设置(管理员表中的权限描述字段 permissions)。

2.1.2. 学生信息管理
  • 学生视角:

    • 查看个人信息,包括学号、姓名、性别、专业和邮箱等,这些信息存储在学生表中,通过专业表关联获取完整信息。
    • 可以修改邮箱和密码,直接更新学生表中的相应字段。
  • 管理员视角:

    • 专业管理:
    • 新增、修改和删除专业信息,操作专业表中的记录。专业表包含专业编号、名称、所属院系和专业负责人等字段。
    • 批量导入专业学生名单,通过专业编号关联学生表和专业表。
    • 学生 - 专业关联:
    • 修改学生所属专业,更新学生表中的 major_id 字段,支持批量调整。

2.1.3. 课程信息管理
  • 管理员功能:

    • 维护课程基础信息,包括课程编号、名称、学分、上课时间地点、考试时间等,操作课程表中的记录。
    • 按专业分配课程,通过课程表中的 major_id 字段关联专业表。
    • 标记专业核心课,通过课程表中的 is_core 字段实现。
    • 分配和修改课程的授课教师,更新课程表中的 teacher_id 字段。
  • 教师功能:

    • 查看所授课程的详细信息,从课程表获取数据。
    • 申请新增课程或调整上课时间,向课程表中插入新记录或更新相应字段。
    • 查看所授课程的所属专业,通过课程表中的 major_id 关联专业表。申请跨专业授课需管理员审批。

2.1.4. 成绩管理
  • 学生功能:

    • 按学期查询课程成绩,通过成绩表中的 student_idcourse_id 关联学生表和课程表,结合 exam_date 字段进行学期筛选。
    • 下载成绩报告单,将查询到的成绩信息进行整理输出。
  • 教师功能:

    • 录入和修改学生成绩,操作成绩表中的 score 字段,支持批量导入 Excel 文件。
    • 查看所授课程的成绩分布,通过对成绩表中的数据进行统计分析,如计算平均分、及格率等。
  • 管理员功能:

    • 按专业统计成绩,通过成绩表、学生表和专业表的关联,进行分组统计,如计算专业排名和挂科率等。
    • 生成成绩报表并打印,将统计结果整理成报表形式。

2.1.5. 课程评价管理
  • 学生功能:

    对已选课程的教师和课程质量进行评价,向评价表中插入新记录,包括评价内容、评分、评价日期等信息。每个课程仅限评价一次,通过评价表中的唯一约束 unique_score 确保。

  • 教师功能:

    • 查看所授课程的评价详情,从评价表中查询相关记录。
    • 统计平均评分,对评价表中的评分字段进行计算。
  • 管理员功能:

      • 监控违规评价,对评价表中的评价内容进行审核。
    • 导出课程评价报告,按专业汇总课程评价,通过评价表、课程表和专业表的关联进行统计分析,辅助优化专业课程设置。

2.2 数据库设计

2.2.1 数据库需求分析

1、用户角色与需求
  • 用户角色:明确系统包含三类用户,分别为管理员、学生和教师。

  • 需求概述

    • 管理员:需要管理学生、教师和课程信息,进行成绩统计和系统设置,监控课程评价等。
    • 学生:希望能够查看个人信息、成绩和已选课程的评价,修改邮箱和密码等。
    • 教师:需要管理授课课程、录入成绩,查看本人授课课程的评价等

2、数据需求分析

实体与属性

  • 学生:包含学号、姓名、性别、班级编号、邮箱、密码、入学时间等属性。
  • 教师:包含教师工号、姓名、性别、职称、邮箱、密码、所属专业编号等属性。
  • 课程:包含课程编号、课程名、学分、授课教师工号、上课时间地点、考试时间、所属专业编号、是否为专业核心课等属性。
  • 专业:包含专业编号、专业名称、所属院系、专业负责人工号等属性。
  • 成绩:包含成绩记录 ID、学生编号、课程编号、成绩分数、成绩类型、考试日期等属性。
  • 评价:包含评价记录 ID、评价学生编号、评价课程编号、评价内容、评价评分、评价日期等属性。

数据关联

  • 学生 - 专业:学生通过所属专业编号直接关联专业表,形成多对一关系(一个学生属于一个专业,一个专业包含多个学生)。
  • 课程 - 专业:课程通过专业编号关联专业表,明确课程所属专业,形成课程对专业的多对一关系。
  • 教师 - 专业:教师通过专业编号关联专业表,表示教师隶属于某个专业,形成教师对专业的多对一关系。
  • 学生 - 课程:学生与课程之间是多对多关系,通过成绩表建立关联。
  • 教师 - 课程:教师与课程之间是多对多关系。
  • 学生 - 评价:学生与评价之间是一对多关系,一个学生可以对多门课程进行评价。
  • 课程 - 评价:课程与评价之间是一对多关系,一门课程可以收到多个学生的评价。

3、功能需求分析

用户登录与权限管理

  • 登录验证:学生、教师和管理员通过邮箱 + 密码登录,系统验证身份并分配权限。
  • 权限控制:不同用户角色具有不同的操作权限,如学生只能查看个人信息和成绩,教师可以录入成绩,管理员可以管理所有信息。

信息管理功能

  • 学生信息管理:包括学生个人信息的查看和修改,以及管理员对班级和专业信息的维护。
  • 课程信息管理:管理员可以维护课程基础信息,分配课程和授课教师;教师可以查看和申请修改所授课程信息。
  • 成绩管理:学生可以查询成绩,教师可以录入和修改成绩,管理员可以进行成绩统计和报表生成。
  • 课程评价管理:学生可以对课程进行评价,教师可以查看评价详情,管理员可以监控违规评价并导出评价报告。
  • 密码管理:学生和教师可以自主修改密码,管理员可以为忘记密码的用户重置密码。
  • 班级管理:实现班级信息的全生命周期管理,包括新增、修改和删除班级信息,以及班级学生的管理。
  • 专业管理:管理学校专业信息,包括新增、修改专业信息,以及查看专业下的班级和课程。


2.2.2 数据库概念结构设计

1. 实体表
表名字段列表主键外键
学生表(Student)学号(ID), 姓名(Name), 性别(Gender), 所属专业编号(MajorID), 邮箱(Email), 密码(Password), 实际入学年份(EnrollYear)学号所属专业编号 → 专业表
教师表(Teacher)教师工号(ID), 姓名(Name), 职称(Title), 邮箱(Email), 密码(Password)教师工号
课程表(Course)课程编号(ID), 课程名(Name), 学分(Credit), 授课教师工号(TeacherID), 上课时间地点(Schedule), 考试时间(ExamTime), 所属专业编号(MajorID), 是否为专业核心课(IsCore)课程编号授课教师工号 → 教师表, 所属专业编号 → 专业表
专业表(Major)专业编号(ID), 专业名称(Name), 所属院系(Department), 专业负责人工号(HeadTeacherID), 默认入学年份(DefaultEnrollYear)专业编号专业负责人工号 → 教师表
成绩表(Score)成绩记录ID(ID), 学生编号(StudentID), 课程编号(CourseID), 成绩分数(Value), 成绩类型(Type), 考试日期(ExamDate)成绩记录ID学生编号 → 学生表, 课程编号 → 课程表
评价表(Review)评价记录ID(ID), 评价学生编号(StudentID), 评价课程编号(CourseID), 评价教师编号(TeacherID), 评价内容(Content), 评价评分(Rating), 评价日期(Date), 是否匿名(IsAnonymous)评价记录ID评价学生编号 → 学生表, 评价课程编号 → 课程表, 评价教师编号 → 教师表
管理员表(Admin)管理员编号(ID), 姓名(Name), 邮箱(Email), 密码(Password), 权限描述(Permission)管理员编号

2. 关联关系表(多对多)
关联表名关联字段关联实体说明
教师-课程关联(Teacher_Course)教师工号(TeacherID), 课程编号(CourseID)教师表 ↔ 课程表解决教师与课程的多对多授课关系

3. 关系说明表
关系名称关联表关联类型实现方式
学生-专业学生表 ↔ 专业表多对一学生表的MajorID外键关联专业表
课程-专业课程表 ↔ 专业表多对一课程表的MajorID外键关联专业表
教师-专业专业表 ↔ 教师表多对一专业表的HeadTeacherID外键关联教师表
学生-课程-成绩学生表 ↔ 成绩表 ↔ 课程表多对多通过成绩表的StudentIDCourseID分别关联学生表和课程表
学生-课程-教师-评价学生表 ↔ 评价表 ↔ 课程表 ↔ 教师表多对多评价表同时关联学生、课程、教师三个实体

4、实体 - 联系的详细说明
  • 学生 - 专业关系:学生通过所属专业编号直接关联到专业表,形成学生对专业的多对一关系。例如,查询 “计算机科学与技术专业” 的所有学生时,可直接通过专业表与学生表的关联关系实现。
  • 专业 - 课程关系:课程通过所属专业编号关联专业表,明确课程的专业归属,如 “数据结构” 课程属于计算机专业,体现课程对专业的多对一关系。
  • 教师 - 专业关系:专业表通过专业负责人工号字段关联教师表,表明每个专业有对应的负责人教师,形成专业对教师的多对一关系(一个专业可能只有一名负责人教师)。
  • 学生 - 课程 - 成绩关系:学生与课程之间的多对多联系通过成绩表实现,成绩表记录了每个学生每门课程的成绩信息,同时包含成绩类型、考试日期等详细数据。
  • 学生 - 课程 - 教师 - 评价关系:评价表同时关联学生、课程和教师三个实体,学生可对所选课程及其授课教师进行评价,评价内容包括文字描述、评分及是否匿名等信息,形成多维度的评价关联体系。
  • 管理员与其他实体关系:管理员通过系统权限对学生、教师、课程、专业等所有实体进行管理操作,如添加、修改、删除实体信息或查询相关数据,体现管理员对其他实体的统一管理权限。


2.2.3 数据库逻辑结构设计

1. 教师表(teacher)
字段名数据类型说明约束
teacher_idVARCHAR(20)教师工号(主键)PRIMARY KEY
teacher_nameVARCHAR(50)教师姓名NOT NULL
teacher_titleVARCHAR(20)职称
teacher_emailVARCHAR(50)邮箱(登录名)UNIQUE, NOT NULL
teacher_password_hashVARCHAR(100)加密后的密码NOT NULL
-- -----------------------------------------------------
-- 教师表:存储教师基本信息和认证信息
-- -----------------------------------------------------
CREATE TABLE teacher (
    teacher_id VARCHAR(20) PRIMARY KEY COMMENT '教师工号(主键)',
    teacher_name VARCHAR(50) NOT NULL COMMENT '教师姓名',
    teacher_title VARCHAR(20) COMMENT '职称',
    teacher_email VARCHAR(50) UNIQUE COMMENT '邮箱(用于登录,唯一约束)',
    teacher_password_hash VARCHAR(100) NOT NULL COMMENT '加密后的密码'
);

-- 为教师表的邮箱字段添加索引
CREATE INDEX idx_teacher_email ON teacher(teacher_email);

2. 专业表(major)
字段名数据类型说明约束
major_idVARCHAR(20)专业编号(主键)PRIMARY KEY
major_nameVARCHAR(50)专业名称UNIQUE, NOT NULL
departmentVARCHAR(50)所属院系NOT NULL
dean_idVARCHAR(20)专业负责人工号FOREIGN KEY (teacher_id)
entry_yearYEAR专业默认入学年份
-- -----------------------------------------------------
-- 专业表:存储学校专业信息(新增入学年份字段)
-- -----------------------------------------------------
CREATE TABLE major (
    major_id VARCHAR(20) PRIMARY KEY COMMENT '专业编号(主键)',
    major_name VARCHAR(50) NOT NULL UNIQUE COMMENT '专业名称',
    department VARCHAR(50) NOT NULL COMMENT '所属院系',
    dean_id VARCHAR(20) COMMENT '专业负责人工号',
    entry_year YEAR COMMENT '专业默认入学年份', -- 新增字段:可存储专业的默认入学年份
    FOREIGN KEY (dean_id) REFERENCES teacher(teacher_id) ON DELETE SET NULL
);

-- 为专业表的院系字段添加索引
CREATE INDEX idx_major_department ON major(department);

3. 学生表(student)
字段名数据类型说明约束
student_idVARCHAR(20)学生学号(主键)PRIMARY KEY
student_nameVARCHAR(50)学生姓名NOT NULL
student_genderENUM(‘M’, ‘F’)性别
major_idVARCHAR(20)所属专业编号FOREIGN KEY (major_id)
student_emailVARCHAR(50)邮箱(登录名)UNIQUE, NOT NULL
student_password_hashVARCHAR(100)加密后的密码NOT NULL
entry_yearYEAR学生入学年份(可选)无```sql
-- -----------------------------------------------------
-- 学生表:存储学生基本信息和认证信息(直接关联专业表)
-- -----------------------------------------------------
CREATE TABLE student (
    student_id VARCHAR(20) PRIMARY KEY COMMENT '学生学号(主键)',
    student_name VARCHAR(50) NOT NULL COMMENT '学生姓名',
    student_gender ENUM('M', 'F') COMMENT '性别',
    major_id VARCHAR(20) NOT NULL COMMENT '所属专业编号', -- 直接关联专业表
    student_email VARCHAR(50) UNIQUE COMMENT '邮箱(用于登录,唯一约束)',
    student_password_hash VARCHAR(100) NOT NULL COMMENT '加密后的密码',
    entry_year YEAR COMMENT '学生实际入学年份', -- 可选字段:若需记录个人入学年份
    FOREIGN KEY (major_id) REFERENCES major(major_id) ON DELETE CASCADE
);

-- 为学生表的邮箱和专业ID添加索引
CREATE INDEX idx_student_email ON student(student_email);
CREATE INDEX idx_student_major_id ON student(major_id);

4. 课程表(course)
字段名数据类型说明约束
course_idVARCHAR(20)课程编号(主键)PRIMARY KEY
course_nameVARCHAR(50)课程名称NOT NULL
course_creditDECIMAL(3,1)学分(支持小数,如 3.5)NOT NULL, CHECK (>=0)
teacher_idVARCHAR(20)授课教师编号FOREIGN KEY (teacher_id)
course_timeVARCHAR(100)上课时间地点
course_exam_timeDATE考试时间
major_idVARCHAR(20)所属专业编号FOREIGN KEY (major_id)
is_coreTINYINT(1)是否为专业核心课(0/1)DEFAULT 0
-- -----------------------------------------------------
-- 课程表:存储课程基本信息和授课安排
-- -----------------------------------------------------
CREATE TABLE course (
    course_id VARCHAR(20) PRIMARY KEY COMMENT '课程编号(主键)',
    course_name VARCHAR(50) NOT NULL COMMENT '课程名称',
    course_credit INT NOT NULL CHECK (course_credit > 0) COMMENT '学分',
    teacher_id VARCHAR(20) COMMENT '授课教师编号',
    course_time VARCHAR(100) COMMENT '上课时间地点',
    course_exam_time DATE COMMENT '考试时间',
    major_id VARCHAR(20) NOT NULL COMMENT '所属专业编号',
    is_core TINYINT(1) DEFAULT 0 COMMENT '是否为专业核心课(0-否,1-是)',
    FOREIGN KEY (teacher_id) REFERENCES teacher(teacher_id) ON DELETE SET NULL,
    FOREIGN KEY (major_id) REFERENCES major(major_id) ON DELETE CASCADE
);

-- 为课程表的教师ID和专业ID添加索引
CREATE INDEX idx_course_teacher_id ON course(teacher_id);
CREATE INDEX idx_course_major_id ON course(major_id);


5. 成绩表(score)
字段名数据类型说明约束
score_idINT成绩记录 ID(自增主键)PRIMARY KEY, AUTO_INCREMENT
student_idVARCHAR(20)学生编号FOREIGN KEY (student_id)
course_idVARCHAR(20)课程编号FOREIGN KEY (course_id)
scoreDECIMAL(5,2)成绩分数(0-100)CHECK (>=0 AND <=100)
score_typeENUM (’ 平时 ', ’ 期中 ', ’ 期末 ', ’ 总评 ')成绩类型DEFAULT ’ 总评’
exam_dateDATE考试日期
-- -----------------------------------------------------
-- 成绩表:存储学生课程成绩
-- -----------------------------------------------------
CREATE TABLE score (
    score_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '成绩记录ID(自增主键)',
    student_id VARCHAR(20) NOT NULL COMMENT '学生编号',
    course_id VARCHAR(20) NOT NULL COMMENT '课程编号',
    score DECIMAL(5,2) CHECK (score >= 0 AND score <= 100) COMMENT '成绩分数',
    score_type ENUM('平时', '期中', '期末', '总评') DEFAULT '总评' COMMENT '成绩类型',
    exam_date DATE COMMENT '考试日期',
    FOREIGN KEY (student_id) REFERENCES student(student_id) ON DELETE CASCADE,
    FOREIGN KEY (course_id) REFERENCES course(course_id) ON DELETE CASCADE,
    UNIQUE KEY unique_score (student_id, course_id, score_type) COMMENT '复合唯一约束'
);

-- 为成绩表的学生ID和课程ID添加复合索引
CREATE INDEX idx_score_student_course ON score(student_id, course_id);

6. 评价表(evaluation)
字段名数据类型说明约束
eval_idINT评价记录 ID(自增主键)PRIMARY KEY, AUTO_INCREMENT
student_idVARCHAR(20)评价学生编号FOREIGN KEY (student_id)
course_idVARCHAR(20)评价课程编号FOREIGN KEY (course_id)
teacher_idVARCHAR(20)评价教师编号FOREIGN KEY (teacher_id)
evaluation_contentTEXT评价内容
evaluation_ratingENUM(‘1’, ‘2’, ‘3’, ‘4’, ‘5’)评分(1-5 星)
eval_dateDATETIME评价日期DEFAULT CURRENT_TIMESTAMP
is_anonymousTINYINT(1)是否匿名(0/1)DEFAULT 0
-- -----------------------------------------------------
-- 评价表:存储学生对课程和教师的评价
-- -----------------------------------------------------
CREATE TABLE evaluation (
    eval_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '评价记录ID(自增主键)',
    student_id VARCHAR(20) NOT NULL COMMENT '评价学生编号',
    course_id VARCHAR(20) NOT NULL COMMENT '评价课程编号',
    teacher_id VARCHAR(20) NOT NULL COMMENT '评价教师编号',
    evaluation_content TEXT COMMENT '评价内容',
    evaluation_rating ENUM('1', '2', '3', '4', '5') COMMENT '评分(1-5星)',
    eval_date DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '评价日期',
    is_anonymous TINYINT(1) DEFAULT 0 COMMENT '是否匿名(0-否,1-是)',
    FOREIGN KEY (student_id) REFERENCES student(student_id) ON DELETE CASCADE,
    FOREIGN KEY (course_id) REFERENCES course(course_id) ON DELETE CASCADE,
    FOREIGN KEY (teacher_id) REFERENCES teacher(teacher_id) ON DELETE CASCADE
);

-- 为评价表的学生ID、课程ID和教师ID添加复合索引
CREATE INDEX idx_evaluation_student_course ON evaluation(student_id, course_id);
CREATE INDEX idx_evaluation_teacher_id ON evaluation(teacher_id);


7. 管理员表(administrator)
字段名数据类型说明约束
admin_idVARCHAR(20)管理员编号(主键)PRIMARY KEY
admin_nameVARCHAR(50)管理员姓名NOT NULL
admin_emailVARCHAR(50)邮箱(登录名)UNIQUE, NOT NULL
admin_password_hashVARCHAR(100)加密后的密码NOT NULL
permissionsTEXT权限描述(JSON 格式)
-- -----------------------------------------------------
-- 管理员表:存储系统管理员信息
-- -----------------------------------------------------
CREATE TABLE administrator (
    admin_id VARCHAR(20) PRIMARY KEY COMMENT '管理员编号(主键)',
    admin_name VARCHAR(50) NOT NULL COMMENT '管理员姓名',
    admin_email VARCHAR(50) UNIQUE COMMENT '邮箱(用于登录,唯一约束)',
    admin_password_hash VARCHAR(100) NOT NULL COMMENT '加密后的密码',
    permissions TEXT COMMENT '权限描述(JSON格式)'
);

-- 为管理员表的邮箱字段添加索引
CREATE INDEX idx_admin_email ON administrator(admin_email);

外键关系建立了表之间的关联,如:

  • major 表 → teacher 表

    • 关联字段major.dean_idteacher.teacher_id
    • 说明:专业表的 dean_id(专业负责人工号)关联教师表的主键 teacher_id,表示专业负责人由教师担任,支持级联置空(ON DELETE SET NULL)。
    • 业务场景:查询 “计算机专业” 的负责人时,通过此关联获取教师姓名。
  • student 表 → major 表

    • 关联字段student.major_idmajor.major_id
    • 说明:学生表的 major_id(所属专业编号)关联专业表的主键 major_id,表示学生直接隶属于某个专业,支持级联删除(ON DELETE CASCADE)。
    • 业务场景:统计 “计算机专业” 的学生名单时,直接通过此关联查询。
  • course 表 → teacher 表

    • 关联字段course.teacher_idteacher.teacher_id
    • 说明:课程表的 teacher_id(授课教师工号)关联教师表的主键 teacher_id,表示课程由某位教师授课,支持级联置空(ON DELETE SET NULL)。
    • 业务场景:查询 “张三老师” 教授的课程时,通过此关联获取课程列表。
  • course 表 → major 表

    • 关联字段course.major_idmajor.major_id
    • 说明:课程表的 major_id(所属专业编号)关联专业表的主键 major_id,表示课程隶属于某个专业,支持级联删除(ON DELETE CASCADE)。
    • 业务场景:为 “计算机专业” 添加核心课时,通过此关联绑定课程与专业。
  • score 表 → student 表

    • 关联字段score.student_idstudent.student_id
    • 说明:成绩表的 student_id(学生学号)关联学生表的主键 student_id,表示成绩属于某位学生,支持级联删除(ON DELETE CASCADE)。
    • 业务场景:学生查询个人成绩时,通过此关联匹配成绩记录。
  • score 表 → course 表

    • 关联字段score.course_idcourse.course_id
    • 说明:成绩表的 course_id(课程编号)关联课程表的主键 course_id,表示成绩对应的课程,支持级联删除(ON DELETE CASCADE)。
    • 业务场景:教师录入 “数据结构” 课程成绩时,通过此关联定位学生记录。
  • evaluation 表 → student 表

    • 关联字段evaluation.student_idstudent.student_id
    • 说明:评价表的 student_id(评价学生学号)关联学生表的主键 student_id,表示评价由某位学生提交,支持级联删除(ON DELETE CASCADE)。
    • 业务场景:管理员查看违规评价时,通过此关联追溯学生信息。
  • evaluation 表 → course 表

    • 关联字段evaluation.course_idcourse.course_id
    • 说明:评价表的 course_id(评价课程编号)关联课程表的主键 course_id,表示评价对应的课程,支持级联删除(ON DELETE CASCADE)。
    • 业务场景:统计 “数据结构” 课程的评价时,通过此关联过滤数据。
  • evaluation 表 → teacher 表

    • 关联字段evaluation.teacher_idteacher.teacher_id
    • 说明:评价表的 teacher_id(评价教师工号)关联教师表的主键 teacher_id,表示评价针对某位教师,支持级联删除(ON DELETE CASCADE)。
    • 业务场景:教师查看个人授课评价时,通过此关联快速筛选记录。


2.2.4 数据库物理结构设计

  • 存储引擎:统一使用 InnoDB,支持事务、外键约束,确保数据完整性与一致性。

  • 字符集:采用 utf8mb4,支持更广泛的字符(如特殊符号、 emoji 等)。

  • 主键:各表均定义明确的主键(如 admin_id、teacher_id 等),用于唯一标识记录。

  • 外键约束:通过外键(如 dean_id、major_id 等)建立表间关联,确保数据引用的有效性。

  • 字段类型:根据业务需求选择合适类型(如 tinyint 表示性别、状态;decimal 表示成绩、评分,保证精度)。

  • 索引:外键字段自动创建索引(此处 InnoDB 通常自动处理),提升关联查询性能。

具体的表结构设计在上面设计数据表的地方已详细给出。

具体操作:

1、索引优化

1.1 移除冗余索引

-- 删除教师表、学生表、管理员表的冗余邮箱索引
DROP INDEX idx_teacher_email ON teacher;

DROP INDEX idx_student_email ON student;

DROP INDEX idx_admin_email ON administrator;

1.2 优化复合索引顺序(左前缀原则)

若高频查询为“按课程统计所有学生成绩”,将索引idx_score_student_course调整为(course_id, student_id)

DROP INDEX idx_score_student_course ON score;
CREATE INDEX idx_score_course_student ON score(course_id, student_id);
评价表(evaluation):若常按 “教师 + 课程” 查询评价,新增复合索引 (teacher_id, course_id)
CREATE INDEX idx_evaluation_teacher_course ON evaluation(teacher_id, course_id);

1.3 添加覆盖索引(减少回表)

成绩表:查询学生成绩及类型时,添加覆盖索引

CREATE INDEX idx_course_major_cover ON course(major_id, course_name, course_credit);

课程表:按专业查询课程名称和学分时,添加覆盖索引

CREATE INDEX idx_course_major_cover ON course(major_id, course_name, course_credit);

表格总结:

表名索引名称索引字段类型用途
teacherteacher_emailteacher_email(UNIQUE)自动索引邮箱登录验证
majoridx_major_departmentdepartmentB+TREE按院系查询专业
classidx_class_major_idmajor_idB+TREE按专业查询班级
studentidx_student_class_idclass_idB+TREE按班级查询学生
courseidx_course_major_idmajor_idB+TREE按专业查询课程
scoreunique_scorestudent_id, course_id, score_type复合唯一索引避免重复成绩记录
evaluationidx_evaluation_teacher_courseteacher_id, course_idB+TREE按教师 + 课程查询评价


2.2.5 数据库视图设计

首先我们要明白视图的含义,不要产生乱构建的情况

  • 简化复杂查询:将复杂的查询封装在视图中,使其他用户或应用程序可以通过简单的方式访问数据。
  • 数据安全:只向用户暴露他们需要的数据,隐藏敏感信息。
  • 数据聚合:对数据进行汇总和统计,方便分析。

视图是一个虚拟的表关系,我们要运用此来对我们的数据库的信息查询更直观简单

我们分别构建三个视图,对数据进行汇总和统计

1、学生-成绩视图:

E-R分析:
学生-成绩视图

-- 创建学生 - 成绩视图
CREATE VIEW student_score_view AS
SELECT
    s.student_name,
    c.course_name,
    sc.score
FROM
    student s
JOIN
    score sc ON s.student_id = sc.student_id
JOIN
    course c ON sc.course_id = c.course_id;
-- 查询学生 - 成绩视图
SELECT * FROM student_score_view;

2、学生-老师-专业视图

E-R图分析:

学生-老师-专业视图

-- 创建学生 - 老师 - 专业视图
CREATE VIEW student_teacher_major_view AS
SELECT
    s.student_name,
    t.teacher_name,
    m.major_name
FROM
    student s
JOIN
    score sc ON s.student_id = sc.student_id
JOIN
    course c ON sc.course_id = c.course_id
JOIN
    teacher t ON c.teacher_id = t.teacher_id
JOIN
    major m ON s.major_id = m.major_id;

3、学生-老师-评分视图

E-R图分析:

学生-老师-评分视图

-- 创建学生 - 老师 - 评分视图
CREATE VIEW student_teacher_rating_view AS
SELECT
    s.student_name,
    t.teacher_name,
    e.evaluation_rating
FROM
    student s
JOIN
    evaluation e ON s.student_id = e.student_id
JOIN
    teacher t ON e.teacher_id = t.teacher_id;
-- 查询学生 - 老师 - 评分视图
SELECT * FROM student_teacher_rating_view;

图形化结果:

图形化结果



2.2.6 函数 设计

我们一共设计以下几个函数便于我们更好的查询和调用各个关系:

函数名称参数返回值功能描述
calculate_student_averagestudent_id VARCHAR(20)DECIMAL(5,2)接受学生 ID 作为参数,返回该学生所有课程的平均成绩
is_core_coursecourse_id VARCHAR(20)VARCHAR(10)接受课程 ID 作为参数,返回该课程是否为专业核心课的判断结果(是 / 否)
get_teacher_course_countteacher_id VARCHAR(20)INT接受教师 ID 作为参数,返回该教师所授课程的数量

函数 1

函数 1. 计算学生平均成绩的函数

-- 1 计算学生平均成绩的函数
DELIMITER $$
CREATE FUNCTION calculate_student_average(student_id VARCHAR(20))
RETURNS DECIMAL(5,2)
DETERMINISTIC
BEGIN
    DECLARE avg_score DECIMAL(5,2);

    SELECT AVG(score) INTO avg_score
    FROM score
    WHERE student_id = score.student_id AND score_type = '总评';

    RETURN avg_score;
END$$
DELIMITER ;

函数 2

函数 2. 检查课程是否为核心课程

-- 2 检查课程是否为核心课的函数
DELIMITER $$

CREATE FUNCTION is_core_course(course_id VARCHAR(20))
RETURNS VARCHAR(10)
DETERMINISTIC
BEGIN
    DECLARE core_status INT UNSIGNED ;

    SELECT is_core INTO core_status
    FROM course
    WHERE course.course_id = course_id;

    RETURN IF(core_status = 1, '是', '否');
END$$
DELIMITER ;

函数 3

函数 3.获取教师所授课程数量

--  5 获取教师所授课程数量的函数
DELIMITER $$
CREATE FUNCTION get_teacher_course_count(teacher_id VARCHAR(20))
RETURNS INT
DETERMINISTIC
BEGIN
    DECLARE course_count INT;

    SELECT COUNT(*) INTO course_count
    FROM course
    WHERE course.teacher_id = teacher_id;

    RETURN course_count;
END$$
DELIMITER ;


2.2.7 存储过程设计

同样的,我们添加四个存储过程,来验证和简化我们的数据库,让我们数据库的功能更加丰富具体

名称输入参数功能作用
add_studentp_student_id(学号) p_student_name(姓名) p_student_gender(性别) p_major_id(专业编号) p_student_email(邮箱) p_student_password_hash(加密密码) p_entry_year(入学年份)student表插入学生信息,包含以下校验: 1. 学号 / 邮箱唯一性(处理1062错误) 2. 专业 ID 存在性校验 插入失败时返回自定义错误信息。
update_teacherin_teacher_id(教师工号) in_teacher_name(姓名) in_teacher_title(职称) in_teacher_email(邮箱) in_teacher_password_hash(加密密码)根据教师工号更新教师信息,支持部分字段更新(参数为NULL时跳过),包含以下校验: 1. 教师 ID 存在性校验 2. 新邮箱唯一性校验(排除自身) 更新失败时返回自定义错误信息。
delete_coursep_course_id(课程编号)根据课程编号删除course表记录,依赖外键级联(scoreevaluation表数据自动删除)。
get_student_scoresp_student_id(学生学号)根据学生学号查询其成绩及关联信息,包括: 学生姓名、课程名、教师名、专业名、成绩、成绩类型 通过多表连接(studentscorecourseteachermajor)获取数据。

存储过程 1

存储过程 1.添加学生信息的存储过程

-- 1. 添加学生信息的存储过程
DELIMITER $$
CREATE PROCEDURE add_student(
    IN p_student_id VARCHAR(20),
    IN p_student_name VARCHAR(50),
    IN p_student_gender ENUM('M', 'F'),
    IN p_major_id VARCHAR(20),
    IN p_student_email VARCHAR(50),
    IN p_student_password_hash VARCHAR(100),
    IN p_entry_year YEAR
)
BEGIN
    DECLARE EXIT HANDLER FOR 1062
    BEGIN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = '添加失败:学号或邮箱已存在';
    END;

    -- 检查专业ID是否存在
    IF NOT EXISTS (SELECT 1 FROM major WHERE major_id = p_major_id) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = '添加失败:专业ID不存在';
    END IF;

    INSERT INTO student (student_id, student_name, student_gender, major_id, student_email, student_password_hash, entry_year)
    VALUES (p_student_id, p_student_name, p_student_gender, p_major_id, p_student_email, p_student_password_hash, p_entry_year);
END$$
DELIMITER ;
  • *流程图:**
    存储过程 1.添加学生信息的存储过程

存储过程 2

存储过程 2.更新教师信息的存储过程

-- 2. 更新教师信息的存储过程
DELIMITER $$
CREATE PROCEDURE update_teacher(
    IN in_teacher_id VARCHAR(20),
    IN in_teacher_name VARCHAR(50),
    IN in_teacher_title VARCHAR(20),
    IN in_teacher_email VARCHAR(50),
    IN in_teacher_password_hash VARCHAR(100)
)
BEGIN
    DECLARE v_count INT;

    -- 检查教师ID是否存在
    IF NOT EXISTS (SELECT 1 FROM teacher WHERE teacher_id = in_teacher_id) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = '更新失败:教师ID不存在';
    END IF;

    -- 检查新邮箱是否存在(排除自身)
    IF in_teacher_email IS NOT NULL THEN
        SELECT COUNT(*) INTO v_count
        FROM teacher
        WHERE teacher_email = in_teacher_email
          AND teacher_id != in_teacher_id;

        IF v_count > 0 THEN
            SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = '更新失败:邮箱已被其他教师使用';
        END IF;
    END IF;

    -- 执行更新
    UPDATE teacher
    SET
        teacher_name = IFNULL(in_teacher_name, teacher_name),
        teacher_title = IFNULL(in_teacher_title, teacher_title),
        teacher_email = IFNULL(in_teacher_email, teacher_email),
        teacher_password_hash = IFNULL(in_teacher_password_hash, teacher_password_hash)
    WHERE teacher_id = in_teacher_id;
END$$
DELIMITER ;
  • 流程图:

存储过程 2.更新教师信息的存储过程


存储过程 3

存储过程 3.删除课程及其相关信息的存储过程

-- 3 删除课程及其相关信息的存储过程
DELIMITER $
CREATE PROCEDURE delete_course(
    IN p_course_id VARCHAR(20)
)
BEGIN
    DELETE FROM course WHERE course_id = p_course_id;
END$$
DELIMITER ;

  • 流程图:
    存储过程 3.删除课程及其相关信息的存储过程

存储过程 4

存储过程 4.查询学生成绩及相关信息的存储过程

-- 4 查询学生成绩及相关信息的存储过程
DELIMITER $$
CREATE PROCEDURE get_student_scores(
    IN p_student_id VARCHAR(20)
)
BEGIN
    SELECT
        s.student_name,
        c.course_name,
        t.teacher_name,
        m.major_name,
        sc.score,
        sc.score_type
    FROM
        student s
    JOIN
        score sc ON s.student_id = sc.student_id
    JOIN
        course c ON sc.course_id = c.course_id
    JOIN
        teacher t ON c.teacher_id = t.teacher_id
    JOIN
        major m ON s.major_id = m.major_id
    WHERE
        s.student_id = p_student_id;
END$$
DELIMITER ;

  • 流程图:
    存储过程 4.查询学生成绩及相关信息的存储过程

最终结果显示

最终结果可视化显示



2.2.8 触发器设计

下面是我们设计的总体几个触发器的说明:

触发器名称触发时机作用表功能描述
before_student_insert插入学生记录前student当向学生表插入记录时,若学生实际入学年份(entry_year)为空, 则自动填充该学生所属专业的默认入学年份(来自major表的entry_year)。
after_major_update更新专业记录后major当专业表的默认入学年份(entry_year)更新时, 自动将对应专业下所有未手动设置入学年份(entry_yearNULL)的学生记录更新为新默认年份。
after_course_update更新课程记录后course当课程表的 “是否为核心课”(is_core)状态从 “非核心课(0)” 变更为 “核心课(1)” 时, 自动向评价表插入一条系统通知记录(标记为匿名评价,评分 5 星)。

触发器 1

触发器 1. 学生入学年份自动填充触发器

-- 1. 学生入学年份自动填充触发器
DELIMITER $$
CREATE TRIGGER before_student_insert BEFORE INSERT ON student
FOR EACH ROW
BEGIN
    DECLARE default_entry_year YEAR;
    SELECT entry_year INTO default_entry_year FROM major WHERE major_id = NEW.major_id;
    IF NEW.entry_year IS NULL THEN
        SET NEW.entry_year = default_entry_year;
    END IF;
END$$
DELIMITER ;
  • 流程图:
    触发器 1. 学生入学年份自动填充触发器

触发器 2

触发器 2. 专业默认入学年份更新触发器

-- 2. 专业默认入学年份更新触发器
DELIMITER $$
CREATE TRIGGER after_major_update AFTER UPDATE ON major
FOR EACH ROW
BEGIN
    IF OLD.entry_year <> NEW.entry_year THEN
        UPDATE student
        SET entry_year = NEW.entry_year
        WHERE major_id = NEW.major_id AND entry_year IS NULL;
    END IF;
END$$
DELIMITER ;
  • 流程图:
    触发器 2. 专业默认入学年份更新触发器

触发器 3

触发器 3. 核心课程状态变更通知触发器

-- 3. 核心课程状态变更通知触发器
DELIMITER $$
CREATE TRIGGER after_course_update AFTER UPDATE ON course
FOR EACH ROW
BEGIN
    -- 当课程变为核心课时
    IF OLD.is_core = 0 AND NEW.is_core = 1 THEN
        INSERT INTO evaluation (student_id, course_id, teacher_id, evaluation_content, evaluation_rating, is_anonymous)
        VALUES ('SYSTEM_NOTICE', NEW.course_id, NEW.teacher_id, '该课程已标记为核心课', '5', 1); -- 匿名系统通知
    END IF;
END$$
DELIMITER ;
  • 流程图:
    触发器 3. 核心课程状态变更通知触发器


三 系统实现

3.1 数据库访问设计

我们前端的设计,总体思想是围绕面向对象的方式封装了底层数据库操作

我们将分成三个大文件,分别实现三个身份(管理员.py,教师登入.py,学生登入.py)来实现,其中每个文件中所对应的功能板块(如管理管登入注册,教师信息界面管理,学生信息界面管理等)用类来封装,如下图:
在这里插入图片描述
在这里插入图片描述


3.1.1 链接管理:
  • PyMySQLUtils类初始化时,使用pymysql.connect()建立数据库连接
  • 参数包含主机地址、用户名、密码和数据库名
  • 创建游标对象用于执行SQL语句
  • 提供close()方法关闭连接和游标
  • 通过类封装避免重复建立连接,提高代码的复用性
class PyMySQLUtils:
    def __init__(self):
        self.db = pymysql.connect(host="*", user="*", password="*", database="*")
        # 这里表示自己的数据库信息
        self.cursor = self.db.cursor()

    def fetchall(self, sql, params=None):
        self.cursor.execute(sql, params if params else ())
        return self.cursor.fetchall()

    def fetchone(self, sql, params=None):
        self.cursor.execute(sql, params if params else ())
        return self.cursor.fetchone()

    def execute(self, sql, params=None):
        try:
            self.cursor.execute(sql, params if params else ())
            self.db.commit()
            print("数据库操作成功!")
        except Exception as e:
            self.db.rollback()
            print(f"数据库操作失败!错误信息: {e}")

    def close(self):
        self.cursor.close()
        self.db.close()

其次,教师登入和学生登入与数据库的连接实现也是一样的

**至此,我们就实现与数据库的链接,我们就可以来设计我们的前端可以修改和插入数据 **

在这里插入图片描述


3.2 登录模块设计

3.2.1 管理员登入设计

1、界面层设计

  • 继承TkinterToplevel窗口类

  • 包含两个输入组件:

  • Label(self.window, text="管理员登录", font=("宋体", 20)).pack(pady=100)
    
            Label(self.window, text="邮箱:", font=tkFont.Font(size=14)).place(x=100, y=200)
            self.admin_email = Entry(self.window, width=20, font=tkFont.Font(size=14), bg='Ivory')
            self.admin_email.place(x=170, y=200)
    
            Label(self.window, text="密码:", font=tkFont.Font(size=14)).place(x=100, y=250)
            self.admin_password = Entry(self.window, width=20, font=tkFont.Font(size=14), bg='Ivory', show='*')
            self.admin_password.place(x=170, y=250)
    
  • 双按钮布局:

  •         Button(self.window, text="确定", width=8, font=tkFont.Font(size=12), command=self.login).place(x=170, y=300)
            Button(self.window, text="返回", width=8, font=tkFont.Font(size=12), command=self.back).place(x=300, y=300)
    

3.2.2 验证逻辑

def login(self):
    utils = PyMySQLUtils()
    # 参数化查询防止SQL注入
    result = utils.fetchone("SELECT * FROM administrator WHERE admin_email = %s", 
                           (self.admin_email.get(),))
    
    # 验证流程
    if not self.admin_email.get() or not self.admin_password.get():
        messagebox.showerror("错误", "登录信息不完整!")
    elif result:
        if self.admin_password.get() == result[3]:  # 密码字段索引为3
            messagebox.showinfo("成功", "登录成功!")
            AdminManagement(self.window)  # 跳转管理界面
        else:
            messagebox.showerror("错误", "密码错误!")
    else:
        messagebox.showerror("错误", "邮箱不存在!")

流程图:

用户输入
  ↓
非空校验 → 失败→显示错误
  ↓
数据库查询(邮箱是否存在)
  ├─存在 → 密码比对 → 匹配→进入系统
  └─不存在 → 显示错误

3.3 功能模块设计

3.3.1 初始化模块设计

数据库操作模块
PyMySQLUtils 类)

这个模块负责与 MySQL 数据库进行交互,提供了常见的数据库操作方法,如查询、插入、更新和删除等。

也就是登入模块设计,在 3.2登入模块设计具体说明


起始菜单模块
StartMenu 类)

该模块是系统的起始界面,提供了管理员注册、登录和退出系统的功能。

class StartMenu:
    def __init__(self, parent_window):
        parent_window.destroy()
        self.window = Tk()
        self.window.title("学生成绩管理系统-管理员版")
        self.window.geometry("500x500")
        self.window.resizable(0, 0)
        Label(self.window, text="学生成绩管理系统", font=("宋体", 20)).pack(pady=100)
        Button(self.window, text="管理员注册", font=tkFont.Font(size=16),
               command=lambda: AdminRegister(self.window), width=30, height=2).pack()
        Button(self.window, text="管理员登录", font=tkFont.Font(size=16),
               command=lambda: AdminLogin(self.window), width=30, height=2).pack()
        Button(self.window, text="退出系统", font=tkFont.Font(size=16),
               command=self.window.destroy, width=30, height=2).pack()
        self.window.mainloop()

以下是各个py文件的设计模块:

3.3.2 管理员py文件
1 管理员登入模块

系统包含三个核心功能模块:

  1. 管理员注册模块 (AdminRegister)

  2. 管理员登录模块 (AdminLogin)

  3. 管理员管理模块 (AdminManagement)

这三个模块形成了完整的管理员操作流程:注册 -> 登录 -> 管理。

# 核心模块示意图(伪代码)
class AdminRegister:          # 管理员注册模块
   def __init__(): ...       # 界面初始化
   def register(): ...       # 注册逻辑

class AdminLogin:             # 管理员登录模块 
   def __init__(): ...       # 界面初始化
   def login(): ...          # 登录验证

class AdminManagement:        # 管理主界面模块
   def __init__(): ...       # 主界面框架
   def student_management(): # 学生管理入口
   def teacher_management(): # 教师管理入口
   ...                       # 其他管理入口

class PyMySQLUtils:           # 数据库工具模块(独立)
   def execute(): ...        # 执行SQL语句
   def fetchone(): ...       # 查询单条数据

1. 管理员认证模块

该模块处理管理员的注册和登录功能,包含表单验证和数据库查询操作。

class AdminRegister:
    def register(self):
        # 表单验证
        if not all([self.admin_id.get(), ...]):
            messagebox.showerror("错误", "注册信息不完整!")
        elif self.admin_password.get() != self.re_password.get():
            messagebox.showerror("错误", "两次密码不相同!")
        else:
            # 数据库查询验证
            result = utils.fetchone("SELECT * FROM administrator WHERE admin_email = %s", ...)
            if result:
                messagebox.showerror("错误", "该邮箱已被注册!")
            else:
                # 插入新管理员
                utils.execute("INSERT INTO administrator(...) VALUES(...)", ...)
                AdminLogin(self.window)  # 注册成功后跳转到登录界面

class AdminLogin:
    def login(self):
        # 查询邮箱是否存在
        result = utils.fetchone("SELECT * FROM administrator WHERE admin_email = %s", ...)
        if not result:
            messagebox.showerror("错误", "邮箱不存在!")
        elif self.admin_password.get() != result[3]:
            messagebox.showerror("错误", "密码错误!")
        else:
            AdminManagement(self.window)  # 登录成功后跳转到管理界面

3. 管理员功能模块

该模块提供管理员的主要功能入口,包含多个管理子系统的导航按钮。

class AdminManagement:
    def __init__(self, parent_window):
        parent_window.destroy()
        self.window = Tk()
        self.window.title("学生成绩管理系统-管理员管理")
        # ... 窗口配置代码 ...
        
        # 功能按钮
        Button(self.window, text="学生信息管理", command=self.student_management).pack(pady=20)
        Button(self.window, text="教师信息管理", command=self.teacher_management).pack(pady=20)
        Button(self.window, text="课程管理", command=self.course_management).pack(pady=20)
        # ... 其他功能按钮 ...
        
    def student_management(self):
        StudentManagement(self.window)  # 跳转到学生管理界面
    def teacher_management(self):
        TeacherManagement(self.window)  # 跳转到教师管理界面
    # ... 其他功能方法 ...

3. 系统流程图
管理员py-管理员登入


4. 结果图示意
在这里插入图片描述

在这里插入图片描述



2 学生信息模块

1. 界面展示与导航模块

  • 主界面:StudentManagement类负责创建学生管理主界面,设置窗口标题、大小等属性,添加搜索框、学生信息展示表格、功能按钮等组件。当从其他界面进入学生管理界面时,销毁父窗口并创建新窗口展示。
  • 弹出窗口:AddStudentDialog和EditStudentDialog类继承自Toplevel,用于创建添加学生和编辑学生信息的弹出窗口,提供输入框、下拉框等组件供用户操作。
class StudentManagement:
    def __init__(self, parent_window):
        parent_window.destroy()
        self.window = Tk()
        self.window.title("学生成绩管理系统-学生管理")
        self.window.geometry("1000x600")
        # 界面组件初始化代码...

class AddStudentDialog(Toplevel):
    def __init__(self, parent, callback):
        super().__init__(parent)
        self.title("添加学生")
        self.geometry("400x400")
        # 添加学生界面组件初始化代码...

class EditStudentDialog(Toplevel):
    def __init__(self, parent, callback, student_info):
        super().__init__(parent)
        self.title("编辑学生")
        self.geometry("400x400")
        # 编辑学生界面组件初始化代码...

2. 学生信息展示与加载模块

  • 信息展示:使用ttk.Treeview展示学生信息,定义展示的列名(学号、姓名、性别等),并设置列宽和表头。通过滚动条实现长列表滚动查看。
  • 信息加载:load_students方法从数据库获取学生信息并插入到Treeview中展示。可根据搜索条件动态更新展示内容。
class StudentManagement:
    def __init__(self, parent_window):
        # ...
        self.columns = ("学号", "姓名", "性别", "专业", "邮箱", "入学年份")
        self.tree = ttk.Treeview(self.tree_frame, show="headings", height=15, columns=self.columns)
        self.tree.pack(side=LEFT)
        # 滚动条配置代码...
        self.load_students()

    def load_students(self, condition=""):
        self.tree.delete(*self.tree.get_children())
        sql = """
            SELECT s.student_id, s.student_name, 
                   CASE WHEN s.student_gender = 'M' THEN '男' WHEN s.student_gender = 'F' THEN '女' ELSE '未知' END,
                   m.major_name, s.student_email, s.entry_year
            FROM student s
            JOIN major m ON s.major_id = m.major_id
        """
        params = []
        if condition:
            sql += " WHERE " + condition
        utils = PyMySQLUtils()
        results = utils.fetchall(sql)
        utils.close()
        for row in results:
            self.tree.insert("", "end", values=row)

3. 学生信息搜索模块

  • 条件获取:search_students方法从界面输入框获取学号、姓名、专业等搜索条件。
  • 条件处理:将获取的条件组装成 SQL 查询条件,调用load_students方法根据条件查询并展示学生信息。
  • 重置功能:reset_search方法清空搜索框内容,调用load_students方法重新展示全部学生信息。
class StudentManagement:
    def search_students(self):
        conditions = []
        student_id = self.search_id.get().strip()
        student_name = self.search_name.get().strip()
        major_name = self.search_major.get().strip()
        # 条件组装代码...
        condition = " AND ".join(conditions) if conditions else ""
        self.load_students(condition)

    def reset_search(self):
        self.search_id.delete(0, END)
        self.search_name.delete(0, END)
        self.search_major.delete(0, END)
        self.load_students()

4. 学生信息操作模块

  • 添加学生:AddStudentDialog类中confirm方法获取添加学生界面输入信息,验证信息合法性后插入数据库,并刷新主界面学生信息展示。
  • 编辑学生:EditStudentDialog类中confirm方法获取编辑学生界面修改后的信息,验证后更新数据库对应记录,并刷新主界面展示。
  • 删除学生:StudentManagement类的delete_student方法,先判断是否选择学生,确认后从数据库删除该学生相关成绩和学生记录,再刷新主界面。
class StudentManagement:
    def add_student(self):
        AddStudentDialog(self.window, self)

    def edit_student(self):
        if hasattr(self,'selected_student'):
            EditStudentDialog(self.window, self, self.selected_student)
        else:
            messagebox.showwarning("警告", "请先选择学生!")

    def delete_student(self):
        if hasattr(self,'selected_student'):
            student_id = self.selected_student[0]
            if messagebox.askyesno("确认", f"确定删除学号 {student_id} 的学生?"):
                utils = PyMySQLUtils()
                try:
                    utils.execute("DELETE FROM score WHERE student_id = %s", (student_id,))
                    utils.execute("DELETE FROM student WHERE student_id = %s", (student_id,))
                    messagebox.showinfo("成功", "删除成功!")
                    self.load_students()
                except Exception as e:
                    messagebox.showerror("错误", f"删除失败:{str(e)}")
                finally:
                    utils.close()
        else:
            messagebox.showwarning("警告", "请先选择学生!")

class AddStudentDialog:
    def confirm(self):
        # 获取输入信息代码...
        if not student_id or not student_name or not major_name:
            messagebox.showwarning("警告", "学号、姓名和专业不能为空!")
            return
        # 验证和插入数据库代码...
        sql = """
            INSERT INTO student 
            (student_id, student_name, student_gender, major_id, 
             student_email, student_password_hash, entry_year)
            VALUES (%s, %s, %s, %s, %s, %s, %s)
        """
        params = (student_id, student_name, gender_code, major_id, student_email, '123456', entry_year)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "学生添加成功!")
        self.callback.load_students()
        self.destroy()

class EditStudentDialog:
    def confirm(self):
        # 获取修改后信息代码...
        if not student_name or not major_name:
            messagebox.showwarning("警告", "姓名和专业不能为空!")
            return
        # 验证和更新数据库代码...
        sql = """
            UPDATE student 
            SET student_name = %s, student_gender = %s, 
                major_id = %s, student_email = %s, entry_year = %s 
            WHERE student_id = %s
        """
        params = (student_name, gender_code, major_id, student_email, entry_year, self.student_id)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "学生信息更新成功!")
        self.callback.load_students()
        self.destroy()

5. Excel 导入导出模块

  • 导入 Excel:import_excel方法通过文件对话框获取 Excel 文件路径,读取文件内容,验证表头和数据合法性,将数据插入或更新到数据库,最后刷新主界面学生信息展示。
  • 导出 Excel:export_excel方法通过文件对话框获取保存路径,从数据库查询学生信息,将信息写入 Excel 文件保存。
class StudentManagement:
    def import_excel(self):
        file_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")]
        )
        if not file_path:
            return
        # 读取文件、验证、插入数据库代码...
        self.load_students()

    def export_excel(self):
        file_path = filedialog.asksaveasfilename(
            title="保存Excel文件",
            defaultextension=".xls",
            filetypes=[("Excel文件", "*.xls"), ("所有文件", "*.*")]
        )
        if file_path:
            # 从数据库查询、写入文件代码...
            messagebox.showinfo("成功", f"数据已导出到 {file_path}")

== 6.流程图==
管理原py_学生


7.结果示意图
在这里插入图片描述
在这里插入图片描述



3 教师模块

1. 界面导航模块

  • 主界面TeacherManagement类负责创建教师信息管理的主界面。在初始化时,销毁传入的父窗口,创建新的窗口并设置标题、大小等属性。在主界面中添加了搜索框架、表格框架和按钮框架,用于展示和操作教师信息。
  • 弹出窗口AddTeacherDialogEditTeacherDialog类继承自Toplevel,分别用于创建添加教师和编辑教师信息的弹出窗口,在窗口中提供相应的输入框、下拉框等组件,方便用户进行信息录入和修改。
class TeacherManagement:
    def __init__(self, parent_window):
        parent_window.destroy()
        self.window = Tk()
        self.window.title("教师信息管理")
        self.window.geometry("1000x600")
        # 界面组件初始化代码...

class AddTeacherDialog(Toplevel):
    def __init__(self, parent, callback):
        super().__init__(parent)
        self.title("添加教师")
        self.geometry("400x350")
        # 添加教师界面组件初始化代码...

class EditTeacherDialog(Toplevel):
    def __init__(self, parent, callback, teacher_info):
        super().__init__(parent)
        self.title("编辑教师")
        self.geometry("400x350")
        # 编辑教师界面组件初始化代码...

2. 教师信息展示模块

  • 信息展示:使用ttk.Treeview来展示教师信息,定义了展示的列名(工号、姓名、职称、邮箱),并设置列宽和表头。同时配置了垂直滚动条,用于在教师信息较多时方便滚动查看。
  • 信息加载load_teachers方法用于从数据库中获取教师信息,并将其插入到Treeview中进行展示。该方法可以根据传入的条件(如搜索条件)动态更新展示的教师信息。
class TeacherManagement:
    def __init__(self, parent_window):
        # ...
        self.columns = ("工号", "姓名", "职称", "邮箱")
        self.tree = ttk.Treeview(self.tree_frame, show="headings", height=15, columns=self.columns)
        self.tree.pack(side=LEFT)
        # 滚动条配置代码...
        self.load_teachers()

    def load_teachers(self, condition=""):
        self.tree.delete(*self.tree.get_children())
        sql = """
            SELECT teacher_id, teacher_name, teacher_title, teacher_email 
            FROM teacher
        """
        params = []
        if condition:
            sql += " WHERE " + condition
        utils = PyMySQLUtils()
        results = utils.fetchall(sql)
        utils.close()
        for row in results:
            self.tree.insert("", "end", values=row)

3. 教师信息搜索模块

  • 条件获取search_teachers方法从界面上的输入框和下拉框中获取工号、姓名、职称等搜索条件。
  • 条件处理:将获取到的搜索条件进行组装,生成 SQL 查询语句中的WHERE子句部分,然后调用load_teachers方法,根据组装好的条件从数据库中查询并展示相应的教师信息。
  • 重置功能reset_search方法用于清空搜索框和下拉框的内容,并调用load_teachers方法重新加载并展示全部教师信息。
class TeacherManagement:
    def search_teachers(self):
        conditions = []
        teacher_id = self.search_id.get().strip()
        teacher_name = self.search_name.get().strip()
        teacher_title = self.search_title.get().strip()
        # 条件组装代码...
        condition = " AND ".join(conditions) if conditions else ""
        self.load_teachers(condition)

    def reset_search(self):
        self.search_id.delete(0, END)
        self.search_name.delete(0, END)
        self.search_title.set("")
        self.load_teachers()

4. 教师信息操作模块

  • 添加教师AddTeacherDialog类中的confirm方法用于获取添加教师界面中用户输入的信息,对信息进行合法性验证(如工号、姓名不能为空,两次密码需一致,工号和邮箱不能重复等),验证通过后将教师信息插入到数据库中,并刷新主界面的教师信息展示。
  • 编辑教师EditTeacherDialog类中的confirm方法获取编辑教师界面中修改后的信息,进行合法性验证(如姓名不能为空,新密码两次输入需一致,邮箱不能被其他教师使用等),验证通过后更新数据库中对应的教师记录,并刷新主界面的展示。
  • 删除教师TeacherManagement类的delete_teacher方法首先判断是否选择了教师,如果已选择,则弹出确认删除对话框,在用户确认后从数据库中删除该教师的信息,并刷新主界面的教师信息展示。
class TeacherManagement:
    def add_teacher(self):
        AddTeacherDialog(self.window, self)

    def edit_teacher(self):
        if hasattr(self,'selected_teacher'):
            EditTeacherDialog(self.window, self, self.selected_teacher)
        else:
            messagebox.showwarning("警告", "请先选择教师!")

    def delete_teacher(self):
        if hasattr(self,'selected_teacher'):
            teacher_id = self.selected_teacher[0]
            if messagebox.askyesno("确认", f"确定删除教师 {teacher_id} 的信息?"):
                utils = PyMySQLUtils()
                try:
                    utils.execute("DELETE FROM teacher WHERE teacher_id = %s", (teacher_id,))
                    messagebox.showinfo("成功", "删除成功!")
                    self.load_teachers()
                except Exception as e:
                    messagebox.showerror("错误", f"删除失败:{str(e)}")
                finally:
                    utils.close()
        else:
            messagebox.showwarning("警告", "请先选择教师!")

class AddTeacherDialog:
    def confirm(self):
        # 获取输入信息代码...
        if not teacher_id or not teacher_name:
            messagebox.showwarning("警告", "工号和姓名不能为空!")
            return
        # 验证和插入数据库代码...
        sql = """
            INSERT INTO teacher 
            (teacher_id, teacher_name, teacher_title, teacher_email, teacher_password_hash)
            VALUES (%s, %s, %s, %s, %s)
        """
        params = (teacher_id, teacher_name, teacher_title, teacher_email, teacher_password)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "教师添加成功!")
        self.callback.load_teachers()
        self.destroy()

class EditTeacherDialog:
    def confirm(self):
        # 获取修改后信息代码...
        if not teacher_name:
            messagebox.showwarning("警告", "姓名不能为空!")
            return
        # 验证和更新数据库代码...
        sql = """
            UPDATE teacher 
            SET teacher_name = %s, teacher_title = %s, teacher_email = %s, teacher_password_hash = %s 
            WHERE teacher_id = %s
        """
        params = (teacher_name, teacher_title, teacher_email, teacher_password, self.teacher_id)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "教师信息更新成功!")
        self.callback.load_teachers()
        self.destroy()

5. Excel 导入导出模块

  • 导入 Excelimport_excel方法通过文件对话框获取用户选择的 Excel 文件路径,根据文件格式(.xls或其他)采用不同方式读取文件内容。验证文件表头是否符合预期,然后逐行读取数据并进行合法性验证(如工号、姓名不能为空,职称需在规定范围内等),根据工号是否存在进行插入或更新数据库操作,最后刷新主界面的教师信息展示。
  • 导出 Excelexport_excel方法通过文件对话框获取保存 Excel 文件的路径,从数据库中查询教师信息,创建 Excel 文件并将表头和教师信息逐行写入文件,保存成功后提示用户。
class TeacherManagement:
    def import_excel(self):
        file_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")]
        )
        if not file_path:
            return
        # 读取文件、验证、插入/更新数据库代码...
        self.load_teachers()

    def export_excel(self):
        file_path = filedialog.asksaveasfilename(
            title="保存Excel文件",
            defaultextension=".xls",
            filetypes=[("Excel文件", "*.xls"), ("所有文件", "*.*")]
        )
        if file_path:
            # 从数据库查询、写入文件代码...
            messagebox.showinfo("成功", f"数据已导出到 {file_path}")

6. 流程图
管理员_教师


7. 结果示意图
管理员——教师
管理员——教师



4 课程模块

1. 界面展示与导航模块

  • 主界面CourseManagement类负责创建课程信息管理的主界面。在初始化时,销毁传入的父窗口,创建新的窗口并设置标题、大小等属性。主界面包含搜索框架(用于输入搜索条件)、表格框架(展示课程信息)和按钮框架(提供操作功能按钮)。
  • 弹出窗口AddCourseDialogEditCourseDialog类继承自Toplevel,分别用于创建添加课程和编辑课程的弹出窗口,在窗口中提供相应的输入框、下拉框等组件,方便用户进行信息录入和修改。
class CourseManagement:
    def __init__(self, parent_window):
        parent_window.destroy()
        self.window = Tk()
        self.window.title("课程信息管理")
        self.window.geometry("1200x600")
        # 界面组件初始化代码...

class AddCourseDialog(Toplevel):
    def __init__(self, parent, callback):
        super().__init__(parent)
        self.title("添加课程")
        self.geometry("500x450")
        # 添加课程界面组件初始化代码...

class EditCourseDialog(Toplevel):
    def __init__(self, parent, callback, course_info):
        super().__init__(parent)
        self.title("编辑课程")
        self.geometry("500x450")
        # 编辑课程界面组件初始化代码...

2. 课程信息展示与加载模块

  • 信息展示:使用ttk.Treeview展示课程信息,定义展示的列名(课程 ID、课程名称等),设置列宽和表头,并配置垂直滚动条,以便在课程信息较多时可滚动查看。
  • 信息加载load_courses方法从数据库获取课程信息,并插入到Treeview中展示。可根据传入的条件(如搜索条件)动态更新展示内容。
class CourseManagement:
    def __init__(self, parent_window):
        # ...
        self.columns = ("课程ID", "课程名称", "学分", "授课教师", "上课时间地点", "考试时间", "所属专业", "是否核心课")
        self.tree = ttk.Treeview(self.tree_frame, show="headings", height=15, columns=self.columns)
        self.tree.pack(side=LEFT)
        # 滚动条配置代码...
        self.load_courses()

    def load_courses(self, condition=""):
        self.tree.delete(*self.tree.get_children())
        sql = """
            SELECT c.course_id, c.course_name, c.course_credit, 
                   t.teacher_name, c.course_time, c.course_exam_time, 
                   m.major_name, c.is_core
            FROM course c
            LEFT JOIN teacher t ON c.teacher_id = t.teacher_id
            LEFT JOIN major m ON c.major_id = m.major_id
        """
        params = []
        if condition:
            sql += " WHERE " + condition
        utils = PyMySQLUtils()
        results = utils.fetchall(sql)
        utils.close()
        for row in results:
            is_core = "是" if row[7] else "否"
            teacher_name = row[3] if row[3] else "未分配"
            exam_time = str(row[5]) if row[5] else ""
            self.tree.insert("", "end", values=(row[0], row[1], row[2], teacher_name, row[4], exam_time, row[6], is_core))

3. 课程信息搜索模块

  • 条件获取search_courses方法从界面输入框和下拉框获取课程 ID、课程名称、授课教师、所属专业、是否核心课等搜索条件。
  • 条件处理:将获取的条件组装成 SQL 查询条件,调用load_courses方法根据条件查询并展示相应课程信息。
  • 重置功能reset_search方法清空搜索框和下拉框内容,调用load_courses方法重新展示全部课程信息。
class CourseManagement:
    def search_courses(self):
        conditions = []
        course_id = self.search_course_id.get().strip()
        course_name = self.search_course_name.get().strip()
        teacher_text = self.search_teacher_id.get().strip()
        major_text = self.search_major_id.get().strip()
        is_core = self.search_is_core.get()
        # 条件组装代码...
        condition = " AND ".join(conditions) if conditions else ""
        self.load_courses(condition)

    def reset_search(self):
        self.search_course_id.delete(0, END)
        self.search_course_name.delete(0, END)
        self.search_teacher_id.set("")
        self.search_major_id.set("")
        self.search_is_core.current(0)
        self.load_courses()

4. 课程信息操作模块

  • 添加课程AddCourseDialog类中confirm方法获取添加课程界面输入信息,进行合法性验证(如课程 ID、课程名称、学分、所属专业不能为空,学分大于 0,考试时间格式正确等),验证通过后插入数据库,并刷新主界面课程信息展示。
  • 编辑课程EditCourseDialog类中confirm方法获取编辑课程界面修改后的信息,进行合法性验证(如课程名称、学分、所属专业不能为空,学分大于 0,考试时间格式正确等),验证通过后更新数据库对应记录,并刷新主界面展示。
  • 删除课程CourseManagement类的delete_course方法判断是否选择课程记录,确认后从数据库删除该记录,并刷新主界面课程信息展示。
class CourseManagement:
    def add_course(self):
        AddCourseDialog(self.window, self)

    def edit_course(self):
        if hasattr(self,'selected_course'):
            EditCourseDialog(self.window, self, self.selected_course)
        else:
            messagebox.showwarning("警告", "请先选择课程!")

    def delete_course(self):
        if hasattr(self,'selected_course'):
            course_id = self.selected_course[0]
            if messagebox.askyesno("确认", f"确定删除课程 {course_id}?"):
                utils = PyMySQLUtils()
                try:
                    utils.execute("DELETE FROM course WHERE course_id = %s", (course_id,))
                    messagebox.showinfo("成功", "删除成功!")
                    self.load_courses()
                except Exception as e:
                    messagebox.showerror("错误", f"删除失败:{str(e)}")
                finally:
                    utils.close()
        else:
            messagebox.showwarning("警告", "请先选择课程!")

class AddCourseDialog:
    def confirm(self):
        # 获取输入信息代码...
        if not all([course_id, course_name, credit, major_id]):
            messagebox.showwarning("警告", "课程ID、课程名称、学分和所属专业不能为空!")
            return
        # 验证和插入数据库代码...
        sql = """
            INSERT INTO course 
            (course_id, course_name, course_credit, teacher_id, 
             course_time, course_exam_time, major_id, is_core)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
        """
        params = (course_id, course_name, credit, teacher_id, course_time, exam_time, major_id, is_core)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "课程添加成功!")
        self.callback.load_courses()
        self.destroy()

class EditCourseDialog:
    def confirm(self):
        # 获取修改后信息代码...
        if not all([course_name, credit, major_id]):
            messagebox.showwarning("警告", "课程名称、学分和所属专业不能为空!")
            return
        # 验证和更新数据库代码...
        sql = """
            UPDATE course 
            SET course_name = %s, course_credit = %s, teacher_id = %s, 
                course_time = %s, course_exam_time = %s, major_id = %s, is_core = %s 
            WHERE course_id = %s
        """
        params = (course_name, credit, teacher_id, course_time, exam_time, major_id, is_core, self.course_id)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "课程更新成功!")
        self.callback.load_courses()
        self.destroy()

5. Excel 导入导出模块

  • 导入 Excelimport_excel方法通过文件对话框获取 Excel 文件路径,读取文件内容,验证表头和数据合法性(如课程 ID、课程名称、学分、所属专业 ID 不能为空,学分大于 0,教师 ID 和专业 ID 存在等),根据记录是否存在进行插入或更新数据库操作,最后刷新主界面课程信息展示。
  • 导出 Excelexport_excel方法通过文件对话框获取保存路径,从数据库查询课程信息,创建 Excel 文件并将表头和课程信息逐行写入文件,保存成功后提示用户。
class CourseManagement:
    def import_excel(self):
        file_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")]
        )
        if not file_path:
            return
        # 读取文件、验证、插入/更新数据库代码...
        self.load_courses()

    def export_excel(self):
        file_path = filedialog.asksaveasfilename(
            title="保存Excel文件",
            defaultextension=".xls",
            filetypes=[("Excel文件", "*.xls"), ("所有文件", "*.*")]
        )
        if file_path:
            # 从数据库查询、写入文件代码...
            messagebox.showinfo("成功", f"数据已导出到 {file_path}")

6. 流程图
管理员_课程


7. 结果示意图
管理员_课程

管理员——课程



5 成绩模块

1. 界面展示与导航模块

  • 主界面ScoreManagement类负责创建学生成绩管理的主界面。初始化时销毁父窗口,创建新窗口并设置标题、大小等属性。主界面包含搜索框架(用于输入搜索条件)、表格框架(展示成绩信息)和按钮框架(提供操作功能按钮)。
  • 弹出窗口AddScoreDialogEditScoreDialog类继承自Toplevel,分别用于创建添加成绩和编辑成绩的弹出窗口,在窗口中提供相应的输入框、下拉框等组件,方便用户进行信息录入和修改。
class ScoreManagement:
    def __init__(self, parent_window):
        parent_window.destroy()
        self.window = Tk()
        self.window.title("学生成绩管理")
        self.window.geometry("1200x600")
        # 界面组件初始化代码...

class AddScoreDialog(Toplevel):
    def __init__(self, parent, callback):
        super().__init__(parent)
        self.title("添加成绩")
        self.geometry("500x350")
        # 添加成绩界面组件初始化代码...

class EditScoreDialog(Toplevel):
    def __init__(self, parent, callback, score_info):
        super().__init__(parent)
        self.title("编辑成绩")
        self.geometry("500x400")
        # 编辑成绩界面组件初始化代码...

2. 成绩信息展示与加载模块

  • 信息展示:使用ttk.Treeview展示成绩信息,定义展示的列名(成绩 ID、学生 ID 等),设置列宽和表头,并配置垂直滚动条,以便在成绩信息较多时可滚动查看。
  • 信息加载load_scores方法从数据库获取成绩信息,并插入到Treeview中展示。可根据传入的条件(如搜索条件)动态更新展示内容。
class ScoreManagement:
    def __init__(self, parent_window):
        # ...
        self.columns = ("成绩ID", "学生ID", "学生姓名", "课程ID", "课程名称", "成绩", "成绩类型", "考试日期")
        self.tree = ttk.Treeview(self.tree_frame, show="headings", height=15, columns=self.columns)
        self.tree.pack(side=LEFT)
        # 滚动条配置代码...
        self.load_scores()

    def load_scores(self, condition=""):
        self.tree.delete(*self.tree.get_children())
        sql = """
            SELECT s.score_id, s.student_id, st.student_name, s.course_id, 
                   c.course_name, s.score, s.score_type, s.exam_date
            FROM score s
            JOIN student st ON s.student_id = st.student_id
            JOIN course c ON s.course_id = c.course_id
        """
        params = []
        if condition:
            sql += " WHERE " + condition
        utils = PyMySQLUtils()
        results = utils.fetchall(sql)
        utils.close()
        for row in results:
            exam_date = str(row[7]) if row[7] else ""
            self.tree.insert("", "end", values=(row[0], row[1], row[2], row[3], row[4], row[5], row[6], exam_date))

3. 成绩信息搜索模块

  • 条件获取search_scores方法从界面输入框和下拉框获取学生 ID、课程 ID、成绩类型、最低分、最高分等搜索条件。
  • 条件处理:将获取的条件组装成 SQL 查询条件,调用load_scores方法根据条件查询并展示相应成绩信息。
  • 重置功能reset_search方法清空搜索框和下拉框内容,调用load_scores方法重新展示全部成绩信息。
class ScoreManagement:
    def search_scores(self):
        conditions = []
        student_text = self.search_student_id.get().strip()
        course_text = self.search_course_id.get().strip()
        score_type = self.search_score_type.get()
        min_score = self.search_min_score.get().strip()
        max_score = self.search_max_score.get().strip()
        # 条件组装代码...
        condition = " AND ".join(conditions) if conditions else ""
        self.load_scores(condition)

    def reset_search(self):
        self.search_student_id.set("")
        self.search_course_id.set("")
        self.search_score_type.current(0)
        self.search_min_score.delete(0, END)
        self.search_max_score.delete(0, END)
        self.load_scores()

4. 成绩信息操作模块

  • 添加成绩AddScoreDialog类中confirm方法获取添加成绩界面输入信息,进行合法性验证(如学生 ID、课程 ID、成绩不能为空,成绩范围合规,成绩类型有效等),验证通过后插入数据库,并刷新主界面成绩信息展示。
  • 编辑成绩EditScoreDialog类中confirm方法获取编辑成绩界面修改后的信息,进行合法性验证(如成绩数字格式、范围,日期格式等),验证通过后更新数据库对应记录,并刷新主界面展示。
  • 删除成绩ScoreManagement类的delete_score方法判断是否选择成绩记录,确认后从数据库删除该记录,并刷新主界面成绩信息展示。
class ScoreManagement:
    def add_score(self):
        AddScoreDialog(self.window, self)

    def edit_score(self):
        if hasattr(self,'selected_score'):
            EditScoreDialog(self.window, self, self.selected_score)
        else:
            messagebox.showwarning("警告", "请先选择成绩记录!")

    def delete_score(self):
        if hasattr(self,'selected_score'):
            score_id = self.selected_score[0]
            if messagebox.askyesno("确认", f"确定删除成绩记录 {score_id}?"):
                utils = PyMySQLUtils()
                try:
                    utils.execute("DELETE FROM score WHERE score_id = %s", (score_id,))
                    messagebox.showinfo("成功", "删除成功!")
                    self.load_scores()
                except Exception as e:
                    messagebox.showerror("错误", f"删除失败:{str(e)}")
                finally:
                    utils.close()
        else:
            messagebox.showwarning("警告", "请先选择成绩记录!")

class AddScoreDialog:
    def confirm(self):
        # 获取输入信息代码...
        if not student_text or not course_text:
            messagebox.showwarning("警告", "学生ID和课程ID不能为空!")
            return
        # 验证和插入数据库代码...
        sql = """
            INSERT INTO score 
            (student_id, course_id, score, score_type, exam_date)
            VALUES (%s, %s, %s, %s, %s)
        """
        params = (student_id, course_id, score, score_type, exam_date)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "成绩添加成功!")
        self.callback.load_scores()
        self.destroy()

class EditScoreDialog:
    def confirm(self):
        # 获取修改后信息代码...
        if score < 0 or score > 100:
            messagebox.showwarning("警告", "成绩必须在0-100之间!")
            return
        # 验证和更新数据库代码...
        sql = """
            UPDATE score 
            SET score = %s, score_type = %s, exam_date = %s 
            WHERE score_id = %s
        """
        params = (score, score_type, exam_date, self.score_id)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "成绩更新成功!")
        self.callback.load_scores()
        self.destroy()

5. Excel 导入导出模块

  • 导入 Excelimport_excel方法通过文件对话框获取 Excel 文件路径,读取文件内容,验证表头和数据合法性(如学生 ID、课程 ID 存在,成绩范围和类型正确,日期格式正确等),根据记录是否存在进行插入或更新数据库操作,最后刷新主界面成绩信息展示。
  • 导出 Excelexport_excel方法通过文件对话框获取保存路径,从数据库查询成绩信息,创建 Excel 文件并将表头和成绩信息逐行写入文件,保存成功后提示用户。
class ScoreManagement:
    def import_excel(self):
        file_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")]
        )
        if not file_path:
            return
        # 读取文件、验证、插入/更新数据库代码...
        self.load_scores()

    def export_excel(self):
        file_path = filedialog.asksaveasfilename(
            title="保存Excel文件",
            defaultextension=".xls",
            filetypes=[("Excel文件", "*.xls"), ("所有文件", "*.*")]
        )
        if file_path:
            # 从数据库查询、写入文件代码...
            messagebox.showinfo("成功", f"数据已导出到 {file_path}")

6. 流程图
管理员_成绩


7. 结果示意图
管理员——成绩
管理员——成绩



6 评价模块

1. 界面展示与导航模块

  • 主界面EvaluationManagement类负责创建学生评价管理的主界面。在初始化时,销毁传入的父窗口,创建新的窗口并设置标题、大小等属性。主界面包含搜索框架(用于输入搜索条件)、表格框架(展示评价信息)和按钮框架(提供操作功能按钮)。
  • 弹出窗口AddEvaluationDialogEditEvaluationDialog类继承自Toplevel,分别用于创建添加评价和编辑评价的弹出窗口,在窗口中提供相应的输入框、下拉框等组件,方便用户进行信息录入和修改。
class EvaluationManagement:
    def __init__(self, parent_window):
        parent_window.destroy()
        self.window = Tk()
        self.window.title("学生评价管理")
        self.window.geometry("1200x600")
        # 界面组件初始化代码...

class AddEvaluationDialog(Toplevel):
    def __init__(self, parent, callback):
        super().__init__(parent)
        self.title("添加评价")
        self.geometry("500x400")
        # 添加评价界面组件初始化代码...

class EditEvaluationDialog(Toplevel):
    def __init__(self, parent, callback, evaluation_info):
        super().__init__(parent)
        self.title("编辑评价")
        self.geometry("500x400")
        # 编辑评价界面组件初始化代码...

2. 评价信息展示与加载模块

  • 信息展示:使用ttk.Treeview展示评价信息,定义展示的列名(评价 ID、学生 ID 等),设置列宽和表头,并配置垂直滚动条,以便在评价信息较多时可滚动查看。
  • 信息加载load_evaluations方法从数据库获取评价信息,并插入到Treeview中展示。可根据传入的条件(如搜索条件)动态更新展示内容。
class EvaluationManagement:
    def __init__(self, parent_window):
        # ...
        self.columns = ("评价ID", "学生ID", "课程ID", "教师ID", "评分", "匿名", "评价日期", "评价内容")
        self.tree = ttk.Treeview(self.tree_frame, show="headings", height=15, columns=self.columns)
        self.tree.pack(side=LEFT)
        # 滚动条配置代码...
        self.load_evaluations()

    def load_evaluations(self, condition=""):
        self.tree.delete(*self.tree.get_children())
        sql = """
            SELECT e.eval_id, e.student_id, e.course_id, e.teacher_id, 
                   e.evaluation_rating, e.is_anonymous, e.eval_date, e.evaluation_content
            FROM evaluation e
        """
        params = []
        if condition:
            sql += " WHERE " + condition
        utils = PyMySQLUtils()
        results = utils.fetchall(sql)
        utils.close()
        for row in results:
            anonymous = "是" if row[5] else "否"
            rating = f"{row[4]}星"
            self.tree.insert("", "end", values=(row[0], row[1], row[2], row[3], rating, anonymous, row[6], row[7]))

3. 评价信息搜索模块

  • 条件获取search_evaluations方法从界面输入框和下拉框获取学生 ID、课程 ID、教师 ID、评分、匿名等搜索条件。
  • 条件处理:将获取的条件组装成 SQL 查询条件,调用load_evaluations方法根据条件查询并展示相应评价信息。
  • 重置功能reset_search方法清空搜索框和下拉框内容,调用load_evaluations方法重新展示全部评价信息。
class EvaluationManagement:
    def search_evaluations(self):
        conditions = []
        student_id = self.search_student.get().strip()
        course_id = self.search_course.get().strip()
        teacher_id = self.search_teacher.get().strip()
        rating = self.search_rating.get()
        anonymous = self.search_anonymous.get()
        # 条件组装代码...
        condition = " AND ".join(conditions) if conditions else ""
        self.load_evaluations(condition)

    def reset_search(self):
        self.search_student.delete(0, END)
        self.search_course.delete(0, END)
        self.search_teacher.delete(0, END)
        self.search_rating.current(0)
        self.search_anonymous.current(0)
        self.load_evaluations()

4. 评价信息操作模块

  • 添加评价AddEvaluationDialog类中confirm方法获取添加评价界面输入信息,进行合法性验证(如学生 ID、课程 ID、教师 ID 存在且教师教授该课程等),验证通过后插入数据库,并刷新主界面评价信息展示。
  • 编辑评价EditEvaluationDialog类中confirm方法获取编辑评价界面修改后的信息,进行合法性验证,验证通过后更新数据库对应记录,并刷新主界面展示。
  • 删除评价EvaluationManagement类的delete_evaluation方法判断是否选择评价记录,确认后从数据库删除该记录,并刷新主界面评价信息展示。
class EvaluationManagement:
    def add_evaluation(self):
        AddEvaluationDialog(self.window, self)

    def edit_evaluation(self):
        if hasattr(self,'selected_evaluation'):
            EditEvaluationDialog(self.window, self, self.selected_evaluation)
        else:
            messagebox.showwarning("警告", "请先选择评价!")

    def delete_evaluation(self):
        if hasattr(self,'selected_evaluation'):
            eval_id = self.selected_evaluation[0]
            if messagebox.askyesno("确认", f"确定删除评价记录 {eval_id}?"):
                utils = PyMySQLUtils()
                try:
                    utils.execute("DELETE FROM evaluation WHERE eval_id = %s", (eval_id,))
                    messagebox.showinfo("成功", "删除成功!")
                    self.load_evaluations()
                except Exception as e:
                    messagebox.showerror("错误", f"删除失败:{str(e)}")
                finally:
                    utils.close()
        else:
            messagebox.showwarning("警告", "请先选择评价!")

class AddEvaluationDialog:
    def confirm(self):
        student_id = self.student_id.get().strip()
        course_id = self.course_id.get().strip()
        teacher_id = self.teacher_id.get().strip()
        rating = self.rating.get()[0]  # 提取数字部分
        anonymous = 1 if self.anonymous.get() == "是" else 0
        content = self.content.get("1.0", END).strip()
        if not all([student_id, course_id, teacher_id]):
            messagebox.showwarning("警告", "学生ID、课程ID和教师ID不能为空!")
            return
        # 验证和插入数据库代码...
        sql = """
            INSERT INTO evaluation 
            (student_id, course_id, teacher_id, evaluation_content, evaluation_rating, is_anonymous)
            VALUES (%s, %s, %s, %s, %s, %s)
        """
        params = (student_id, course_id, teacher_id, content, rating, anonymous)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "评价添加成功!")
        self.callback.load_evaluations()
        self.destroy()

class EditEvaluationDialog:
    def confirm(self):
        rating = self.rating.get()[0]  # 提取数字部分
        anonymous = 1 if self.anonymous.get() == "是" else 0
        content = self.content.get("1.0", END).strip()
        # 验证和更新数据库代码...
        sql = """
            UPDATE evaluation 
            SET evaluation_content = %s, evaluation_rating = %s, is_anonymous = %s 
            WHERE eval_id = %s
        """
        params = (content, rating, anonymous, self.eval_id)
        utils.execute(sql, params)
        messagebox.showinfo("成功", "评价更新成功!")
        self.callback.load_evaluations()
        self.destroy()

5. Excel 导入导出模块

  • 导入 Excelimport_excel方法通过文件对话框获取 Excel 文件路径,读取文件内容,验证表头和数据合法性(如学生 ID、课程 ID、教师 ID 存在且学生选修该课程、教师教授该课程等),验证通过后插入数据库,并刷新主界面评价信息展示。
  • 导出 Excelexport_excel方法通过文件对话框获取保存路径,从数据库查询评价信息,创建 Excel 文件并将表头和评价信息逐行写入文件,保存成功后提示用户。
class EvaluationManagement:
    def import_excel(self):
        file_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")]
        )
        if not file_path:
            return
        # 读取文件、验证、插入数据库代码...
        self.load_evaluations()

    def export_excel(self):
        file_path = filedialog.asksaveasfilename(
            title="保存Excel文件",
            defaultextension=".xls",
            filetypes=[("Excel文件", "*.xls"), ("所有文件", "*.*")]
        )
        if file_path:
            # 从数据库查询、写入文件代码...
            messagebox.showinfo("成功", f"数据已导出到 {file_path}")

6. 流程图
管理员_评价


7. 结果示意图
管理员——评价
管理员——评价



3.4 系统主模块设计

思路步骤

设计思路:设计一个主界面,让用户可以选择管理员、教师、学生三种身份登录系统,点击相应身份后跳转到对应身份的登录或管理页面。

具体步骤:

  1. 确定主界面结构
    主界面应简洁明了,包含欢迎信息和三个身份选择按钮。使用tkinter库创建图形用户界面(GUI)。
  2. 导入必要的模块和类
    从不同的文件中导入各个身份对应的类,这些类负责处理相应身份的登录和管理功能。例如,从管理员登入.py导入AdminLogin,从教师登入.py导入TeacherStartMenu,从学生登入.py导入StudentStartMenu。
  3. 创建主界面类
    定义一个StartMenu类,该类继承自tkinter的Frame或直接操作Tk窗口,用于创建主界面。
  4. 实现按钮点击事件处理方法
    为每个身份选择按钮定义对应的点击事件处理方法,当用户点击按钮时,销毁当前主界面窗口,并创建一个新的窗口,实例化相应身份的类。
  5. 主程序入口
    在if name == “main”:块中,创建一个Tk窗口实例,实例化StartMenu类,并启动主事件循环。
import tkinter as tk
from tkinter import messagebox
from 管理员登入 import AdminLogin
from 教师登入 import TeacherStartMenu
from 学生登入 import StudentStartMenu


class StartMenu:
    def __init__(self, window):
        self.window = window
        self.window.title("蟹&李学生管理系统")
        self.window.geometry("500x500")
        self.window.resizable(0, 0)

        # 欢迎标签
        tk.Label(self.window, text="欢迎使用<星航智学>学生管理系统", font=("宋体", 20)).pack(pady=100)

        # 管理员按钮
        tk.Button(self.window, text="管理员身份", font=("宋体", 16),
                  command=self.admin_login, width=30, height=2).pack()

        # 教师按钮
        tk.Button(self.window, text="教师身份", font=("宋体", 16),
                  command=self.teacher_login, width=30, height=2).pack()

        # 学生按钮
        tk.Button(self.window, text="学生身份", font=("宋体", 16),
                  command=self.student_login, width=30, height=2).pack()

    def admin_login(self):
        self.window.destroy()
        AdminLogin(tk.Tk())

    def teacher_login(self):
        self.window.destroy()
        TeacherStartMenu(tk.Tk())

    def student_login(self):
        self.window.destroy()
        StudentStartMenu(tk.Tk())


if __name__ == "__main__":
    root = tk.Tk()
    app = StartMenu(root)
    root.mainloop()

页面效果

main页面效果

四 系统测试(正在完善)

4.1 数据库测试 设计

测试数据框架设计

测试核心需求的评价表关系是否合理:

这里我们来回顾以下我们的需求分析和各关系之间的关系:

总体需求分析:

使用学生管理系统的学校有若干个专业
学生表,学生自己的信息,一个学生只能在一个专业中,只能有一个邮箱注册
教师表,一个老师可以授课多个专业,但只能授课一个课程,但是课程号可以有多个
课程表,一个课程对应多个学生+多个老师,以及学分等其他属性
成绩表,供学生查看,老师填写,管理员修改(甲方核心需求)
评分表,学生填写,老师查看,管理员监控违规评价(甲方核心需求)
该系统通过输入正确的用户名和密码进行登录

我们来设计一个数据框架,使得可以测试到不同的合理数据以及错误数据

分别是三个专业,六个学生,三个教师,三门课程,我们来测试评价表(核心需求)是否合理报错


框架如下:
在这里插入图片描述


在这里插入图片描述




4.2 数据库 测试内容

4.2.1 核心需求1评分表需求测试

情况1:学生如果以及评价了全部的老师和课程,则不能再评价:
在这里插入图片描述


情况2:当一个评价都没填写时候,可以选择填写,且老师会自动随着课程而变化
在这里插入图片描述
在这里插入图片描述


情况3:已经评价过的课程不能再次评价

比如这里学生已经评价过了操作系统,就只有专业导论是可以评价的了,情况合理准确
在这里插入图片描述


以下是对于老师的情况:
情况:老师只能看见所授课程学生的评价信息,且匿名以后无法看见学生学号

且这里老师不能删改评论,因为在需求分析中我们知道,只有管理员可以修改评论
在这里插入图片描述


对于管理员的情况:
情况1:管理员可以添加删改评论,而且添加评论时候也要符合对应关系

比如这里因为S001评价了C001,那么在选择学生id以后课程id可选只有C002了
在这里插入图片描述


情况2:管理员可以修改评论,防止恶意评论(满足核心需求)

在这里插入图片描述

修改以后老师页面也发生修改
在这里插入图片描述


情况3:在管理员导入数据方面,如果导入的数据中评价信息不符合不能导入

这里是老师和课程不对应的情况
在这里插入图片描述
在这里插入图片描述


这里是学生和课程不对应的情况,不对应课程自然就是不对应老师
在这里插入图片描述
在这里插入图片描述


情况4:学生已经评价了老师不能再次添加

这里学生S001已经评价了T001老师了,就不能再次导入评价
在这里插入图片描述


总结分析

在评分系统中

  • 我们为了满足学生只能评价对应的课程和老师,我们的做法就是学生在添加评价的时候课程id是只能选择的,也就是只能选择自己学的课程id,而对应的老师是关联这个课程id的,那么这个问题就解决了!!
  • 因为管理员可以修改和删除评论,所以管理员在添加评论的时候也是可以选择的,选择了一个学生以后,那么课程只能选对应的课程,也就避免了不匹配的问题,而在excel导入方面,我们去匹配导入的数据中学生课程老师的匹配是否存在,在判断能否导入,不能则输出对应的报错:课程和老师不匹配?课程(老师)和学生不匹配?是否重复评价?
  • 那么我们就解决了全部的不合理的边缘的数据测试!!!!!!


4.2.2 核心需求2excel需求测试
1. 学生信息插入excel

错误数据:
在这里插入图片描述

情况1 :当excel中学生的性别不是男或女时 无法成功插入
在这里插入图片描述


情况2:当插入的专业不是已有专业的时候
在这里插入图片描述



2. 教师信息插入excel

当导入excel中教师的职称不符合选项时 会报错:职称错误

在这里插入图片描述

在这里插入图片描述



3. 课程信息插入excel

情况1 :当导入教师表里没有的老师ID时 会报错:教师不存在
在这里插入图片描述

在这里插入图片描述


情况2:当导入专业表里没有的专业ID时 会报错:专业ID不存在
在这里插入图片描述

在这里插入图片描述



4. 成绩信息插入excel

错误数据:
在这里插入图片描述

情况1:当学生的学号在学生表里不存在时,会报错:学生ID不存在
在这里插入图片描述


情况2:当课程课号在课程表里不存在时,会报错:课程ID不存在
在这里插入图片描述


情况3:当成绩类型在成绩表里不存在时,会报错:无效的成绩类型

在这里插入图片描述



5. 评价信息插入excel

评分一定要在1-5之间,在此范围之外会报错:评分错误 并提示允许值的范围是1-5
在这里插入图片描述

在这里插入图片描述

其他的情况在上面的评价表的具体分析中已经涉及到了全部的错误数据



4.2.3 前端的各表查找功能

视频演示

前端各表的查找



至此,我们就完成了学生成绩管理系统数据库的全部设计,完成了甲方提出的——评价表的管理、excel表格的导入导出、搜索功能的实现——的全部功能,其次,我们并对每个核心需求做出了适当的数据测试(包括合理的数据和错误的数据),完善数据库和可视化界面链接的完整新,维护数据库的健壮性。



疑问和问题解决

范式问题,是否要修改表的结构关系?—合理不用修改

前端解决方案是否合理? — 进行两次版本修改

怎么形成完整的测试数据框架? — 用少量但全面的数据,专业*3,老师*3,学生*6,课程*3,管理员*1,可以覆盖全部需求

前端的部署和数据库的对接是否合理完善?—检查测试ing




温馨说明:

学力有限,拙文恐有未周,敬祈读者批评指正,由甚感激!若有讹误或排版不当,尚祈见谅!
☺️☺️☺️☺️☺️

在Lua中实现面向对象编程可以通过使用表(table)来模拟类和对象。Lua 5.1手册详细介绍了Lua语言的API,包括如何使用表、元表和元方法来构建面向对象的系统。具体步骤如下: 参考资源链接:[Lua 5.1手册:入门与API详解](https://wenku.csdn.net/doc/mtdoy1dgms?spm=1055.2569.3001.10343) 1. 创建一个表来表示类,并在这个表中定义类的属性和方法。这些属性和方法就是类的成员。 2. 创建一个表来表示对象实例,通常通过调用类(即第一个表)来生成。 3. 使用元表和元方法来模拟继承和方法重写等面向对象的高级特性。 以下是Lua代码示例: ```lua -- 定义一个名为 'ClassA' 的表来作为类 local ClassA = {} function ClassA:new(o, value) o = o or {} setmetatable(o, self) self.__index = self self.value = value or 0 return o end function ClassA:setValue(v) self.value = v end function ClassA:getValue() return self.value end -- 创建一个 'ClassA' 的实例 local instance = ClassA:new() -- 置对象实例的值 instancesetValue(10) print(instance:getValue()) -- 输出: 10 -- 定义一个名为 'ClassB' 的表来继承 'ClassA' local ClassB = ClassA:new() function ClassB:new(o, value) o = o or ClassA:new(o, value) setmetatable(o, self) self.__index = self return o end -- 'ClassB' 可以有自己的方法 function ClassB:getValue() return 参考资源链接:[Lua 5.1手册:入门与API详解](https://wenku.csdn.net/doc/mtdoy1dgms?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值