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.
208 lines
9.2 KiB
208 lines
9.2 KiB
import math
|
|
|
|
from astropy.version import major
|
|
from pyasn1_modules.rfc2985 import gender
|
|
from 面向对象.dal.student_dal_json import StudentDAL
|
|
from 面向对象.dal.student_dal_csv import StudentDALCSV # 新增导入CSV存储类
|
|
from 面向对象.model.student import Student
|
|
from typing import List, Optional
|
|
from datetime import date
|
|
import json
|
|
import os
|
|
|
|
|
|
class StudentBLL:
|
|
def __init__(self, dal: StudentDAL):
|
|
self.dal = dal
|
|
|
|
def add_student(self, student: Student) -> bool:
|
|
"""添加学生,增加身份证号唯一性检查"""
|
|
if self.dal.check_student_exists(student.stu_id):
|
|
raise ValueError(f"学生 ID {student.stu_id} 已存在。")
|
|
if student.id_card and self.dal.check_id_card_exists(student.id_card):
|
|
raise ValueError(f"身份证号 {student.id_card} 已存在。")
|
|
if not student.is_valid:
|
|
raise ValueError(f"学生数据校验不通过。错误信息:{student.get_errors()}")
|
|
return self.dal.add_student(student)
|
|
|
|
def delete_student(self, stu_id: str) -> bool:
|
|
if not self.dal.check_student_exists(stu_id):
|
|
raise ValueError(f"学生 ID {stu_id} 不存在。")
|
|
return self.dal.delete_student(stu_id)
|
|
|
|
def update_student(self, stu_id: str, student: Student) -> bool:
|
|
"""更新学生全部信息,增加身份证号校验"""
|
|
if not self.dal.check_student_exists(student):
|
|
raise ValueError(f"学生 ID {stu_id} 不存在。")
|
|
if student.id_card and self.dal.check_id_card_exists(student.id_card):
|
|
existing_student = self.dal.find_student_by_id_card(student.id_card)
|
|
if existing_student.stu_id != stu_id: # 检查是否是同一个学生
|
|
raise ValueError(f"身份证号 {student.id_card} 已被其他学生使用。")
|
|
if not student.is_valid:
|
|
raise ValueError(f"学生数据校验不通过。错误信息:{student.get_errors()}")
|
|
return self.dal.update_student(stu_id, student)
|
|
|
|
def update_student_partial(self, stu_id: str,gender:bool or str,major:str, name: Optional[str] = None, height: Optional[int] = None,
|
|
birth_date: Optional[date] = None, enrollment_date: Optional[date] = None,
|
|
class_name: Optional[str] = None, id_card: Optional[str] = None) -> bool:
|
|
"""部分更新学生信息,支持更新身份证号"""
|
|
if not self.dal.check_student_exists(stu_id):
|
|
raise ValueError(f"学生 ID {stu_id} 不存在。")
|
|
|
|
# 检查身份证号是否已被使用(如果提供了新的身份证号)
|
|
if id_card and self.dal.check_id_card_exists(id_card):
|
|
existing_student = self.dal.find_student_by_id_card(id_card)
|
|
if existing_student.stu_id != stu_id: # 检查是否是同一个学生
|
|
raise ValueError(f"身份证号 {id_card} 已被其他学生使用。")
|
|
|
|
# 如果提供了身份证号,需要创建临时学生对象进行验证
|
|
if id_card:
|
|
current_student = self.dal.find_student_by_stu_id(stu_id)
|
|
# 创建临时学生对象,只更新需要修改的字段
|
|
temp_student = Student(
|
|
stu_id=current_student.stu_id,
|
|
name=name if name is not None else current_student.name,
|
|
height=height if height is not None else current_student.height,
|
|
birth_date=birth_date if birth_date is not None else current_student.birth_date,
|
|
enrollment_date=enrollment_date if enrollment_date is not None else current_student.enrollment_date,
|
|
class_name=class_name if class_name is not None else current_student.class_name,
|
|
id_card=id_card,
|
|
gender=gender,
|
|
major=major
|
|
)
|
|
if not temp_student.is_valid:
|
|
raise ValueError(f"学生数据校验不通过。错误信息:{temp_student.get_errors()}")
|
|
|
|
return self.dal.update_student_partial(stu_id, name, height, birth_date, enrollment_date, class_name, id_card)
|
|
|
|
def get_student_by_id(self, stu_id: str) -> Optional[Student]:
|
|
return self.dal.find_student_by_stu_id(stu_id)
|
|
|
|
def get_student_by_id_card(self, id_card: str) -> Optional[Student]:
|
|
"""通过身份证号获取学生信息"""
|
|
return self.dal.find_student_by_id_card(id_card)
|
|
|
|
def get_students_by_name(self, name: str) -> List[Student]:
|
|
return self.dal.find_students_by_name(name)
|
|
|
|
def get_students_by_class(self, class_name: str) -> List[Student]:
|
|
return self.dal.find_students_by_class_name(class_name)
|
|
|
|
def get_all_students(self) -> List[Student]:
|
|
return self.dal.get_all_students()
|
|
|
|
def get_student_count(self) -> int:
|
|
return self.dal.get_student_count()
|
|
|
|
def get_students_by_height(self, min_height: int, max_height: int) -> List[Student]:
|
|
students = self.dal.get_all_students()
|
|
return [s for s in students if min_height <= s.height <= max_height]
|
|
|
|
def get_avg_height(self) -> float:
|
|
"""计算平均身高"""
|
|
students = self.dal.get_all_students()
|
|
if not students:
|
|
return 0.0
|
|
total_height = sum(student.height for student in students)
|
|
return total_height / len(students)
|
|
|
|
def get_avg_gender(self)-> str | float:
|
|
""""计算性别比例"""
|
|
students = self.dal.get_all_students()
|
|
if not students:
|
|
return "无学生数据"
|
|
male_count = 0
|
|
female_count = 0
|
|
for student in students:
|
|
if student.gender=="男":
|
|
male_count+=1
|
|
elif student.gender=="女":
|
|
female_count+=1
|
|
total =male_count+female_count
|
|
if total==0:
|
|
return "无有效性别数据"
|
|
if male_count==0:
|
|
return "全为女生"
|
|
if female_count==0:
|
|
return "全为男生"
|
|
gcd_value=math.gcd(male_count,female_count)
|
|
ratio_male = male_count // gcd_value
|
|
ratio_female = female_count // gcd_value
|
|
|
|
return f"{ratio_male}:{ratio_female}"
|
|
|
|
|
|
def get_students_by_enrollment_year(self, year: int) -> List[Student]:
|
|
students = self.dal.get_all_students()
|
|
return [student for student in students if student.enrollment_date.year == year]
|
|
|
|
def get_students_by_age(self, min_age: int, max_age: int) -> List[Student]:
|
|
today = date.today()
|
|
students = self.dal.get_all_students()
|
|
age_filtered_students = []
|
|
for student in students:
|
|
age = today.year - student.birth_date.year - (
|
|
(today.month, today.day) < (student.birth_date.month, student.birth_date.day))
|
|
if min_age <= age <= max_age:
|
|
age_filtered_students.append(student)
|
|
return age_filtered_students
|
|
|
|
def export_students(self, file_path: str) -> bool:
|
|
"""导出学生数据,自动根据文件扩展名选择格式"""
|
|
ext = os.path.splitext(file_path)[1].lower()
|
|
students = self.get_all_students()
|
|
|
|
try:
|
|
if ext == '.json':
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
json.dump([student.to_dict() for student in students], f, ensure_ascii=False, indent=4)
|
|
elif ext == '.csv':
|
|
# 使用CSV存储类导出
|
|
csv_dal = StudentDALCSV(file_path)
|
|
csv_dal.save_students(students)
|
|
else:
|
|
raise ValueError(f"不支持的文件格式: {ext}")
|
|
return True
|
|
except Exception as e:
|
|
print(f"导出学生数据时出错: {e}")
|
|
return False
|
|
|
|
def import_students(self, file_path: str) -> bool:
|
|
"""导入学生数据,自动根据文件扩展名选择格式"""
|
|
ext = os.path.splitext(file_path)[1].lower()
|
|
|
|
try:
|
|
if ext == '.json':
|
|
# 使用JSON存储类导入
|
|
json_dal = StudentDAL(file_path)
|
|
students = json_dal.load_students()
|
|
elif ext == '.csv':
|
|
# 使用CSV存储类导入
|
|
csv_dal = StudentDALCSV(file_path)
|
|
students = csv_dal.load_students()
|
|
else:
|
|
raise ValueError(f"不支持的文件格式: {ext}")
|
|
|
|
# 导入前验证数据
|
|
for student in students:
|
|
if not student.is_valid:
|
|
print(f"导入学生数据时校验不通过。学生ID:{student.stu_id},错误信息:{student.get_errors()}")
|
|
continue
|
|
|
|
# 检查学号和身份证号唯一性
|
|
if self.dal.check_student_exists(student.stu_id):
|
|
print(f"导入失败: 学生 ID {student.stu_id} 已存在。")
|
|
continue
|
|
if student.id_card and self.dal.check_id_card_exists(student.id_card):
|
|
print(f"导入失败: 身份证号 {student.id_card} 已存在。")
|
|
continue
|
|
|
|
self.dal.add_student(student)
|
|
|
|
return True
|
|
except Exception as e:
|
|
print(f"导入学生数据时出错: {e}")
|
|
return False
|
|
|
|
def clear_all_students(self) -> None:
|
|
self.dal.clear_all_students() |