Compare commits
No commits in common. 'main' and 'master_lxq' have entirely different histories.
main
...
master_lxq
@ -0,0 +1,3 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
@ -0,0 +1 @@
|
||||
student_bll.py
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.12" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.11" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/PythonProject.iml" filepath="$PROJECT_DIR$/.idea/PythonProject.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,188 @@
|
||||
from datetime import date
|
||||
from typing import Optional, Dict, Union, Any
|
||||
|
||||
# ============== 数据模型层 ==============
|
||||
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
|
||||
self.id_card = id_card
|
||||
self.stu_id = stu_id
|
||||
self.gender = gender
|
||||
self.height = height
|
||||
self.weight = weight
|
||||
self.enrollment_date = enrollment_date
|
||||
self.class_name = class_name
|
||||
self.major = major
|
||||
|
||||
# 从身份证号生成的属性
|
||||
self._birthday = None
|
||||
self._age = None
|
||||
|
||||
# 错误信息字典
|
||||
self._errors = {}
|
||||
|
||||
# 初始化时进行数据校验
|
||||
self.validate()
|
||||
|
||||
@property
|
||||
def birthday(self) -> date:
|
||||
"""从身份证号提取出生日期"""
|
||||
if not self._birthday and self.id_card and len(self.id_card) == 18:
|
||||
birth_str = self.id_card[6:14]
|
||||
try:
|
||||
self._birthday = date.fromisoformat(birth_str)
|
||||
except:
|
||||
self._birthday = date(1900, 1, 1)
|
||||
return self._birthday
|
||||
|
||||
@property
|
||||
def age(self) -> int:
|
||||
"""计算年龄"""
|
||||
if not self._age and self.birthday:
|
||||
today = date.today()
|
||||
self._age = today.year - self.birthday.year
|
||||
if today < date(today.year, self.birthday.month, self.birthday.day):
|
||||
self._age -= 1
|
||||
return self._age
|
||||
|
||||
@property
|
||||
def enrollment_date(self) -> Optional[date]:
|
||||
"""入学日期属性"""
|
||||
return self._enrollment_date
|
||||
|
||||
@enrollment_date.setter
|
||||
def enrollment_date(self, value: Optional[Union[date, str]]):
|
||||
"""入学日期设置器,支持日期对象或字符串"""
|
||||
if value is None:
|
||||
self._enrollment_date = None
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
self._enrollment_date = date.fromisoformat(value)
|
||||
except:
|
||||
self._enrollment_date = None
|
||||
else:
|
||||
self._enrollment_date = value
|
||||
|
||||
@property
|
||||
def errors(self) -> Dict[str, str]:
|
||||
"""获取所有验证错误信息"""
|
||||
return self._errors
|
||||
|
||||
@property
|
||||
def is_valid(self) -> bool:
|
||||
"""判断学生信息是否有效"""
|
||||
return not bool(self._errors)
|
||||
|
||||
def validate(self) -> None:
|
||||
"""验证学生信息的合法性"""
|
||||
self._errors = {}
|
||||
|
||||
# 验证姓名
|
||||
if not self.name or len(self.name) < 2 or len(self.name) > 20:
|
||||
self._errors["name"] = "姓名必须在2到20个字符之间"
|
||||
elif not self.name.isalpha():
|
||||
self._errors["name"] = "姓名不能包含数字和特殊符号"
|
||||
|
||||
# 验证身份证号
|
||||
if not self.__validate_id_card(self.id_card):
|
||||
self._errors["id_card"] = "身份证号格式不正确"
|
||||
|
||||
# 验证学号
|
||||
if not self.stu_id:
|
||||
self._errors["stu_id"] = "学号不能为空"
|
||||
|
||||
# 验证身高
|
||||
if self.height is not None and (self.height < 50 or self.height > 250):
|
||||
self._errors["height"] = "身高必须在50到250厘米之间"
|
||||
|
||||
# 验证体重
|
||||
if self.weight is not None and (self.weight < 5 or self.weight > 300):
|
||||
self._errors["weight"] = "体重必须在5到300千克之间"
|
||||
|
||||
# 验证入学日期
|
||||
if self.enrollment_date and self.birthday and self.enrollment_date < self.birthday:
|
||||
self._errors["enrollment_date"] = "入学日期不能早于出生日期"
|
||||
|
||||
@staticmethod
|
||||
def __validate_id_card(id_card: str) -> bool:
|
||||
"""验证身份证号是否符合国家标准"""
|
||||
if not id_card or len(id_card) != 18:
|
||||
return False
|
||||
|
||||
# 检查前17位是否为数字
|
||||
if not id_card[:17].isdigit():
|
||||
return False
|
||||
|
||||
# 验证出生日期
|
||||
birth_str = id_card[6:14]
|
||||
try:
|
||||
date.fromisoformat(birth_str)
|
||||
except:
|
||||
return False
|
||||
|
||||
# 验证校验位
|
||||
factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] # 加权因子
|
||||
check_codes = '10X98765432' # 校验码映射
|
||||
total = sum(int(id_card[i]) * factors[i] for i in range(17))
|
||||
check_code = check_codes[total % 11]
|
||||
|
||||
return check_code == id_card[17].upper()
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""将学生对象转换为字典"""
|
||||
result = self.__dict__.copy()
|
||||
# 处理日期类型
|
||||
if result.get('_enrollment_date'):
|
||||
result['enrollment_date'] = result['_enrollment_date'].isoformat()
|
||||
# 移除内部属性
|
||||
if '_birthday' in result:
|
||||
del result['_birthday']
|
||||
if '_age' in result:
|
||||
del result['_age']
|
||||
if '_errors' in result:
|
||||
del result['_errors']
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict[str, Any]) -> 'Student':
|
||||
"""从字典创建学生对象"""
|
||||
if not isinstance(data, dict):
|
||||
raise TypeError("数据必须是字典类型")
|
||||
|
||||
# 处理入学日期
|
||||
enrollment_date = data.get('enrollment_date')
|
||||
if enrollment_date and isinstance(enrollment_date, str):
|
||||
try:
|
||||
data['enrollment_date'] = date.fromisoformat(enrollment_date)
|
||||
except:
|
||||
data['enrollment_date'] = None
|
||||
|
||||
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=data.get('enrollment_date'),
|
||||
class_name=data.get('class_name'),
|
||||
major=data.get('major')
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""学生对象的字符串表示"""
|
||||
attrs = [f"{k}='{v}'" for k, v in self.to_dict().items() if v is not None]
|
||||
return f"Student({', '.join(attrs)})"
|
||||
|
||||
@ -0,0 +1,308 @@
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import date
|
||||
from typing import List, Optional, Dict, Any
|
||||
|
||||
|
||||
class Student:
|
||||
pass
|
||||
|
||||
|
||||
class IStudentDAL(ABC):
|
||||
"""学生信息数据访问层接口"""
|
||||
|
||||
@abstractmethod
|
||||
def get_by_id(self, id_card: str) -> Optional[Student]:
|
||||
"""根据身份证号获取学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
|
||||
"""根据学号获取学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_all(self) -> List[Student]:
|
||||
"""获取所有学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add(self, student: Student) -> bool:
|
||||
"""添加学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete(self, id_card: str) -> bool:
|
||||
"""根据身份证号删除学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_by_stu_id(self, stu_id: str) -> bool:
|
||||
"""根据学号删除学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update(self, student: Student) -> bool:
|
||||
"""更新学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def is_exist(self, id_card: str) -> bool:
|
||||
"""检查学生是否存在"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def is_exist_stu_id(self, stu_id: str) -> bool:
|
||||
"""检查学号是否存在"""
|
||||
pass
|
||||
|
||||
|
||||
class JsonStudentDAL(IStudentDAL):
|
||||
"""JSON文件数据访问实现"""
|
||||
|
||||
def __init__(self, file_path: str):
|
||||
"""初始化JSON数据访问层"""
|
||||
self.file_path = file_path
|
||||
self._ensure_file_exists()
|
||||
|
||||
def _ensure_file_exists(self) -> None:
|
||||
"""确保数据文件存在"""
|
||||
if not os.path.exists(self.file_path):
|
||||
with open(self.file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump([], f, ensure_ascii=False, indent=4)
|
||||
|
||||
def _load(self) -> List[Dict[str, Any]]:
|
||||
"""从文件加载学生数据"""
|
||||
try:
|
||||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except (json.JSONDecodeError, FileNotFoundError):
|
||||
return []
|
||||
|
||||
def _save(self, students: List[Dict[str, Any]]) -> None:
|
||||
"""保存学生数据到文件"""
|
||||
with open(self.file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(students, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def get_by_id(self, id_card: str) -> Optional[Student]:
|
||||
"""根据身份证号获取学生信息"""
|
||||
students = self._load()
|
||||
for data in students:
|
||||
if data.get('id_card') == id_card:
|
||||
return Student.from_dict(data)
|
||||
return None
|
||||
|
||||
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
|
||||
"""根据学号获取学生信息"""
|
||||
students = self._load()
|
||||
for data in students:
|
||||
if data.get('stu_id') == stu_id:
|
||||
return Student.from_dict(data)
|
||||
return None
|
||||
|
||||
def get_all(self) -> List[Student]:
|
||||
"""获取所有学生信息"""
|
||||
students_data = self._load()
|
||||
return [Student.from_dict(data) for data in students_data]
|
||||
|
||||
def add(self, student: Student) -> bool:
|
||||
"""添加学生信息"""
|
||||
if self.is_exist(student.id_card) or self.is_exist_stu_id(student.stu_id):
|
||||
return False
|
||||
|
||||
students = self._load()
|
||||
students.append(student.to_dict())
|
||||
self._save(students)
|
||||
return True
|
||||
|
||||
def delete(self, id_card: str) -> bool:
|
||||
"""根据身份证号删除学生信息"""
|
||||
students = self._load()
|
||||
original_length = len(students)
|
||||
students = [s for s in students if s.get('id_card') != id_card]
|
||||
|
||||
if len(students) < original_length:
|
||||
self._save(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete_by_stu_id(self, stu_id: str) -> bool:
|
||||
"""根据学号删除学生信息"""
|
||||
students = self._load()
|
||||
original_length = len(students)
|
||||
students = [s for s in students if s.get('stu_id') != stu_id]
|
||||
|
||||
if len(students) < original_length:
|
||||
self._save(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def update(self, student: Student) -> bool:
|
||||
"""更新学生信息"""
|
||||
students = self._load()
|
||||
updated = False
|
||||
|
||||
for i, data in enumerate(students):
|
||||
if data.get('id_card') == student.id_card:
|
||||
students[i] = student.to_dict()
|
||||
updated = True
|
||||
break
|
||||
|
||||
if updated:
|
||||
self._save(students)
|
||||
return updated
|
||||
|
||||
def is_exist(self, id_card: str) -> bool:
|
||||
"""检查学生是否存在"""
|
||||
return self.get_by_id(id_card) is not None
|
||||
|
||||
def is_exist_stu_id(self, stu_id: str) -> bool:
|
||||
"""检查学号是否存在"""
|
||||
return self.get_by_stu_id(stu_id) is not None
|
||||
|
||||
|
||||
class CsvStudentDAL(IStudentDAL):
|
||||
"""CSV文件数据访问实现"""
|
||||
|
||||
FIELD_TYPES = {
|
||||
'height': int,
|
||||
'weight': float,
|
||||
'gender': lambda x: True if x == 'True' else False if x == 'False' else None,
|
||||
}
|
||||
|
||||
def __init__(self, file_path: str):
|
||||
"""初始化CSV数据访问层"""
|
||||
self.file_path = file_path
|
||||
self._ensure_file_exists()
|
||||
|
||||
def _ensure_file_exists(self) -> None:
|
||||
"""确保数据文件存在"""
|
||||
if not os.path.exists(self.file_path):
|
||||
with open(self.file_path, 'w', encoding='utf-8-sig', newline='') as f:
|
||||
writer = csv.DictWriter(f, fieldnames=self._get_fieldnames())
|
||||
writer.writeheader()
|
||||
|
||||
def _get_fieldnames(self) -> List[str]:
|
||||
"""获取CSV文件字段名"""
|
||||
return [
|
||||
'name', 'id_card', 'stu_id', 'gender', 'height',
|
||||
'weight', 'enrollment_date', 'class_name', 'major'
|
||||
]
|
||||
|
||||
def _convert_row(self, row: Dict[str, str]) -> Dict[str, Any]:
|
||||
"""转换CSV行数据为字典"""
|
||||
result = {}
|
||||
for key, value in row.items():
|
||||
if not value:
|
||||
result[key] = None
|
||||
else:
|
||||
converter = self.FIELD_TYPES.get(key)
|
||||
if converter:
|
||||
result[key] = converter(value)
|
||||
elif key == 'enrollment_date':
|
||||
try:
|
||||
result[key] = date.fromisoformat(value)
|
||||
except:
|
||||
result[key] = value
|
||||
else:
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
def _load(self) -> List[Dict[str, Any]]:
|
||||
"""从文件加载学生数据"""
|
||||
try:
|
||||
with open(self.file_path, 'r', encoding='utf-8-sig', newline='') as f:
|
||||
reader = csv.DictReader(f)
|
||||
return [self._convert_row(row) for row in reader]
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def _save(self, students: List[Dict[str, Any]]) -> None:
|
||||
"""保存学生数据到文件"""
|
||||
with open(self.file_path, 'w', encoding='utf-8-sig', newline='') as f:
|
||||
writer = csv.DictWriter(f, fieldnames=self._get_fieldnames())
|
||||
writer.writeheader()
|
||||
for student in students:
|
||||
# 转换日期为字符串
|
||||
if student.get('enrollment_date') and isinstance(student['enrollment_date'], date):
|
||||
student['enrollment_date'] = student['enrollment_date'].isoformat()
|
||||
writer.writerow(student)
|
||||
|
||||
def get_by_id(self, id_card: str) -> Optional[Student]:
|
||||
"""根据身份证号获取学生信息"""
|
||||
students = self._load()
|
||||
for data in students:
|
||||
if data.get('id_card') == id_card:
|
||||
return Student.from_dict(data)
|
||||
return None
|
||||
|
||||
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
|
||||
"""根据学号获取学生信息"""
|
||||
students = self._load()
|
||||
for data in students:
|
||||
if data.get('stu_id') == stu_id:
|
||||
return Student.from_dict(data)
|
||||
return None
|
||||
|
||||
def get_all(self) -> List[Student]:
|
||||
"""获取所有学生信息"""
|
||||
students_data = self._load()
|
||||
return [Student.from_dict(data) for data in students_data]
|
||||
|
||||
def add(self, student: Student) -> bool:
|
||||
"""添加学生信息"""
|
||||
if self.is_exist(student.id_card) or self.is_exist_stu_id(student.stu_id):
|
||||
return False
|
||||
|
||||
students = self._load()
|
||||
students.append(student.to_dict())
|
||||
self._save(students)
|
||||
return True
|
||||
|
||||
def delete(self, id_card: str) -> bool:
|
||||
"""根据身份证号删除学生信息"""
|
||||
students = self._load()
|
||||
original_length = len(students)
|
||||
students = [s for s in students if s.get('id_card') != id_card]
|
||||
|
||||
if len(students) < original_length:
|
||||
self._save(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete_by_stu_id(self, stu_id: str) -> bool:
|
||||
"""根据学号删除学生信息"""
|
||||
students = self._load()
|
||||
original_length = len(students)
|
||||
students = [s for s in students if s.get('stu_id') != stu_id]
|
||||
|
||||
if len(students) < original_length:
|
||||
self._save(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def update(self, student: Student) -> bool:
|
||||
"""更新学生信息"""
|
||||
students = self._load()
|
||||
updated = False
|
||||
|
||||
for i, data in enumerate(students):
|
||||
if data.get('id_card') == student.id_card:
|
||||
students[i] = student.to_dict()
|
||||
updated = True
|
||||
break
|
||||
|
||||
if updated:
|
||||
self._save(students)
|
||||
return updated
|
||||
|
||||
def is_exist(self, id_card: str) -> bool:
|
||||
"""检查学生是否存在"""
|
||||
return self.get_by_id(id_card) is not None
|
||||
|
||||
def is_exist_stu_id(self, stu_id: str) -> bool:
|
||||
"""检查学号是否存在"""
|
||||
return self.get_by_stu_id(stu_id) is not None
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
from 面向对象方法三层.ui.student_ui import StudentUI
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 默认为JSON文件存储
|
||||
default_file = "students.json"
|
||||
print(f"使用默认数据文件: {default_file}")
|
||||
|
||||
ui = StudentUI(default_file)
|
||||
ui.run()
|
||||
@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "李宇哲",
|
||||
"id_card": "362425200605012231",
|
||||
"stu_id": "123456",
|
||||
"gender": true,
|
||||
"height": 156,
|
||||
"weight": 56.0,
|
||||
"_enrollment_date":
|
||||
@ -0,0 +1,387 @@
|
||||
from datetime import date
|
||||
|
||||
from 面向对象方法三层.bll.student_bll import Student
|
||||
from 面向对象方法三层.model.student import StudentBLL
|
||||
|
||||
|
||||
class StudentUI:
|
||||
"""学生信息管理系统用户界面"""
|
||||
|
||||
def __init__(self, file_path: str):
|
||||
"""初始化用户界面"""
|
||||
self.bll = StudentBLL(file_path)
|
||||
self.running = True
|
||||
|
||||
def display_main_menu(self) -> None:
|
||||
"""显示主菜单"""
|
||||
print("\n===== 学生信息管理系统 =====")
|
||||
print("1. 添加学生信息")
|
||||
print("2. 删除学生信息")
|
||||
print("3. 更新学生信息")
|
||||
print("4. 查询学生信息")
|
||||
print("5. 统计分析")
|
||||
print("6. 数据导入导出")
|
||||
print("7. 清空所有学生信息")
|
||||
print("0. 退出系统")
|
||||
print("==========================")
|
||||
|
||||
def display_query_menu(self) -> None:
|
||||
"""显示查询菜单"""
|
||||
print("\n===== 查询学生信息 =====")
|
||||
print("1. 查询所有学生")
|
||||
print("2. 按身份证号查询")
|
||||
print("3. 按学号查询")
|
||||
print("4. 按姓名查询")
|
||||
print("5. 按班级查询")
|
||||
print("6. 按专业查询")
|
||||
print("0. 返回上一级")
|
||||
print("======================")
|
||||
|
||||
def display_stats_menu(self) -> None:
|
||||
"""显示统计菜单"""
|
||||
print("\n===== 统计分析 =====")
|
||||
print("1. 学生总数")
|
||||
print("2. 各专业学生人数")
|
||||
print("3. 平均身高")
|
||||
print("4. 平均体重")
|
||||
print("0. 返回上一级")
|
||||
print("====================")
|
||||
|
||||
def display_import_export_menu(self) -> None:
|
||||
"""显示数据导入导出菜单"""
|
||||
print("\n===== 数据导入导出 =====")
|
||||
print("1. 导出到JSON")
|
||||
print("2. 从JSON导入")
|
||||
print("3. 导出到CSV")
|
||||
print("4. 从CSV导入")
|
||||
print("0. 返回上一级")
|
||||
print("========================")
|
||||
|
||||
def get_input(self, prompt: str) -> str:
|
||||
"""获取用户输入"""
|
||||
return input(prompt).strip()
|
||||
|
||||
def add_student(self) -> None:
|
||||
"""添加学生信息"""
|
||||
print("\n--- 添加学生信息 ---")
|
||||
name = self.get_input("姓名: ")
|
||||
id_card = self.get_input("身份证号: ")
|
||||
stu_id = self.get_input("学号: ")
|
||||
|
||||
gender = self.get_input("性别(1-男, 0-女, 直接回车-未知): ")
|
||||
if gender == '1':
|
||||
gender = True
|
||||
elif gender == '0':
|
||||
gender = False
|
||||
else:
|
||||
gender = None
|
||||
|
||||
height_str = self.get_input("身高(cm, 直接回车-未知): ")
|
||||
height = int(height_str) if height_str else None
|
||||
|
||||
weight_str = self.get_input("体重(kg, 保留一位小数, 直接回车-未知): ")
|
||||
weight = float(weight_str) if weight_str else None
|
||||
|
||||
enrollment_date = self.get_input("入学日期(YYYY-MM-DD, 直接回车-未知): ")
|
||||
enrollment_date = date.fromisoformat(enrollment_date) if enrollment_date else None
|
||||
|
||||
class_name = self.get_input("班级名称(直接回车-未知): ")
|
||||
major = self.get_input("专业(直接回车-未知): ")
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
if self.bll.add_student(student):
|
||||
print("学生添加成功!")
|
||||
else:
|
||||
print("学生添加失败,身份证号或学号已存在!")
|
||||
except ValueError as e:
|
||||
print(f"操作失败: {e}")
|
||||
|
||||
def delete_student(self) -> None:
|
||||
"""删除学生信息"""
|
||||
print("\n--- 删除学生信息 ---")
|
||||
print("1. 按身份证号删除")
|
||||
print("2. 按学号删除")
|
||||
choice = self.get_input("请选择: ")
|
||||
|
||||
try:
|
||||
if choice == '1':
|
||||
id_card = self.get_input("请输入身份证号: ")
|
||||
if self.bll.delete_student(id_card):
|
||||
print("学生删除成功!")
|
||||
else:
|
||||
print("学生不存在!")
|
||||
elif choice == '2':
|
||||
stu_id = self.get_input("请输入学号: ")
|
||||
if self.bll.delete_student_by_stu_id(stu_id):
|
||||
print("学生删除成功!")
|
||||
else:
|
||||
print("学生不存在!")
|
||||
else:
|
||||
print("无效选择!")
|
||||
except ValueError as e:
|
||||
print(f"操作失败: {e}")
|
||||
|
||||
def update_student(self) -> None:
|
||||
"""更新学生信息"""
|
||||
print("\n--- 更新学生信息 ---")
|
||||
id_card = self.get_input("请输入要更新的学生身份证号: ")
|
||||
|
||||
student = self.bll.get_student_by_id(id_card)
|
||||
if not student:
|
||||
print("学生不存在!")
|
||||
return
|
||||
|
||||
print(f"\n当前学生信息: {student}")
|
||||
|
||||
name = self.get_input(f"姓名[{student.name}]: ") or student.name
|
||||
gender = self.get_input(f"性别(1-男, 0-女, 直接回车[{student.gender}]): ")
|
||||
if gender:
|
||||
gender = True if gender == '1' else False
|
||||
else:
|
||||
gender = student.gender
|
||||
|
||||
height_str = self.get_input(f"身高(cm, 直接回车[{student.height}]): ")
|
||||
height = int(height_str) if height_str else student.height
|
||||
|
||||
weight_str = self.get_input(f"体重(kg, 直接回车[{student.weight}]): ")
|
||||
weight = float(weight_str) if weight_str else student.weight
|
||||
|
||||
enrollment_date = self.get_input(f"入学日期(YYYY-MM-DD, 直接回车[{student.enrollment_date}]): ")
|
||||
enrollment_date = date.fromisoformat(enrollment_date) if enrollment_date else student.enrollment_date
|
||||
|
||||
class_name = self.get_input(f"班级名称[{student.class_name}]: ") or student.class_name
|
||||
major = self.get_input(f"专业[{student.major}]: ") or student.major
|
||||
|
||||
try:
|
||||
updated_student = Student(
|
||||
name=name,
|
||||
id_card=id_card,
|
||||
stu_id=student.stu_id,
|
||||
gender=gender,
|
||||
height=height,
|
||||
weight=weight,
|
||||
enrollment_date=enrollment_date,
|
||||
class_name=class_name,
|
||||
major=major
|
||||
)
|
||||
|
||||
if self.bll.update_student(updated_student):
|
||||
print("学生信息更新成功!")
|
||||
else:
|
||||
print("学生信息更新失败!")
|
||||
except ValueError as e:
|
||||
print(f"操作失败: {e}")
|
||||
|
||||
def query_student(self) -> None:
|
||||
"""查询学生信息"""
|
||||
while True:
|
||||
self.display_query_menu()
|
||||
choice = self.get_input("请选择操作: ")
|
||||
|
||||
if choice == '0':
|
||||
break
|
||||
|
||||
try:
|
||||
if choice == '1':
|
||||
# 查询所有学生
|
||||
students = self.bll.get_all_students()
|
||||
if not students:
|
||||
print("没有学生信息!")
|
||||
else:
|
||||
print("\n--- 所有学生信息 ---")
|
||||
for i, student in enumerate(students, 1):
|
||||
print(f"{i}. {student}")
|
||||
|
||||
elif choice == '2':
|
||||
# 按身份证号查询
|
||||
id_card = self.get_input("请输入身份证号: ")
|
||||
student = self.bll.get_student_by_id(id_card)
|
||||
if student:
|
||||
print(f"\n--- 学生信息 ---: {student}")
|
||||
else:
|
||||
print("未找到该学生!")
|
||||
|
||||
elif choice == '3':
|
||||
# 按学号查询
|
||||
stu_id = self.get_input("请输入学号: ")
|
||||
student = self.bll.get_student_by_stu_id(stu_id)
|
||||
if student:
|
||||
print(f"\n--- 学生信息 ---: {student}")
|
||||
else:
|
||||
print("未找到该学生!")
|
||||
|
||||
elif choice == '4':
|
||||
# 按姓名查询
|
||||
name = self.get_input("请输入姓名(支持模糊查询): ")
|
||||
students = self.bll.search_by_name(name)
|
||||
if not students:
|
||||
print("未找到该学生!")
|
||||
else:
|
||||
print(f"\n--- 查找结果({len(students)}人) ---")
|
||||
for i, student in enumerate(students, 1):
|
||||
print(f"{i}. {student}")
|
||||
|
||||
elif choice == '5':
|
||||
# 按班级查询
|
||||
class_name = self.get_input("请输入班级名称(支持模糊查询): ")
|
||||
students = self.bll.search_by_class(class_name)
|
||||
if not students:
|
||||
print("未找到该班级的学生!")
|
||||
else:
|
||||
print(f"\n--- 查找结果({len(students)}人) ---")
|
||||
for i, student in enumerate(students, 1):
|
||||
print(f"{i}. {student}")
|
||||
|
||||
elif choice == '6':
|
||||
# 按专业查询
|
||||
major = self.get_input("请输入专业名称(支持模糊查询): ")
|
||||
students = self.bll.search_by_major(major)
|
||||
if not students:
|
||||
print("未找到该专业的学生!")
|
||||
else:
|
||||
print(f"\n--- 查找结果({len(students)}人) ---")
|
||||
for i, student in enumerate(students, 1):
|
||||
print(f"{i}. {student}")
|
||||
|
||||
else:
|
||||
print("无效选择!")
|
||||
except Exception as e:
|
||||
print(f"查询出错: {e}")
|
||||
|
||||
def show_stats(self) -> None:
|
||||
"""显示统计信息"""
|
||||
while True:
|
||||
self.display_stats_menu()
|
||||
choice = self.get_input("请选择操作: ")
|
||||
|
||||
if choice == '0':
|
||||
break
|
||||
|
||||
try:
|
||||
if choice == '1':
|
||||
# 学生总数
|
||||
count = self.bll.count_students()
|
||||
print(f"\n学生总数: {count}人")
|
||||
|
||||
elif choice == '2':
|
||||
# 各专业学生人数
|
||||
major_counts = self.bll.count_by_major()
|
||||
if not major_counts:
|
||||
print("没有学生信息!")
|
||||
else:
|
||||
print("\n各专业学生人数:")
|
||||
for major, count in major_counts.items():
|
||||
print(f"{major}: {count}人")
|
||||
|
||||
elif choice == '3':
|
||||
# 平均身高
|
||||
avg_height = self.bll.average_height()
|
||||
print(f"\n平均身高: {avg_height:.2f}cm")
|
||||
|
||||
elif choice == '4':
|
||||
# 平均体重
|
||||
avg_weight = self.bll.average_weight()
|
||||
print(f"\n平均体重: {avg_weight:.2f}kg")
|
||||
|
||||
else:
|
||||
print("无效选择!")
|
||||
except Exception as e:
|
||||
print(f"统计出错: {e}")
|
||||
|
||||
def import_export_data(self) -> None:
|
||||
"""数据导入导出"""
|
||||
while True:
|
||||
self.display_import_export_menu()
|
||||
choice = self.get_input("请选择操作: ")
|
||||
|
||||
if choice == '0':
|
||||
break
|
||||
|
||||
try:
|
||||
if choice == '1':
|
||||
# 导出到JSON
|
||||
file_path = self.get_input("请输入导出文件路径: ")
|
||||
if self.bll.export_to_json(file_path):
|
||||
print(f"数据已成功导出到 {file_path}")
|
||||
else:
|
||||
print("导出失败!")
|
||||
|
||||
elif choice == '2':
|
||||
# 从JSON导入
|
||||
file_path = self.get_input("请输入导入文件路径: ")
|
||||
count = self.bll.import_from_json(file_path)
|
||||
print(f"成功导入 {count} 条学生记录")
|
||||
|
||||
elif choice == '3':
|
||||
# 导出到CSV
|
||||
file_path = self.get_input("请输入导出文件路径: ")
|
||||
if self.bll.export_to_csv(file_path):
|
||||
print(f"数据已成功导出到 {file_path}")
|
||||
else:
|
||||
print("导出失败!")
|
||||
|
||||
elif choice == '4':
|
||||
# 从CSV导入
|
||||
file_path = self.get_input("请输入导入文件路径: ")
|
||||
count = self.bll.import_from_csv(file_path)
|
||||
print(f"成功导入 {count} 条学生记录")
|
||||
|
||||
else:
|
||||
print("无效选择!")
|
||||
except Exception as e:
|
||||
print(f"操作出错: {e}")
|
||||
|
||||
def clear_students(self) -> None:
|
||||
"""清空所有学生信息"""
|
||||
print("\n--- 清空所有学生信息 ---")
|
||||
confirm = self.get_input("确定要清空所有学生信息吗?(y/n): ")
|
||||
if confirm.lower() == 'y':
|
||||
# 这里简单实现,实际应更安全
|
||||
open(self.bll.file_path, 'w', encoding='utf-8').close()
|
||||
print("所有学生信息已清空!")
|
||||
else:
|
||||
print("已取消清空操作。")
|
||||
|
||||
def run(self) -> None:
|
||||
"""运行系统"""
|
||||
print("学生信息管理系统启动中...")
|
||||
|
||||
while self.running:
|
||||
self.display_main_menu()
|
||||
choice = self.get_input("请选择操作: ")
|
||||
|
||||
try:
|
||||
if choice == '1':
|
||||
self.add_student()
|
||||
elif choice == '2':
|
||||
self.delete_student()
|
||||
elif choice == '3':
|
||||
self.update_student()
|
||||
elif choice == '4':
|
||||
self.query_student()
|
||||
elif choice == '5':
|
||||
self.show_stats()
|
||||
elif choice == '6':
|
||||
self.import_export_data()
|
||||
elif choice == '7':
|
||||
self.clear_students()
|
||||
elif choice == '0':
|
||||
self.running = False
|
||||
print("感谢使用学生信息管理系统,再见!")
|
||||
else:
|
||||
print("无效选择,请重新输入!")
|
||||
except Exception as e:
|
||||
print(f"操作出错: {e}")
|
||||
|
||||
Loading…
Reference in new issue