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

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()