|
|
from datetime import date, datetime
|
|
|
from typing import List, Optional
|
|
|
from ..bll.student_bll import StudentBLL
|
|
|
from ..model.student import Student
|
|
|
|
|
|
|
|
|
class StudentConsoleUI:
|
|
|
"""学生信息管理系统的控制台用户界面"""
|
|
|
|
|
|
def __init__(self, bll: StudentBLL):
|
|
|
self.bll = bll
|
|
|
|
|
|
def display_menu(self):
|
|
|
"""显示主菜单"""
|
|
|
print("\n" + "=" * 50)
|
|
|
print("学生信息管理系统".center(50))
|
|
|
print("=" * 50)
|
|
|
print("1. 添加学生")
|
|
|
print("2. 删除学生")
|
|
|
print("3. 修改学生信息")
|
|
|
print("4. 查看学生详细信息")
|
|
|
print("5. 查询学生")
|
|
|
print("6. 统计功能")
|
|
|
print("7. 数据导入导出")
|
|
|
print("8. 退出系统")
|
|
|
print("=" * 50)
|
|
|
|
|
|
def run(self):
|
|
|
"""运行系统"""
|
|
|
while True:
|
|
|
self.display_menu()
|
|
|
choice = input("请输入您的选择: ")
|
|
|
|
|
|
if choice == '1':
|
|
|
self.add_student()
|
|
|
elif choice == '2':
|
|
|
self.delete_student()
|
|
|
elif choice == '3':
|
|
|
self.update_student()
|
|
|
elif choice == '4':
|
|
|
self.view_student_details()
|
|
|
elif choice == '5':
|
|
|
self.search_students()
|
|
|
elif choice == '6':
|
|
|
self.statistics_menu()
|
|
|
elif choice == '7':
|
|
|
self.import_export_menu()
|
|
|
elif choice == '8':
|
|
|
print("感谢使用学生信息管理系统,再见!")
|
|
|
break
|
|
|
else:
|
|
|
print("无效的选择,请重新输入!")
|
|
|
|
|
|
def add_student(self):
|
|
|
"""添加学生界面"""
|
|
|
print("\n添加学生")
|
|
|
print("-" * 50)
|
|
|
|
|
|
name = input("姓名: ")
|
|
|
id_card = input("身份证号: ")
|
|
|
stu_id = input("学号: ")
|
|
|
|
|
|
gender_input = input("性别 (男/女,可选): ")
|
|
|
gender = None
|
|
|
if gender_input:
|
|
|
gender = gender_input.lower() == '男'
|
|
|
|
|
|
height = input("身高 (cm,可选): ")
|
|
|
height = int(height) if height else None
|
|
|
|
|
|
weight = input("体重 (kg,可选): ")
|
|
|
weight = float(weight) if weight else None
|
|
|
|
|
|
enrollment_date = input("入学日期 (YYYY-MM-DD,可选): ")
|
|
|
enrollment_date = datetime.strptime(enrollment_date, '%Y-%m-%d').date() if enrollment_date else None
|
|
|
|
|
|
class_name = input("班级名称 (可选): ")
|
|
|
major = input("专业名称 (可选): ")
|
|
|
email = input("电子邮箱 (可选): ")
|
|
|
phone = input("联系电话 (可选): ")
|
|
|
|
|
|
student = Student(
|
|
|
name=name,
|
|
|
id_card=id_card,
|
|
|
stu_id=stu_id,
|
|
|
gender=gender,
|
|
|
height=height,
|
|
|
weight=weight,
|
|
|
enrollment_date=enrollment_date,
|
|
|
class_name=class_name,
|
|
|
major=major,
|
|
|
email=email,
|
|
|
phone=phone
|
|
|
)
|
|
|
|
|
|
success, message = self.bll.add_student(student)
|
|
|
if success:
|
|
|
print("添加成功!")
|
|
|
else:
|
|
|
print(f"添加失败: {message}")
|
|
|
|
|
|
def delete_student(self):
|
|
|
"""删除学生界面"""
|
|
|
print("\n删除学生")
|
|
|
print("-" * 50)
|
|
|
print("1. 根据身份证号删除")
|
|
|
print("2. 根据学号删除")
|
|
|
choice = input("请选择删除方式: ")
|
|
|
|
|
|
if choice == '1':
|
|
|
id_card = input("请输入要删除的学生身份证号: ")
|
|
|
if self.bll.delete_student_by_id(id_card):
|
|
|
print("删除成功!")
|
|
|
else:
|
|
|
print("删除失败,未找到该学生!")
|
|
|
elif choice == '2':
|
|
|
stu_id = input("请输入要删除的学生学号: ")
|
|
|
if self.bll.delete_student_by_stu_id(stu_id):
|
|
|
print("删除成功!")
|
|
|
else:
|
|
|
print("删除失败,未找到该学生!")
|
|
|
else:
|
|
|
print("无效的选择!")
|
|
|
|
|
|
def update_student(self):
|
|
|
"""修改学生信息界面"""
|
|
|
print("\n修改学生信息")
|
|
|
print("-" * 50)
|
|
|
id_card = input("请输入要修改的学生身份证号: ")
|
|
|
|
|
|
student = self.bll.get_student_by_id(id_card)
|
|
|
if not student:
|
|
|
print("未找到该学生!")
|
|
|
return
|
|
|
|
|
|
print(f"当前学生信息 - 姓名: {student.name}, 学号: {student.stu_id}")
|
|
|
|
|
|
name = input(f"姓名 ({student.name}): ") or student.name
|
|
|
stu_id = input(f"学号 ({student.stu_id}): ") or student.stu_id
|
|
|
|
|
|
gender_input = input(f"性别 ({'男' if student.gender else '女' if student.gender is not None else '未设置'}): ")
|
|
|
gender = student.gender
|
|
|
if gender_input:
|
|
|
gender = gender_input.lower() == '男'
|
|
|
|
|
|
height = input(f"身高 ({student.height} cm): ")
|
|
|
height = int(height) if height else student.height
|
|
|
|
|
|
weight = input(f"体重 ({student.weight} kg): ")
|
|
|
weight = float(weight) if weight else student.weight
|
|
|
|
|
|
enrollment_date = input(f"入学日期 ({student.enrollment_date}): ")
|
|
|
enrollment_date = datetime.strptime(enrollment_date,
|
|
|
'%Y-%m-%d').date() if enrollment_date else student.enrollment_date
|
|
|
|
|
|
class_name = input(f"班级名称 ({student.class_name}): ") or student.class_name
|
|
|
major = input(f"专业名称 ({student.major}): ") or student.major
|
|
|
email = input(f"电子邮箱 ({student.email}): ") or student.email
|
|
|
phone = input(f"联系电话 ({student.phone}): ") or student.phone
|
|
|
|
|
|
student.name = name
|
|
|
student.stu_id = stu_id
|
|
|
student.gender = gender
|
|
|
student.height = height
|
|
|
student.weight = weight
|
|
|
student.enrollment_date = enrollment_date
|
|
|
student.class_name = class_name
|
|
|
student.major = major
|
|
|
student.email = email
|
|
|
student.phone = phone
|
|
|
|
|
|
success, message = self.bll.update_student(student)
|
|
|
if success:
|
|
|
print("修改成功!")
|
|
|
else:
|
|
|
print(f"修改失败: {message}")
|
|
|
|
|
|
def view_student_details(self):
|
|
|
"""查看学生详细信息界面"""
|
|
|
print("\n查看学生详细信息")
|
|
|
print("-" * 50)
|
|
|
print("1. 根据身份证号查询")
|
|
|
print("2. 根据学号查询")
|
|
|
choice = input("请选择查询方式: ")
|
|
|
|
|
|
if choice == '1':
|
|
|
id_card = input("请输入学生身份证号: ")
|
|
|
student = self.bll.get_student_by_id(id_card)
|
|
|
elif choice == '2':
|
|
|
stu_id = input("请输入学生学号: ")
|
|
|
student = self.bll.get_student_by_stu_id(stu_id)
|
|
|
else:
|
|
|
print("无效的选择!")
|
|
|
return
|
|
|
|
|
|
if not student:
|
|
|
print("未找到该学生!")
|
|
|
return
|
|
|
|
|
|
self._print_student_details(student)
|
|
|
|
|
|
def _print_student_details(self, student: Student):
|
|
|
"""打印学生详细信息"""
|
|
|
print("\n" + "-" * 50)
|
|
|
print(f"姓名: {student.name}")
|
|
|
print(f"身份证号: {student.id_card}")
|
|
|
print(f"学号: {student.stu_id}")
|
|
|
print(f"性别: {'男' if student.gender else '女' if student.gender is not None else '未设置'}")
|
|
|
print(f"年龄: {student.age if student.age is not None else '未知'}")
|
|
|
print(f"出生日期: {student.birthday if student.birthday else '未知'}")
|
|
|
print(f"身高: {student.height} cm" if student.height else "身高: 未设置")
|
|
|
print(f"体重: {student.weight} kg" if student.weight else "体重: 未设置")
|
|
|
print(f"入学日期: {student.enrollment_date}" if student.enrollment_date else "入学日期: 未设置")
|
|
|
print(f"班级: {student.class_name if student.class_name else '未设置'}")
|
|
|
print(f"专业: {student.major if student.major else '未设置'}")
|
|
|
print(f"电子邮箱: {student.email if student.email else '未设置'}")
|
|
|
print(f"联系电话: {student.phone if student.phone else '未设置'}")
|
|
|
print("-" * 50)
|
|
|
|
|
|
def search_students(self):
|
|
|
"""查询学生界面"""
|
|
|
print("\n查询学生")
|
|
|
print("-" * 50)
|
|
|
print("1. 按姓名查询")
|
|
|
print("2. 按班级查询")
|
|
|
print("3. 按专业查询")
|
|
|
choice = input("请选择查询方式: ")
|
|
|
|
|
|
if choice == '1':
|
|
|
keyword = input("请输入姓名关键词: ")
|
|
|
students = self.bll.search_students_by_name(keyword)
|
|
|
elif choice == '2':
|
|
|
keyword = input("请输入班级关键词: ")
|
|
|
students = self.bll.search_students_by_class(keyword)
|
|
|
elif choice == '3':
|
|
|
keyword = input("请输入专业关键词: ")
|
|
|
students = self.bll.search_students_by_major(keyword)
|
|
|
else:
|
|
|
print("无效的选择!")
|
|
|
return
|
|
|
|
|
|
if not students:
|
|
|
print("未找到匹配的学生!")
|
|
|
return
|
|
|
|
|
|
print(f"\n共找到 {len(students)} 名学生:")
|
|
|
for i, student in enumerate(students, 1):
|
|
|
print(
|
|
|
f"{i}. {student.name} - {student.stu_id} - {student.class_name if student.class_name else '未知班级'}")
|
|
|
|
|
|
view_choice = input("是否查看详情?(y/n): ")
|
|
|
if view_choice.lower() == 'y':
|
|
|
detail_index = input("请输入要查看的学生序号: ")
|
|
|
try:
|
|
|
index = int(detail_index) - 1
|
|
|
if 0 <= index < len(students):
|
|
|
self._print_student_details(students[index])
|
|
|
else:
|
|
|
print("无效的序号!")
|
|
|
except ValueError:
|
|
|
print("请输入有效的数字!")
|
|
|
|
|
|
def statistics_menu(self):
|
|
|
"""统计功能菜单"""
|
|
|
print("\n统计功能")
|
|
|
print("-" * 50)
|
|
|
print("1. 学生总数")
|
|
|
print("2. 各专业学生人数")
|
|
|
print("3. 计算平均身高")
|
|
|
print("4. 计算平均体重")
|
|
|
print("5. 统计性别比例")
|
|
|
choice = input("请选择统计功能: ")
|
|
|
|
|
|
if choice == '1':
|
|
|
total = self.bll.get_total_students()
|
|
|
print(f"学生总数: {total} 人")
|
|
|
elif choice == '2':
|
|
|
major_count = self.bll.get_students_by_major()
|
|
|
print("\n各专业学生人数:")
|
|
|
for major, count in major_count.items():
|
|
|
print(f"{major}: {count} 人")
|
|
|
elif choice == '3':
|
|
|
print("1. 全部学生平均身高")
|
|
|
print("2. 按班级计算平均身高")
|
|
|
print("3. 按专业计算平均身高")
|
|
|
sub_choice = input("请选择计算方式: ")
|
|
|
|
|
|
if sub_choice == '1':
|
|
|
avg_height = self.bll.calculate_average_height()
|
|
|
print(f"全部学生平均身高: {avg_height:.2f} cm")
|
|
|
elif sub_choice == '2':
|
|
|
class_name = input("请输入班级名称: ")
|
|
|
avg_height = self.bll.calculate_average_height('class', class_name)
|
|
|
print(f"{class_name} 班级平均身高: {avg_height:.2f} cm")
|
|
|
elif sub_choice == '3':
|
|
|
major = input("请输入专业名称: ")
|
|
|
avg_height = self.bll.calculate_average_height('major', major)
|
|
|
print(f"{major} 专业平均身高: {avg_height:.2f} cm")
|
|
|
else:
|
|
|
print("无效的选择!")
|
|
|
elif choice == '4':
|
|
|
print("1. 全部学生平均体重")
|
|
|
print("2. 按班级计算平均体重")
|
|
|
print("3. 按专业计算平均体重")
|
|
|
sub_choice = input("请选择计算方式: ")
|
|
|
|
|
|
if sub_choice == '1':
|
|
|
avg_weight = self.bll.calculate_average_weight()
|
|
|
print(f"全部学生平均体重: {avg_weight:.2f} kg")
|
|
|
elif sub_choice == '2':
|
|
|
class_name = input("请输入班级名称: ")
|
|
|
avg_weight = self.bll.calculate_average_weight('class', class_name)
|
|
|
print(f"{class_name} 班级平均体重: {avg_weight:.2f} kg")
|
|
|
elif sub_choice == '3':
|
|
|
major = input("请输入专业名称: ")
|
|
|
avg_weight = self.bll.calculate_average_weight('major', major)
|
|
|
print(f"{major} 专业平均体重: {avg_weight:.2f} kg")
|
|
|
else:
|
|
|
print("无效的选择!")
|
|
|
elif choice == '5':
|
|
|
ratio = self.bll.get_gender_ratio()
|
|
|
print("\n性别比例统计:")
|
|
|
print(f"总人数: {ratio['total']}")
|
|
|
print(f"男生人数: {ratio['male']} ({ratio['male_ratio']:.2%})")
|
|
|
print(f"女生人数: {ratio['female']} ({ratio['female_ratio']:.2%})")
|
|
|
else:
|
|
|
print("无效的选择!")
|
|
|
|
|
|
def import_export_menu(self):
|
|
|
"""数据导入导出菜单"""
|
|
|
print("\n数据导入导出")
|
|
|
print("-" * 50)
|
|
|
print("1. 导出学生数据到CSV")
|
|
|
print("2. 导出学生数据到JSON")
|
|
|
print("3. 从CSV导入学生数据")
|
|
|
print("4. 从JSON导入学生数据")
|
|
|
choice = input("请选择操作: ")
|
|
|
|
|
|
# 这里只是示例,实际实现需要根据具体的数据存储方式编写
|
|
|
if choice in ['1', '2', '3', '4']:
|
|
|
print("功能开发中,暂未实现...")
|
|
|
else:
|
|
|
print("无效的选择!")
|
|
|
def _get_age(self, birthday: Optional[date]) -> Optional[int]:
|
|
|
"""计算学生年龄"""
|
|
|
if not birthday:
|
|
|
return None
|
|
|
today = date.today()
|
|
|
age = today.year - birthday.year - ((today.month, today.day) < (birthday.month, birthday.day))
|
|
|
return age |