|
|
|
@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
from datetime import date
|
|
|
|
|
|
|
|
from bll.student_bll import StudentBLL
|
|
|
|
|
|
|
|
from dal.student_dal_json import StudentDAL
|
|
|
|
|
|
|
|
from model.Student import Student
|
|
|
|
|
|
|
|
from dal.student_dal_json import StudentDALJSON # 确保导入
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class StudentUI:
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
|
|
parent_dir = os.path.dirname(current_dir)
|
|
|
|
|
|
|
|
file_path = os.path.join(parent_dir, "data", "student.json")
|
|
|
|
|
|
|
|
dal = StudentDAL(file_path)
|
|
|
|
|
|
|
|
self.bll = StudentBLL(dal)
|
|
|
|
|
|
|
|
self.file_path = file_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def display_menu(self):
|
|
|
|
|
|
|
|
"""显示主菜单"""
|
|
|
|
|
|
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print(" 学生信息管理系统 - 主菜单 ")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print("1. 添加学生信息")
|
|
|
|
|
|
|
|
print("2. 删除学生信息")
|
|
|
|
|
|
|
|
print("3. 更新学生信息")
|
|
|
|
|
|
|
|
print("4. 查询学生信息")
|
|
|
|
|
|
|
|
print("5. 统计分析")
|
|
|
|
|
|
|
|
print("6. 数据导入导出")
|
|
|
|
|
|
|
|
print("7. 清空所有学生信息")
|
|
|
|
|
|
|
|
print("0. 退出系统")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def display_query_menu(self):
|
|
|
|
|
|
|
|
"""显示查询子菜单"""
|
|
|
|
|
|
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print(" 学生信息管理系统 - 查询菜单 ")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print("1. 查询所有学生")
|
|
|
|
|
|
|
|
print("2. 按身份证号查询")
|
|
|
|
|
|
|
|
print("3. 按学号查询")
|
|
|
|
|
|
|
|
print("4. 按姓名查询")
|
|
|
|
|
|
|
|
print("5. 按班级查询")
|
|
|
|
|
|
|
|
print("0. 返回上一级")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def display_stats_menu(self):
|
|
|
|
|
|
|
|
"""显示统计分析子菜单"""
|
|
|
|
|
|
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print(" 学生信息管理系统 - 统计分析菜单 ")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print("1. 学生总数")
|
|
|
|
|
|
|
|
print("2. 平均身高")
|
|
|
|
|
|
|
|
print("3. 按身高范围统计")
|
|
|
|
|
|
|
|
print("4. 按入学年份统计")
|
|
|
|
|
|
|
|
print("5. 按年龄范围统计")
|
|
|
|
|
|
|
|
print("0. 返回上一级")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def display_import_export_menu(self):
|
|
|
|
|
|
|
|
"""显示数据导入导出子菜单"""
|
|
|
|
|
|
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print(" 学生信息管理系统 - 数据导入导出菜单 ")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print("1. 导出数据到JSON")
|
|
|
|
|
|
|
|
print("2. 从JSON导入数据")
|
|
|
|
|
|
|
|
print("3. 导出数据到CSV")
|
|
|
|
|
|
|
|
print("4. 从CSV导入数据")
|
|
|
|
|
|
|
|
print("0. 返回上一级")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_input(self, prompt: str) -> str:
|
|
|
|
|
|
|
|
"""获取用户输入,添加异常处理"""
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
return input(prompt).strip()
|
|
|
|
|
|
|
|
except EOFError:
|
|
|
|
|
|
|
|
return "0" # 按Ctrl+D视为退出
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_student(self):
|
|
|
|
|
|
|
|
"""添加学生信息"""
|
|
|
|
|
|
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
print(" 添加学生信息 ")
|
|
|
|
|
|
|
|
print("*" * 50)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
name = self.get_input("请输入姓名: ")
|
|
|
|
|
|
|
|
id_number = self.get_input("请输入身份证号: ")
|
|
|
|
|
|
|
|
while not re.match(r'^\d{17}[\dXx]$', id_number):
|
|
|
|
|
|
|
|
print("身份证号格式不正确,请输入 18 位身份证号。")
|
|
|
|
|
|
|
|
id_number = self.get_input("请输入身份证号: ")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
student_id = self.get_input("请输入学号: ")
|
|
|
|
|
|
|
|
if re.match(r'^\d{10,15}$', student_id): # 假设学号是10 - 15位数字
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
print("学号格式不正确,请输入10到15位数字")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gender = self.get_input("请输入性别(男/女): ")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
height = float(self.get_input("请输入身高(cm): "))
|
|
|
|
|
|
|
|
if height <= 0 or height > 250:
|
|
|
|
|
|
|
|
raise ValueError
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
except ValueError:
|
|
|
|
|
|
|
|
print("身高必须为0到250之间的有效数值,请重新输入")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
weight = float(self.get_input("请输入体重(kg): "))
|
|
|
|
|
|
|
|
if weight <= 0 or weight > 500:
|
|
|
|
|
|
|
|
raise ValueError
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
except ValueError:
|
|
|
|
|
|
|
|
print("体重必须为0到500之间的有效数值,请重新输入")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 从身份证号中提取出生日期
|
|
|
|
|
|
|
|
birth_date_str = id_number[6:14]
|
|
|
|
|
|
|
|
birth_date = date(int(birth_date_str[:4]), int(birth_date_str[4:6]), int(birth_date_str[6:]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 修改后的日期输入验证
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
enrollment_date = self.get_input("请输入入学日期(YYYY-MM-DD): ")
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
enrollment_date_obj = date.fromisoformat(enrollment_date)
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
except ValueError:
|
|
|
|
|
|
|
|
print("日期格式错误,请使用 YYYY-MM-DD 格式(例如:2023-09-01)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class_name = self.get_input("请输入班级: ")
|
|
|
|
|
|
|
|
major = self.get_input("请输入专业: ")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建 Student 对象
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
student = Student(
|
|
|
|
|
|
|
|
sid=student_id,
|
|
|
|
|
|
|
|
name=name,
|
|
|
|
|
|
|
|
height=height,
|
|
|
|
|
|
|
|
birth_date=birth_date, # 使用从身份证提取的出生日期
|
|
|
|
|
|
|
|
enrollment_date=enrollment_date_obj,
|
|
|
|
|
|
|
|
class_name=class_name
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if self.bll.add_student(student):
|
|
|
|
|
|
|
|
print("学生信息添加成功!")
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
print("学生信息添加失败。")
|
|
|
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
|
|
print(f"添加学生失败: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_import_export(self, choice):
|
|
|
|
|
|
|
|
if choice == '1':
|
|
|
|
|
|
|
|
file_path = self.get_input("请输入要导出的 JSON 文件路径: ")
|
|
|
|
|
|
|
|
self.bll.dal.export_to_json(file_path)
|
|
|
|
|
|
|
|
print("数据导出到 JSON 成功!")
|
|
|
|
|
|
|
|
elif choice == '2':
|
|
|
|
|
|
|
|
file_path = self.get_input("请输入要导入的 JSON 文件路径: ")
|
|
|
|
|
|
|
|
self.bll.dal.import_from_json(file_path)
|
|
|
|
|
|
|
|
print("数据从 JSON 导入成功!")
|
|
|
|
|
|
|
|
elif choice == '3':
|
|
|
|
|
|
|
|
file_path = self.get_input("请输入要导出的 CSV 文件路径: ")
|
|
|
|
|
|
|
|
self.bll.dal.export_to_csv(file_path)
|
|
|
|
|
|
|
|
print("数据导出到 CSV 成功!")
|
|
|
|
|
|
|
|
elif choice == '4':
|
|
|
|
|
|
|
|
file_path = self.get_input("请输入要导入的 CSV 文件路径: ")
|
|
|
|
|
|
|
|
self.bll.dal.import_from_csv(file_path)
|
|
|
|
|
|
|
|
print("数据从 CSV 导入成功!")
|