|
|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
|
|
|
|
|
# !/usr/bin/env python3
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
@ -7,11 +8,14 @@
|
|
|
|
|
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from tkinter import messagebox, ttk
|
|
|
|
|
import random
|
|
|
|
|
from typing import List, Optional
|
|
|
|
|
|
|
|
|
|
from backend_service import BackendService
|
|
|
|
|
from question_generator import Expression
|
|
|
|
|
from user_manager import UserManager
|
|
|
|
|
from question_bank import QuestionBank
|
|
|
|
|
from quiz import Quiz
|
|
|
|
|
from question_generator import Expression
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MathQuizApp:
|
|
|
|
|
"""
|
|
|
|
|
@ -31,7 +35,8 @@ class MathQuizApp:
|
|
|
|
|
self.root.configure(bg="#f0f0f0")
|
|
|
|
|
|
|
|
|
|
# 初始化系统组件
|
|
|
|
|
self.backend_service = BackendService()
|
|
|
|
|
self.user_manager = UserManager()
|
|
|
|
|
self.question_bank = QuestionBank()
|
|
|
|
|
|
|
|
|
|
# 设置样式
|
|
|
|
|
self.setup_styles()
|
|
|
|
|
@ -45,7 +50,7 @@ class MathQuizApp:
|
|
|
|
|
self.quiz_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.result_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.change_password_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.delete_account_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.delete_account_frame = tk.Frame(self.root, bg="#f0f0f0") # 添加删除账户框架
|
|
|
|
|
|
|
|
|
|
# 初始化应用状态
|
|
|
|
|
self.current_quiz: Optional[Quiz] = None
|
|
|
|
|
@ -88,7 +93,7 @@ class MathQuizApp:
|
|
|
|
|
self.quiz_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.result_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.change_password_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.delete_account_frame = tk.Frame(self.root, bg="#f0f0f0")
|
|
|
|
|
self.delete_account_frame = tk.Frame(self.root, bg="#f0f0f0") # 添加删除账户框架
|
|
|
|
|
|
|
|
|
|
def show_frame(self, frame: tk.Frame):
|
|
|
|
|
"""
|
|
|
|
|
@ -97,12 +102,9 @@ class MathQuizApp:
|
|
|
|
|
@param frame: 要显示的框架
|
|
|
|
|
"""
|
|
|
|
|
# 隐藏所有框架
|
|
|
|
|
for f in [self.login_frame, self.register_frame,
|
|
|
|
|
self.set_password_frame,
|
|
|
|
|
self.main_menu_frame, self.quiz_setup_frame,
|
|
|
|
|
self.quiz_frame,
|
|
|
|
|
self.result_frame, self.change_password_frame,
|
|
|
|
|
self.delete_account_frame]:
|
|
|
|
|
for f in [self.login_frame, self.register_frame, self.set_password_frame,
|
|
|
|
|
self.main_menu_frame, self.quiz_setup_frame, self.quiz_frame,
|
|
|
|
|
self.result_frame, self.change_password_frame, self.delete_account_frame]:
|
|
|
|
|
f.pack_forget()
|
|
|
|
|
|
|
|
|
|
# 显示指定框架
|
|
|
|
|
@ -117,53 +119,37 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建登录界面
|
|
|
|
|
main_frame = tk.Frame(self.login_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.login_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=50, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=self.primary_color)
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 30))
|
|
|
|
|
tk.Label(title_frame, text="用户登录", font=self.title_font,
|
|
|
|
|
bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
tk.Label(title_frame, text="用户登录", font=self.title_font, bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
form_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
form_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="用户名:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.login_email_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
relief=tk.FLAT, bd=5,
|
|
|
|
|
tk.Label(form_frame, text="用户名:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.login_email_entry = tk.Entry(form_frame, width=30, font=self.normal_font, relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.login_email_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="密码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.login_password_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
show="*", relief=tk.FLAT,
|
|
|
|
|
tk.Label(form_frame, text="密码:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.login_password_entry = tk.Entry(form_frame, width=30, font=self.normal_font, show="*", relief=tk.FLAT,
|
|
|
|
|
bd=5, bg="#f0f0f0")
|
|
|
|
|
self.login_password_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="登录", command=self.login, width=20,
|
|
|
|
|
bg=self.primary_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="注册新用户",
|
|
|
|
|
command=self.show_register_frame, width=20,
|
|
|
|
|
bg=self.secondary_color,
|
|
|
|
|
tk.Button(button_frame, text="登录", command=self.login, width=20, bg=self.primary_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="注册新用户", command=self.show_register_frame, width=20, bg=self.secondary_color,
|
|
|
|
|
fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=5)
|
|
|
|
|
tk.Button(button_frame, text="注销账户",
|
|
|
|
|
command=self.show_delete_account_frame, width=20,
|
|
|
|
|
bg=self.danger_color,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=5)
|
|
|
|
|
tk.Button(button_frame, text="注销账户", command=self.show_delete_account_frame, width=20, bg=self.danger_color,
|
|
|
|
|
fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=5)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=5)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.login_frame)
|
|
|
|
|
|
|
|
|
|
@ -178,10 +164,10 @@ class MathQuizApp:
|
|
|
|
|
messagebox.showerror("错误", "请输入用户名和密码")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if self.backend_service.login(username, password):
|
|
|
|
|
if self.user_manager.login(username, password):
|
|
|
|
|
messagebox.showinfo("成功", "登录成功")
|
|
|
|
|
self.show_main_menu_frame()
|
|
|
|
|
# 错误信息在backend_service.login中已经显示
|
|
|
|
|
# 错误信息在user_manager.login中已经显示
|
|
|
|
|
|
|
|
|
|
def show_register_frame(self):
|
|
|
|
|
"""
|
|
|
|
|
@ -192,62 +178,44 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建注册界面
|
|
|
|
|
main_frame = tk.Frame(self.register_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.register_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=30, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=self.primary_color)
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(title_frame, text="用户注册", font=self.title_font,
|
|
|
|
|
bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
tk.Label(title_frame, text="用户注册", font=self.title_font, bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
form_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
form_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="用户名:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.register_username_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
relief=tk.FLAT, bd=5,
|
|
|
|
|
tk.Label(form_frame, text="用户名:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.register_username_entry = tk.Entry(form_frame, width=30, font=self.normal_font, relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.register_username_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="邮箱:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.register_email_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
relief=tk.FLAT, bd=5,
|
|
|
|
|
tk.Label(form_frame, text="邮箱:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.register_email_entry = tk.Entry(form_frame, width=30, font=self.normal_font, relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.register_email_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
tk.Button(form_frame, text="获取注册码",
|
|
|
|
|
command=self.send_registration_code, width=20,
|
|
|
|
|
bg=self.primary_color,
|
|
|
|
|
tk.Button(form_frame, text="获取注册码", command=self.send_registration_code, width=20, bg=self.primary_color,
|
|
|
|
|
fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="注册码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.registration_code_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
relief=tk.FLAT, bd=5,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="注册码:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.registration_code_entry = tk.Entry(form_frame, width=30, font=self.normal_font, relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.registration_code_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="验证注册码",
|
|
|
|
|
command=self.verify_registration_code, width=20,
|
|
|
|
|
tk.Button(button_frame, text="验证注册码", command=self.verify_registration_code, width=20,
|
|
|
|
|
bg=self.success_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回登录", command=self.show_login_frame,
|
|
|
|
|
width=20, bg="#cccccc",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回登录", command=self.show_login_frame, width=20, bg="#cccccc",
|
|
|
|
|
fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=5)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=5)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.register_frame)
|
|
|
|
|
|
|
|
|
|
@ -263,7 +231,7 @@ class MathQuizApp:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 注意:register_user 方法内部已经包含了消息提示,不需要额外的消息框
|
|
|
|
|
self.backend_service.register_user(email, username)
|
|
|
|
|
self.user_manager.register_user(email, username)
|
|
|
|
|
|
|
|
|
|
def verify_registration_code(self):
|
|
|
|
|
"""
|
|
|
|
|
@ -276,7 +244,7 @@ class MathQuizApp:
|
|
|
|
|
messagebox.showerror("错误", "请输入邮箱和注册码")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if self.backend_service.verify_registration_code(email, code):
|
|
|
|
|
if self.user_manager.verify_registration_code(email, code):
|
|
|
|
|
messagebox.showinfo("成功", "注册码验证成功,请设置密码")
|
|
|
|
|
self.show_set_password_frame(email)
|
|
|
|
|
|
|
|
|
|
@ -291,54 +259,40 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建设置密码界面
|
|
|
|
|
main_frame = tk.Frame(self.set_password_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.set_password_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=30, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=self.primary_color)
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(title_frame, text="设置密码", font=self.title_font,
|
|
|
|
|
bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
tk.Label(title_frame, text="设置密码", font=self.title_font, bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
form_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
form_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="邮箱: " + email, font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
tk.Label(form_frame, text="邮箱: " + email, font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="密码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff", fg=self.primary_color).pack(
|
|
|
|
|
tk.Label(form_frame, text="密码:", font=self.normal_font, bg="#ffffff", fg=self.primary_color).pack(
|
|
|
|
|
pady=(10, 5), anchor="w")
|
|
|
|
|
tk.Label(form_frame, text="(6-10位,必须包含大小写字母和数字)",
|
|
|
|
|
font=("Arial", 10), bg="#ffffff",
|
|
|
|
|
tk.Label(form_frame, text="(6-10位,必须包含大小写字母和数字)", font=("Arial", 10), bg="#ffffff",
|
|
|
|
|
fg="gray").pack(pady=5, anchor="w")
|
|
|
|
|
self.set_password_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
show="*", relief=tk.FLAT, bd=5,
|
|
|
|
|
self.set_password_entry = tk.Entry(form_frame, width=30, font=self.normal_font, show="*", relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.set_password_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="确认密码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.confirm_password_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
show="*", relief=tk.FLAT,
|
|
|
|
|
tk.Label(form_frame, text="确认密码:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.confirm_password_entry = tk.Entry(form_frame, width=30, font=self.normal_font, show="*", relief=tk.FLAT,
|
|
|
|
|
bd=5, bg="#f0f0f0")
|
|
|
|
|
self.confirm_password_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="设置密码",
|
|
|
|
|
command=lambda: self.set_password(email), width=20,
|
|
|
|
|
tk.Button(button_frame, text="设置密码", command=lambda: self.set_password(email), width=20,
|
|
|
|
|
bg=self.success_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回登录", command=self.show_login_frame,
|
|
|
|
|
width=20, bg="#cccccc",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回登录", command=self.show_login_frame, width=20, bg="#cccccc",
|
|
|
|
|
fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=5)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=5)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.set_password_frame)
|
|
|
|
|
|
|
|
|
|
@ -359,7 +313,8 @@ class MathQuizApp:
|
|
|
|
|
messagebox.showerror("错误", "两次输入的密码不一致")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if self.backend_service.set_password(email, password):
|
|
|
|
|
if self.user_manager.set_password(email, password):
|
|
|
|
|
messagebox.showinfo("成功", "密码设置成功,请登录")
|
|
|
|
|
self.show_login_frame()
|
|
|
|
|
|
|
|
|
|
def show_main_menu_frame(self):
|
|
|
|
|
@ -371,47 +326,34 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建主菜单界面
|
|
|
|
|
main_frame = tk.Frame(self.main_menu_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.main_menu_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=30, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=self.primary_color)
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(title_frame, text="主菜单", font=self.title_font,
|
|
|
|
|
bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
tk.Label(title_frame, text="主菜单", font=self.title_font, bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
username = self.backend_service.get_current_username()
|
|
|
|
|
tk.Label(main_frame, text=f"欢迎, {username}!",
|
|
|
|
|
font=self.header_font, bg="#ffffff").pack(pady=10)
|
|
|
|
|
user_email = self.user_manager.current_user.email if self.user_manager.current_user else "未知用户"
|
|
|
|
|
tk.Label(main_frame, text=f"欢迎, {user_email}!", font=self.header_font, bg="#ffffff").pack(pady=10)
|
|
|
|
|
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="小学题目",
|
|
|
|
|
command=lambda: self.show_quiz_setup_frame("elementary"),
|
|
|
|
|
width=20, height=2, bg="#4CAF50", fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0).pack(
|
|
|
|
|
tk.Button(button_frame, text="小学题目", command=lambda: self.show_quiz_setup_frame("elementary"),
|
|
|
|
|
width=20, height=2, bg="#4CAF50", fg="white", font=self.button_font, relief=tk.FLAT, bd=0).pack(
|
|
|
|
|
pady=10)
|
|
|
|
|
tk.Button(button_frame, text="初中题目",
|
|
|
|
|
command=lambda: self.show_quiz_setup_frame("middle"),
|
|
|
|
|
width=20, height=2, bg="#2196F3", fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0).pack(
|
|
|
|
|
tk.Button(button_frame, text="初中题目", command=lambda: self.show_quiz_setup_frame("middle"),
|
|
|
|
|
width=20, height=2, bg="#2196F3", fg="white", font=self.button_font, relief=tk.FLAT, bd=0).pack(
|
|
|
|
|
pady=10)
|
|
|
|
|
tk.Button(button_frame, text="高中题目",
|
|
|
|
|
command=lambda: self.show_quiz_setup_frame("high"),
|
|
|
|
|
width=20, height=2, bg="#FF9800", fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0).pack(
|
|
|
|
|
tk.Button(button_frame, text="高中题目", command=lambda: self.show_quiz_setup_frame("high"),
|
|
|
|
|
width=20, height=2, bg="#FF9800", fg="white", font=self.button_font, relief=tk.FLAT, bd=0).pack(
|
|
|
|
|
pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="修改密码",
|
|
|
|
|
command=self.show_change_password_frame,
|
|
|
|
|
width=20, bg=self.secondary_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
tk.Button(button_frame, text="修改密码", command=self.show_change_password_frame,
|
|
|
|
|
width=20, bg=self.secondary_color, fg="white", font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="退出登录", command=self.logout,
|
|
|
|
|
width=20, bg=self.danger_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
pady=5).pack(pady=5)
|
|
|
|
|
tk.Button(button_frame, text="退出登录", command=self.logout, width=20, bg=self.danger_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, pady=5).pack(pady=5)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.main_menu_frame)
|
|
|
|
|
|
|
|
|
|
@ -428,45 +370,34 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建测验设置界面
|
|
|
|
|
main_frame = tk.Frame(self.quiz_setup_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.quiz_setup_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=30, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
level_names = {"elementary": "小学", "middle": "初中", "high": "高中"}
|
|
|
|
|
level_colors = {"elementary": "#4CAF50", "middle": "#2196F3",
|
|
|
|
|
"high": "#FF9800"}
|
|
|
|
|
level_colors = {"elementary": "#4CAF50", "middle": "#2196F3", "high": "#FF9800"}
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=level_colors[level])
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(title_frame, text=f"{level_names[level]}数学题目",
|
|
|
|
|
font=self.title_font, bg=level_colors[level],
|
|
|
|
|
tk.Label(title_frame, text=f"{level_names[level]}数学题目", font=self.title_font, bg=level_colors[level],
|
|
|
|
|
fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
form_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
form_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="请输入题目数量 (10-30):",
|
|
|
|
|
font=self.normal_font, bg="#ffffff").pack(pady=10)
|
|
|
|
|
self.question_count_entry = tk.Entry(form_frame, width=20,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
justify="center",
|
|
|
|
|
relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
tk.Label(form_frame, text="请输入题目数量 (10-30):", font=self.normal_font, bg="#ffffff").pack(pady=10)
|
|
|
|
|
self.question_count_entry = tk.Entry(form_frame, width=20, font=self.normal_font, justify="center",
|
|
|
|
|
relief=tk.FLAT, bd=5, bg="#f0f0f0")
|
|
|
|
|
self.question_count_entry.pack(pady=5)
|
|
|
|
|
self.question_count_entry.insert(0, "10") # 默认10题
|
|
|
|
|
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="开始答题", command=self.start_quiz,
|
|
|
|
|
width=20, bg=self.success_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回主菜单",
|
|
|
|
|
command=self.show_main_menu_frame, width=20, bg="#cccccc",
|
|
|
|
|
tk.Button(button_frame, text="开始答题", command=self.start_quiz, width=20, bg=self.success_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回主菜单", command=self.show_main_menu_frame, width=20, bg="#cccccc",
|
|
|
|
|
fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=5)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=5)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.quiz_setup_frame)
|
|
|
|
|
|
|
|
|
|
@ -486,17 +417,18 @@ class MathQuizApp:
|
|
|
|
|
self.question_count = count
|
|
|
|
|
|
|
|
|
|
# 生成题目
|
|
|
|
|
if self.backend_service.start_quiz(self.current_level, self.question_count):
|
|
|
|
|
try:
|
|
|
|
|
questions = self.question_bank.generate_questions(self.current_level, self.question_count)
|
|
|
|
|
self.current_quiz = Quiz(questions)
|
|
|
|
|
self.show_quiz_frame()
|
|
|
|
|
else:
|
|
|
|
|
messagebox.showerror("错误", "生成题目时出错")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
messagebox.showerror("错误", f"生成题目时出错: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def show_quiz_frame(self):
|
|
|
|
|
"""
|
|
|
|
|
显示答题界面
|
|
|
|
|
"""
|
|
|
|
|
current_question = self.backend_service.get_current_question()
|
|
|
|
|
if not current_question:
|
|
|
|
|
if not self.current_quiz:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 清除之前的内容
|
|
|
|
|
@ -504,40 +436,40 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建答题界面
|
|
|
|
|
main_frame = tk.Frame(self.quiz_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
current_question = self.current_quiz.get_current_question()
|
|
|
|
|
if not current_question:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
main_frame = tk.Frame(self.quiz_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=20, padx=30, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
# 显示题目进度
|
|
|
|
|
progress_info = self.backend_service.get_quiz_progress()
|
|
|
|
|
progress = f"题目 {progress_info['current_index'] + 1}/{progress_info['total_questions']}"
|
|
|
|
|
progress = f"题目 {self.current_quiz.current_question_index + 1}/{len(self.current_quiz.questions)}"
|
|
|
|
|
progress_frame = tk.Frame(main_frame, bg=self.primary_color)
|
|
|
|
|
progress_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(progress_frame, text=progress, font=self.header_font,
|
|
|
|
|
bg=self.primary_color, fg="white").pack(pady=10)
|
|
|
|
|
tk.Label(progress_frame, text=progress, font=self.header_font, bg=self.primary_color, fg="white").pack(pady=10)
|
|
|
|
|
|
|
|
|
|
# 显示题目
|
|
|
|
|
question_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
question_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(question_frame, text="题目:", font=self.header_font,
|
|
|
|
|
bg="#ffffff").pack(pady=(10, 5))
|
|
|
|
|
tk.Label(question_frame, text="题目:", font=self.header_font, bg="#ffffff").pack(pady=(10, 5))
|
|
|
|
|
question_text = str(current_question)
|
|
|
|
|
tk.Label(question_frame, text=question_text,
|
|
|
|
|
font=("Arial", 16, "bold"), bg="#ffffff",
|
|
|
|
|
wraplength=500).pack(
|
|
|
|
|
tk.Label(question_frame, text=question_text, font=("Arial", 16, "bold"), bg="#ffffff", wraplength=500).pack(
|
|
|
|
|
pady=10)
|
|
|
|
|
|
|
|
|
|
# 获取固定选项
|
|
|
|
|
options = self.backend_service.get_current_options()
|
|
|
|
|
options = self.current_quiz.get_current_options()
|
|
|
|
|
|
|
|
|
|
# 显示选项
|
|
|
|
|
tk.Label(main_frame, text="请选择答案:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=(20, 10))
|
|
|
|
|
tk.Label(main_frame, text="请选择答案:", font=self.normal_font, bg="#ffffff").pack(pady=(20, 10))
|
|
|
|
|
|
|
|
|
|
self.answer_var = tk.StringVar()
|
|
|
|
|
# 设置默认选项为用户之前的选择(如果有)
|
|
|
|
|
current_answer = progress_info['current_answer']
|
|
|
|
|
current_answer = self.current_quiz.answers[self.current_quiz.current_question_index]
|
|
|
|
|
# print(current_answer)
|
|
|
|
|
# print(self.current_quiz.current_question_index)
|
|
|
|
|
# print(self.current_quiz.answers[:5]) 调试功能
|
|
|
|
|
if current_answer is not None:
|
|
|
|
|
self.answer_var.set(current_answer)
|
|
|
|
|
else:
|
|
|
|
|
@ -547,50 +479,84 @@ class MathQuizApp:
|
|
|
|
|
options_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
for i, option in enumerate(options):
|
|
|
|
|
tk.Radiobutton(options_frame,
|
|
|
|
|
text=f"{['A', 'B', 'C', 'D'][i]}. {option}",
|
|
|
|
|
variable=self.answer_var, value=option,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
bg="#ffffff", selectcolor="#e0e0e0",
|
|
|
|
|
activebackground="#f0f0f0").pack(
|
|
|
|
|
anchor="w", padx=50, pady=5)
|
|
|
|
|
tk.Radiobutton(options_frame, text=f"{['A', 'B', 'C', 'D'][i]}. {option}",
|
|
|
|
|
variable=self.answer_var, value=option, font=self.normal_font,
|
|
|
|
|
bg="#ffffff", selectcolor="#e0e0e0", activebackground="#f0f0f0").pack(anchor="w", padx=50,
|
|
|
|
|
pady=5)
|
|
|
|
|
|
|
|
|
|
# 按钮框架
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
if progress_info['current_index'] > 0:
|
|
|
|
|
tk.Button(button_frame, text="上一题",
|
|
|
|
|
command=self.previous_question, bg="#cccccc",
|
|
|
|
|
fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
if self.current_quiz.current_question_index > 0:
|
|
|
|
|
tk.Button(button_frame, text="上一题", command=self.previous_question, bg="#cccccc", fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="提交答案", command=self.submit_answer,
|
|
|
|
|
bg=self.success_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
if progress_info['current_index'] < progress_info['total_questions'] - 1:
|
|
|
|
|
tk.Button(button_frame, text="下一题",
|
|
|
|
|
command=self.next_question, bg=self.primary_color,
|
|
|
|
|
fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
tk.Button(main_frame, text="返回主菜单",
|
|
|
|
|
command=self.show_main_menu_frame, width=15,
|
|
|
|
|
bg=self.danger_color,
|
|
|
|
|
tk.Button(button_frame, text="提交答案", command=self.submit_answer, bg=self.success_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
if self.current_quiz.current_question_index < len(self.current_quiz.questions) - 1:
|
|
|
|
|
tk.Button(button_frame, text="下一题", command=self.next_question, bg=self.primary_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
tk.Button(main_frame, text="返回主菜单", command=self.show_main_menu_frame, width=15, bg=self.danger_color,
|
|
|
|
|
fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=10)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=10)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.quiz_frame)
|
|
|
|
|
|
|
|
|
|
def generate_options(self, correct_answer) -> List[float]:
|
|
|
|
|
"""
|
|
|
|
|
为题目生成选项
|
|
|
|
|
|
|
|
|
|
@param correct_answer: 正确答案
|
|
|
|
|
@return: 选项列表
|
|
|
|
|
"""
|
|
|
|
|
# 生成4个选项,其中一个是正确答案
|
|
|
|
|
options = {correct_answer}
|
|
|
|
|
|
|
|
|
|
# 添加一些干扰项
|
|
|
|
|
if isinstance(correct_answer, int):
|
|
|
|
|
while len(options) < 4:
|
|
|
|
|
# 生成不同长度的干扰项,避免正确答案总是最长的
|
|
|
|
|
if random.random() < 0.5:
|
|
|
|
|
# 生成1-2位数的干扰项
|
|
|
|
|
options.add(random.randint(0, 99))
|
|
|
|
|
else:
|
|
|
|
|
# 生成2-3位数的干扰项
|
|
|
|
|
options.add(random.randint(10, 999))
|
|
|
|
|
else:
|
|
|
|
|
# 浮点数情况
|
|
|
|
|
while len(options) < 4:
|
|
|
|
|
# 随机生成不同长度的浮点数选项
|
|
|
|
|
if random.random() < 0.33:
|
|
|
|
|
# 生成1位小数的数
|
|
|
|
|
options.add(round(random.uniform(0, 100), 1))
|
|
|
|
|
elif random.random() < 0.66:
|
|
|
|
|
# 生成2位小数的数
|
|
|
|
|
options.add(round(random.uniform(0, 100), 2))
|
|
|
|
|
else:
|
|
|
|
|
# 生成整数
|
|
|
|
|
options.add(random.randint(0, 100))
|
|
|
|
|
|
|
|
|
|
# 如果选项不足4个,补充一些随机数
|
|
|
|
|
while len(options) < 4:
|
|
|
|
|
if random.random() < 0.5:
|
|
|
|
|
options.add(random.randint(0, 100))
|
|
|
|
|
else:
|
|
|
|
|
options.add(round(random.uniform(0, 100), random.choice([0, 1, 2])))
|
|
|
|
|
|
|
|
|
|
options_list = list(options)
|
|
|
|
|
random.shuffle(options_list)
|
|
|
|
|
return options_list[:4]
|
|
|
|
|
|
|
|
|
|
def submit_answer(self):
|
|
|
|
|
"""
|
|
|
|
|
提交答案
|
|
|
|
|
"""
|
|
|
|
|
if not self.current_quiz:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
answer_str = self.answer_var.get()
|
|
|
|
|
if not answer_str: # 检查字符串是否为空
|
|
|
|
|
messagebox.showerror("错误", "请选择一个答案")
|
|
|
|
|
@ -599,12 +565,10 @@ class MathQuizApp:
|
|
|
|
|
try:
|
|
|
|
|
# 验证答案是否为有效数字
|
|
|
|
|
float(answer_str)
|
|
|
|
|
if not self.backend_service.answer_question(answer_str):
|
|
|
|
|
messagebox.showerror("错误", "提交答案失败")
|
|
|
|
|
return
|
|
|
|
|
self.current_quiz.answer_question(answer_str)
|
|
|
|
|
|
|
|
|
|
# 如果是最后一题,显示结果
|
|
|
|
|
if self.backend_service.is_quiz_finished():
|
|
|
|
|
if self.current_quiz.is_finished():
|
|
|
|
|
self.show_result_frame()
|
|
|
|
|
else:
|
|
|
|
|
messagebox.showinfo("提示", "答案已提交")
|
|
|
|
|
@ -615,22 +579,24 @@ class MathQuizApp:
|
|
|
|
|
"""
|
|
|
|
|
下一题
|
|
|
|
|
"""
|
|
|
|
|
if not self.current_quiz:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 保存当前答案(如果有选择)
|
|
|
|
|
answer_str = self.answer_var.get()
|
|
|
|
|
if answer_str: # 检查字符串是否非空
|
|
|
|
|
try:
|
|
|
|
|
# 验证答案是否为有效数字
|
|
|
|
|
float(answer_str)
|
|
|
|
|
self.backend_service.answer_question(answer_str)
|
|
|
|
|
self.current_quiz.answer_question(answer_str)
|
|
|
|
|
except ValueError:
|
|
|
|
|
pass # 如果答案无效,保持为None
|
|
|
|
|
|
|
|
|
|
if self.backend_service.next_question():
|
|
|
|
|
if self.current_quiz.next_question():
|
|
|
|
|
self.show_quiz_frame()
|
|
|
|
|
else:
|
|
|
|
|
# 已经是最后一题
|
|
|
|
|
progress_info = self.backend_service.get_quiz_progress()
|
|
|
|
|
if progress_info['current_answer'] is not None:
|
|
|
|
|
if self.current_quiz.answers[self.current_quiz.current_question_index] is not None:
|
|
|
|
|
# 如果最后一题已答题,显示结果
|
|
|
|
|
self.show_result_frame()
|
|
|
|
|
else:
|
|
|
|
|
@ -640,66 +606,83 @@ class MathQuizApp:
|
|
|
|
|
"""
|
|
|
|
|
上一题
|
|
|
|
|
"""
|
|
|
|
|
if not self.current_quiz:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 保存当前答案(如果有选择)
|
|
|
|
|
answer_str = self.answer_var.get()
|
|
|
|
|
if answer_str: # 检查字符串是否非空
|
|
|
|
|
try:
|
|
|
|
|
# 验证答案是否为有效数字
|
|
|
|
|
float(answer_str)
|
|
|
|
|
self.backend_service.answer_question(answer_str)
|
|
|
|
|
self.current_quiz.answer_question(answer_str)
|
|
|
|
|
except ValueError:
|
|
|
|
|
pass # 如果答案无效,保持为None
|
|
|
|
|
|
|
|
|
|
if self.backend_service.previous_question():
|
|
|
|
|
if self.current_quiz.previous_question():
|
|
|
|
|
self.show_quiz_frame()
|
|
|
|
|
|
|
|
|
|
def show_result_frame(self):
|
|
|
|
|
"""
|
|
|
|
|
显示结果界面
|
|
|
|
|
"""
|
|
|
|
|
if not self.current_quiz:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 清除之前的内容
|
|
|
|
|
for widget in self.result_frame.winfo_children():
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 计算得分
|
|
|
|
|
score = self.backend_service.calculate_score()
|
|
|
|
|
grade_info = self.backend_service.get_score_grade(score)
|
|
|
|
|
score = self.current_quiz.calculate_score()
|
|
|
|
|
|
|
|
|
|
# 创建结果界面
|
|
|
|
|
main_frame = tk.Frame(self.result_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.result_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=30, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=self.primary_color)
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(title_frame, text="测验结果", font=self.title_font,
|
|
|
|
|
bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
tk.Label(title_frame, text="测验结果", font=self.title_font, bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
result_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
result_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
# 根据后端返回的颜色标识获取对应颜色
|
|
|
|
|
color_map = {
|
|
|
|
|
"success": self.success_color,
|
|
|
|
|
"warning": self.warning_color,
|
|
|
|
|
"danger": self.danger_color
|
|
|
|
|
}
|
|
|
|
|
score_color = color_map.get(grade_info["color"], self.dark_text)
|
|
|
|
|
# 根据得分显示不同颜色的分数
|
|
|
|
|
score_color = self.danger_color if score < 60 else self.warning_color if score < 80 else self.success_color
|
|
|
|
|
|
|
|
|
|
tk.Label(result_frame, text=f"您的得分: {score:.1f}%",
|
|
|
|
|
font=("Arial", 20, "bold"), fg=score_color,
|
|
|
|
|
tk.Label(result_frame, text=f"您的得分: {score:.1f}%", font=("Arial", 20, "bold"), fg=score_color,
|
|
|
|
|
bg="#ffffff").pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(result_frame, text=grade_info["comment"], font=self.header_font,
|
|
|
|
|
fg=score_color, bg="#ffffff").pack(pady=10)
|
|
|
|
|
# 根据得分显示评语
|
|
|
|
|
if score >= 90:
|
|
|
|
|
comment = "优秀! 继续保持!"
|
|
|
|
|
comment_color = self.success_color
|
|
|
|
|
elif score >= 80:
|
|
|
|
|
comment = "良好! 还可以做得更好!"
|
|
|
|
|
comment_color = self.success_color
|
|
|
|
|
elif score >= 60:
|
|
|
|
|
comment = "及格了,需要继续努力!"
|
|
|
|
|
comment_color = self.warning_color
|
|
|
|
|
else:
|
|
|
|
|
comment = "需要加强练习哦!"
|
|
|
|
|
comment_color = self.danger_color
|
|
|
|
|
|
|
|
|
|
tk.Label(result_frame, text=comment, font=self.header_font, fg=comment_color, bg="#ffffff").pack(pady=10)
|
|
|
|
|
|
|
|
|
|
# 显示答题详情
|
|
|
|
|
result_details = self.backend_service.get_quiz_result_details()
|
|
|
|
|
correct_count = result_details.get("correct_count", 0)
|
|
|
|
|
total_count = result_details.get("total_count", 0)
|
|
|
|
|
correct_count = 0
|
|
|
|
|
for q, a in zip(self.current_quiz.questions, self.current_quiz.answers):
|
|
|
|
|
if a is not None:
|
|
|
|
|
try:
|
|
|
|
|
# 将字符串答案转换为浮点数进行比较
|
|
|
|
|
if abs(q.answer - float(a)) < 1e-6:
|
|
|
|
|
correct_count += 1
|
|
|
|
|
except ValueError:
|
|
|
|
|
# 如果转换失败,说明答案无效,不计入正确答案
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
tk.Label(result_frame, text=f"答对: {correct_count}/{total_count}",
|
|
|
|
|
font=self.normal_font, bg="#ffffff").pack(
|
|
|
|
|
total_count = len(self.current_quiz.questions)
|
|
|
|
|
tk.Label(result_frame, text=f"答对: {correct_count}/{total_count}", font=self.normal_font, bg="#ffffff").pack(
|
|
|
|
|
pady=5)
|
|
|
|
|
|
|
|
|
|
# 按钮
|
|
|
|
|
@ -707,19 +690,14 @@ class MathQuizApp:
|
|
|
|
|
button_frame.pack(pady=30)
|
|
|
|
|
|
|
|
|
|
level_names = {"elementary": "小学", "middle": "初中", "high": "高中"}
|
|
|
|
|
tk.Button(button_frame,
|
|
|
|
|
text=f"继续{level_names[self.current_level]}题目",
|
|
|
|
|
command=lambda: self.show_quiz_setup_frame(
|
|
|
|
|
self.current_level), width=20, bg=self.primary_color,
|
|
|
|
|
tk.Button(button_frame, text=f"继续{level_names[self.current_level]}题目",
|
|
|
|
|
command=lambda: self.show_quiz_setup_frame(self.current_level), width=20, bg=self.primary_color,
|
|
|
|
|
fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="返回主菜单",
|
|
|
|
|
command=self.show_main_menu_frame, width=15, bg="#cccccc",
|
|
|
|
|
tk.Button(button_frame, text="返回主菜单", command=self.show_main_menu_frame, width=15, bg="#cccccc",
|
|
|
|
|
fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.result_frame)
|
|
|
|
|
|
|
|
|
|
@ -732,60 +710,43 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建修改密码界面
|
|
|
|
|
main_frame = tk.Frame(self.change_password_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.change_password_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=30, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=self.primary_color)
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(title_frame, text="修改密码", font=self.title_font,
|
|
|
|
|
bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
tk.Label(title_frame, text="修改密码", font=self.title_font, bg=self.primary_color, fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
form_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
form_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="原密码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.old_password_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
show="*", relief=tk.FLAT, bd=5,
|
|
|
|
|
tk.Label(form_frame, text="原密码:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.old_password_entry = tk.Entry(form_frame, width=30, font=self.normal_font, show="*", relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.old_password_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="新密码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff", fg=self.primary_color).pack(
|
|
|
|
|
tk.Label(form_frame, text="新密码:", font=self.normal_font, bg="#ffffff", fg=self.primary_color).pack(
|
|
|
|
|
pady=(10, 5), anchor="w")
|
|
|
|
|
tk.Label(form_frame, text="(6-10位,必须包含大小写字母和数字)",
|
|
|
|
|
font=("Arial", 10), bg="#ffffff",
|
|
|
|
|
tk.Label(form_frame, text="(6-10位,必须包含大小写字母和数字)", font=("Arial", 10), bg="#ffffff",
|
|
|
|
|
fg="gray").pack(pady=5, anchor="w")
|
|
|
|
|
self.new_password_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
show="*", relief=tk.FLAT, bd=5,
|
|
|
|
|
self.new_password_entry = tk.Entry(form_frame, width=30, font=self.normal_font, show="*", relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.new_password_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="确认新密码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.confirm_new_password_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
show="*",
|
|
|
|
|
relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
tk.Label(form_frame, text="确认新密码:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.confirm_new_password_entry = tk.Entry(form_frame, width=30, font=self.normal_font, show="*",
|
|
|
|
|
relief=tk.FLAT, bd=5, bg="#f0f0f0")
|
|
|
|
|
self.confirm_new_password_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="修改密码", command=self.change_password,
|
|
|
|
|
width=20, bg=self.success_color,
|
|
|
|
|
tk.Button(button_frame, text="修改密码", command=self.change_password, width=20, bg=self.success_color,
|
|
|
|
|
fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回主菜单",
|
|
|
|
|
command=self.show_main_menu_frame, width=20, bg="#cccccc",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=10)
|
|
|
|
|
tk.Button(button_frame, text="返回主菜单", command=self.show_main_menu_frame, width=20, bg="#cccccc",
|
|
|
|
|
fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10, pady=5).pack(pady=5)
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0, padx=10, pady=5).pack(pady=5)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.change_password_frame)
|
|
|
|
|
|
|
|
|
|
@ -805,16 +766,16 @@ class MathQuizApp:
|
|
|
|
|
messagebox.showerror("错误", "新密码和确认密码不一致")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if self.backend_service.change_password(old_password, new_password):
|
|
|
|
|
if self.user_manager.change_password(old_password, new_password):
|
|
|
|
|
messagebox.showinfo("成功", "密码修改成功")
|
|
|
|
|
self.show_main_menu_frame()
|
|
|
|
|
# 错误信息在backend_service.change_password中已经显示
|
|
|
|
|
# 错误信息在user_manager.change_password中已经显示
|
|
|
|
|
|
|
|
|
|
def logout(self):
|
|
|
|
|
"""
|
|
|
|
|
退出登录
|
|
|
|
|
"""
|
|
|
|
|
self.backend_service.logout()
|
|
|
|
|
self.user_manager.logout()
|
|
|
|
|
self.show_login_frame()
|
|
|
|
|
|
|
|
|
|
def show_delete_account_frame(self):
|
|
|
|
|
@ -826,42 +787,31 @@ class MathQuizApp:
|
|
|
|
|
widget.destroy()
|
|
|
|
|
|
|
|
|
|
# 创建注销账户界面
|
|
|
|
|
main_frame = tk.Frame(self.delete_account_frame, bg="#ffffff",
|
|
|
|
|
relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame = tk.Frame(self.delete_account_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
|
|
|
|
|
main_frame.pack(pady=30, padx=50, fill="both", expand=True)
|
|
|
|
|
|
|
|
|
|
title_frame = tk.Frame(main_frame, bg=self.danger_color)
|
|
|
|
|
title_frame.pack(fill="x", pady=(0, 20))
|
|
|
|
|
tk.Label(title_frame, text="注销账户", font=self.title_font,
|
|
|
|
|
bg=self.danger_color, fg="white").pack(pady=20)
|
|
|
|
|
tk.Label(title_frame, text="注销账户", font=self.title_font, bg=self.danger_color, fg="white").pack(pady=20)
|
|
|
|
|
|
|
|
|
|
warning_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
warning_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(warning_frame,
|
|
|
|
|
text="警告:此操作将永久删除您的账户和所有数据!",
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
tk.Label(warning_frame, text="警告:此操作将永久删除您的账户和所有数据!", font=self.normal_font,
|
|
|
|
|
fg=self.danger_color, bg="#ffffff").pack(pady=5)
|
|
|
|
|
tk.Label(warning_frame, text="请确认您的邮箱和密码:",
|
|
|
|
|
font=self.normal_font, fg=self.danger_color,
|
|
|
|
|
tk.Label(warning_frame, text="请确认您的邮箱和密码:", font=self.normal_font, fg=self.danger_color,
|
|
|
|
|
bg="#ffffff").pack(pady=5)
|
|
|
|
|
|
|
|
|
|
form_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
form_frame.pack(pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="邮箱:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=10, anchor="w")
|
|
|
|
|
self.delete_email_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
relief=tk.FLAT, bd=5,
|
|
|
|
|
tk.Label(form_frame, text="邮箱:", font=self.normal_font, bg="#ffffff").pack(pady=10, anchor="w")
|
|
|
|
|
self.delete_email_entry = tk.Entry(form_frame, width=30, font=self.normal_font, relief=tk.FLAT, bd=5,
|
|
|
|
|
bg="#f0f0f0")
|
|
|
|
|
self.delete_email_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
tk.Label(form_frame, text="密码:", font=self.normal_font,
|
|
|
|
|
bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.delete_password_entry = tk.Entry(form_frame, width=30,
|
|
|
|
|
font=self.normal_font,
|
|
|
|
|
show="*", relief=tk.FLAT,
|
|
|
|
|
tk.Label(form_frame, text="密码:", font=self.normal_font, bg="#ffffff").pack(pady=5, anchor="w")
|
|
|
|
|
self.delete_password_entry = tk.Entry(form_frame, width=30, font=self.normal_font, show="*", relief=tk.FLAT,
|
|
|
|
|
bd=5, bg="#f0f0f0")
|
|
|
|
|
self.delete_password_entry.pack(pady=5)
|
|
|
|
|
|
|
|
|
|
@ -869,16 +819,11 @@ class MathQuizApp:
|
|
|
|
|
button_frame = tk.Frame(main_frame, bg="#ffffff")
|
|
|
|
|
button_frame.pack(pady=20)
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="确认注销",
|
|
|
|
|
command=self.confirm_delete_account,
|
|
|
|
|
width=15, bg=self.danger_color, fg="white",
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10,
|
|
|
|
|
tk.Button(button_frame, text="确认注销", command=self.confirm_delete_account,
|
|
|
|
|
width=15, bg=self.danger_color, fg="white", font=self.button_font, relief=tk.FLAT, bd=0, padx=10,
|
|
|
|
|
pady=5).pack(side="left", padx=10)
|
|
|
|
|
tk.Button(button_frame, text="取消", command=self.show_login_frame,
|
|
|
|
|
width=15, bg="#cccccc", fg=self.dark_text,
|
|
|
|
|
font=self.button_font, relief=tk.FLAT, bd=0,
|
|
|
|
|
padx=10,
|
|
|
|
|
width=15, bg="#cccccc", fg=self.dark_text, font=self.button_font, relief=tk.FLAT, bd=0, padx=10,
|
|
|
|
|
pady=5).pack(side="left", padx=10)
|
|
|
|
|
|
|
|
|
|
self.show_frame(self.delete_account_frame)
|
|
|
|
|
@ -896,14 +841,15 @@ class MathQuizApp:
|
|
|
|
|
|
|
|
|
|
# 确认操作
|
|
|
|
|
if messagebox.askyesno("确认注销", "确定要注销账户吗?此操作无法撤销!"):
|
|
|
|
|
if self.backend_service.delete_account(email, password):
|
|
|
|
|
messagebox.showinfo("成功",
|
|
|
|
|
"账户已注销,您可以使用该邮箱重新注册")
|
|
|
|
|
if self.user_manager.delete_account(email, password):
|
|
|
|
|
messagebox.showinfo("成功", "账户已注销,您可以使用该邮箱重新注册")
|
|
|
|
|
self.show_login_frame()
|
|
|
|
|
# 错误信息在backend_service.delete_account中已经显示
|
|
|
|
|
# 错误信息在user_manager.delete_account中已经显示
|
|
|
|
|
|
|
|
|
|
def delete_account(self):
|
|
|
|
|
"""
|
|
|
|
|
注销账户(从主菜单调用的旧方法,保持兼容性)
|
|
|
|
|
"""
|
|
|
|
|
self.show_delete_account_frame()
|
|
|
|
|
self.show_delete_account_frame()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|