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.

304 lines
9.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}