"""
图形界面版学生成绩分析系统
功能：成绩管理、走势图、时间筛选、基本统计
"""

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
import os
import json
import warnings
import statistics
import tkinter as tk
from tkinter import ttk, messagebox, filedialog, scrolledtext
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib
warnings.filterwarnings('ignore')

# 设置中文字体
try:
    matplotlib.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'DejaVu Sans', 'Microsoft YaHei']
    matplotlib.rcParams['axes.unicode_minus'] = False
except:
    pass

class ScoreAnalysis:
    def __init__(self):
        """初始化成绩分析系统"""
        self.data_file = "scores_data.json"
        self.init_default_settings()
        self.data = self.load_data()
        self.course_colors = {
            "语文": "#FF6B6B", "数学": "#4ECDC4", "英语": "#45B7D1",
            "物理": "#96CEB4", "化学": "#FFEAA7", "生物": "#DDA0DD",
            "历史": "#FFB347", "地理": "#77DD77", "政治": "#AEC6CF"
        }
        
    def init_default_settings(self):
        """初始化默认设置"""
        self.exam_types = {
            "daily": "日常测验",
            "quiz": "小测验", 
            "monthly": "月考",
            "midterm": "期中考试",
            "final": "期末考试"
        }
        
    def load_data(self):
        """加载已有数据或创建新数据结构"""
        if os.path.exists(self.data_file):
            try:
                with open(self.data_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except Exception as e:
                print(f"加载数据失败: {e}，创建新数据文件")
                return self.create_empty_data_structure()
        else:
            return self.create_empty_data_structure()
    
    def create_empty_data_structure(self):
        """创建空数据结构"""
        return {
            "students": {},
            "courses": [],
            "exams": [],
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
    
    def save_data(self):
        """保存数据到文件"""
        try:
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(self.data, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"保存数据失败: {e}")
            return False
    
    def get_course_color(self, course_name):
        """获取课程颜色"""
        return self.course_colors.get(course_name, "#888888")
    
    def get_exam_date(self, exam_name):
        """获取考试日期"""
        for exam in self.data["exams"]:
            if exam["name"] == exam_name and "date" in exam:
                try:
                    return datetime.strptime(exam["date"], "%Y-%m-%d")
                except:
                    pass
        return datetime.now()
    
    def validate_score(self, score):
        """验证分数有效性"""
        try:
            score_float = float(score)
            if 0 <= score_float <= 100:
                return score_float
            else:
                return None
        except ValueError:
            return None
    
    def validate_date(self, date_str):
        """验证日期格式"""
        try:
            datetime.strptime(date_str, "%Y-%m-%d")
            return True
        except ValueError:
            return False
    
    def get_time_filtered_exams(self, start_date=None, end_date=None):
        """获取时间筛选后的考试"""
        filtered_exams = []
        
        for exam in self.data["exams"]:
            if "date" not in exam:
                continue
                
            exam_date = datetime.strptime(exam["date"], "%Y-%m-%d")
            
            # 时间筛选
            if start_date and exam_date < datetime.strptime(start_date, "%Y-%m-%d"):
                continue
            if end_date and exam_date > datetime.strptime(end_date, "%Y-%m-%d"):
                continue
                
            filtered_exams.append(exam)
        
        return sorted(filtered_exams, key=lambda x: x["date"])
    
    def get_student_scores_by_time(self, student_name, start_date=None, end_date=None):
        """获取学生指定时间范围内的成绩"""
        if student_name not in self.data["students"]:
            return {}
        
        student_scores = self.data["students"][student_name]["scores"]
        filtered_scores = {}
        
        exams = self.get_time_filtered_exams(start_date, end_date)
        for exam in exams:
            exam_name = exam["name"]
            if exam_name in student_scores:
                filtered_scores[exam_name] = student_scores[exam_name]
        
        return filtered_scores
    
    def analyze_score_trend(self, scores_list):
        """分析成绩趋势"""
        if len(scores_list) < 2:
            return {"trend": "stable", "description": "数据不足"}
        
        # 简单趋势分析
        first = scores_list[0]
        last = scores_list[-1]
        avg = statistics.mean(scores_list)
        
        if last - first > 10:
            trend = "sharp_up"
            description = "快速上升"
        elif last - first > 5:
            trend = "up"
            description = "上升"
        elif last - first < -10:
            trend = "sharp_down"
            description = "快速下降"
        elif last - first < -5:
            trend = "down"
            description = "下降"
        else:
            trend = "stable"
            description = "稳定"
        
        return {
            "trend": trend,
            "description": description,
            "first_score": first,
            "last_score": last,
            "average": avg,
            "improvement": last - first
        }
    
    def get_score_distribution(self, scores):
        """获取成绩分布"""
        if not scores:
            return {}
            
        bins = [0, 60, 70, 80, 90, 100]
        labels = ['不及格', '及格', '中等', '良好', '优秀']
        distribution = {label: 0 for label in labels}
        
        for score in scores:
            for i, (low, high) in enumerate(zip(bins[:-1], bins[1:])):
                if low <= score <= high:
                    distribution[labels[i]] += 1
                    break
        
        total = len(scores)
        return {
            "count": distribution,
            "percentage": {k: (v/total*100) for k, v in distribution.items()},
            "total": total
        }
    
    def generate_progress_report(self, student_name, start_date=None, end_date=None):
        """生成学生进步报告"""
        if student_name not in self.data["students"]:
            return None
        
        scores = self.get_student_scores_by_time(student_name, start_date, end_date)
        if not scores:
            return None
        
        student_info = self.data["students"][student_name]
        
        # 收集所有成绩
        all_scores = []
        for exam_scores in scores.values():
            all_scores.extend(exam_scores.values())
        
        # 收集各科目成绩
        all_courses = set()
        for exam_scores in scores.values():
            all_courses.update(exam_scores.keys())
        
        course_analysis = {}
        for course in all_courses:
            course_scores = []
            for exam_scores in scores.values():
                if course in exam_scores:
                    course_scores.append(exam_scores[course])
            
            if course_scores:
                trend = self.analyze_score_trend(course_scores)
                distribution = self.get_score_distribution(course_scores)
                
                course_analysis[course] = {
                    "average": statistics.mean(course_scores),
                    "highest": max(course_scores),
                    "lowest": min(course_scores),
                    "trend": trend,
                    "distribution": distribution
                }
        
        # 生成报告
        report = {
            "student_info": {
                "name": student_name,
                "id": student_info.get("id", ""),
                "class": student_info.get("class", "")
            },
            "time_range": {
                "start_date": start_date,
                "end_date": end_date
            },
            "summary": {
                "total_exams": len(scores),
                "total_scores": len(all_scores),
                "average_score": statistics.mean(all_scores) if all_scores else 0,
                "highest_score": max(all_scores) if all_scores else 0,
                "lowest_score": min(all_scores) if all_scores else 0,
                "distribution": self.get_score_distribution(all_scores)
            },
            "course_analysis": course_analysis
        }
        
        return report
    
    def add_student(self, name, student_id, student_class=""):
        """添加学生"""
        if name in self.data["students"]:
            return False, "学生已存在！"
        
        self.data["students"][name] = {
            "id": student_id,
            "class": student_class,
            "scores": {},
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        
        if self.save_data():
            return True, f"学生 {name} 添加成功！"
        else:
            return False, "保存数据失败！"
    
    def add_course(self, course_name):
        """添加课程"""
        if course_name in self.data["courses"]:
            return False, "课程已存在！"
        
        self.data["courses"].append(course_name)
        
        if self.save_data():
            return True, f"课程 {course_name} 添加成功！"
        else:
            return False, "保存数据失败！"
    
    def add_exam(self, exam_name, exam_date, exam_type="月考"):
        """添加考试"""
        for exam in self.data["exams"]:
            if exam["name"] == exam_name:
                return False, "考试已存在！"
        
        if not self.validate_date(exam_date):
            return False, "日期格式无效！"
        
        self.data["exams"].append({
            "name": exam_name,
            "date": exam_date,
            "type": exam_type,
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        })
        
        if self.save_data():
            return True, f"考试 {exam_name} 添加成功！"
        else:
            return False, "保存数据失败！"
    
    def add_score(self, student_name, exam_name, course_name, score):
        """添加成绩"""
        if student_name not in self.data["students"]:
            return False, "学生不存在！"
        
        # 验证考试是否存在
        exam_exists = False
        for exam in self.data["exams"]:
            if exam["name"] == exam_name:
                exam_exists = True
                break
        
        if not exam_exists:
            return False, "考试不存在！"
        
        validated_score = self.validate_score(score)
        if validated_score is None:
            return False, "分数无效！必须在0-100之间。"
        
        # 添加成绩
        if exam_name not in self.data["students"][student_name]["scores"]:
            self.data["students"][student_name]["scores"][exam_name] = {}
        
        self.data["students"][student_name]["scores"][exam_name][course_name] = validated_score
        
        if self.save_data():
            return True, f"成绩添加成功：{student_name} 的 {course_name} 成绩为 {validated_score}"
        else:
            return False, "保存数据失败！"
    
    def get_students_list(self):
        """获取学生列表"""
        return list(self.data["students"].keys())
    
    def get_exams_list(self):
        """获取考试列表"""
        return [exam["name"] for exam in self.data["exams"]]
    
    def get_courses_list(self):
        """获取课程列表"""
        return self.data["courses"]

class ScoreAnalysisGUI:
    def __init__(self, root):
        """初始化GUI界面"""
        self.root = root
        self.root.title("学生成绩分析系统")
        self.root.geometry("1200x800")
        
        # 初始化分析系统
        self.system = ScoreAnalysis()
        
        # 设置样式
        self.setup_styles()
        
        # 创建主界面
        self.create_main_interface()
        
        # 加载数据
        self.load_initial_data()
    
    def setup_styles(self):
        """设置界面样式"""
        style = ttk.Style()
        style.theme_use('clam')
        
        # 自定义颜色
        self.bg_color = "#f0f0f0"
        self.button_color = "#4A90E2"
        self.text_bg = "#ffffff"
        
        self.root.configure(bg=self.bg_color)
    
    def create_main_interface(self):
        """创建主界面"""
        # 创建顶部框架
        top_frame = tk.Frame(self.root, bg=self.bg_color)
        top_frame.pack(fill=tk.X, padx=20, pady=10)
        
        # 标题
        title_label = tk.Label(top_frame, text="学生成绩分析系统", 
                             font=("Arial", 24, "bold"), 
                             bg=self.bg_color, fg="#2c3e50")
        title_label.pack(side=tk.LEFT)
        
        # 状态标签
        self.status_label = tk.Label(top_frame, text="就绪", 
                                   font=("Arial", 10), 
                                   bg=self.bg_color, fg="#7f8c8d")
        self.status_label.pack(side=tk.RIGHT)
        
        # 创建主框架
        main_frame = tk.Frame(self.root, bg=self.bg_color)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
        
        # 左侧控制面板
        control_frame = tk.LabelFrame(main_frame, text="功能控制", 
                                    font=("Arial", 12, "bold"),
                                    bg=self.bg_color, padx=10, pady=10)
        control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))
        
        # 右侧显示区域
        display_frame = tk.Frame(main_frame, bg=self.bg_color)
        display_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        
        # 创建控制按钮
        self.create_control_buttons(control_frame)
        
        # 创建显示区域
        self.create_display_area(display_frame)
    
    def create_control_buttons(self, parent):
        """创建控制按钮"""
        button_config = {
            "font": ("Arial", 10),
            "bg": self.button_color,
            "fg": "white",
            "activebackground": "#357ae8",
            "activeforeground": "white",
            "relief": tk.RAISED,
            "bd": 2,
            "padx": 20,
            "pady": 10,
            "width": 20
        }
        
        # 学生管理
        student_frame = tk.Frame(parent, bg=self.bg_color)
        student_frame.pack(fill=tk.X, pady=5)
        
        tk.Button(student_frame, text="添加学生", command=self.show_add_student_window, **button_config).pack(fill=tk.X)
        tk.Button(student_frame, text="查看学生列表", command=self.show_students_list, **button_config).pack(fill=tk.X, pady=5)
        
        # 课程管理
        course_frame = tk.Frame(parent, bg=self.bg_color)
        course_frame.pack(fill=tk.X, pady=5)
        
        tk.Button(course_frame, text="添加课程", command=self.show_add_course_window, **button_config).pack(fill=tk.X)
        tk.Button(course_frame, text="查看课程列表", command=self.show_courses_list, **button_config).pack(fill=tk.X, pady=5)
        
        # 考试管理
        exam_frame = tk.Frame(parent, bg=self.bg_color)
        exam_frame.pack(fill=tk.X, pady=5)
        
        tk.Button(exam_frame, text="添加考试", command=self.show_add_exam_window, **button_config).pack(fill=tk.X)
        tk.Button(exam_frame, text="查看考试列表", command=self.show_exams_list, **button_config).pack(fill=tk.X, pady=5)
        
        # 成绩管理
        score_frame = tk.Frame(parent, bg=self.bg_color)
        score_frame.pack(fill=tk.X, pady=5)
        
        tk.Button(score_frame, text="录入成绩", command=self.show_add_score_window, **button_config).pack(fill=tk.X)
        tk.Button(score_frame, text="查看成绩走势图", command=self.show_plot_window, **button_config).pack(fill=tk.X, pady=5)
        tk.Button(score_frame, text="生成进步报告", command=self.show_report_window, **button_config).pack(fill=tk.X)
        
        # 系统功能
        system_frame = tk.Frame(parent, bg=self.bg_color)
        system_frame.pack(fill=tk.X, pady=5)
        
        tk.Button(system_frame, text="数据统计", command=self.show_statistics, **button_config).pack(fill=tk.X)
        tk.Button(system_frame, text="导出数据", command=self.export_data, **button_config).pack(fill=tk.X, pady=5)
        tk.Button(system_frame, text="关于系统", command=self.show_about, **button_config).pack(fill=tk.X)
    
    def create_display_area(self, parent):
        """创建显示区域"""
        # 创建笔记本（标签页）
        self.notebook = ttk.Notebook(parent)
        self.notebook.pack(fill=tk.BOTH, expand=True)
        
        # 创建文本显示标签页
        self.text_tab = tk.Frame(self.notebook, bg=self.text_bg)
        self.notebook.add(self.text_tab, text="信息显示")
        
        self.text_display = scrolledtext.ScrolledText(self.text_tab, 
                                                     font=("Arial", 10),
                                                     bg=self.text_bg,
                                                     wrap=tk.WORD)
        self.text_display.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建图表显示标签页
        self.plot_tab = tk.Frame(self.notebook, bg=self.text_bg)
        self.notebook.add(self.plot_tab, text="图表显示")
        
        # 初始文本
        self.text_display.insert(tk.END, "欢迎使用学生成绩分析系统！\n")
        self.text_display.insert(tk.END, "="*50 + "\n")
        self.text_display.insert(tk.END, "请使用左侧功能按钮开始操作。\n")
        self.text_display.config(state=tk.DISABLED)
    
    def load_initial_data(self):
        """加载初始数据"""
        if not os.path.exists(self.system.data_file):
            self.add_sample_data()
    
    def add_sample_data(self):
        """添加示例数据"""
        # 添加示例学生
        self.system.add_student("张三", "2023001", "高一(1)班")
        self.system.add_student("李四", "2023002", "高一(1)班")
        
        # 添加示例课程
        for course in ["语文", "数学", "英语", "物理", "化学", "生物"]:
            self.system.add_course(course)
        
        # 添加示例考试
        exams = [
            ("第一次月考", "2023-09-10"),
            ("期中考试", "2023-10-20"),
            ("第二次月考", "2023-11-15"),
            ("期末考试", "2023-12-25")
        ]
        
        for exam_name, exam_date in exams:
            self.system.add_exam(exam_name, exam_date)
        
        # 为张三添加示例成绩
        scores_data = {
            "张三": {
                "第一次月考": {"语文": 85, "数学": 78, "英语": 88, "物理": 82},
                "期中考试": {"语文": 82, "数学": 85, "英语": 85, "物理": 80, "化学": 78},
                "第二次月考": {"语文": 88, "数学": 88, "英语": 90, "物理": 85, "化学": 82},
                "期末考试": {"语文": 90, "数学": 90, "英语": 92, "物理": 88, "化学": 85, "生物": 90}
            }
        }
        
        for student_name, exams_data in scores_data.items():
            for exam_name, courses_data in exams_data.items():
                for course_name, score in courses_data.items():
                    self.system.add_score(student_name, exam_name, course_name, score)
        
        self.update_status("示例数据已初始化完成！")
    
    def update_text_display(self, text, clear=False):
        """更新文本显示区域"""
        self.text_display.config(state=tk.NORMAL)
        if clear:
            self.text_display.delete(1.0, tk.END)
        self.text_display.insert(tk.END, text + "\n")
        self.text_display.see(tk.END)
        self.text_display.config(state=tk.DISABLED)
    
    def update_status(self, message):
        """更新状态栏"""
        self.status_label.config(text=message)
        self.root.update()
    
    def show_add_student_window(self):
        """显示添加学生窗口"""
        window = tk.Toplevel(self.root)
        window.title("添加学生")
        window.geometry("400x300")
        window.configure(bg=self.bg_color)
        
        # 标题
        tk.Label(window, text="添加新学生", font=("Arial", 16, "bold"), 
                bg=self.bg_color).pack(pady=20)
        
        # 表单框架
        form_frame = tk.Frame(window, bg=self.bg_color)
        form_frame.pack(pady=20, padx=40, fill=tk.BOTH)
        
        # 姓名
        tk.Label(form_frame, text="姓名:", bg=self.bg_color, font=("Arial", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        name_entry = tk.Entry(form_frame, font=("Arial", 10), width=30)
        name_entry.grid(row=0, column=1, pady=5, padx=(10, 0))
        
        # 学号
        tk.Label(form_frame, text="学号:", bg=self.bg_color, font=("Arial", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        id_entry = tk.Entry(form_frame, font=("Arial", 10), width=30)
        id_entry.grid(row=1, column=1, pady=5, padx=(10, 0))
        
        # 班级
        tk.Label(form_frame, text="班级:", bg=self.bg_color, font=("Arial", 10)).grid(row=2, column=0, sticky=tk.W, pady=5)
        class_entry = tk.Entry(form_frame, font=("Arial", 10), width=30)
        class_entry.grid(row=2, column=1, pady=5, padx=(10, 0))
        
        def add_student():
            name = name_entry.get().strip()
            student_id = id_entry.get().strip()
            student_class = class_entry.get().strip()
            
            if not name or not student_id:
                messagebox.showerror("错误", "姓名和学号不能为空！")
                return
            
            success, message = self.system.add_student(name, student_id, student_class)
            if success:
                messagebox.showinfo("成功", message)
                self.update_text_display(f"已添加学生: {name} (学号: {student_id}, 班级: {student_class})")
                window.destroy()
            else:
                messagebox.showerror("错误", message)
        
        # 按钮框架
        button_frame = tk.Frame(window, bg=self.bg_color)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="添加", command=add_student, 
                 bg=self.button_color, fg="white", 
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=window.destroy,
                 bg="#95a5a6", fg="white",
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
    
    def show_add_course_window(self):
        """显示添加课程窗口"""
        window = tk.Toplevel(self.root)
        window.title("添加课程")
        window.geometry("400x200")
        window.configure(bg=self.bg_color)
        
        tk.Label(window, text="添加新课程", font=("Arial", 16, "bold"), 
                bg=self.bg_color).pack(pady=20)
        
        form_frame = tk.Frame(window, bg=self.bg_color)
        form_frame.pack(pady=20, padx=40, fill=tk.BOTH)
        
        tk.Label(form_frame, text="课程名称:", bg=self.bg_color, font=("Arial", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        course_entry = tk.Entry(form_frame, font=("Arial", 10), width=30)
        course_entry.grid(row=0, column=1, pady=5, padx=(10, 0))
        
        def add_course():
            course_name = course_entry.get().strip()
            
            if not course_name:
                messagebox.showerror("错误", "课程名称不能为空！")
                return
            
            success, message = self.system.add_course(course_name)
            if success:
                messagebox.showinfo("成功", message)
                self.update_text_display(f"已添加课程: {course_name}")
                window.destroy()
            else:
                messagebox.showerror("错误", message)
        
        button_frame = tk.Frame(window, bg=self.bg_color)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="添加", command=add_course, 
                 bg=self.button_color, fg="white", 
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=window.destroy,
                 bg="#95a5a6", fg="white",
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
    
    def show_add_exam_window(self):
        """显示添加考试窗口"""
        window = tk.Toplevel(self.root)
        window.title("添加考试")
        window.geometry("400x300")
        window.configure(bg=self.bg_color)
        
        tk.Label(window, text="添加新考试", font=("Arial", 16, "bold"), 
                bg=self.bg_color).pack(pady=20)
        
        form_frame = tk.Frame(window, bg=self.bg_color)
        form_frame.pack(pady=20, padx=40, fill=tk.BOTH)
        
        # 考试名称
        tk.Label(form_frame, text="考试名称:", bg=self.bg_color, font=("Arial", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        exam_entry = tk.Entry(form_frame, font=("Arial", 10), width=30)
        exam_entry.grid(row=0, column=1, pady=5, padx=(10, 0))
        
        # 考试日期
        tk.Label(form_frame, text="考试日期:", bg=self.bg_color, font=("Arial", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        date_entry = tk.Entry(form_frame, font=("Arial", 10), width=30)
        date_entry.insert(0, datetime.now().strftime("%Y-%m-%d"))
        date_entry.grid(row=1, column=1, pady=5, padx=(10, 0))
        
        # 考试类型
        tk.Label(form_frame, text="考试类型:", bg=self.bg_color, font=("Arial", 10)).grid(row=2, column=0, sticky=tk.W, pady=5)
        type_var = tk.StringVar(value="月考")
        type_menu = ttk.Combobox(form_frame, textvariable=type_var, 
                               values=["日常测验", "小测验", "月考", "期中考试", "期末考试"],
                               state="readonly", width=28)
        type_menu.grid(row=2, column=1, pady=5, padx=(10, 0))
        
        def add_exam():
            exam_name = exam_entry.get().strip()
            exam_date = date_entry.get().strip()
            exam_type = type_var.get()
            
            if not exam_name or not exam_date:
                messagebox.showerror("错误", "考试名称和日期不能为空！")
                return
            
            success, message = self.system.add_exam(exam_name, exam_date, exam_type)
            if success:
                messagebox.showinfo("成功", message)
                self.update_text_display(f"已添加考试: {exam_name} ({exam_date}, {exam_type})")
                window.destroy()
            else:
                messagebox.showerror("错误", message)
        
        button_frame = tk.Frame(window, bg=self.bg_color)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="添加", command=add_exam, 
                 bg=self.button_color, fg="white", 
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=window.destroy,
                 bg="#95a5a6", fg="white",
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
    
    def show_add_score_window(self):
        """显示添加成绩窗口"""
        window = tk.Toplevel(self.root)
        window.title("录入成绩")
        window.geometry("500x400")
        window.configure(bg=self.bg_color)
        
        tk.Label(window, text="录入成绩", font=("Arial", 16, "bold"), 
                bg=self.bg_color).pack(pady=20)
        
        form_frame = tk.Frame(window, bg=self.bg_color)
        form_frame.pack(pady=20, padx=40, fill=tk.BOTH)
        
        # 学生选择
        tk.Label(form_frame, text="选择学生:", bg=self.bg_color, font=("Arial", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        students = self.system.get_students_list()
        student_var = tk.StringVar()
        student_menu = ttk.Combobox(form_frame, textvariable=student_var, 
                                   values=students, state="readonly", width=28)
        student_menu.grid(row=0, column=1, pady=5, padx=(10, 0))
        
        # 考试选择
        tk.Label(form_frame, text="选择考试:", bg=self.bg_color, font=("Arial", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        exams = self.system.get_exams_list()
        exam_var = tk.StringVar()
        exam_menu = ttk.Combobox(form_frame, textvariable=exam_var, 
                                values=exams, state="readonly", width=28)
        exam_menu.grid(row=1, column=1, pady=5, padx=(10, 0))
        
        # 课程选择
        tk.Label(form_frame, text="选择课程:", bg=self.bg_color, font=("Arial", 10)).grid(row=2, column=0, sticky=tk.W, pady=5)
        courses = self.system.get_courses_list()
        course_var = tk.StringVar()
        course_menu = ttk.Combobox(form_frame, textvariable=course_var, 
                                  values=courses, state="readonly", width=28)
        course_menu.grid(row=2, column=1, pady=5, padx=(10, 0))
        
        # 成绩输入
        tk.Label(form_frame, text="成绩:", bg=self.bg_color, font=("Arial", 10)).grid(row=3, column=0, sticky=tk.W, pady=5)
        score_entry = tk.Entry(form_frame, font=("Arial", 10), width=30)
        score_entry.grid(row=3, column=1, pady=5, padx=(10, 0))
        
        def add_score():
            student_name = student_var.get()
            exam_name = exam_var.get()
            course_name = course_var.get()
            score = score_entry.get().strip()
            
            if not student_name or not exam_name or not course_name or not score:
                messagebox.showerror("错误", "请填写所有字段！")
                return
            
            success, message = self.system.add_score(student_name, exam_name, course_name, score)
            if success:
                messagebox.showinfo("成功", message)
                self.update_text_display(f"已录入成绩: {student_name} 的 {course_name} 在 {exam_name} 中得分 {score}")
                window.destroy()
            else:
                messagebox.showerror("错误", message)
        
        button_frame = tk.Frame(window, bg=self.bg_color)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="录入", command=add_score, 
                 bg=self.button_color, fg="white", 
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=window.destroy,
                 bg="#95a5a6", fg="white",
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
    
    def show_plot_window(self):
        """显示成绩走势图窗口"""
        window = tk.Toplevel(self.root)
        window.title("成绩走势图")
        window.geometry("800x600")
        window.configure(bg=self.bg_color)
        
        tk.Label(window, text="查看成绩走势图", font=("Arial", 16, "bold"), 
                bg=self.bg_color).pack(pady=20)
        
        # 选择框架
        select_frame = tk.Frame(window, bg=self.bg_color)
        select_frame.pack(pady=20, padx=40, fill=tk.X)
        
        # 学生选择
        tk.Label(select_frame, text="选择学生:", bg=self.bg_color, font=("Arial", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        students = self.system.get_students_list()
        student_var = tk.StringVar()
        student_menu = ttk.Combobox(select_frame, textvariable=student_var, 
                                   values=students, state="readonly", width=30)
        student_menu.grid(row=0, column=1, pady=5, padx=(10, 0))
        
        # 时间范围选择
        tk.Label(select_frame, text="时间范围:", bg=self.bg_color, font=("Arial", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        time_var = tk.StringVar(value="全部时间")
        time_options = ["全部时间", "最近一个月", "最近三个月", "最近半年"]
        time_menu = ttk.Combobox(select_frame, textvariable=time_var, 
                                values=time_options, state="readonly", width=30)
        time_menu.grid(row=1, column=1, pady=5, padx=(10, 0))
        
        def get_time_range():
            """获取时间范围"""
            time_choice = time_var.get()
            today = datetime.now()
            
            if time_choice == "全部时间":
                return None, None
            elif time_choice == "最近一个月":
                start_date = (today - timedelta(days=30)).strftime("%Y-%m-%d")
                end_date = today.strftime("%Y-%m-%d")
            elif time_choice == "最近三个月":
                start_date = (today - timedelta(days=90)).strftime("%Y-%m-%d")
                end_date = today.strftime("%Y-%m-%d")
            elif time_choice == "最近半年":
                start_date = (today - timedelta(days=180)).strftime("%Y-%m-%d")
                end_date = today.strftime("%Y-%m-%d")
            else:
                return None, None
            
            return start_date, end_date
        
        def show_plot():
            """显示图表"""
            student_name = student_var.get()
            if not student_name:
                messagebox.showerror("错误", "请选择学生！")
                return
            
            start_date, end_date = get_time_range()
            
            # 获取成绩数据
            scores = self.system.get_student_scores_by_time(student_name, start_date, end_date)
            if not scores:
                messagebox.showerror("错误", f"{student_name} 在指定时间范围内没有成绩数据")
                return
            
            # 获取所有考试和课程
            exams = sorted(scores.keys(), key=lambda x: self.system.get_exam_date(x))
            courses = set()
            for exam_scores in scores.values():
                courses.update(exam_scores.keys())
            courses = list(courses)
            
            if not exams or not courses:
                messagebox.showerror("错误", "没有足够的成绩数据来绘制图表")
                return
            
            # 创建图表
            fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
            
            # 图1：成绩趋势图
            for i, course in enumerate(courses):
                course_scores = []
                valid_exams = []
                
                for exam in exams:
                    if course in scores[exam]:
                        course_scores.append(scores[exam][course])
                        valid_exams.append(exam)
                
                if course_scores:
                    exam_dates = [self.system.get_exam_date(exam) for exam in valid_exams]
                    ax1.plot(exam_dates, course_scores, 'o-', 
                            label=course, 
                            color=self.system.get_course_color(course),
                            linewidth=2,
                            markersize=8)
            
            ax1.set_title(f'{student_name} 成绩走势图', fontsize=14, fontweight='bold')
            ax1.set_xlabel('考试时间')
            ax1.set_ylabel('成绩（分）')
            ax1.grid(True, alpha=0.3)
            ax1.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
            ax1.set_ylim(0, 105)
            plt.setp(ax1.get_xticklabels(), rotation=45, ha='right')
            
            # 图2：平均分柱状图
            course_avgs = []
            for course in courses:
                course_scores = []
                for exam_scores in scores.values():
                    if course in exam_scores:
                        course_scores.append(exam_scores[course])
                
                if course_scores:
                    course_avgs.append(statistics.mean(course_scores))
                else:
                    course_avgs.append(0)
            
            bars = ax2.bar(courses, course_avgs, 
                          color=[self.system.get_course_color(c) for c in courses],
                          alpha=0.7)
            
            for bar, avg in zip(bars, course_avgs):
                height = bar.get_height()
                ax2.text(bar.get_x() + bar.get_width()/2., height + 1,
                        f'{avg:.1f}', ha='center', va='bottom')
            
            ax2.set_title('各科目平均分', fontsize=12, fontweight='bold')
            ax2.set_xlabel('科目')
            ax2.set_ylabel('平均分')
            ax2.set_xticklabels(courses, rotation=45, ha='right')
            ax2.set_ylim(0, 105)
            ax2.grid(True, alpha=0.3, axis='y')
            
            plt.tight_layout()
            
            # 显示图表
            self.notebook.select(1)  # 切换到图表标签页
            for widget in self.plot_tab.winfo_children():
                widget.destroy()
            
            canvas = FigureCanvasTkAgg(fig, master=self.plot_tab)
            canvas.draw()
            canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
            
            # 添加工具栏
            toolbar = NavigationToolbar2Tk(canvas, self.plot_tab)
            toolbar.update()
            toolbar.pack(side=tk.BOTTOM, fill=tk.X)
            
            # 更新文本显示
            time_text = f"时间范围: {start_date or '全部时间'} 至 {end_date or '全部时间'}"
            self.update_text_display(f"显示 {student_name} 的成绩走势图\n{time_text}", clear=True)
            
            window.destroy()
        
        # 按钮框架
        button_frame = tk.Frame(window, bg=self.bg_color)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="显示图表", command=show_plot, 
                 bg=self.button_color, fg="white", 
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=window.destroy,
                 bg="#95a5a6", fg="white",
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
    
    def show_report_window(self):
        """显示报告窗口"""
        window = tk.Toplevel(self.root)
        window.title("生成进步报告")
        window.geometry("600x400")
        window.configure(bg=self.bg_color)
        
        tk.Label(window, text="生成进步报告", font=("Arial", 16, "bold"), 
                bg=self.bg_color).pack(pady=20)
        
        # 选择框架
        select_frame = tk.Frame(window, bg=self.bg_color)
        select_frame.pack(pady=20, padx=40, fill=tk.X)
        
        # 学生选择
        tk.Label(select_frame, text="选择学生:", bg=self.bg_color, font=("Arial", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        students = self.system.get_students_list()
        student_var = tk.StringVar()
        student_menu = ttk.Combobox(select_frame, textvariable=student_var, 
                                   values=students, state="readonly", width=30)
        student_menu.grid(row=0, column=1, pady=5, padx=(10, 0))
        
        # 时间范围选择
        tk.Label(select_frame, text="时间范围:", bg=self.bg_color, font=("Arial", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        time_var = tk.StringVar(value="全部时间")
        time_options = ["全部时间", "最近一个月", "最近三个月", "最近半年"]
        time_menu = ttk.Combobox(select_frame, textvariable=time_var, 
                                values=time_options, state="readonly", width=30)
        time_menu.grid(row=1, column=1, pady=5, padx=(10, 0))
        
        def get_time_range():
            """获取时间范围"""
            time_choice = time_var.get()
            today = datetime.now()
            
            if time_choice == "全部时间":
                return None, None
            elif time_choice == "最近一个月":
                start_date = (today - timedelta(days=30)).strftime("%Y-%m-%d")
                end_date = today.strftime("%Y-%m-%d")
            elif time_choice == "最近三个月":
                start_date = (today - timedelta(days=90)).strftime("%Y-%m-%d")
                end_date = today.strftime("%Y-%m-%d")
            elif time_choice == "最近半年":
                start_date = (today - timedelta(days=180)).strftime("%Y-%m-%d")
                end_date = today.strftime("%Y-%m-%d")
            else:
                return None, None
            
            return start_date, end_date
        
        def generate_report():
            """生成报告"""
            student_name = student_var.get()
            if not student_name:
                messagebox.showerror("错误", "请选择学生！")
                return
            
            start_date, end_date = get_time_range()
            report = self.system.generate_progress_report(student_name, start_date, end_date)
            
            if not report:
                messagebox.showerror("错误", f"{student_name} 在指定时间范围内没有成绩数据")
                return
            
            # 显示报告
            self.update_text_display(f"\n{'='*60}", clear=True)
            self.update_text_display(f"           {student_name} 成绩报告")
            self.update_text_display(f"{'='*60}")
            self.update_text_display(f"学号: {report['student_info']['id']}")
            self.update_text_display(f"班级: {report['student_info']['class']}")
            self.update_text_display(f"时间范围: {report['time_range']['start_date'] or '全部时间'} 至 {report['time_range']['end_date'] or '全部时间'}")
            self.update_text_display(f"考试次数: {report['summary']['total_exams']}")
            self.update_text_display(f"总体平均分: {report['summary']['average_score']:.1f}")
            self.update_text_display(f"最高分: {report['summary']['highest_score']:.1f}")
            self.update_text_display(f"最低分: {report['summary']['lowest_score']:.1f}")
            self.update_text_display(f"\n各科目分析:")
            
            for course, analysis in report['course_analysis'].items():
                self.update_text_display(f"\n  {course}:")
                self.update_text_display(f"    平均分: {analysis['average']:.1f}")
                self.update_text_display(f"    最高分: {analysis['highest']:.1f}")
                self.update_text_display(f"    最低分: {analysis['lowest']:.1f}")
                self.update_text_display(f"    趋势: {analysis['trend']['description']}")
                self.update_text_display(f"    进步幅度: {analysis['trend']['improvement']:.1f}")
            
            self.update_text_display(f"\n成绩分布:")
            for grade, count in report['summary']['distribution']['count'].items():
                percentage = report['summary']['distribution']['percentage'][grade]
                self.update_text_display(f"  {grade}: {count}人 ({percentage:.1f}%)")
            
            self.update_text_display(f"\n{'='*60}")
            
            window.destroy()
        
        # 按钮框架
        button_frame = tk.Frame(window, bg=self.bg_color)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="生成报告", command=generate_report, 
                 bg=self.button_color, fg="white", 
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=window.destroy,
                 bg="#95a5a6", fg="white",
                 font=("Arial", 10), padx=20, pady=5).pack(side=tk.LEFT, padx=10)
    
    def show_students_list(self):
        """显示学生列表"""
        students = self.system.get_students_list()
        
        self.update_text_display("\n学生列表:", clear=True)
        self.update_text_display("="*40)
        
        if not students:
            self.update_text_display("目前没有学生信息")
            return
        
        for name in students:
            info = self.system.data["students"][name]
            self.update_text_display(f"\n姓名：{name}")
            self.update_text_display(f"学号：{info.get('id', '未设置')}")
            self.update_text_display(f"班级：{info.get('class', '未设置')}")
            exam_count = len(info.get('scores', {}))
            self.update_text_display(f"考试次数：{exam_count}")
            self.update_text_display("-"*40)
    
    def show_exams_list(self):
        """显示考试列表"""
        exams = self.system.get_exams_list()
        
        self.update_text_display("\n考试列表:", clear=True)
        self.update_text_display("="*60)
        
        if not exams:
            self.update_text_display("目前没有考试信息")
            return
        
        for exam_name in exams:
            exam_info = None
            for exam in self.system.data["exams"]:
                if exam["name"] == exam_name:
                    exam_info = exam
                    break
            
            if exam_info:
                self.update_text_display(f"\n考试名称：{exam_name}")
                self.update_text_display(f"考试日期：{exam_info.get('date', '未设置')}")
                self.update_text_display(f"考试类型：{exam_info.get('type', '未设置')}")
                self.update_text_display("-"*60)
    
    def show_courses_list(self):
        """显示课程列表"""
        courses = self.system.get_courses_list()
        
        self.update_text_display("\n课程列表:", clear=True)
        self.update_text_display("="*30)
        
        if not courses:
            self.update_text_display("目前没有课程信息")
            return
        
        for i, course in enumerate(courses, 1):
            self.update_text_display(f"{i:2d}. {course}")
        
        self.update_text_display("-"*30)
    
    def show_statistics(self):
        """显示数据统计"""
        self.update_text_display("\n系统数据统计:", clear=True)
        self.update_text_display("="*50)
        
        # 学生统计
        student_count = len(self.system.data["students"])
        self.update_text_display(f"学生总数: {student_count}")
        
        # 考试统计
        exam_count = len(self.system.data["exams"])
        self.update_text_display(f"考试总数: {exam_count}")
        
        # 课程统计
        course_count = len(self.system.data["courses"])
        self.update_text_display(f"课程总数: {course_count}")
        
        # 成绩统计
        total_scores = 0
        for student_info in self.system.data["students"].values():
            for exam_scores in student_info.get("scores", {}).values():
                total_scores += len(exam_scores)
        
        self.update_text_display(f"成绩记录总数: {total_scores}")
        self.update_text_display("="*50)
    
    def export_data(self):
        """导出数据"""
        file_path = filedialog.asksaveasfilename(
            defaultextension=".json",
            filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
            initialfile="scores_data_backup.json"
        )
        
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(self.system.data, f, ensure_ascii=False, indent=2)
                messagebox.showinfo("成功", f"数据已导出到: {file_path}")
                self.update_text_display(f"数据已导出到: {file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"导出失败: {e}")
    
    def show_about(self):
        """显示关于信息"""
        about_text = """
学生成绩分析系统 v2.0
====================
功能说明:
1. 学生管理: 添加、查看学生信息
2. 课程管理: 添加、查看课程信息
3. 考试管理: 添加、查看考试信息
4. 成绩管理: 录入、查看成绩
5. 数据分析: 成绩走势图、进步报告
6. 数据导出: 导出系统数据

使用说明:
1. 首次运行会自动创建示例数据
2. 所有数据自动保存到本地文件
3. 支持图形化界面操作

开发者: 腾讯AI编程助手
版本: 2.0
"""
        self.update_text_display(about_text, clear=True)

def main():
    """主程序"""
    root = tk.Tk()
    app = ScoreAnalysisGUI(root)
    root.mainloop()

if __name__ == "__main__":
    main()
