You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wlhdl/ui/add_student.py

488 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import json
import csv
from datetime import date
from typing import List, Tuple
from BLL.add_student import StudentBLL
from model.student import Student
from DAL.clear_all_student import CsvStudentDAL
from DAL.clear_all_student import JsonStudentDAL
def display_menu():
print("\n=== 学生信息管理系统 ====")
print("1. 添加学生信息")
print("2. 删除学生信息")
print("3. 更新学生信息")
print("4. 查询学生信息")
print("5. 统计分析")
print("6. 数据导入导出")
print("7. 清空所有学生信息")
print("8. 退出系统")
print("---")
def display_query_menu():
print("\n==== 查询学生信息 ====")
print("1. 查询所有学生")
print("2. 按身份证号查询")
print("3. 按学号查询")
print("4. 按姓名查询")
print("5. 按班级查询")
print("6. 按专业查询")
print("7. 返回上一级")
print("=======================")
def display_stats_menu():
print("\n==== 统计分析 ====")
print("1. 学生总数")
print("2. 平均身高")
print("3. 按身高范围统计")
print("4. 按入学年份统计")
print("5. 按年龄范围统计")
print("6. 按专业分组统计")
print("7. 性别比例")
print("8. 返回上一级")
print("=======================")
def display_import_export_menu():
print("\n==== 数据导入导出 ====")
print("1. 导出数据到JSON")
print("2. 从JSON导入数据")
print("3. 导出数据到CSV")
print("4. 从CSV导入数据")
print("5. 返回上一级")
print("=======================")
def display_students(students: List[Student]):
if not students:
print("没有找到学生信息")
return
print("\n学生信息列表:")
print("-" * 120)
print(
f"{'姓名':<10}{'学号':<15}{'身份证号':<20}{'性别':<6}{'年龄':<6}{'身高':<6}{'体重':<6}{'班级':<10}{'专业':<15}{'入学日期':<12}")
print("-" * 120)
for student in students:
gender = '' if student.gender else '' if student.gender is not None else '未知'
print(
f"{student.name:<10}{student.stu_id:<15}{student.id_card:<20}"
f"{gender:<6}{student.age or '-':<6}{student.height or '-':<6}"
f"{student.weight or '-':<6}{student.class_name or '-':<10}"
f"{student.major or '-':<15}{student.enrollment_date or '-'}"
)
print("-" * 120)
print(f"共找到 {len(students)} 名学生")
class StudentTUI:
def __init__(self, bll: StudentBLL):
self.bll = bll
def run(self):
while True:
display_menu()
choice = input("请选择操作: ").strip()
if choice == '1':
self.add_student()
elif choice == '2':
self.delete_student()
elif choice == '3':
self.update_student()
elif choice == '4':
self.query_students()
elif choice == '5':
self.stats_students()
elif choice == '6':
self.import_export_data()
elif choice == '7':
self.clear_all_students()
elif choice == '8':
print("感谢使用学生信息管理系统,再见!")
break
else:
print("无效的选择,请重新输入!")
def add_student(self):
print("\n==== 添加学生信息 ====")
try:
name = input("姓名: ").strip()
id_card = input("身份证号: ").strip()
stu_id = input("学号: ").strip()
gender = input("性别(男/女): ").strip().lower() == ''
height = int(input("身高(cm): ").strip())
weight = float(input("体重(kg): ").strip())
enrollment_date = input("入学日期(YYYY-MM-DD): ").strip()
class_name = input("班级名称: ").strip()
major = input("专业: ").strip()
email = input("邮箱(可选): ").strip() or None
phone = input("手机号(可选): ").strip() or None
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
)
if self.bll.add_student(student):
print("学生信息添加成功!")
else:
print("添加失败,可能学号或身份证号已存在")
except ValueError as e:
print(f"输入错误: {e}")
except Exception as e:
print(f"添加学生信息时出错: {e}")
def delete_student(self):
print("\n==== 删除学生信息 ====")
print("1. 按身份证号删除")
print("2. 按学号删除")
choice = input("请选择删除方式: ").strip()
if choice == '1':
id_card = input("请输入身份证号: ").strip()
try:
if self.bll.delete_student_by_id_card(id_card):
print("学生信息删除成功!")
else:
print("删除失败,未找到匹配的学生")
except ValueError as e:
print(f"错误: {e}")
elif choice == '2':
stu_id = input("请输入学号: ").strip()
try:
if self.bll.delete_student_by_stu_id(stu_id):
print("学生信息删除成功!")
else:
print("删除失败,未找到匹配的学生")
except ValueError as e:
print(f"错误: {e}")
else:
print("无效的选择")
def update_student(self):
print("\n==== 更新学生信息 ====")
id_card = input("请输入要更新的学生身份证号: ").strip()
try:
student = self.bll.get_student_by_id_card(id_card)
if not student:
print("未找到该学生")
return
print("当前学生信息:")
print(student)
print("\n请输入要更新的字段 (留空表示不更新):")
name = input(f"姓名({student.name}): ").strip() or student.name
stu_id = input(f"学号({student.stu_id}): ").strip() or student.stu_id
gender = input(f"性别(男/女)({'' if student.gender else ''}): ").strip()
gender = gender.lower() == '' if gender else student.gender
height = input(f"身高({student.height}): ").strip()
height = int(height) if height else student.height
weight = input(f"体重({student.weight}): ").strip()
weight = float(weight) if weight else student.weight
enrollment_date = input(f"入学日期({student.enrollment_date}): ").strip()
enrollment_date = enrollment_date or student.enrollment_date
class_name = input(f"班级名称({student.class_name}): ").strip() or student.class_name
major = input(f"专业({student.major}): ").strip() or student.major
email = input(f"邮箱({student.email}): ").strip() or student.email
phone = input(f"手机号({student.phone}): ").strip() or student.phone
updated_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
)
if self.bll.update_student(id_card, updated_student):
print("学生信息更新成功!")
else:
print("更新失败")
except ValueError as e:
print(f"输入错误: {e}")
except Exception as e:
print(f"更新学生信息时出错: {e}")
def query_students(self):
while True:
display_query_menu()
choice = input("请选择查询方式: ").strip()
if choice == '1': # 查询所有学生
students = self.bll.get_all_students()
display_students(students)
elif choice == '2': # 按身份证号查询
id_card = input("请输入身份证号: ").strip()
student = self.bll.get_student_by_id_card(id_card)
if student:
display_students([student])
else:
print("未找到匹配的学生")
elif choice == '3': # 按学号查询
stu_id = input("请输入学号: ").strip()
student = self.bll.get_student_by_stu_id(stu_id)
if student:
display_students([student])
else:
print("未找到匹配的学生")
elif choice == '4': # 按姓名查询
name = input("请输入姓名: ").strip()
students = self.bll.get_students_by_name(name)
display_students(students)
elif choice == '5': # 按班级查询
class_name = input("请输入班级名称: ").strip()
students = self.bll.get_students_by_class_name(class_name)
display_students(students)
elif choice == '6': # 按专业查询
major = input("请输入专业名称: ").strip()
students = self.bll.get_students_by_major(major)
display_students(students)
elif choice == '7': # 返回上一级
break
else:
print("无效的选择,请重新输入!")
def stats_students(self):
while True:
display_stats_menu()
choice = input("请选择统计方式: ").strip()
if choice == '1': # 学生总数
count = self.bll.get_student_count()
print(f"\n学生总数: {count}")
elif choice == '2': # 平均身高
avg_height = self.bll.get_average_height()
print(f"\n平均身高: {avg_height:.2f} cm")
elif choice == '3': # 按身高范围统计
min_height = int(input("最小身高(cm): ").strip())
max_height = int(input("最大身高(cm): ").strip())
students = self.bll.get_students_by_height_range(min_height, max_height)
print(f"\n身高在 {min_height}-{max_height} cm 的学生 ({len(students)} 人):")
display_students(students)
elif choice == '4': # 按入学年份统计
year = int(input("请输入入学年份: ").strip())
students = self.bll.get_students_by_enrollment_year(year)
print(f"\n{year}年入学的学生 ({len(students)} 人):")
display_students(students)
elif choice == '5': # 按年龄范围统计
min_age = int(input("最小年龄: ").strip())
max_age = int(input("最大年龄: ").strip())
students = self.bll.get_students_by_age_range(min_age, max_age)
print(f"\n年龄在 {min_age}-{max_age} 岁的学生 ({len(students)} 人):")
display_students(students)
elif choice == '6': # 按专业分组统计
groups = self.bll.get_students_by_major_group()
for major, students in groups.items():
print(f"\n专业: {major} ({len(students)} 人)")
display_students(students)
elif choice == '7': # 性别比例
ratio = self.bll.get_gender_ratio()
print(f"\n性别比例:")
print(f"男生: {ratio.get(True, 0.0):.2f}%")
print(f"女生: {ratio.get(False, 0.0):.2f}%")
elif choice == '8': # 返回上一级
break
else:
print("无效的选择,请重新输入!")
def import_export_data(self):
while True:
display_import_export_menu()
choice = input("请选择操作: ").strip()
if choice == '1': # 导出到JSON
file_path = input("请输入导出文件路径: ").strip()
if self.export_to_json(file_path):
print("导出成功!")
else:
print("导出失败")
elif choice == '2': # 从JSON导入
file_path = input("请输入导入文件路径: ").strip()
success, error = self.import_from_json(file_path)
print(f"导入完成: 成功 {success} 条, 失败 {error}")
elif choice == '3': # 导出到CSV
file_path = input("请输入导出文件路径: ").strip()
if self.export_to_csv(file_path):
print("导出成功!")
else:
print("导出失败")
elif choice == '4': # 从CSV导入
file_path = input("请输入导入文件路径: ").strip()
success, error = self.import_from_csv(file_path)
print(f"导入完成: 成功 {success} 条, 失败 {error}")
elif choice == '5': # 返回上一级
break
else:
print("无效的选择,请重新输入!")
def clear_all_students(self):
confirm = input("确定要清空所有学生信息吗? (y/n): ").strip().lower()
if confirm == 'y':
self.bll.clear_all_students()
print("所有学生信息已清空!")
else:
print("操作已取消")
def export_to_json(self, file_path: str) -> bool:
"""导出学生信息到JSON文件"""
students = self.bll.get_all_students()
try:
with open(file_path, 'w', encoding='utf-8') as f:
json.dump([s.to_dict() for s in students], f, ensure_ascii=False, indent=4)
return True
except Exception as e:
print(f"导出学生数据到JSON时出错: {e}")
return False
def import_from_json(self, file_path: str) -> Tuple[int, int]:
"""从JSON文件导入学生信息"""
success_count = 0
error_count = 0
try:
with open(file_path, 'r', encoding='utf-8') as f:
student_dicts = json.load(f)
for s_dict in student_dicts:
try:
student = Student.from_dict(s_dict)
if self.bll.add_student(student):
success_count += 1
except Exception as e:
error_count += 1
print(f"导入学生数据时出错: {e}")
return success_count, error_count
except Exception as e:
print(f"从JSON导入学生数据时出错: {e}")
return 0, 0
def export_to_csv(self, file_path: str) -> bool:
"""导出学生信息到CSV文件"""
students = self.bll.get_all_students()
if not students:
return False
try:
with open(file_path, 'w', encoding='utf-8', newline='') as f:
# 获取第一个学生的字段作为CSV表头
fieldnames = list(students[0].to_dict().keys())
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for student in students:
writer.writerow(student.to_dict())
return True
except Exception as e:
print(f"导出学生数据到CSV时出错: {e}")
return False
def import_from_csv(self, file_path: str) -> Tuple[int, int]:
"""从CSV文件导入学生信息"""
success_count = 0
error_count = 0
try:
with open(file_path, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
# 转换数据类型
converted_row = {}
for key, value in row.items():
if key in ['birth_date', 'enrollment_date'] and value:
converted_row[key] = date.fromisoformat(value)
elif key in ['height', 'weight'] and value:
converted_row[key] = float(value) if value else 0.0
else:
converted_row[key] = value
student = Student.from_dict(converted_row)
if self.bll.add_student(student):
success_count += 1
except Exception as e:
error_count += 1
print(f"导入学生数据时出错: {e}")
return success_count, error_count
except Exception as e:
print(f"从CSV导入学生数据时出错: {e}")
return 0, 0
def main():
# 选择存储方式
print("请选择数据存储方式:")
print("1. JSON")
print("2. CSV")
storage_choice = input("请输入选择 (1/2): ").strip()
file_path = "students.json" if storage_choice == '1' else "students.csv"
# 创建数据访问层
if storage_choice == '1':
dal = JsonStudentDAL(file_path)
elif storage_choice == '2':
dal = CsvStudentDAL(file_path)
else:
print("无效的选择默认使用JSON存储")
dal = JsonStudentDAL("students.json")
# 创建业务逻辑层
bll = StudentBLL(dal)
# 创建用户界面
tui = StudentTUI(bll)
tui.run()
def fun(self):
"""运行UI"""
while True:
self.display_menu()
choice = input("请选择操作: ").strip()
if choice == '1':
self.add_student()
elif choice == '2':
self.delete_student()
elif choice == '3':
self.update_student()
elif choice == '5':
self.show_stats()
elif choice == '6':
self.import_export_data()
elif choice == '7':
self.clear_students()
elif choice == '8':
self.query_student()
elif choice == '4':
print("感谢使用学生信息管理系统!")
break
else:
print("无效的选择,请重新输入!")
if __name__ == "__main__":
main()