""" 数学学习软件 - 数据管理模块 负责用户数据存储、题目生成等业务逻辑 """ import json import os import random import re import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from typing import Dict, List, Tuple, Optional from email_config import get_smtp_config, DEFAULT_SENDER_CONFIG class DataManager: """数据管理类,负责用户信息和题目数据的管理""" def __init__(self): self.users_file = "users.json" self.email_config_file = "email_config.json" self.current_user = None # 邮件配置 self.sender_config = DEFAULT_SENDER_CONFIG self.ensure_data_files() self.load_email_config() def ensure_data_files(self): """确保数据文件存在""" if not os.path.exists(self.users_file): with open(self.users_file, 'w', encoding='utf-8') as f: json.dump({}, f, ensure_ascii=False, indent=2) def load_email_config(self): """加载邮箱配置""" try: if os.path.exists(self.email_config_file): with open(self.email_config_file, 'r', encoding='utf-8') as f: config = json.load(f) self.sender_config.update(config) except Exception as e: print(f"加载邮箱配置失败: {e}") def load_users(self) -> Dict: """加载用户数据""" try: with open(self.users_file, 'r', encoding='utf-8') as f: return json.load(f) except: return {} def save_users(self, users_data: Dict): """保存用户数据""" with open(self.users_file, 'w', encoding='utf-8') as f: json.dump(users_data, f, ensure_ascii=False, indent=2) def generate_verification_code(self) -> str: """生成6位数字验证码""" return str(random.randint(100000, 999999)) def send_verification_email(self, email: str, verification_code: str) -> bool: """发送验证码邮件""" try: # 检查发送邮箱配置 if (self.sender_config["email"] == "your_email@qq.com" or self.sender_config["password"] == "your_app_password"): print("请先配置发送邮箱信息") # 在没有配置邮箱的情况下,返回验证码供测试使用 print(f"测试模式 - 验证码: {verification_code}") return True # 获取SMTP配置 smtp_config = get_smtp_config(self.sender_config["email"]) # 创建邮件内容 msg = MIMEMultipart() msg['From'] = self.sender_config['email'] # QQ邮箱要求简单格式 msg['To'] = email msg['Subject'] = "数学学习软件 - 注册验证码" # 邮件正文 body = f"""欢迎使用数学学习软件! 您的注册验证码是:{verification_code} 请在软件中输入此验证码完成注册。 验证码有效期为10分钟。 如果您没有申请注册,请忽略此邮件。 祝您学习愉快! {self.sender_config['name']}""" msg.attach(MIMEText(body, 'plain', 'utf-8')) # 连接SMTP服务器并发送邮件 server = smtplib.SMTP(smtp_config["smtp_server"], smtp_config["smtp_port"]) if smtp_config["use_tls"]: server.starttls() # 启用TLS加密 server.login(self.sender_config["email"], self.sender_config["password"]) text = msg.as_string() server.sendmail(self.sender_config["email"], email, text) server.quit() return True except Exception as e: print(f"邮件发送失败: {e}") # 测试模式:如果邮件发送失败,在控制台显示验证码 print(f"测试模式 - 验证码: {verification_code}") return True # 返回True以便测试 def register_user(self, email: str, username: str) -> bool: """用户注册,发送验证码到邮箱""" users = self.load_users() if email in users: raise ValueError("该邮箱已注册") # 检查用户名是否已存在 for user_data in users.values(): if user_data.get("username") == username: raise ValueError("该用户名已存在") verification_code = self.generate_verification_code() # 发送验证码邮件 if not self.send_verification_email(email, verification_code): raise ValueError("验证码邮件发送失败,请检查邮箱地址") users[email] = { "username": username, "verification_code": verification_code, "verified": False, "password": None } self.save_users(users) return True def verify_registration(self, email: str, code: str) -> bool: """验证注册码""" users = self.load_users() if email not in users: return False if users[email]["verification_code"] == code: users[email]["verified"] = True self.save_users(users) return True return False def validate_password(self, password: str) -> bool: """验证密码格式:6-10位,必须含大小写字母和数字""" if len(password) < 6 or len(password) > 10: return False has_upper = bool(re.search(r'[A-Z]', password)) has_lower = bool(re.search(r'[a-z]', password)) has_digit = bool(re.search(r'\d', password)) return has_upper and has_lower and has_digit def set_password(self, email: str, password: str) -> bool: """设置用户密码""" if not self.validate_password(password): return False users = self.load_users() if email not in users or not users[email]["verified"]: return False users[email]["password"] = password self.save_users(users) return True def login(self, email: str, password: str) -> bool: """用户登录""" users = self.load_users() if email not in users: return False user = users[email] if user["verified"] and user["password"] == password: self.current_user = email return True return False def change_password(self, old_password: str, new_password: str) -> bool: """修改密码""" if not self.current_user: return False users = self.load_users() user = users[self.current_user] if user["password"] != old_password: return False if not self.validate_password(new_password): return False user["password"] = new_password self.save_users(users) return True def logout(self): """用户登出""" self.current_user = None def get_current_username(self) -> str: """获取当前登录用户的用户名""" if not self.current_user: return "" users = self.load_users() if self.current_user in users: return users[self.current_user].get("username", "") return "" class QuestionGenerator: """题目生成器""" def __init__(self): self.difficulty_levels = { "小学": {"range": (1, 100), "operations": ["+", "-", "*"]}, "初中": {"range": (1, 1000), "operations": ["+", "-", "*", "/"]}, "高中": {"range": (1, 10000), "operations": ["+", "-", "*", "/", "**"]} } def generate_question(self, level: str) -> Dict: """生成单个题目""" config = self.difficulty_levels[level] min_val, max_val = config["range"] operations = config["operations"] # 随机选择运算符 operation = random.choice(operations) if operation == "**": # 幂运算特殊处理 base = random.randint(2, 10) exponent = random.randint(2, 4) question = f"{base}^{exponent} = ?" correct_answer = base ** exponent elif operation == "/": # 除法确保整除 divisor = random.randint(2, 20) quotient = random.randint(2, max_val // divisor) dividend = divisor * quotient question = f"{dividend} ÷ {divisor} = ?" correct_answer = quotient else: # 加减乘法 num1 = random.randint(min_val, max_val) num2 = random.randint(min_val, max_val) if operation == "+": question = f"{num1} + {num2} = ?" correct_answer = num1 + num2 elif operation == "-": # 确保结果为正数 if num1 < num2: num1, num2 = num2, num1 question = f"{num1} - {num2} = ?" correct_answer = num1 - num2 else: # multiplication question = f"{num1} × {num2} = ?" correct_answer = num1 * num2 # 生成选项 options = self.generate_options(correct_answer) return { "question": question, "options": options, "correct_answer": correct_answer } def generate_options(self, correct_answer: int) -> List[int]: """生成四个选项,其中一个是正确答案""" options = [correct_answer] # 生成3个错误选项 while len(options) < 4: # 在正确答案附近生成错误选项 offset = random.randint(-abs(correct_answer)//2, abs(correct_answer)//2) if offset == 0: offset = random.choice([-1, 1]) * random.randint(1, 10) wrong_answer = correct_answer + offset if wrong_answer > 0 and wrong_answer not in options: options.append(wrong_answer) # 打乱选项顺序 random.shuffle(options) return options def generate_test_paper(self, level: str, question_count: int) -> List[Dict]: """生成试卷""" questions = [] generated_questions = set() # 用于避免重复题目 attempts = 0 while len(questions) < question_count and attempts < question_count * 10: question_data = self.generate_question(level) question_text = question_data["question"] if question_text not in generated_questions: generated_questions.add(question_text) questions.append(question_data) attempts += 1 return questions class ScoreCalculator: """分数计算器""" @staticmethod def calculate_score(correct_count: int, total_count: int) -> int: """计算分数(百分制)""" if total_count == 0: return 0 return int((correct_count / total_count) * 100) @staticmethod def get_grade_comment(score: int) -> str: """根据分数获取评价""" if score >= 90: return "优秀!继续保持!" elif score >= 80: return "良好!再接再厉!" elif score >= 70: return "中等,还需努力!" elif score >= 60: return "及格,继续加油!" else: return "需要更多练习!"