diff --git a/dal/student_dal_json.py b/dal/student_dal_json.py index 77f5377..83f6273 100644 --- a/dal/student_dal_json.py +++ b/dal/student_dal_json.py @@ -1,7 +1,8 @@ import json -import os, sys +import os, sys,csv from datetime import date from typing import List, Optional +from model.Student import Student import csv current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -10,6 +11,107 @@ sys.path.append(parent_dir) from model.Student import Student +class StudentDALJSON: + def __init__(self, file_path="students.json"): + self.file_path = file_path + + def get_all_students(self): + try: + with open(self.file_path, 'r', encoding='utf-8') as file: + student_dicts = json.load(file) + return [Student.from_dict(s) for s in student_dicts] + except (FileNotFoundError, json.JSONDecodeError): + return [] + + def save_students(self, students): + student_dicts = [student.to_dict() for student in students] + with open(self.file_path, 'w', encoding='utf-8') as file: + json.dump(student_dicts, file, ensure_ascii=False, indent=4) + + # 新增:导出为JSON + def export_to_json(self, file_path=None): + if not file_path: + file_path = self.file_path + students = self.get_all_students() + if not students: + print("没有数据可导出") + return + try: + with open(file_path, 'w', encoding='utf-8') as f: + json.dump([s.to_dict() for s in students], f, ensure_ascii=False, indent=4) + print(f"数据已导出到 {file_path}") + except Exception as e: + print(f"导出失败: {e}") + + # 新增:导出为CSV + def export_to_csv(self, file_path="students.csv"): + students = self.get_all_students() + if not students: + print("没有数据可导出") + return + try: + with open(file_path, 'w', encoding='utf-8-sig', newline='') as f: + writer = csv.DictWriter( + f, + fieldnames=[ + 'student_id', 'name', 'gender', 'age', 'class_name', + 'major', 'phone', 'email', 'id_number', + 'height', 'weight', 'birth_date', 'enrollment_date' + ] + ) + writer.writeheader() + for student in students: + data = student.to_dict() + # 将日期对象转换为字符串 + data['birth_date'] = data['birth_date'].isoformat() + data['enrollment_date'] = data['enrollment_date'].isoformat() + writer.writerow(data) + print(f"数据已导出到 {file_path}") + except Exception as e: + print(f"导出失败: {e}") + + # 新增:从JSON导入 + def import_from_json(self, file_path): + try: + with open(file_path, 'r', encoding='utf-8') as f: + student_dicts = json.load(f) + students = [] + for data in student_dicts: + # 转换日期字符串为日期对象 + data['birth_date'] = date.fromisoformat(data['birth_date']) + data['enrollment_date'] = date.fromisoformat(data['enrollment_date']) + students.append(Student.from_dict(data)) + self.save_students(students) + print(f"从 {file_path} 导入成功") + except FileNotFoundError: + print(f"文件不存在: {file_path}") + except json.JSONDecodeError: + print(f"JSON格式错误: {file_path}") + except Exception as e: + print(f"导入失败: {e}") + + # 新增:从CSV导入 + def import_from_csv(self, file_path): + try: + with open(file_path, 'r', encoding='utf-8-sig') as f: + reader = csv.DictReader(f) + student_dicts = list(reader) + students = [] + for data in student_dicts: + # 转换数值类型 + data['age'] = int(data['age']) + data['height'] = float(data['height']) + data['weight'] = float(data['weight']) + # 转换日期类型 + data['birth_date'] = date.fromisoformat(data['birth_date']) + data['enrollment_date'] = date.fromisoformat(data['enrollment_date']) + students.append(Student.from_dict(data)) + self.save_students(students) + print(f"从 {file_path} 导入成功") + except FileNotFoundError: + print(f"文件不存在: {file_path}") + except Exception as e: + print(f"导入失败: {e}") class StudentDAL: def __init__(self, file_path: str): self.file_path = file_path @@ -109,10 +211,17 @@ class StudentDAL: json.dump(student_dicts, file, ensure_ascii=False, indent=4) def import_from_json(self, file_path): - with open(file_path, mode='r', encoding='utf-8') as file: - student_dicts = json.load(file) - students = [Student.from_dict(student_dict) for student_dict in student_dicts] - self.save_students(students) + try: + with open(file_path, mode='r', encoding='utf-8') as file: + student_dicts = json.load(file) + students = [Student.from_dict(student_dict) for student_dict in student_dicts] + self.save_students(students) + except FileNotFoundError: + print(f"文件 {file_path} 未找到。") + except json.JSONDecodeError: + print(f"文件 {file_path} 不是有效的 JSON 文件。") + except ValueError as e: + print(f"数据转换错误: {e}") def export_to_csv(self, file_path): students = self.load_students() @@ -124,15 +233,20 @@ class StudentDAL: writer.writerow(student.to_dict()) def import_from_csv(self, file_path): - students = [] - with open(file_path, mode='r', encoding='utf-8') as file: - reader = csv.DictReader(file) - for row in reader: - row['birth_date'] = date.fromisoformat(row['birth_date']) - row['enrollment_date'] = date.fromisoformat(row['enrollment_date']) - student = Student.from_dict(row) - students.append(student) - self.save_students(students) + try: + students = [] + with open(file_path, mode='r', encoding='utf-8') as file: + reader = csv.DictReader(file) + for row in reader: + row['birth_date'] = date.fromisoformat(row['birth_date']) + row['enrollment_date'] = date.fromisoformat(row['enrollment_date']) + student = Student.from_dict(row) + students.append(student) + self.save_students(students) + except FileNotFoundError: + print(f"文件 {file_path} 未找到。") + except ValueError as e: + print(f"日期格式错误: {e}") def get_average_height(self): students = self.load_students() @@ -152,4 +266,24 @@ class StudentDAL: def count_students_by_age_range(self, min_age, max_age): today = date.today() students = self.load_students() - return len([student for student in students if min_age <= today.year - student.birth_date.year <= max_age]) \ No newline at end of file + return len([student for student in students if min_age <= today.year - student.birth_date.year <= max_age]) + + def backup_data(self, backup_path): + try: + with open(self.file_path, mode='r', encoding='utf-8') as src_file, \ + open(backup_path, mode='w', encoding='utf-8') as dst_file: + dst_file.write(src_file.read()) + print(f"数据备份到 {backup_path} 成功。") + except Exception as e: + print(f"数据备份失败: {e}") + + def restore_data(self, backup_path): + try: + with open(backup_path, mode='r', encoding='utf-8') as src_file, \ + open(self.file_path, mode='w', encoding='utf-8') as dst_file: + dst_file.write(src_file.read()) + print(f"数据从 {backup_path} 恢复成功。") + except FileNotFoundError: + print(f"备份文件 {backup_path} 未找到。") + except Exception as e: + print(f"数据恢复失败: {e}") \ No newline at end of file diff --git a/data/student.json b/data/student.json index 0637a08..450a476 100644 --- a/data/student.json +++ b/data/student.json @@ -1 +1,10 @@ -[] \ No newline at end of file +[ + { + "sid": "110309230907041", + "name": "cgt", + "height": 180, + "birth_date": "2023-09-01", + "enrollment_date": "2023-09-01", + "class_name": "cls2" + } +] \ No newline at end of file diff --git a/main.py b/main.py index 2fd46b5..66dc6f5 100644 --- a/main.py +++ b/main.py @@ -126,4 +126,3 @@ def main(): if __name__ == '__main__': main() - print(123) \ No newline at end of file diff --git a/model/Student.py b/model/Student.py index 2325357..e9afce0 100644 --- a/model/Student.py +++ b/model/Student.py @@ -18,8 +18,8 @@ class Student: self._validation_errors.append(f"身高{self.height}cm超出合理范围") def _validate_name(self) -> None: - if not (2 <= len(self.name) <=20): - self._validation_errors.append("姓名长度需在2-20个字符之间") + if not (2 <= len(self.name) <= 20) or not self.name.isprintable(): + self._validation_errors.append("姓名长度需在2-20个字符之间且为可打印字符") if not self.name.isprintable(): self._validation_errors.append("姓名长度需在2-20个字符之间") def _validate_date(self) -> None: diff --git a/ui/studentui.py b/ui/studentui.py index c1c69da..0675ab4 100644 --- a/ui/studentui.py +++ b/ui/studentui.py @@ -1,8 +1,9 @@ -import os +import os,re from datetime import date from bll.student_bll import StudentBLL from dal.student_dal_json import StudentDAL from model.Student import Student +from dal.student_dal_json import StudentDALJSON # 确保导入 class StudentUI: def __init__(self): @@ -87,7 +88,18 @@ class StudentUI: name = self.get_input("请输入姓名: ") id_number = self.get_input("请输入身份证号: ") - student_id = self.get_input("请输入学号: ") + # 验证学号格式(新增) + id_number = self.get_input("请输入身份证号: ") + while not re.match(r'^\d{17}[\dXx]$', id_number): + print("身份证号格式不正确,请输入 18 位身份证号。") + id_number = self.get_input("请输入身份证号: ") + + while True: + student_id = self.get_input("请输入学号: ") + if re.match(r'^\d{10,15}$', student_id): # 假设学号是8-12位数字 + break + print("学号格式不正确,请输入8-12位数字") + gender = self.get_input("请输入性别(男/女): ") while True: @@ -108,37 +120,34 @@ class StudentUI: except ValueError: print("体重必须为0到500之间的有效数值,请重新输入") - enrollment_date = self.get_input("请输入入学日期(YYYY-MM-DD): ") + # 修改后的日期输入验证 + while True: + enrollment_date = self.get_input("请输入入学日期(YYYY-MM-DD): ") + try: + date_obj = date.fromisoformat(enrollment_date) + break + except ValueError: + print("日期格式错误,请使用 YYYY-MM-DD 格式(例如:2023-09-01)") + class_name = self.get_input("请输入班级: ") major = self.get_input("请输入专业: ") - student = Student( - name=name, - id_number=id_number, - student_id=student_id, - gender=gender, - height=height, - weight=weight, - enrollment_date=enrollment_date, - class_name=class_name, - - major=major - ) - student = Student( - sid=student_id, # 注意这里添加了 sid - name=name, - height=height, - birth_date=date.fromisoformat(enrollment_date), # 假设入学日期作为示例,可根据实际情况修改 - enrollment_date=date.fromisoformat(enrollment_date), - class_name=class_name - ) + # 创建 Student 对象 try: + student = Student( + sid=student_id, + name=name, + height=height, + birth_date=date_obj, # 使用验证后的日期对象 + enrollment_date=date_obj, # 使用验证后的日期对象 + class_name=class_name + ) if self.bll.add_student(student): print("学生信息添加成功!") else: print("学生信息添加失败。") except ValueError as e: - print(e) + print(f"添加学生失败: {e}") def handle_import_export(self, choice): if choice == '1':