from typing import List, Optional from ..dal.student_dal import IStudentDAL from ..model.student import Student from ..util.validator import Validator class StudentBLL: """学生信息管理系统的业务逻辑层,处理学生信息的业务逻辑和数据验证""" def __init__(self, dal: IStudentDAL): """ 初始化业务逻辑层 Args: dal: 数据访问层对象,实现IStudentDAL接口 """ self.dal = dal def add_student(self, student: Student) -> (bool, str): """ 添加学生信息,包含完整的数据验证流程 Args: student: 要添加的学生对象 Returns: 元组(操作是否成功, 操作结果信息) """ # 验证学生基本信息格式 if not Validator.validate_id_card(student.id_card): return False, "身份证号码格式不正确" if not Validator.validate_stu_id(student.stu_id): return False, "学号格式不正确" if not Validator.validate_name(student.name): return False, "姓名格式不正确,必须为2-20个中文字符" if student.height is not None and not Validator.validate_height(student.height): return False, "身高必须在50-250cm之间" if student.weight is not None and not Validator.validate_weight(student.weight): return False, "体重必须在5-300kg之间" if student.email and not Validator.validate_email(student.email): return False, "电子邮箱格式不正确" if student.phone and not Validator.validate_phone(student.phone): return False, "手机号码格式不正确" # 验证入学日期与出生日期的逻辑关系 if student.enrollment_date and student.birthday: if not Validator.validate_enrollment_date(student.enrollment_date, student.birthday): return False, "入学日期不能早于出生日期" # 检查数据唯一性 if self.dal.get_by_id(student.id_card): return False, "该身份证号已存在" if self.dal.get_by_stu_id(student.stu_id): return False, "该学号已存在" # 执行数据添加操作 if self.dal.add(student): return True, "学生添加成功" else: return False, "学生添加失败" def update_student(self, student: Student) -> (bool, str): """ 更新学生信息,包含与添加操作相同的数据验证流程 Args: student: 包含更新信息的学生对象,通过id_card匹配记录 Returns: 元组(操作是否成功, 操作结果信息) """ # 重复添加操作中的数据验证逻辑 if not Validator.validate_id_card(student.id_card): return False, "身份证号码格式不正确" if not Validator.validate_stu_id(student.stu_id): return False, "学号格式不正确" if not Validator.validate_name(student.name): return False, "姓名格式不正确,必须为2-20个中文字符" if student.height is not None and not Validator.validate_height(student.height): return False, "身高必须在50-250cm之间" if student.weight is not None and not Validator.validate_weight(student.weight): return False, "体重必须在5-300kg之间" if student.email and not Validator.validate_email(student.email): return False, "电子邮箱格式不正确" if student.phone and not Validator.validate_phone(student.phone): return False, "手机号码格式不正确" if student.enrollment_date and student.birthday: if not Validator.validate_enrollment_date(student.enrollment_date, student.birthday): return False, "入学日期不能早于出生日期" # 执行数据更新操作 if self.dal.update(student): return True, "学生信息更新成功" else: return False, "学生信息更新失败,未找到该学生" def delete_student_by_id(self, id_card: str) -> bool: """ 根据身份证号删除学生记录 Args: id_card: 要删除学生的身份证号 Returns: 操作是否成功 """ return self.dal.delete_by_id(id_card) def delete_student_by_stu_id(self, stu_id: str) -> bool: """ 根据学号删除学生记录 Args: stu_id: 要删除学生的学号 Returns: 操作是否成功 """ return self.dal.delete_by_stu_id(stu_id) def get_student_by_id(self, id_card: str) -> Optional[Student]: """ 根据身份证号查询学生信息 Args: id_card: 要查询学生的身份证号 Returns: 匹配的学生对象,未找到返回None """ return self.dal.get_by_id(id_card) def get_student_by_stu_id(self, stu_id: str) -> Optional[Student]: """ 根据学号查询学生信息 Args: stu_id: 要查询学生的学号 Returns: 匹配的学生对象,未找到返回None """ return self.dal.get_by_stu_id(stu_id) def get_all_students(self) -> List[Student]: """ 获取系统中所有学生记录 Returns: 包含所有学生对象的列表 """ return self.dal.get_all() def search_students_by_name(self, name: str) -> List[Student]: """ 根据姓名模糊查询学生信息 Args: name: 要查询的姓名关键词 Returns: 包含匹配学生对象的列表 """ return self.dal.search_by_name(name) def search_students_by_class(self, class_name: str) -> List[Student]: """ 根据班级模糊查询学生信息 Args: class_name: 要查询的班级关键词 Returns: 包含匹配学生对象的列表 """ return self.dal.search_by_class(class_name) def search_students_by_major(self, major: str) -> List[Student]: """ 根据专业模糊查询学生信息 Args: major: 要查询的专业关键词 Returns: 包含匹配学生对象的列表 """ return self.dal.search_by_major(major) def get_total_students(self) -> int: """ 获取系统中学生总数 Returns: 学生总人数 """ return len(self.get_all_students()) def get_students_by_major(self) -> dict: """ 统计各专业学生分布情况 Returns: 字典,键为专业名称,值为该专业学生人数 """ major_count = {} for student in self.get_all_students(): if student.major: major_count[student.major] = major_count.get(student.major, 0) + 1 return major_count def calculate_average_height(self, group_by: str = None, group_value: str = None) -> float: """ 计算学生平均身高,支持按班级或专业分组计算 Args: group_by: 分组依据,可选'class'或'major',不分组时为None group_value: 分组值,如具体班级名称或专业名称 Returns: 平均身高,单位厘米,无有效数据时返回0 """ students = self.get_all_students() # 按指定条件筛选学生群体 if group_by == 'class': students = [s for s in students if s.class_name == group_value] elif group_by == 'major': students = [s for s in students if s.major == group_value] # 过滤有效身高数据并计算平均值 heights = [s.height for s in students if s.height is not None] return sum(heights) / len(heights) if heights else 0 def calculate_average_weight(self, group_by: str = None, group_value: str = None) -> float: """ 计算学生平均体重,支持按班级或专业分组计算 Args: group_by: 分组依据,可选'class'或'major',不分组时为None group_value: 分组值,如具体班级名称或专业名称 Returns: 平均体重,单位千克,无有效数据时返回0 """ students = self.get_all_students() # 按指定条件筛选学生群体 if group_by == 'class': students = [s for s in students if s.class_name == group_value] elif group_by == 'major': students = [s for s in students if s.major == group_value] # 过滤有效体重数据并计算平均值 weights = [s.weight for s in students if s.weight is not None] return sum(weights) / len(weights) if weights else 0 def get_gender_ratio(self) -> dict: """ 统计学生性别比例 Returns: 包含以下键的字典: - total: 总人数 - male: 男生人数 - female: 女生人数 - male_ratio: 男生比例 - female_ratio: 女生比例 """ total = 0 male_count = 0 female_count = 0 # 遍历统计性别分布 for student in self.get_all_students(): if student.gender is not None: total += 1 if student.gender: male_count += 1 else: female_count += 1 # 计算比例并返回结果 return { 'total': total, 'male': male_count, 'female': female_count, 'male_ratio': male_count / total if total > 0 else 0, 'female_ratio': female_count / total if total > 0 else 0 }