import tkinter as tk
from tkinter import ttk, messagebox
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
import json
import os


class ScoreAnalysisApp:
    def __init__(self, root):
        self.root = root
        self.root.title("成绩走势分析系统")
        self.root.geometry("1200x700")

        # 存储成绩数据
        self.scores_data = {}
        self.subjects = ["语文", "数学", "英语", "物理", "化学", "生物", "历史", "地理", "政治"]

        # 设置样式
        self.setup_styles()

        # 创建界面
        self.create_widgets()

        # 加载示例数据
        self.load_sample_data()

    def setup_styles(self):
        """设置界面样式"""
        style = ttk.Style()
        style.theme_use('clam')

        # 自定义颜色
        self.bg_color = "#f0f0f0"
        self.primary_color = "#4a6fa5"
        self.secondary_color = "#166088"

        self.root.configure(bg=self.bg_color)

    def create_widgets(self):
        """创建界面组件"""
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(1, weight=1)

        # 左侧控制面板
        control_frame = ttk.LabelFrame(main_frame, text="数据控制", padding="10")
        control_frame.grid(row=0, column=0, rowspan=2, sticky=(
            tk.W, tk.E, tk.N, tk.S), padx=(0, 10))

        # 右侧图表区域
        chart_frame = ttk.LabelFrame(main_frame, text="成绩走势图", padding="10")
        chart_frame.grid(row=0, column=1, sticky=(tk.W, tk.E, tk.N, tk.S))
        chart_frame.columnconfigure(0, weight=1)
        chart_frame.rowconfigure(0, weight=1)

        # 底部状态栏
        status_frame = ttk.Frame(main_frame, padding="5")
        status_frame.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=(10, 0))

        # 创建控制面板组件
        self.create_control_panel(control_frame)

        # 创建图表区域
        self.create_chart_area(chart_frame)

        # 创建状态栏
        self.create_status_bar(status_frame)

    def create_control_panel(self, parent):
        """创建控制面板"""
        # 学生姓名
        ttk.Label(parent, text="学生姓名:").grid(
            row=0, column=0, sticky=tk.W, pady=5)
        self.name_var = tk.StringVar(value="张三")
        name_entry = ttk.Entry(parent, textvariable=self.name_var, width=20)
        name_entry.grid(row=0, column=1, pady=5, padx=(5, 0))

        # 选择科目
        ttk.Label(parent, text="选择科目:").grid(
            row=1, column=0, sticky=tk.W, pady=5)
        self.subject_var = tk.StringVar(value="数学")
        subject_combo = ttk.Combobox(parent, textvariable=self.subject_var,
                                     values=self.subjects, state="readonly", width=18)
        subject_combo.grid(row=1, column=1, pady=5, padx=(5, 0))
        subject_combo.bind('<<ComboboxSelected>>', self.update_chart)

        # 添加成绩按钮
        ttk.Button(parent, text="添加成绩记录", command=self.add_score_record,
                   style="Accent.TButton").grid(row=2, column=0, columnspan=2, pady=10)

        # 批量添加按钮
        ttk.Button(parent, text="批量添加成绩", command=self.batch_add_scores).grid(
            row=3, column=0, columnspan=2, pady=5)

        # 显示所有科目按钮
        ttk.Button(parent, text="显示所有科目走势", command=self.show_all_subjects).grid(
            row=4, column=0, columnspan=2, pady=5)

        # 分析按钮
        ttk.Button(parent, text="成绩分析报告", command=self.generate_report).grid(
            row=5, column=0, columnspan=2, pady=5)

        # 保存/加载按钮
        ttk.Button(parent, text="保存数据", command=self.save_data).grid(
            row=6, column=0, pady=5, padx=(0, 2))
        ttk.Button(parent, text="加载数据", command=self.load_data).grid(
            row=6, column=1, pady=5, padx=(2, 0))

        # 分隔线
        ttk.Separator(parent, orient='horizontal').grid(
            row=7, column=0, columnspan=2, pady=20, sticky=(tk.W, tk.E))

        # 图表设置
        ttk.Label(parent, text="图表设置", font=('TkDefaultFont', 10, 'bold')).grid(
            row=8, column=0, columnspan=2, sticky=tk.W)

        # 显示网格
        self.grid_var = tk.BooleanVar(value=True)
        grid_check = ttk.Checkbutton(parent, text="显示网格", variable=self.grid_var,
                                     command=self.update_chart)
        grid_check.grid(row=9, column=0, columnspan=2, sticky=tk.W, pady=5)

        # 显示平均线
        self.avg_var = tk.BooleanVar(value=True)
        avg_check = ttk.Checkbutton(parent, text="显示平均线", variable=self.avg_var,
                                    command=self.update_chart)
        avg_check.grid(row=10, column=0, columnspan=2, sticky=tk.W, pady=5)

        # 显示趋势线
        self.trend_var = tk.BooleanVar(value=True)
        trend_check = ttk.Checkbutton(parent, text="显示趋势线", variable=self.trend_var,
                                      command=self.update_chart)
        trend_check.grid(row=11, column=0, columnspan=2, sticky=tk.W, pady=5)

        # 图表样式
        ttk.Label(parent, text="图表样式:").grid(
            row=12, column=0, sticky=tk.W, pady=5)
        self.style_var = tk.StringVar(value="line")
        style_combo = ttk.Combobox(parent, textvariable=self.style_var,
                                   values=["line", "scatter", "bar", "area"],
                                   state="readonly", width=18)
        style_combo.grid(row=12, column=1, pady=5, padx=(5, 0))
        style_combo.bind('<<ComboboxSelected>>', self.update_chart)

    def create_chart_area(self, parent):
        """创建图表区域"""
        # 创建图表
        self.fig = Figure(figsize=(10, 6), dpi=100, facecolor='#f8f9fa')
        self.ax = self.fig.add_subplot(111)

        # 设置图表样式
        self.ax.set_facecolor('#ffffff')
        self.fig.patch.set_facecolor('#f8f9fa')

        # 创建canvas
        self.canvas = FigureCanvasTkAgg(self.fig, parent)
        self.canvas.get_tk_widget().grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 添加工具栏
        toolbar_frame = ttk.Frame(parent)
        toolbar_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(5, 0))

        # 简单工具栏按钮
        ttk.Button(toolbar_frame, text="保存图表",
                   command=self.save_chart).pack(side=tk.LEFT, padx=2)
        ttk.Button(toolbar_frame, text="重置视图",
                   command=self.reset_view).pack(side=tk.LEFT, padx=2)

        # 显示初始图表
        self.update_chart()

    def create_status_bar(self, parent):
        """创建状态栏"""
        self.status_var = tk.StringVar(value="就绪")
        status_label = ttk.Label(
            parent, textvariable=self.status_var, relief=tk.SUNKEN)
        status_label.pack(side=tk.LEFT, fill=tk.X, expand=True)

        # 显示当前学生
        self.current_student_var = tk.StringVar(value="当前学生: 张三")
        student_label = ttk.Label(
            parent, textvariable=self.current_student_var)
        student_label.pack(side=tk.RIGHT, padx=(0, 10))

    def load_sample_data(self):
        """加载示例数据"""
        student_name = self.name_var.get()

        # 为每个科目生成示例数据
        for subject in self.subjects:
            dates = []
            scores = []

            # 生成最近6次考试数据
            base_date = datetime.now() - timedelta(days=180)
            for i in range(6):
                date = base_date + timedelta(days=i*30)
                dates.append(date.strftime("%Y-%m-%d"))

                # 生成模拟成绩（带有一些随机波动）
                if subject == "数学":
                    base_score = 85 + np.random.uniform(-5, 5)
                elif subject == "语文":
                    base_score = 80 + np.random.uniform(-5, 5)
                elif subject == "英语":
                    base_score = 88 + np.random.uniform(-5, 5)
                else:
                    base_score = 75 + np.random.uniform(-5, 5)

                scores.append(
                    min(100, max(0, round(base_score + np.random.uniform(-8, 8), 1))))

            self.scores_data[subject] = {
                'dates': dates,
                'scores': scores
            }

        self.status_var.set("示例数据已加载")

    def update_chart(self, event=None):
        """更新图表"""
        try:
            # 清空图表
            self.ax.clear()

            subject = self.subject_var.get()
            student_name = self.name_var.get()

            if subject not in self.scores_data:
                self.ax.text(0.5, 0.5, f"暂无{subject}成绩数据",
                             ha='center', va='center', transform=self.ax.transAxes,
                             fontsize=12, color='gray')
                self.canvas.draw()
                return

            dates = self.scores_data[subject]['dates']
            scores = self.scores_data[subject]['scores']

            if not dates or not scores:
                self.ax.text(0.5, 0.5, f"暂无{subject}成绩数据",
                             ha='center', va='center', transform=self.ax.transAxes,
                             fontsize=12, color='gray')
                self.canvas.draw()
                return

            # 转换日期格式
            date_nums = range(len(dates))

            # 根据选择的样式绘制图表
            chart_style = self.style_var.get()

            if chart_style == "line":
                self.ax.plot(date_nums, scores, 'o-', color=self.primary_color,
                             linewidth=2, markersize=8, markerfacecolor='white',
                             markeredgewidth=2, label='成绩')
            elif chart_style == "scatter":
                self.ax.scatter(date_nums, scores, color=self.primary_color,
                                s=100, alpha=0.7, label='成绩')
            elif chart_style == "bar":
                bars = self.ax.bar(date_nums, scores, color=self.primary_color,
                                   alpha=0.7, label='成绩')
                # 在柱状图上显示数值
                for bar in bars:
                    height = bar.get_height()
                    self.ax.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                                 f'{height}', ha='center', va='bottom', fontsize=9)
            elif chart_style == "area":
                self.ax.fill_between(
                    date_nums, scores, alpha=0.3, color=self.primary_color)
                self.ax.plot(date_nums, scores, 'o-', color=self.primary_color,
                             linewidth=2, markersize=8, markerfacecolor='white',
                             markeredgewidth=2, label='成绩')

            # 设置x轴标签
            self.ax.set_xticks(date_nums)
            self.ax.set_xticklabels(dates, rotation=45, ha='right')

            # 设置图表标题和标签
            self.ax.set_title(f'{student_name}的{subject}成绩走势图',
                              fontsize=14, fontweight='bold', pad=20)
            self.ax.set_xlabel('考试日期', fontsize=12)
            self.ax.set_ylabel('成绩', fontsize=12)

            # 设置y轴范围
            self.ax.set_ylim(0, 100)

            # 显示网格
            if self.grid_var.get():
                self.ax.grid(True, linestyle='--', alpha=0.3, color='gray')

            # 显示平均线
            if self.avg_var.get() and len(scores) > 0:
                avg_score = np.mean(scores)
                self.ax.axhline(y=avg_score, color='red',
                                linestyle='--', alpha=0.7, linewidth=1.5)
                self.ax.text(len(dates)-0.5, avg_score, f' 平均: {avg_score:.1f}',
                             verticalalignment='center', color='red', fontweight='bold')

            # 显示趋势线
            if self.trend_var.get() and len(scores) > 1:
                z = np.polyfit(date_nums, scores, 1)
                p = np.poly1d(z)
                self.ax.plot(date_nums, p(date_nums), "r--",
                             alpha=0.7, linewidth=1.5, label='趋势线')

                # 计算趋势
                trend = "上升" if z[0] > 0 else "下降" if z[0] < 0 else "平稳"
                self.ax.text(0.02, 0.98, f'趋势: {trend}', transform=self.ax.transAxes,
                             fontsize=10, verticalalignment='top',
                             bbox=dict(boxstyle='round', facecolor='yellow', alpha=0.5))

            # 添加图例
            self.ax.legend(loc='upper left')

            # 调整布局
            self.fig.tight_layout()

            # 更新状态
            self.current_student_var.set(f"当前学生: {student_name}")
            self.status_var.set(f"{subject}成绩图表已更新 - 共{len(scores)}次考试记录")

            # 重绘画布
            self.canvas.draw()

        except Exception as e:
            messagebox.showerror("错误", f"更新图表时出错: {str(e)}")

    def add_score_record(self):
        """添加成绩记录"""
        dialog = tk.Toplevel(self.root)
        dialog.title("添加成绩记录")
        dialog.geometry("400x300")
        dialog.transient(self.root)
        dialog.grab_set()

        # 居中对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry(f'{width}x{height}+{x}+{y}')

        # 创建表单
        ttk.Label(dialog, text="科目:").grid(
            row=0, column=0, padx=10, pady=10, sticky=tk.W)
        subject_combo = ttk.Combobox(
            dialog, values=self.subjects, state="readonly")
        subject_combo.grid(row=0, column=1, padx=10,
                           pady=10, sticky=(tk.W, tk.E))
        subject_combo.current(0)

        ttk.Label(dialog, text="考试日期 (YYYY-MM-DD):").grid(row=1,
                                                          column=0, padx=10, pady=10, sticky=tk.W)
        date_entry = ttk.Entry(dialog)
        date_entry.grid(row=1, column=1, padx=10, pady=10, sticky=(tk.W, tk.E))
        date_entry.insert(0, datetime.now().strftime("%Y-%m-%d"))

        ttk.Label(dialog, text="成绩 (0-100):").grid(row=2,
                                                   column=0, padx=10, pady=10, sticky=tk.W)
        score_var = tk.DoubleVar()
        score_entry = ttk.Entry(dialog, textvariable=score_var)
        score_entry.grid(row=2, column=1, padx=10,
                         pady=10, sticky=(tk.W, tk.E))

        # 按钮框架
        button_frame = ttk.Frame(dialog)
        button_frame.grid(row=3, column=0, columnspan=2, pady=20)

        def save_score():
            try:
                subject = subject_combo.get()
                date = date_entry.get()
                score = float(score_var.get())

                if not 0 <= score <= 100:
                    messagebox.showerror("错误", "成绩必须在0-100之间")
                    return

                # 验证日期格式
                datetime.strptime(date, "%Y-%m-%d")

                # 添加成绩记录
                if subject not in self.scores_data:
                    self.scores_data[subject] = {'dates': [], 'scores': []}

                # 如果日期已存在，更新成绩
                if date in self.scores_data[subject]['dates']:
                    index = self.scores_data[subject]['dates'].index(date)
                    self.scores_data[subject]['scores'][index] = score
                else:
                    # 按日期排序插入
                    dates = self.scores_data[subject]['dates']
                    scores = self.scores_data[subject]['scores']

                    # 找到插入位置
                    insert_index = 0
                    for i, d in enumerate(dates):
                        if datetime.strptime(d, "%Y-%m-%d") < datetime.strptime(date, "%Y-%m-%d"):
                            insert_index = i + 1

                    dates.insert(insert_index, date)
                    scores.insert(insert_index, score)

                dialog.destroy()
                self.update_chart()
                messagebox.showinfo("成功", f"{subject}成绩记录已添加")

            except ValueError as e:
                messagebox.showerror("错误", f"输入数据无效: {str(e)}")

        ttk.Button(button_frame, text="保存", command=save_score,
                   width=10).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=dialog.destroy,
                   width=10).pack(side=tk.LEFT, padx=10)

    def batch_add_scores(self):
        """批量添加成绩"""
        dialog = tk.Toplevel(self.root)
        dialog.title("批量添加成绩")
        dialog.geometry("500x400")
        dialog.transient(self.root)
        dialog.grab_set()

        # 创建文本框用于批量输入
        text_frame = ttk.Frame(dialog, padding="10")
        text_frame.pack(fill=tk.BOTH, expand=True)

        ttk.Label(
            text_frame, text="每行格式: 科目,日期(YYYY-MM-DD),成绩").pack(anchor=tk.W, pady=(0, 5))

        text_widget = tk.Text(text_frame, height=15, width=50)
        text_widget.pack(fill=tk.BOTH, expand=True)

        # 示例数据
        example = """数学,2024-01-15,85.5
数学,2024-02-20,88.0
英语,2024-01-15,92.0
英语,2024-02-20,90.5"""
        text_widget.insert("1.0", example)

        # 按钮框架
        button_frame = ttk.Frame(dialog, padding="10")
        button_frame.pack(fill=tk.X)

        def process_batch():
            text = text_widget.get("1.0", tk.END).strip()
            lines = text.split('\n')

            added_count = 0
            error_lines = []

            for i, line in enumerate(lines, 1):
                line = line.strip()
                if not line:
                    continue

                try:
                    parts = [p.strip() for p in line.split(',')]
                    if len(parts) != 3:
                        raise ValueError("格式不正确")

                    subject, date_str, score_str = parts

                    if subject not in self.subjects:
                        raise ValueError(f"科目'{subject}'不存在")

                    score = float(score_str)
                    if not 0 <= score <= 100:
                        raise ValueError("成绩必须在0-100之间")

                    # 验证日期
                    datetime.strptime(date_str, "%Y-%m-%d")

                    # 添加到数据
                    if subject not in self.scores_data:
                        self.scores_data[subject] = {'dates': [], 'scores': []}

                    # 如果日期已存在，更新成绩
                    if date_str in self.scores_data[subject]['dates']:
                        index = self.scores_data[subject]['dates'].index(
                            date_str)
                        self.scores_data[subject]['scores'][index] = score
                    else:
                        # 按日期排序插入
                        dates = self.scores_data[subject]['dates']
                        scores = self.scores_data[subject]['scores']

                        insert_index = 0
                        for j, d in enumerate(dates):
                            if datetime.strptime(d, "%Y-%m-%d") < datetime.strptime(date_str, "%Y-%m-%d"):
                                insert_index = j + 1

                        dates.insert(insert_index, date_str)
                        scores.insert(insert_index, score)

                    added_count += 1

                except Exception as e:
                    error_lines.append(f"第{i}行: {line} - 错误: {str(e)}")

            dialog.destroy()
            self.update_chart()

            if error_lines:
                error_msg = f"成功添加{added_count}条记录\n\n错误行:\n" + \
                    "\n".join(error_lines)
                messagebox.showwarning("部分成功", error_msg)
            else:
                messagebox.showinfo("成功", f"成功添加{added_count}条记录")

        ttk.Button(button_frame, text="导入", command=process_batch).pack(
            side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="取消", command=dialog.destroy).pack(
            side=tk.LEFT, padx=5)

    def show_all_subjects(self):
        """显示所有科目走势"""
        # 创建新窗口显示所有科目
        all_subjects_window = tk.Toplevel(self.root)
        all_subjects_window.title("所有科目成绩走势对比")
        all_subjects_window.geometry("1000x700")

        # 创建图表
        fig = Figure(figsize=(12, 8))
        ax = fig.add_subplot(111)

        # 为每个科目绘制走势
        for i, subject in enumerate(self.subjects):
            if subject in self.scores_data and len(self.scores_data[subject]['scores']) > 0:
                dates = self.scores_data[subject]['dates']
                scores = self.scores_data[subject]['scores']

                # 使用数字代替日期
                x = range(len(scores))
                ax.plot(x, scores, 'o-', label=subject,
                        linewidth=2, markersize=6)

        ax.set_title(f"{self.name_var.get()} - 所有科目成绩走势对比",
                     fontsize=14, fontweight='bold')
        ax.set_xlabel("考试次数", fontsize=12)
        ax.set_ylabel("成绩", fontsize=12)
        ax.set_ylim(0, 100)
        ax.grid(True, alpha=0.3)
        ax.legend(loc='best')

        # 显示到窗口
        canvas = FigureCanvasTkAgg(fig, all_subjects_window)
        canvas.draw()
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

        # 添加工具栏
        toolbar_frame = ttk.Frame(all_subjects_window)
        toolbar_frame.pack(fill=tk.X, padx=10, pady=5)

        def save_comparison_chart():
            filename = f"所有科目对比_{self.name_var.get()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
            fig.savefig(filename, dpi=300, bbox_inches='tight')
            messagebox.showinfo("成功", f"图表已保存为: {filename}")

        ttk.Button(toolbar_frame, text="保存图表",
                   command=save_comparison_chart).pack(side=tk.LEFT)

    def generate_report(self):
        """生成成绩分析报告"""
        try:
            report_text = f"成绩分析报告\n"
            report_text += f"学生: {self.name_var.get()}\n"
            report_text += f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
            report_text += "="*50 + "\n\n"

            overall_stats = {
                'total_exams': 0,
                'avg_all': 0,
                'best_subject': '',
                'best_score': 0,
                'worst_subject': '',
                'worst_score': 100
            }

            subject_scores = []

            for subject in self.subjects:
                if subject in self.scores_data and len(self.scores_data[subject]['scores']) > 0:
                    scores = self.scores_data[subject]['scores']
                    avg_score = np.mean(scores)
                    max_score = max(scores)
                    min_score = min(scores)
                    trend = "上升" if scores[-1] > scores[0] else "下降" if scores[-1] < scores[0] else "平稳"

                    report_text += f"{subject}:\n"
                    report_text += f"  平均分: {avg_score:.1f}\n"
                    report_text += f"  最高分: {max_score:.1f}\n"
                    report_text += f"  最低分: {min_score:.1f}\n"
                    report_text += f"  趋势: {trend}\n"
                    report_text += f"  考试次数: {len(scores)}\n\n"

                    subject_scores.append((subject, avg_score))

                    # 更新总体统计
                    overall_stats['total_exams'] += len(scores)
                    overall_stats['avg_all'] += avg_score

                    if avg_score > overall_stats['best_score']:
                        overall_stats['best_score'] = avg_score
                        overall_stats['best_subject'] = subject

                    if avg_score < overall_stats['worst_score']:
                        overall_stats['worst_score'] = avg_score
                        overall_stats['worst_subject'] = subject

            if subject_scores:
                overall_stats['avg_all'] /= len(subject_scores)

                report_text += "="*50 + "\n"
                report_text += "总体分析:\n"
                report_text += f"总考试次数: {overall_stats['total_exams']}\n"
                report_text += f"所有科目平均分: {overall_stats['avg_all']:.1f}\n"
                report_text += f"优势科目: {overall_stats['best_subject']} ({overall_stats['best_score']:.1f})\n"
                report_text += f"待提高科目: {overall_stats['worst_subject']} ({overall_stats['worst_score']:.1f})\n\n"

                # 按平均分排序
                sorted_subjects = sorted(
                    subject_scores, key=lambda x: x[1], reverse=True)
                report_text += "科目排名:\n"
                for i, (subject, score) in enumerate(sorted_subjects, 1):
                    report_text += f"{i}. {subject}: {score:.1f}\n"

            # 显示报告
            report_window = tk.Toplevel(self.root)
            report_window.title("成绩分析报告")
            report_window.geometry("500x600")

            text_widget = tk.Text(
                report_window, wrap=tk.WORD, font=("Consolas", 10))
            text_widget.insert("1.0", report_text)
            text_widget.config(state=tk.DISABLED)

            scrollbar = ttk.Scrollbar(
                report_window, orient=tk.VERTICAL, command=text_widget.yview)
            text_widget.configure(yscrollcommand=scrollbar.set)

            scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
            text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

            # 添加保存按钮
            button_frame = ttk.Frame(report_window)
            button_frame.pack(fill=tk.X, padx=10, pady=5)

            def save_report():
                filename = f"成绩报告_{self.name_var.get()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
                with open(filename, 'w', encoding='utf-8') as f:
                    f.write(report_text)
                messagebox.showinfo("成功", f"报告已保存为: {filename}")

            ttk.Button(button_frame, text="保存报告",
                       command=save_report).pack(side=tk.LEFT)

        except Exception as e:
            messagebox.showerror("错误", f"生成报告时出错: {str(e)}")

    def save_data(self):
        """保存数据到文件"""
        try:
            data_to_save = {
                'student_name': self.name_var.get(),
                'scores_data': self.scores_data
            }

            filename = f"成绩数据_{self.name_var.get()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(data_to_save, f, ensure_ascii=False, indent=2)

            self.status_var.set(f"数据已保存到: {filename}")
            messagebox.showinfo("成功", f"数据已保存到: {filename}")

        except Exception as e:
            messagebox.showerror("错误", f"保存数据时出错: {str(e)}")

    def load_data(self):
        """从文件加载数据"""
        try:
            # 这里简化处理，实际应用中应该使用文件对话框
            filename = tk.filedialog.askopenfilename(
                title="选择数据文件",
                filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
            )

            if filename:
                with open(filename, 'r', encoding='utf-8') as f:
                    data = json.load(f)

                self.name_var.set(
                    data.get('student_name', self.name_var.get()))
                self.scores_data = data.get('scores_data', {})

                self.update_chart()
                self.status_var.set(f"数据已从 {os.path.basename(filename)} 加载")

        except Exception as e:
            messagebox.showerror("错误", f"加载数据时出错: {str(e)}")

    def save_chart(self):
        """保存当前图表为图片"""
        try:
            filename = f"成绩图表_{self.name_var.get()}_{self.subject_var.get()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
            self.fig.savefig(filename, dpi=300, bbox_inches='tight')
            self.status_var.set(f"图表已保存为: {filename}")
            messagebox.showinfo("成功", f"图表已保存为: {filename}")
        except Exception as e:
            messagebox.showerror("错误", f"保存图表时出错: {str(e)}")

    def reset_view(self):
        """重置图表视图"""
        self.update_chart()


def main():
    """主函数"""
    root = tk.Tk()
    app = ScoreAnalysisApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()
