commit ef8573eb4215c9d1aa9c6574ebb0aca7c3f46431
Author: 19602 <1960219918@qq.com>
Date: Wed Jun 25 10:06:26 2025 +0800
1
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..359bb53
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..3e14072
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..a82d671
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/python2.iml b/.idea/python2.iml
new file mode 100644
index 0000000..5b13fa1
--- /dev/null
+++ b/.idea/python2.iml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bll/StudentBLL.py b/bll/StudentBLL.py
new file mode 100644
index 0000000..ec55c29
--- /dev/null
+++ b/bll/StudentBLL.py
@@ -0,0 +1,92 @@
+from datetime import date
+from typing import List, Optional
+from dal.StudentDAL import StudentDAL
+from student.Student import Student
+
+
+class StudentBLL:
+ def __init__(self, dal: StudentDAL):
+ self.dal = dal
+
+ def add_student(self, student: Student):
+ if not student.is_valid:
+ errors = ", ".join(student.get_errors())
+ raise ValueError(f"学生数据校验失败: {errors}")
+
+ if not self.dal.add_student(student):
+ raise ValueError("添加失败,身份证号或学号可能已存在")
+
+ def delete_student(self, stu_id: str):
+ if not self.dal.delete_student(stu_id):
+ raise ValueError(f"找不到学号为 {stu_id} 的学生")
+
+ def update_student(self, stu_id: str, student: Student):
+ if not student.is_valid:
+ errors = ", ".join(student.get_errors())
+ raise ValueError(f"学生数据校验失败: {errors}")
+
+ if not self.dal.update_student(stu_id, student):
+ raise ValueError(f"找不到学号为 {stu_id} 的学生")
+
+ def get_student_by_id_card(self, id_card: str) -> Optional[Student]:
+ return self.dal.get_by_id_card(id_card)
+
+ def get_student_by_stu_id(self, stu_id: str) -> Optional[Student]:
+ return self.dal.get_by_stu_id(stu_id)
+
+ def get_all_students(self) -> List[Student]:
+ return self.dal.get_all()
+
+ def search_students(self, search_type: str, keyword: str) -> List[Student]:
+ search_type = search_type.lower()
+ if search_type == 'name':
+ return self.dal.search_by_name(keyword)
+ elif search_type == 'class':
+ return self.dal.search_by_class(keyword)
+ elif search_type == 'major':
+ return self.dal.search_by_major(keyword)
+ else:
+ return []
+
+ def get_student_count(self) -> int:
+ return self.dal.get_student_count()
+
+ def get_major_counts(self) -> dict:
+ return self.dal.get_major_counts()
+
+ def calculate_avg_height(self) -> float:
+ students = self.dal.get_all()
+ heights = [s.height for s in students if s.height is not None]
+ if not heights:
+ return 0.0
+ return sum(heights) / len(heights)
+
+ def calculate_avg_weight(self) -> float:
+ students = self.dal.get_all()
+ weights = [s.weight for s in students if s.weight is not None]
+ if not weights:
+ return 0.0
+ return sum(weights) / len(weights)
+
+ def get_students_by_age(self, min_age: int, max_age: int) -> List[Student]:
+ today = date.today()
+ students = self.dal.get_all()
+ result = []
+
+ for student in students:
+ if student.age is None:
+ continue
+
+ if min_age <= student.age <= max_age:
+ result.append(student)
+
+ return result
+
+ def export_data(self, file_path: str) -> bool:
+ return self.dal.export_data(file_path)
+
+ def import_data(self, file_path: str) -> bool:
+ return self.dal.import_data(file_path)
+
+ def clear_all(self) -> bool:
+ return self.dal.clear_all()
\ No newline at end of file
diff --git a/bll/__init__.py b/bll/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/dal/StudentDAL.py b/dal/StudentDAL.py
new file mode 100644
index 0000000..b8c8481
--- /dev/null
+++ b/dal/StudentDAL.py
@@ -0,0 +1,157 @@
+import os
+import json
+from datetime import date
+from typing import List, Optional
+from student.Student import Student
+
+
+class StudentDAL:
+ def __init__(self, file_path: str):
+ self.file_path = file_path
+ self._ensure_file_exists()
+
+ def _ensure_file_exists(self):
+ """确保文件存在"""
+ if not os.path.exists(self.file_path):
+ os.makedirs(os.path.dirname(self.file_path), exist_ok=True)
+ with open(self.file_path, 'w', encoding='utf-8') as f:
+ json.dump([], f)
+
+ def _load_data(self) -> List[dict]:
+ """加载数据"""
+ try:
+ with open(self.file_path, 'r', encoding='utf-8') as f:
+ return json.load(f)
+ except (FileNotFoundError, json.JSONDecodeError):
+ return []
+
+ def _save_data(self, data: List[dict]):
+ """保存数据"""
+ with open(self.file_path, 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False, indent=4)
+
+ def add_student(self, student: Student) -> bool:
+ data = self._load_data()
+
+ # 检查身份证号是否唯一
+ if any(s['id_card'] == student.id_card for s in data):
+ return False
+
+ # 检查学号是否唯一
+ if any(s['stu_id'] == student.stu_id for s in data):
+ return False
+
+ data.append(student.to_dict())
+ self._save_data(data)
+ return True
+
+ def get_by_id_card(self, id_card: str) -> Optional[Student]:
+ data = self._load_data()
+ for student_dict in data:
+ if student_dict['id_card'] == id_card:
+ return Student.from_dict(student_dict)
+ return None
+
+ def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
+ data = self._load_data()
+ for student_dict in data:
+ if student_dict['stu_id'] == stu_id:
+ return Student.from_dict(student_dict)
+ return None
+
+ def get_all(self) -> List[Student]:
+ return [Student.from_dict(d) for d in self._load_data()]
+
+ def update_student(self, stu_id: str, student: Student) -> bool:
+ data = self._load_data()
+ updated = False
+
+ for i, student_dict in enumerate(data):
+ if student_dict['stu_id'] == stu_id:
+ # 保留原始身份证号
+ new_data = student.to_dict()
+ new_data['id_card'] = student_dict['id_card']
+ data[i] = new_data
+ updated = True
+ break
+
+ if updated:
+ self._save_data(data)
+ return updated
+
+ def delete_student(self, stu_id: str) -> bool:
+ data = self._load_data()
+ original_count = len(data)
+ data = [s for s in data if s['stu_id'] != stu_id]
+
+ if len(data) < original_count:
+ self._save_data(data)
+ return True
+ return False
+
+ def search_by_name(self, name: str) -> List[Student]:
+ data = self._load_data()
+ name_lower = name.lower()
+ return [
+ Student.from_dict(d)
+ for d in data
+ if name_lower in d['name'].lower()
+ ]
+
+ def search_by_class(self, class_name: str) -> List[Student]:
+ data = self._load_data()
+ class_lower = class_name.lower()
+ return [
+ Student.from_dict(d)
+ for d in data
+ if d.get('class_name') and class_lower in d['class_name'].lower()
+ ]
+
+ def search_by_major(self, major: str) -> List[Student]:
+ data = self._load_data()
+ major_lower = major.lower()
+ return [
+ Student.from_dict(d)
+ for d in data
+ if d.get('major') and major_lower in d['major'].lower()
+ ]
+
+ def get_student_count(self) -> int:
+ return len(self._load_data())
+
+ def get_major_counts(self) -> dict:
+ data = self._load_data()
+ counts = {}
+ for student_dict in data:
+ major = student_dict.get('major', '未指定')
+ counts[major] = counts.get(major, 0) + 1
+ return counts
+
+ def clear_all(self) -> bool:
+ self._save_data([])
+ return True
+
+ def export_data(self, file_path: str) -> bool:
+ data = self._load_data()
+ try:
+ with open(file_path, 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False, indent=4)
+ return True
+ except Exception:
+ return False
+
+ def import_data(self, file_path: str) -> bool:
+ try:
+ with open(file_path, 'r', encoding='utf-8') as f:
+ new_data = json.load(f)
+
+ current_data = self._load_data()
+ current_ids = {s['id_card'] for s in current_data}
+
+ # 只导入不重复的学生
+ to_import = [s for s in new_data if s['id_card'] not in current_ids]
+
+ self._save_data(current_data + to_import)
+ return True
+ except Exception:
+ return False
\ No newline at end of file
diff --git a/dal/__init__.py b/dal/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/data/students.json b/data/students.json
new file mode 100644
index 0000000..e69de29
diff --git a/date/__init__.py b/date/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/date/student.json.py b/date/student.json.py
new file mode 100644
index 0000000..e69de29
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..fcc3d52
--- /dev/null
+++ b/main.py
@@ -0,0 +1,21 @@
+from dal.StudentDAL import StudentDAL
+from bll.StudentBLL import StudentBLL
+from tui.StudentTUI import StudentTUI
+
+
+def main():
+ # 初始化数据访问层
+ dal = StudentDAL("data/students.json")
+
+ # 初始化业务逻辑层
+ bll = StudentBLL(dal)
+
+ # 初始化用户界面
+ tui = StudentTUI(bll)
+
+ # 启动系统
+ tui.run()
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/student/Student.py b/student/Student.py
new file mode 100644
index 0000000..35aa224
--- /dev/null
+++ b/student/Student.py
@@ -0,0 +1,179 @@
+import re
+from datetime import date
+from typing import Optional, Union
+
+
+class Student:
+ def __init__(self,
+ name: str,
+ id_card: str,
+ stu_id: str,
+ gender: Optional[bool] = None,
+ height: Optional[int] = None,
+ weight: Optional[float] = None,
+ enrollment_date: Optional[Union[date, str]] = None,
+ class_name: Optional[str] = None,
+ major: Optional[str] = None):
+
+ # 基本信息
+ self.name = name.strip()
+ self.id_card = id_card.strip()
+ self.stu_id = stu_id.strip()
+ self.gender = gender
+ self.height = height
+ self.weight = weight
+ self.class_name = class_name.strip() if class_name else None
+ self.major = major.strip() if major else None
+
+ # 处理日期类型 - 将字符串转换为 date 对象
+ self.enrollment_date = self._parse_date(enrollment_date)
+
+ # 从身份证生成字段
+ self.birthday = self._extract_birthday_from_id_card()
+ self.age = self._calculate_age()
+
+ # 验证错误信息
+ self._validation_errors = []
+ self._validate()
+
+ def _parse_date(self, date_value: Optional[Union[date, str]]) -> Optional[date]:
+ """将日期值解析为 date 对象"""
+ if date_value is None:
+ return None
+ if isinstance(date_value, date):
+ return date_value
+ try:
+ return date.fromisoformat(date_value)
+ except (ValueError, TypeError):
+ return None
+
+ def _extract_birthday_from_id_card(self) -> Optional[date]:
+ """从身份证号提取出生日期"""
+ if len(self.id_card) != 18:
+ return None
+
+ try:
+ birth_str = self.id_card[6:14]
+ return date(int(birth_str[0:4]), int(birth_str[4:6]), int(birth_str[6:8]))
+ except (ValueError, IndexError):
+ return None
+
+ def _calculate_age(self) -> Optional[int]:
+ """计算年龄"""
+ if not self.birthday:
+ return None
+
+ today = date.today()
+ age = today.year - self.birthday.year
+ # 如果生日还没过,年龄减1
+ if (today.month, today.day) < (self.birthday.month, self.birthday.day):
+ age -= 1
+ return age
+
+ def _validate(self):
+ """执行所有验证"""
+ self._validate_id_card()
+ self._validate_stu_id()
+ self._validate_name()
+ self._validate_height()
+ self._validate_weight()
+ self._validate_dates()
+
+ def _validate_id_card(self):
+ """验证身份证号:18位,校验位正确"""
+ if len(self.id_card) != 18:
+ self._validation_errors.append("身份证号必须是18位")
+ return
+
+ # 校验位验证
+ factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
+ check_codes = '10X98765432'
+
+ try:
+ total = sum(int(self.id_card[i]) * factors[i] for i in range(17))
+ if check_codes[total % 11] != self.id_card[17].upper():
+ self._validation_errors.append("身份证号校验位不正确")
+ except ValueError:
+ self._validation_errors.append("身份证号包含无效字符")
+
+ def _validate_stu_id(self):
+ """验证学号:格式规则(简单示例)"""
+ if not re.match(r'^[A-Za-z0-9]{8,12}$', self.stu_id):
+ self._validation_errors.append("学号格式不正确,应为8-12位字母数字组合")
+
+ def _validate_name(self):
+ """验证姓名:2-20个字符,不能包含数字和特殊符号"""
+ if not (2 <= len(self.name) <= 20):
+ self._validation_errors.append("姓名长度需在2-20个字符之间")
+
+ if not re.match(r'^[\u4e00-\u9fa5a-zA-Z·\s]+$', self.name):
+ self._validation_errors.append("姓名不能包含数字和特殊符号")
+
+ def _validate_height(self):
+ """验证身高:50-250cm之间"""
+ if self.height is not None and not (50 <= self.height <= 250):
+ self._validation_errors.append(f"身高{self.height}cm超出合理范围(50-250厘米)")
+
+ def _validate_weight(self):
+ """验证体重:5-300kg之间"""
+ if self.weight is not None and not (5 <= self.weight <= 300):
+ self._validation_errors.append(f"体重{self.weight}kg超出合理范围(5-300千克)")
+
+ def _validate_dates(self):
+ """验证日期:入学日期不能早于出生日期"""
+ if self.birthday and self.enrollment_date:
+ if self.enrollment_date < self.birthday:
+ self._validation_errors.append("入学日期不能早于出生日期")
+
+ if self.enrollment_date and self.enrollment_date > date.today():
+ self._validation_errors.append("入学日期不能在未来")
+
+ @property
+ def is_valid(self) -> bool:
+ return len(self._validation_errors) == 0
+
+ def get_errors(self) -> list:
+ return self._validation_errors.copy()
+
+ def to_dict(self) -> dict:
+ """将对象序列化为字典"""
+ return {
+ 'name': self.name,
+ 'id_card': self.id_card,
+ 'stu_id': self.stu_id,
+ 'gender': self.gender,
+ 'height': self.height,
+ 'weight': self.weight,
+ 'enrollment_date': self.enrollment_date.isoformat() if self.enrollment_date else None,
+ 'class_name': self.class_name,
+ 'major': self.major,
+ 'birthday': self.birthday.isoformat() if self.birthday else None,
+ 'age': self.age
+ }
+
+ @classmethod
+ def from_dict(cls, data: dict) -> 'Student':
+ """从字典创建对象"""
+ # 解析日期字符串为 date 对象
+ enrollment_date = data.get('enrollment_date')
+ birthday = data.get('birthday')
+
+ return cls(
+ name=data.get('name', ''),
+ id_card=data.get('id_card', ''),
+ stu_id=data.get('stu_id', ''),
+ gender=data.get('gender'),
+ height=data.get('height'),
+ weight=data.get('weight'),
+ enrollment_date=enrollment_date,
+ class_name=data.get('class_name'),
+ major=data.get('major')
+ )
+
+ def __repr__(self) -> str:
+ gender_str = "男" if self.gender is True else "女" if self.gender is False else "未知"
+ return (
+ f"Student(name='{self.name}', id_card='{self.id_card}', stu_id='{self.stu_id}', "
+ f"gender={gender_str}, height={self.height}, weight={self.weight}, "
+ f"class_name='{self.class_name}', major='{self.major}')"
+ )
\ No newline at end of file
diff --git a/student/__init__.py b/student/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tui/StudentTUI.py b/tui/StudentTUI.py
new file mode 100644
index 0000000..788702f
--- /dev/null
+++ b/tui/StudentTUI.py
@@ -0,0 +1,292 @@
+from datetime import date
+from bll.StudentBLL import StudentBLL
+from dal.StudentDAL import StudentDAL
+from student.Student import Student
+
+
+class StudentTUI:
+ def __init__(self, bll: StudentBLL):
+ self.bll = bll
+
+ def display_menu(self):
+ print("\n===== 学生信息管理系统 =====")
+ print("1. 添加学生")
+ print("2. 删除学生")
+ print("3. 更新学生")
+ print("4. 查询学生")
+ print("5. 统计分析")
+ print("6. 导入导出")
+ print("7. 清空数据")
+ print("0. 退出系统")
+ print("==========================")
+
+ def run(self):
+ while True:
+ self.display_menu()
+ choice = input("请选择操作: ").strip()
+
+ if choice == "0":
+ print("再见!")
+ break
+ elif 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.show_stats()
+ elif choice == "6":
+ self.import_export()
+ elif choice == "7":
+ self.clear_data()
+ else:
+ print("无效选择,请重试")
+
+ def add_student(self):
+ print("\n--- 添加学生 ---")
+ name = input("姓名: ").strip()
+ id_card = input("身份证号: ").strip()
+ stu_id = input("学号: ").strip()
+ gender = self.input_gender()
+ height = self.input_int("身高(cm): ")
+ weight = self.input_float("体重(kg): ")
+ enrollment_date = self.input_date("入学日期(YYYY-MM-DD): ")
+ class_name = input("班级: ").strip()
+ major = input("专业: ").strip()
+
+ try:
+ 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
+ )
+ self.bll.add_student(student)
+ print("添加成功!")
+ except ValueError as e:
+ print(f"添加失败: {e}")
+
+ def input_gender(self):
+ """输入性别"""
+ while True:
+ gender = input("性别(1.男 2.女 3.跳过): ").strip()
+ if gender == '1':
+ return True
+ elif gender == '2':
+ return False
+ elif gender == '3':
+ return None
+ else:
+ print("无效选择,请重新输入")
+
+ def input_int(self, prompt: str):
+ """输入整数"""
+ while True:
+ value = input(prompt).strip()
+ try:
+ return int(value) if value else None
+ except ValueError:
+ print("请输入有效的整数")
+
+ def input_float(self, prompt: str):
+ """输入浮点数"""
+ while True:
+ value = input(prompt).strip()
+ try:
+ return float(value) if value else None
+ except ValueError:
+ print("请输入有效的数字")
+
+ def input_date(self, prompt: str):
+ """输入日期"""
+ while True:
+ try:
+ date_str = input(prompt).strip()
+ if not date_str:
+ return None
+ return date.fromisoformat(date_str)
+ except ValueError:
+ print("日期格式应为YYYY-MM-DD")
+
+ def delete_student(self):
+ print("\n--- 删除学生 ---")
+ stu_id = input("请输入学号: ").strip()
+ try:
+ self.bll.delete_student(stu_id)
+ print("删除成功!")
+ except ValueError as e:
+ print(f"删除失败: {e}")
+
+ def update_student(self):
+ print("\n--- 更新学生 ---")
+ stu_id = input("请输入学号: ").strip()
+ student = self.bll.get_student_by_stu_id(stu_id)
+
+ if not student:
+ print("学生不存在")
+ return
+
+ print(f"当前信息: {student}")
+ name = input(f"新姓名({student.name}): ").strip() or student.name
+ id_card = input(f"新身份证号({student.id_card}): ").strip() or student.id_card
+ new_stu_id = input(f"新学号({student.stu_id}): ").strip() or student.stu_id
+ gender = self.input_gender_update(student.gender)
+ height = self.input_int(f"新身高({student.height}): ") or student.height
+ weight = self.input_float(f"新体重({student.weight}): ") or student.weight
+ enrollment_date = self.input_date_update(student.enrollment_date)
+ class_name = input(f"新班级({student.class_name}): ").strip() or student.class_name
+ major = input(f"新专业({student.major}): ").strip() or student.major
+
+ try:
+ updated_student = Student(
+ name=name,
+ id_card=id_card,
+ stu_id=new_stu_id,
+ gender=gender,
+ height=height,
+ weight=weight,
+ enrollment_date=enrollment_date,
+ class_name=class_name,
+ major=major
+ )
+
+ # 如果学号改变了,需要先删除旧记录
+ if new_stu_id != stu_id:
+ self.bll.delete_student(stu_id)
+
+ self.bll.add_student(updated_student)
+ print("更新成功!")
+ except ValueError as e:
+ print(f"更新失败: {e}")
+
+ def input_gender_update(self, current_gender):
+ current = "男" if current_gender is True else "女" if current_gender is False else "未指定"
+ print(f"当前性别: {current}")
+ return self.input_gender()
+
+ def input_date_update(self, current_date):
+ """输入日期(更新时)"""
+ if current_date:
+ print(f"当前日期: {current_date.isoformat()}")
+ return self.input_date("新的日期(YYYY-MM-DD): ") or current_date
+
+ def query_students(self):
+ print("\n--- 查询学生 ---")
+ print("1. 按身份证号查询")
+ print("2. 按学号查询")
+ print("3. 按姓名查询")
+ print("4. 按班级查询")
+ print("5. 按专业查询")
+ print("6. 所有学生")
+ choice = input("请选择查询方式: ").strip()
+
+ students = []
+ if choice == "1":
+ id_card = input("请输入身份证号: ").strip()
+ student = self.bll.get_student_by_id_card(id_card)
+ if student:
+ students = [student]
+ elif choice == "2":
+ stu_id = input("请输入学号: ").strip()
+ student = self.bll.get_student_by_stu_id(stu_id)
+ if student:
+ students = [student]
+ elif choice == "3":
+ name = input("请输入姓名: ").strip()
+ students = self.bll.search_students('name', name)
+ elif choice == "4":
+ class_name = input("请输入班级: ").strip()
+ students = self.bll.search_students('class', class_name)
+ elif choice == "5":
+ major = input("请输入专业: ").strip()
+ students = self.bll.search_students('major', major)
+ elif choice == "6":
+ students = self.bll.get_all_students()
+ else:
+ print("无效选择")
+ return
+
+ self.print_students(students)
+
+ def print_students(self, students):
+ if not students:
+ print("没有找到学生")
+ return
+
+ print("\n身份证号\t学号\t姓名\t性别\t身高\t体重\t班级\t专业\t年龄")
+ print("=" * 100)
+ for s in students:
+ gender = "男" if s.gender is True else "女" if s.gender is False else "未知"
+ print(f"{s.id_card}\t{s.stu_id}\t{s.name}\t{gender}\t"
+ f"{s.height or '--'}\t{s.weight or '--'}\t"
+ f"{s.class_name or '--'}\t{s.major or '--'}\t"
+ f"{s.age or '--'}")
+ print(f"共找到 {len(students)} 名学生")
+
+ def show_stats(self):
+ print("\n--- 统计分析 ---")
+ print("1. 学生总数")
+ print("2. 专业分布")
+ print("3. 平均身高")
+ print("4. 平均体重")
+ print("5. 按年龄范围查询")
+ choice = input("请选择统计项目: ").strip()
+
+ if choice == "1":
+ count = self.bll.get_student_count()
+ print(f"学生总数: {count}")
+ elif choice == "2":
+ major_counts = self.bll.get_major_counts()
+ print("\n专业分布:")
+ for major, count in major_counts.items():
+ print(f" {major}: {count}人")
+ elif choice == "3":
+ avg_height = self.bll.calculate_avg_height()
+ print(f"平均身高: {avg_height:.1f} cm")
+ elif choice == "4":
+ avg_weight = self.bll.calculate_avg_weight()
+ print(f"平均体重: {avg_weight:.1f} kg")
+ elif choice == "5":
+ min_age = int(input("最小年龄: "))
+ max_age = int(input("最大年龄: "))
+ students = self.bll.get_students_by_age(min_age, max_age)
+ self.print_students(students)
+ else:
+ print("无效选择")
+
+ def import_export(self):
+ print("\n--- 导入导出 ---")
+ print("1. 导出数据")
+ print("2. 导入数据")
+ choice = input("请选择操作: ").strip()
+
+ if choice == "1":
+ file_path = input("导出文件路径: ").strip()
+ if self.bll.export_data(file_path):
+ print("导出成功!")
+ else:
+ print("导出失败")
+ elif choice == "2":
+ file_path = input("导入文件路径: ").strip()
+ if self.bll.import_data(file_path):
+ print("导入成功!")
+ else:
+ print("导入失败")
+ else:
+ print("无效选择")
+
+ def clear_data(self):
+ confirm = input("确定要清空所有数据吗?(y/n): ").strip().lower()
+ if confirm == 'y':
+ if self.bll.clear_all():
+ print("数据已清空")
+ else:
+ print("清空失败")
\ No newline at end of file
diff --git a/tui/__init__.py b/tui/__init__.py
new file mode 100644
index 0000000..e69de29