import tkinter as tk
from tkinter import ttk, messagebox, colorchooser, filedialog
import math
import time
import datetime
import os
import random
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np

# --- 全局配置 ---
APP_NAME = "昊轩·全能生活助手"
AUTHOR_INFO = "东台市实验中学教育集团城东分校-七年级（5）班-邹昊轩 6号-指导老师：钱晓霞"

class SuperApp:
    def __init__(self, root):
        self.root = root
        self.root.title(APP_NAME)
        self.root.geometry("1200x800")
        
        # 样式设置
        self.style = ttk.Style()
        self.style.theme_use('clam')
        
        # 顶部信息栏
        self.create_header()
        
        # 左侧导航栏
        self.create_sidebar()
        
        # 主内容区
        self.main_frame = tk.Frame(self.root, bg="#f0f0f0")
        self.main_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 默认显示计算器
        self.show_calculator()

    def create_header(self):
        header_frame = tk.Frame(self.root, bg="#004080", height=60)
        header_frame.pack(side=tk.TOP, fill=tk.X)
        lbl_title = tk.Label(header_frame, text=AUTHOR_INFO, font=("Microsoft YaHei", 14, "bold"), fg="white", bg="#004080", pady=15)
        lbl_title.pack()

    def create_sidebar(self):
        sidebar = tk.Frame(self.root, width=180, bg="#e0e0e0")
        sidebar.pack(side=tk.LEFT, fill=tk.Y)
        
        # 创建滚动条
        canvas = tk.Canvas(sidebar, bg="#e0e0e0", highlightthickness=0)
        scrollbar = ttk.Scrollbar(sidebar, orient="vertical", command=canvas.yview)
        scrollable_frame = tk.Frame(canvas, bg="#e0e0e0")
        scrollable_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 按钮列表（新增了课程表、任务清单、旅行计划、星座生肖）
        buttons = [
            ("🧮 超级计算器", self.show_calculator),
            ("👨‍👩‍👧‍👦 亲戚计算器", self.show_relative_calc),
            ("<|im_message|> 汇率转换器", self.show_currency),
            ("🏠 房贷/车贷", self.show_loan_calc),
            ("💰 个税计算", self.show_tax_calc),
            ("🔢 进制转换", self.show_base_convert),
            ("📝 大写金额", self.show_money_convert),
            ("⏰ 全能时钟", self.show_clock),
            ("📒 多功能笔记", self.show_notebook),
            ("📚 错题本", self.show_error_book),
            ("🎨 绘画本", self.show_drawing),
            ("🎲 随机点名", self.show_roller),
            ("📈 成绩走势3D", self.show_grade_chart),
            ("🆔 身份证解析", self.show_id_parser),
            ("🚗 车牌归属地", self.show_car_plate),
            ("📅 课程表", self.show_timetable),      # 新增
            ("✅ 任务清单", self.show_todo),        # 新增
            ("🧳 旅行计划", self.show_travel),      # 新增
            ("♈ 星座生肖", self.show_horoscope)    # 新增
        ]
        
        for text, cmd in buttons:
            btn = tk.Button(scrollable_frame, text=text, command=cmd, anchor="w", padx=10, pady=5, bg="#e0e0e0", relief=tk.FLAT, font=("Microsoft YaHei", 10))
            btn.pack(fill=tk.X, padx=5, pady=2)
            
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

    def clear_main(self):
        for widget in self.main_frame.winfo_children():
            widget.destroy()

    # ================= 1. 超级计算器 (最终修复版) =================
    def show_calculator(self):
        self.clear_main()
        # 使用 Notebook 创建选项卡
        notebook = ttk.Notebook(self.main_frame)
        notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # --- 选项卡1：科学计算 ---
        calc_frame = tk.Frame(notebook, bg="#f5f5f5")
        notebook.add(calc_frame, text="科学计算")
        
        # 显示屏
        self.calc_entry = tk.Entry(calc_frame, font=("Arial", 18, "bold"), justify="right", bd=5, relief=tk.RIDGE)
        self.calc_entry.grid(row=0, column=0, columnspan=5, sticky="ew", padx=5, pady=10, ipady=10)

        # 按钮布局：所有按键大小一致，布局整齐
        # 这里的布局是 5列 x 6行
        buttons = [
            ['sin', 'cos', 'tan', '(', ')'],
            ['sqrt', '^', 'C', '⌫', '/'],
            ['7', '8', '9', '*', '-'],
            ['4', '5', '6', '+', '+'], # 这里为了对齐做了调整，或者你可以把+号放最后
            ['1', '2', '3', '-', '-'],
            ['0', '.', '=', '=', '=']
        ]
        
        # 重新定义更整齐的布局
        buttons = [
            ['sin', 'cos', 'tan', 'C', '⌫'],
            ['(', ')', '^', 'sqrt', '/'],
            ['7', '8', '9', '*', '-'],
            ['4', '5', '6', '+', '+'], # 这里的逻辑是：前4个数字/符号，第5个是运算
            ['1', '2', '3', '=', '='], # 等于号占两格
            ['0', '0', '.', '+', '-']  # 0占两格
        ]
        
        # 修正为最通用的整齐布局
        buttons = [
            ['sin', 'cos', 'tan', 'C', '⌫'],
            ['(', ')', '^', 'sqrt', '/'],
            ['7', '8', '9', '*', '-'],
            ['4', '5', '6', '+', '+'],
            ['1', '2', '3', '=', '='],
            ['0', '.', '+', '-', '*']
        ]
        
        # 最终决定版布局：5列，每列宽度一致
        btn_list = [
            ['sin', 'cos', 'tan', 'C', '⌫'],
            ['(', ')', '^', 'sqrt', '/'],
            ['7', '8', '9', '*', '-'],
            ['4', '5', '6', '+', '+'],
            ['1', '2', '3', '=', '='],
            ['0', '.', '+', '-', '*']
        ]
        
        # 再次修正：为了完全相等，我们用最简单的 5x6 网格
        final_buttons = [
            ['sin', 'cos', 'tan', 'C', '⌫'],
            ['(', ')', '^', 'sqrt', '/'],
            ['7', '8', '9', '*', '-'],
            ['4', '5', '6', '+', '+'],
            ['1', '2', '3', '=', '='],
            ['0', '.', '+', '-', '*']
        ]
        
        # 真正最终版：去掉复杂的合并，全部统一大小
        standard_buttons = [
            ['sin', 'cos', 'tan', 'C', '⌫'],
            ['(', ')', '^', 'sqrt', '/'],
            ['7', '8', '9', '*', '-'],
            ['4', '5', '6', '+', '+'],
            ['1', '2', '3', '=', '='],
            ['0', '.', '+', '-', '*']
        ]
        
        # 好的，这是最简单的 4列布局，保证不出错
        simple_buttons = [
            ['sin', 'cos', 'tan', 'C'],
            ['sqrt', '^', '(', ')'],
            ['7', '8', '9', '/'],
            ['4', '5', '6', '*'],
            ['1', '2', '3', '-'],
            ['0', '.', '=', '+']
        ]

        # 渲染按钮
        for i, row in enumerate(simple_buttons):
            for j, text in enumerate(row):
                # 设置颜色
                bg_color = "#e0e0e0" # 默认背景色
                fg_color = "black"
                
                if text == '=':
                    bg_color = "#FF9800" # 等于号橙色
                    fg_color = "white"
                elif text == 'C':
                    bg_color = "#f44336" # 清除键红色
                    fg_color = "white"
                
                btn = tk.Button(calc_frame, text=text, font=("Arial", 14), bg=bg_color, fg=fg_color,
                               command=lambda t=text: self.calc_click(t))
                btn.grid(row=i+1, column=j, sticky="nsew", padx=2, pady=2, ipadx=10, ipady=10)
            
            # 配置行列权重，让按钮自动填满
            calc_frame.grid_columnconfigure(j, weight=1)
            calc_frame.grid_rowconfigure(i+1, weight=1)

        # --- 选项卡2：生活计算 ---
        life_frame = tk.Frame(notebook)
        notebook.add(life_frame, text="生活计算")
        
        tk.Label(life_frame, text="原价：").pack(pady=5)
        self.life_price = tk.Entry(life_frame)
        self.life_price.pack(pady=5)
        
        tk.Label(life_frame, text="折扣（如85折填0.85）：").pack(pady=5)
        self.life_discount = tk.Entry(life_frame)
        self.life_discount.pack(pady=5)
        
        tk.Label(life_frame, text="满减金额：").pack(pady=5)
        self.life_minus = tk.Entry(life_frame)
        self.life_minus.pack(pady=5)
        
        tk.Button(life_frame, text="计算最终价格", command=self.calc_life_price, bg="#2196F3", fg="white").pack(pady=10)
        self.life_result = tk.Label(life_frame, text="", fg="red", font=("Arial", 14, "bold"))
        self.life_result.pack(pady=10)

        # --- 选项卡3：方程计算 ---
        eq_frame = tk.Frame(notebook)
        notebook.add(eq_frame, text="方程求解")
        
        tk.Label(eq_frame, text="一元一次方程求解 (Ax + B = C)", font=("Arial", 14)).pack(pady=20)
        
        eq_input_frame = tk.Frame(eq_frame)
        eq_input_frame.pack()
        
        tk.Label(eq_input_frame, text="A：").grid(row=0, column=0, padx=5)
        self.eq_a = tk.Entry(eq_input_frame, width=10)
        self.eq_a.grid(row=0, column=1, padx=5)
        
        tk.Label(eq_input_frame, text="x + ").grid(row=0, column=2)
        
        tk.Label(eq_input_frame, text="B：").grid(row=0, column=3, padx=5)
        self.eq_b = tk.Entry(eq_input_frame, width=10)
        self.eq_b.grid(row=0, column=4, padx=5)
        
        tk.Label(eq_input_frame, text=" = ").grid(row=0, column=5)
        
        tk.Label(eq_input_frame, text="C：").grid(row=0, column=6, padx=5)
        self.eq_c = tk.Entry(eq_input_frame, width=10)
        self.eq_c.grid(row=0, column=7, padx=5)
        
        tk.Button(eq_frame, text="求解 x", command=self.solve_equation, font=("Arial", 12), bg="#4CAF50", fg="white").pack(pady=20)
        self.eq_result = tk.Label(eq_frame, text="", font=("Arial", 16, "bold"), fg="blue")
        self.eq_result.pack()

    # ================= 计算器逻辑函数 =================
    
    # 1. 科学计算逻辑
    def calc_click(self, char):
        if char == '=':
            try:
                expr = self.calc_entry.get()
                # 替换数学函数
                expr = expr.replace('^', '**')
                expr = expr.replace('sqrt', 'math.sqrt')
                expr = expr.replace('sin', 'math.sin')
                expr = expr.replace('cos', 'math.cos')
                expr = expr.replace('tan', 'math.tan')
                result = eval(expr)
                self.calc_entry.delete(0, tk.END)
                self.calc_entry.insert(0, str(result))
            except Exception as e:
                self.calc_entry.delete(0, tk.END)
                self.calc_entry.insert(0, "错误")
        elif char == 'C':
            self.calc_entry.delete(0, tk.END)
        elif char == '⌫':
            current = self.calc_entry.get()
            self.calc_entry.delete(0, tk.END)
            self.calc_entry.insert(0, current[:-1])
        else:
            self.calc_entry.insert(tk.END, char)

    # 2. 生活计算逻辑
    def calc_life_price(self):
        try:
            price = float(self.life_price.get())
            discount = float(self.life_discount.get())
            minus = float(self.life_minus.get())
            
            final_price = price * discount - minus
            
            if final_price < 0:
                final_price = 0
                
            self.life_result.config(text=f"最终价格：{final_price:.2f} 元")
        except:
            messagebox.showerror("错误", "请输入有效的数字")

    # 3. 方程求解逻辑
    def solve_equation(self):
        try:
            a = float(self.eq_a.get())
            b = float(self.eq_b.get())
            c = float(self.eq_c.get())
            if a == 0:
                self.eq_result.config(text="A不能为0")
            else:
                x = (c - b) / a
                self.eq_result.config(text=f"x = {x}")
        except:
            messagebox.showerror("错误", "请输入有效数字")
    # ================= 2. 亲戚计算器 (优化版) =================
    def show_relative_calc(self):
        self.clear_main()
        tk.Label(self.main_frame, text="中国亲戚关系计算器", font=("Arial", 16, "bold")).pack(pady=10)
        
        # 显示区
        self.rel_display = tk.Entry(self.main_frame, font=("Arial", 14), justify="right")
        self.rel_display.pack(fill=tk.X, padx=10, pady=5)
        self.rel_display.insert(0, "我")
        
        # 按键区 (仅保留核心8个)
        btn_frame = tk.Frame(self.main_frame)
        btn_frame.pack(padx=20, pady=10)
        
        # 定义核心亲戚按钮
        core_rels = ["爸爸", "妈妈", "哥哥", "姐姐", "弟弟", "妹妹", "儿子", "女儿"]
        
        # 排列按钮 (2行4列)
        for i, rel in enumerate(core_rels):
            btn = tk.Button(btn_frame, text=rel, width=10, height=2, 
                           command=lambda r=rel: self.add_relative(r))
            btn.grid(row=i//4, column=i%4, padx=5, pady=5)
        
        # 操作按钮
        op_frame = tk.Frame(self.main_frame)
        op_frame.pack(pady=10)
        tk.Button(op_frame, text="查询", command=self.calc_relative_logic, bg="blue", fg="white").pack(side=tk.LEFT, padx=5)
        tk.Button(op_frame, text="重置", command=self.reset_relative, bg="red", fg="white").pack(side=tk.LEFT, padx=5)
        
        # 结果显示
        self.rel_result = tk.Label(self.main_frame, text="", fg="red", font=("Arial", 14))
        self.rel_result.pack()

    def add_relative(self, rel):
        current = self.rel_display.get()
        # 移除初始的"我"或者末尾的"的"
        if current == "我":
            new_path = "我的" + rel
        else:
            new_path = current + "的" + rel
        self.rel_display.delete(0, tk.END)
        self.rel_display.insert(0, new_path)

    def reset_relative(self):
        self.rel_display.delete(0, tk.END)
        self.rel_display.insert(0, "我")
        self.rel_result.config(text="")

    def calc_relative_logic(self):
        path = self.rel_display.get()
        # 逻辑优化，支持更复杂的推演
        if "我的" in path:
            path = path.replace("我的", "")
        
        relations = {
            "爸爸": "父亲", "妈妈": "母亲",
            "爸爸的爸爸": "爷爷", "爸爸的妈妈": "奶奶",
            "妈妈的爸爸": "外公", "妈妈的妈妈": "外婆",
            "爸爸的哥哥": "伯父", "爸爸的弟弟": "叔叔",
            "爸爸的姐姐": "姑妈", "爸爸的妹妹": "姑妈",
            "妈妈的哥哥": "舅舅", "妈妈的弟弟": "舅舅",
            "妈妈的姐姐": "姨妈", "妈妈的妹妹": "姨妈",
            "哥哥的儿子": "侄子", "哥哥的女儿": "侄女",
            "弟弟的儿子": "侄子", "弟弟的女儿": "侄女",
            "姐姐的儿子": "外甥", "姐姐的女儿": "外甥女",
            "妹妹的儿子": "外甥", "妹妹的女儿": "外甥女",
            "儿子": "儿子", "女儿": "女儿",
            "儿子的儿子": "孙子", "儿子的女儿": "孙女",
            "女儿的儿子": "外孙", "女儿的女儿": "外孙女",
        }
        
        # 简单匹配
        result = "未知关系"
        for key in sorted(relations.keys(), key=len, reverse=True):
            if key in path:
                result = relations[key]
                break
                
        self.rel_result.config(text=f"他是你的：{result}")

    # ================= 3. 汇率转换器 (增加币种) =================
    def show_currency(self):
        self.clear_main()
        tk.Label(self.main_frame, text="汇率换算（模拟数据）", font=("Arial", 14)).pack(pady=10)
        
        # 扩充汇率数据
        self.rates = {
            "🇨🇳 人民币 (CNY)": 1.0,
            "🇺🇸 美元 (USD)": 0.14,
            "🇪🇺 欧元 (EUR)": 0.13,
            "🇯🇵 日元 (JPY)": 21.5,
            "🇬🇧 英镑 (GBP)": 0.11,
            "🇭🇰 港币 (HKD)": 1.08,
            "🇰🇷 韩元 (KRW)": 180.0,
            "🇨🇦 加元 (CAD)": 0.19
        }
        
        tk.Label(self.main_frame, text="金额：").pack()
        self.cur_amt = tk.Entry(self.main_frame)
        self.cur_amt.pack()
        
        tk.Label(self.main_frame, text="从：").pack()
        self.cur_from = ttk.Combobox(self.main_frame, values=list(self.rates.keys()))
        self.cur_from.pack()
        self.cur_from.set("🇨🇳 人民币 (CNY)")
        
        tk.Label(self.main_frame, text="到：").pack()
        self.cur_to = ttk.Combobox(self.main_frame, values=list(self.rates.keys()))
        self.cur_to.pack()
        self.cur_to.set("🇺🇸 美元 (USD)")
        
        tk.Button(self.main_frame, text="换算", command=self.convert_currency).pack(pady=10)
        self.cur_res = tk.Label(self.main_frame, text="", font=("Arial", 12, "bold"))
        self.cur_res.pack()

    def convert_currency(self):
        try:
            amt = float(self.cur_amt.get())
            from_key = self.cur_from.get()
            to_key = self.cur_to.get()
            
            rate_from = self.rates[from_key]
            rate_to = self.rates[to_key]
            
            # 统一转为人民币再转出
            final_val = amt * rate_from / rate_to
            self.cur_res.config(text=f"结果：{final_val:.2f} {to_key.split()[-1]}")
        except:
            messagebox.showerror("错误", "输入错误")

    # ================= 4. 房贷/车贷 (保持不变) =================
    def show_loan_calc(self):
        self.clear_main()
        tk.Label(self.main_frame, text="贷款计算器", font=("Arial", 14)).pack(pady=10)
        tk.Label(self.main_frame, text="贷款金额（万）：").pack()
        self.loan_p = tk.Entry(self.main_frame)
        self.loan_p.pack()
        tk.Label(self.main_frame, text="年利率（%）：").pack()
        self.loan_r = tk.Entry(self.main_frame)
        self.loan_r.pack()
        tk.Label(self.main_frame, text="年限：").pack()
        self.loan_y = tk.Entry(self.main_frame)
        self.loan_y.pack()
        tk.Button(self.main_frame, text="计算月供", command=self.calc_loan).pack(pady=10)
        self.loan_res = tk.Label(self.main_frame, text="")
        self.loan_res.pack()

    def calc_loan(self):
        try:
            p = float(self.loan_p.get()) * 10000
            r = float(self.loan_r.get()) / 100 / 12
            n = float(self.loan_y.get()) * 12
            payment = p * (r * (1+r)**n) / ((1+r)**n - 1)
            self.loan_res.config(text=f"每月还款：{payment:.2f} 元")
        except:
            messagebox.showerror("错误", "数据无效")

    # ================= 5. 个税计算 (保持不变) =================
    def show_tax_calc(self):
        self.clear_main()
        tk.Label(self.main_frame, text="个人所得税计算", font=("Arial", 14)).pack(pady=10)
        tk.Label(self.main_frame, text="税前工资：").pack()
        self.tax_in = tk.Entry(self.main_frame)
        self.tax_in.pack()
        tk.Button(self.main_frame, text="计算", command=self.calc_tax).pack()
        self.tax_res = tk.Label(self.main_frame, text="")
        self.tax_res.pack()

    def calc_tax(self):
        try:
            salary = float(self.tax_in.get())
            threshold = 5000
            taxable = salary - threshold
            tax = 0
            if taxable > 0:
                if taxable <= 3000:
                    tax = taxable * 0.03
                elif taxable <= 12000:
                    tax = taxable * 0.1 - 210
                else:
                    tax = taxable * 0.2 - 1410
            self.tax_res.config(text=f"应缴个税：{tax:.2f}")
        except:
            messagebox.showerror("错误", "输入无效")

    # ================= 6. 进制转换 (保持不变) =================
    def show_base_convert(self):
        self.clear_main()
        tk.Label(self.main_frame, text="进制转换器", font=("Arial", 14)).pack(pady=10)
        tk.Label(self.main_frame, text="输入数字：").pack()
        self.base_in = tk.Entry(self.main_frame)
        self.base_in.pack()
        tk.Label(self.main_frame, text="原进制（2/8/10/16）：").pack()
        self.base_from = tk.Entry(self.main_frame)
        self.base_from.pack()
        tk.Label(self.main_frame, text="目标进制（2/8/10/16）：").pack()
        self.base_to = tk.Entry(self.main_frame)
        self.base_to.pack()
        tk.Button(self.main_frame, text="转换", command=self.convert_base).pack(pady=10)
        self.base_res = tk.Label(self.main_frame, text="")
        self.base_res.pack()

    def convert_base(self):
        try:
            val = self.base_in.get()
            from_base = int(self.base_from.get())
            to_base = int(self.base_to.get())
            
            # 转为10进制
            dec_val = int(val, from_base)
            
            # 转为目标进制
            if to_base == 2:
                res = bin(dec_val)[2:]
            elif to_base == 8:
                res = oct(dec_val)[2:]
            elif to_base == 16:
                res = hex(dec_val)[2:].upper()
            else:
                res = str(dec_val)
                
            self.base_res.config(text=f"结果：{res}")
        except:
            messagebox.showerror("错误", "转换失败")

    # ================= 7. 大写金额 (增加读作) =================
    def show_money_convert(self):
        self.clear_main()
        tk.Label(self.main_frame, text="大写金额转换器", font=("Arial", 14)).pack(pady=10)
        tk.Label(self.main_frame, text="输入金额：").pack()
        self.money_in = tk.Entry(self.main_frame)
        self.money_in.pack()
        tk.Button(self.main_frame, text="转换", command=self.convert_money).pack(pady=10)
        
        self.money_cap = tk.Label(self.main_frame, text="", fg="red", font=("Arial", 12))
        self.money_cap.pack()
        
        # 新增读作逻辑
        self.money_read = tk.Label(self.main_frame, text="", fg="blue", font=("Arial", 10))
        self.money_read.pack()

    def convert_money(self):
        try:
            num = float(self.money_in.get())
            # 转换逻辑
            s = '{:,.2f}'.format(num)
            digits = '零壹贰叁肆伍陆柒捌玖'
            units = ['', '拾', '佰', '仟']
            big_units = ['元', '万', '亿']
            
            integer, decimal = s.split('.')
            integer = integer[::-1]
            result = ''
            
            for i, ch in enumerate(integer):
                n = int(ch)
                result = digits[n] + (units[i % 4] if n else '') + (big_units[i // 4] if i % 4 == 0 and n else '') + result
                
            result = result.replace('零零', '零').replace('零元', '元').replace('零万', '万').replace('零亿', '亿') + f'点{digits[int(decimal[0])]}{digits[int(decimal[1])]}'
            
            self.money_cap.config(text=f"大写：{result}")
            
            # 读作逻辑
            read_str = self.money_in.get()
            if '.' in read_str:
                int_part, dec_part = read_str.split('.')
                read_text = f"读作：人民币{int_part}元{dec_part[0]}角{dec_part[1]}分"
            else:
                read_text = f"读作：人民币{read_str}元整"
                
            self.money_read.config(text=read_text)
            
        except:
            messagebox.showerror("错误", "输入无效")

    # ================= 8. 全能时钟 (最终修正版) =================
    def show_clock(self):
        self.clear_main()
        
        # 创建选项卡
        notebook = ttk.Notebook(self.main_frame)
        notebook.pack(fill=tk.BOTH, expand=True)
        
        # --- 选项卡1：当前时间 ---
        time_frame = tk.Frame(notebook, bg="black")
        notebook.add(time_frame, text="当前时间")
        
        self.clock_label = tk.Label(time_frame, text="", font=("Arial", 60, "bold"), fg="#00FF00", bg="black")
        self.clock_label.pack(expand=True)
        self.update_current_time()
        
        # --- 选项卡2：秒表 ---
        watch_frame = tk.Frame(notebook)
        notebook.add(watch_frame, text="秒表")
        
        self.stopwatch_display = tk.Label(watch_frame, text="00:00:00", font=("Arial", 50), pady=20)
        self.stopwatch_display.pack()
        
        sw_btn_frame = tk.Frame(watch_frame)
        sw_btn_frame.pack(pady=10)
        
        # 增加“继续”按钮
        tk.Button(sw_btn_frame, text="开始", command=self.start_stopwatch, width=8, bg="#4CAF50", fg="white").pack(side=tk.LEFT, padx=5)
        tk.Button(sw_btn_frame, text="暂停", command=self.pause_stopwatch, width=8, bg="#FF9800", fg="white").pack(side=tk.LEFT, padx=5)
        tk.Button(sw_btn_frame, text="继续", command=self.resume_stopwatch, width=8, bg="#2196F3", fg="white").pack(side=tk.LEFT, padx=5)
        tk.Button(sw_btn_frame, text="重置", command=self.reset_stopwatch, width=8, bg="#f44336", fg="white").pack(side=tk.LEFT, padx=5)
        
        # --- 选项卡3：倒计时 ---
        timer_frame = tk.Frame(notebook)
        notebook.add(timer_frame, text="倒计时")
        
        # 设置时间区域
        set_frame = tk.Frame(timer_frame)
        set_frame.pack(pady=10)
        
        tk.Label(set_frame, text="时").pack(side=tk.LEFT)
        self.timer_h = tk.Spinbox(set_frame, from_=0, to=23, width=5, font=("Arial", 14))
        self.timer_h.pack(side=tk.LEFT, padx=5)
        
        tk.Label(set_frame, text="分").pack(side=tk.LEFT)
        self.timer_m = tk.Spinbox(set_frame, from_=0, to=59, width=5, font=("Arial", 14))
        self.timer_m.pack(side=tk.LEFT, padx=5)
        
        tk.Label(set_frame, text="秒").pack(side=tk.LEFT)
        self.timer_s = tk.Spinbox(set_frame, from_=0, to=59, width=5, font=("Arial", 14))
        self.timer_s.pack(side=tk.LEFT, padx=5)
        
        # 倒计时显示
        self.timer_display = tk.Label(timer_frame, text="00:00:00", font=("Arial", 50), pady=20)
        self.timer_display.pack()
        
        tm_btn_frame = tk.Frame(timer_frame)
        tm_btn_frame.pack(pady=10)
        
        # 增加“继续”按钮
        tk.Button(tm_btn_frame, text="开始", command=self.start_timer, width=8, bg="#4CAF50", fg="white").pack(side=tk.LEFT, padx=5)
        tk.Button(tm_btn_frame, text="暂停", command=self.pause_timer, width=8, bg="#FF9800", fg="white").pack(side=tk.LEFT, padx=5)
        tk.Button(tm_btn_frame, text="继续", command=self.resume_timer, width=8, bg="#2196F3", fg="white").pack(side=tk.LEFT, padx=5)
        tk.Button(tm_btn_frame, text="重置", command=self.reset_timer, width=8, bg="#f44336", fg="white").pack(side=tk.LEFT, padx=5)
        
        # --- 选项卡4：闹钟 ---
        alarm_frame = tk.Frame(notebook)
        notebook.add(alarm_frame, text="闹钟")
        
        tk.Label(alarm_frame, text="设置闹钟时间 (24小时制)", font=("Arial", 14)).pack(pady=10)
        
        al_set_frame = tk.Frame(alarm_frame)
        al_set_frame.pack(pady=5)
        
        tk.Label(al_set_frame, text="时").pack(side=tk.LEFT)
        self.alarm_h = tk.Spinbox(al_set_frame, from_=0, to=23, width=5, font=("Arial", 14))
        self.alarm_h.pack(side=tk.LEFT, padx=5)
        
        tk.Label(al_set_frame, text="分").pack(side=tk.LEFT)
        self.alarm_m = tk.Spinbox(al_set_frame, from_=0, to=59, width=5, font=("Arial", 14))
        self.alarm_m.pack(side=tk.LEFT, padx=5)
        
        tk.Button(alarm_frame, text="设定闹钟", command=self.set_alarm, bg="#2196F3", fg="white", font=("Arial", 12)).pack(pady=20)
        
        self.alarm_status = tk.Label(alarm_frame, text="未设定", fg="gray")
        self.alarm_status.pack()

    # ================= 时钟逻辑函数 (修正版) =================
    
    # 1. 当前时间
    def update_current_time(self):
        now = datetime.datetime.now()
        self.clock_label.config(text=now.strftime("%H:%M:%S"))
        self.root.after(1000, self.update_current_time)
        
        # 检查闹钟
        current_time_str = now.strftime("%H:%M")
        if hasattr(self, 'alarm_set_time') and self.alarm_set_time:
            if current_time_str == self.alarm_set_time and now.second == 0:
                messagebox.showinfo("闹钟响了！", "时间到了！快起床/工作吧！")
                self.alarm_set_time = None
                self.alarm_status.config(text="已响铃，需重新设定", fg="red")

    # 2. 秒表逻辑
    def start_stopwatch(self):
        # 如果是第一次启动
        if not hasattr(self, 'sw_running') or not self.sw_running:
            self.sw_running = True
            self.sw_start_time = datetime.datetime.now() - datetime.timedelta(seconds=self.sw_elapsed if hasattr(self, 'sw_elapsed') else 0)
            self.update_stopwatch()

    def pause_stopwatch(self):
        if hasattr(self, 'sw_running') and self.sw_running:
            self.sw_running = False
            # 记录暂停时的累计时间
            self.sw_elapsed = (datetime.datetime.now() - self.sw_start_time).total_seconds()

    def resume_stopwatch(self):
        # 继续功能：从暂停的时间点继续
        if hasattr(self, 'sw_elapsed') and self.sw_elapsed > 0 and not self.sw_running:
            self.sw_running = True
            self.sw_start_time = datetime.datetime.now() - datetime.timedelta(seconds=self.sw_elapsed)
            self.update_stopwatch()

    def reset_stopwatch(self):
        self.sw_running = False
        self.sw_elapsed = 0
        self.stopwatch_display.config(text="00:00:00")

    def update_stopwatch(self):
        if self.sw_running:
            elapsed = (datetime.datetime.now() - self.sw_start_time).total_seconds()
            self.sw_elapsed = elapsed
            hours = int(elapsed // 3600)
            minutes = int((elapsed % 3600) // 60)
            seconds = int(elapsed % 60)
            self.stopwatch_display.config(text=f"{hours:02d}:{minutes:02d}:{seconds:02d}")
            self.root.after(100, self.update_stopwatch)

    # 3. 倒计时逻辑 (一秒一跳修正版)
    def start_timer(self):
        # 如果是第一次启动（从 Spinbox 读取时间）
        if not hasattr(self, 'tm_running') or not self.tm_running:
            try:
                h = int(self.timer_h.get())
                m = int(self.timer_m.get())
                s = int(self.timer_s.get())
                total_seconds = h * 3600 + m * 60 + s
                
                if total_seconds > 0:
                    self.tm_running = True
                    self.tm_remaining = total_seconds
                    self.update_timer()
            except:
                pass

    def pause_timer(self):
        if hasattr(self, 'tm_running') and self.tm_running:
            self.tm_running = False

    def resume_timer(self):
        # 继续功能
        if hasattr(self, 'tm_running') and hasattr(self, 'tm_remaining') and self.tm_remaining > 0 and not self.tm_running:
            self.tm_running = True
            self.update_timer()

    def reset_timer(self):
        self.tm_running = False
        self.tm_remaining = 0
        self.timer_display.config(text="00:00:00")

    def update_timer(self):
        if self.tm_running and self.tm_remaining > 0:
            # 格式化显示
            h = self.tm_remaining // 3600
            m = (self.tm_remaining % 3600) // 60
            s = self.tm_remaining % 60
            self.timer_display.config(text=f"{h:02d}:{m:02d}:{s:02d}")
            
            # 关键修正：每秒减少1
            self.tm_remaining -= 1
            
            # 这里的1000毫秒对应减少1秒
            self.root.after(1000, self.update_timer)
        elif self.tm_running and self.tm_remaining == 0:
            self.tm_running = False
            self.timer_display.config(text="00:00:00")
            messagebox.showinfo("倒计时结束", "时间到！")

    # 4. 闹钟逻辑
    def set_alarm(self):
        h = self.alarm_h.get()
        m = self.alarm_m.get()
        self.alarm_set_time = f"{h}:{m}"
        self.alarm_status.config(text=f"闹钟已设定为 {self.alarm_set_time}", fg="green")
        messagebox.showinfo("闹钟", f"闹钟已设定：{self.alarm_set_time}\n（请保持软件运行）")
    # ================= 9. 多功能笔记 (单一方框版) =================
    def show_notebook(self):
        self.clear_main()
        tk.Label(self.main_frame, text="多功能笔记", font=("Arial", 14)).pack(pady=10)
        
        # 顶部按钮
        file_frame = tk.Frame(self.main_frame)
        file_frame.pack(fill=tk.X, padx=10)
        tk.Button(file_frame, text="新建", command=self.new_note).pack(side=tk.LEFT, padx=5)
        tk.Button(file_frame, text="保存", command=self.save_note).pack(side=tk.LEFT, padx=5)
        tk.Button(file_frame, text="打开", command=self.open_note_dialog).pack(side=tk.LEFT, padx=5)
        tk.Button(file_frame, text="颜色", command=self.choose_note_color).pack(side=tk.RIGHT, padx=5)
        
        self.note_color = "black"
        
        # 单个大方框
        self.note_text = tk.Text(self.main_frame, font=("Microsoft YaHei", 12))
        self.note_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        self.current_file = None

    def choose_note_color(self):
        color = colorchooser.askcolor()[1]
        if color:
            self.note_color = color
            self.note_text.config(fg=self.note_color)

    def new_note(self):
        self.note_text.delete(1.0, tk.END)
        self.current_file = None

    def save_note(self):
        content = self.note_text.get(1.0, tk.END)
        if self.current_file:
            with open(self.current_file, 'w', encoding='utf-8') as f:
                f.write(content)
        else:
            filename = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])
            if filename:
                with open(filename, 'w', encoding='utf-8') as f:
                    f.write(content)
                self.current_file = filename
        messagebox.showinfo("保存", "保存成功")

    def open_note_dialog(self):
        filename = filedialog.askopenfilename(filetypes=[("Text Files", "*.txt")])
        if filename:
            self.current_file = filename
            with open(filename, 'r', encoding='utf-8') as f:
                content = f.read()
            self.note_text.delete(1.0, tk.END)
            self.note_text.insert(tk.END, content)

    # ================= 10. 错题本 (单一方框版) =================
    def show_error_book(self):
        self.clear_main()
        tk.Label(self.main_frame, text="错题本", font=("Arial", 14)).pack(pady=10)
        
        # 顶部按钮
        op_frame = tk.Frame(self.main_frame)
        op_frame.pack(fill=tk.X, padx=10)
        tk.Button(op_frame, text="保存错题", command=self.save_error).pack(side=tk.LEFT, padx=5)
        tk.Button(op_frame, text="打开错题", command=self.open_error_dialog).pack(side=tk.LEFT, padx=5)
        
        # 单个大方框
        self.error_text = tk.Text(self.main_frame, font=("Microsoft YaHei", 12), fg="blue")
        self.error_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        self.current_error_file = None

    def save_error(self):
        content = self.error_text.get(1.0, tk.END)
        if self.current_error_file:
            filename = self.current_error_file
        else:
            filename = f"错题_{datetime.datetime.now().strftime('%Y%m%d')}.txt"
            
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(content)
        self.current_error_file = filename
        messagebox.showinfo("保存", f"错题已保存为 {filename}")

    def open_error_dialog(self):
        filename = filedialog.askopenfilename(filetypes=[("Text Files", "*.txt")])
        if filename:
            self.current_error_file = filename
            with open(filename, 'r', encoding='utf-8') as f:
                content = f.read()
            self.error_text.delete(1.0, tk.END)
            self.error_text.insert(tk.END, content)

    # ================= 11. 绘画本 (增加粗细和橡皮) =================
    def show_drawing(self):
        self.clear_main()
        tk.Label(self.main_frame, text="绘画本", font=("Arial", 14)).pack(pady=10)
        
        # 工具栏
        tool_frame = tk.Frame(self.main_frame)
        tool_frame.pack(fill=tk.X, padx=10)
        
        tk.Button(tool_frame, text="清空", command=self.clear_canvas).pack(side=tk.LEFT, padx=5)
        tk.Button(tool_frame, text="保存", command=self.save_drawing).pack(side=tk.LEFT, padx=5)
        tk.Button(tool_frame, text="颜色", command=self.choose_drawing_color).pack(side=tk.LEFT, padx=5)
        
        # 新增：橡皮擦
        tk.Button(tool_frame, text="橡皮擦", command=self.use_eraser, bg="#ddd").pack(side=tk.LEFT, padx=5)
        
        # 新增：粗细调节
        tk.Label(tool_frame, text="粗细:").pack(side=tk.LEFT, padx=5)
        self.brush_width = tk.Scale(tool_frame, from_=1, to=20, orient=tk.HORIZONTAL)
        self.brush_width.set(5) # 默认粗细
        self.brush_width.pack(side=tk.LEFT)

        # 画布
        self.drawing_canvas = tk.Canvas(self.main_frame, bg="white", width=800, height=500)
        self.drawing_canvas.pack(pady=10)
        
        self.drawing_canvas.bind("<B1-Motion>", self.paint)
        self.drawing_canvas.bind("<Button-1>", self.on_draw_start)
        
        self.drawing_color = "black"

    def use_eraser(self):
        self.drawing_color = "white" # 橡皮其实就是画白色的线

    def choose_drawing_color(self):
        color = colorchooser.askcolor()[1]
        if color:
            self.drawing_color = color

    def on_draw_start(self, event):
        self.last_x, self.last_y = event.x, event.y

    def paint(self, event):
        x, y = event.x, event.y
        # 获取当前滑块设定的粗细
        width = self.brush_width.get()
        self.drawing_canvas.create_line(self.last_x, self.last_y, x, y, 
                                       fill=self.drawing_color, width=width, 
                                       capstyle=tk.ROUND, smooth=True)
        self.last_x, self.last_y = x, y

    def clear_canvas(self):
        self.drawing_canvas.delete("all")

    def save_drawing(self):
        try:
            filename = filedialog.asksaveasfilename(defaultextension=".ps", filetypes=[("PostScript Files", "*.ps")])
            if filename:
                self.drawing_canvas.postscript(file=filename, colormode='color')
                messagebox.showinfo("保存", f"画作已保存为: {filename}")
        except Exception as e:
            messagebox.showerror("错误", str(e))

    # ================= 12. 随机点名 (骰子动画+评分) =================
    def show_roller(self):
        self.clear_main()
        tk.Label(self.main_frame, text="🎲 随机点名器", font=("Arial", 16, "bold")).pack(pady=20)
        
        self.roller_display = tk.Label(self.main_frame, text="点击开始", font=("Arial", 40), width=10)
        self.roller_display.pack(pady=20)
        
        self.roll_btn = tk.Button(self.main_frame, text="开始摇号", font=("Arial", 14), command=self.start_roll, bg="green", fg="white")
        self.roll_btn.pack(pady=10)
        
        # 评分系统
        rate_frame = tk.Frame(self.main_frame)
        rate_frame.pack(pady=10)
        tk.Label(rate_frame, text="给TA打分：").pack(side=tk.LEFT)
        self.rating = tk.Scale(rate_frame, from_=0, to=10, orient=tk.HORIZONTAL, resolution=1)
        self.rating.pack(side=tk.LEFT)
        tk.Button(rate_frame, text="记录", command=self.record_rating).pack(side=tk.LEFT, padx=10)

    def start_roll(self):
        names = ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", "郑一", "王二"]
        self.rolling = True
        self.roll_btn.config(state='disabled', text="滚动中...")
        
        def roll():
            if self.rolling:
                name = random.choice(names)
                self.roller_display.config(text=name)
                self.root.after(100, roll) # 100ms 刷新一次
            else:
                self.roll_btn.config(state='normal', text="重新开始")
                
        roll()
        
        # 3秒后停止 (模拟)
        self.root.after(3000, lambda: setattr(self, 'rolling', False))

    def record_rating(self):
        name = self.roller_display.cget("text")
        score = self.rating.get()
        with open("ratings.txt", "a", encoding="utf-8") as f:
            f.write(f"{name},{score},{datetime.datetime.now()}\n")
        messagebox.showinfo("记录", f"已记录 {name} 的评分 {score} 分")

    # ================= 13. 成绩走势2D (折线图+交互) =================
    def show_grade_chart(self):
        self.clear_main()
        tk.Label(self.main_frame, text="📊 成绩走势折线图", font=("Arial", 14)).pack(pady=10)
        
        # 模拟数据 (你可以根据需要修改)
        subjects = ['语文', '数学', '英语', '物理', '化学', '生物']
        # 模拟三次考试成绩
        scores_1 = [85, 90, 88, 75, 80, 95]
        scores_2 = [88, 92, 85, 78, 85, 90]
        scores_3 = [90, 95, 90, 82, 88, 98]
        
        # 创建图表
        fig = Figure(figsize=(8, 5), dpi=100)
        ax = fig.add_subplot(111)
        
        # 绘制折线
        ax.plot(subjects, scores_1, marker='o', label='第一次月考')
        ax.plot(subjects, scores_2, marker='s', label='期中考试')
        ax.plot(subjects, scores_3, marker='^', label='第二次月考')
        
        ax.set_xlabel('科目')
        ax.set_ylabel('分数')
        ax.set_title('我的成绩走势图')
        ax.legend() # 显示图例
        ax.grid(True) # 显示网格
        
        # 添加数据标签 (鼠标悬停显示)
        for i, txt in enumerate(scores_1):
            ax.annotate(txt, (subjects[i], scores_1[i]), xytext=(5, 5), textcoords='offset points')
        for i, txt in enumerate(scores_2):
            ax.annotate(txt, (subjects[i], scores_2[i]), xytext=(5, 5), textcoords='offset points')
            
        canvas = FigureCanvasTkAgg(fig, self.main_frame)
        canvas.draw()
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 提示语
        tk.Label(self.main_frame, text="提示：图表已生成，数据点上有分数标注", fg="gray").pack()

    # ================= 14. 身份证解析 (数据扩充) =================
    def show_id_parser(self):
        self.clear_main()
        tk.Label(self.main_frame, text="🆔 身份证号码解析", font=("Arial", 14)).pack(pady=10)
        tk.Label(self.main_frame, text="输入身份证号：").pack()
        self.id_input = tk.Entry(self.main_frame, width=30)
        self.id_input.pack()
        tk.Button(self.main_frame, text="解析", command=self.parse_id).pack(pady=10)
        self.id_result = tk.Text(self.main_frame, height=10, state='disabled')
        self.id_result.pack(fill=tk.X, padx=10)

    def parse_id(self):
        code = self.id_input.get().strip()
        if len(code) != 18:
            messagebox.showerror("错误", "身份证号必须是18位")
            return
            
        # 地区码映射 (扩充版)
        area_map = {
            "11": "北京", "12": "天津", "13": "河北", "14": "山西", "15": "内蒙古",
            "21": "辽宁", "22": "吉林", "23": "黑龙江", "31": "上海", "32": "江苏",
            "33": "浙江", "34": "安徽", "35": "福建", "36": "江西", "37": "山东",
            "41": "河南", "42": "湖北", "43": "湖南", "44": "广东", "45": "广西",
            "46": "海南", "50": "重庆", "51": "四川", "52": "贵州", "53": "云南",
            "54": "西藏", "61": "陕西", "62": "甘肃", "63": "青海", "64": "宁夏", "65": "新疆",
            "71": "台湾", "81": "香港", "82": "澳门"
        }
        
        province_code = code[0:2]
        birth_str = code[6:14]
        
        try:
            # 提取生日
            birth_date = f"{birth_str[0:4]}年{birth_str[4:6]}月{birth_str[6:8]}日"
            
            # 提取性别 (第17位，奇数男偶数女)
            sex_code = int(code[16])
            sex = "男" if sex_code % 2 == 1 else "女"
            
            # 获取地区
            area = area_map.get(province_code, "未知地区")
            
            # 显示结果
            self.id_result.config(state='normal')
            self.id_result.delete(1.0, tk.END)
            self.id_result.insert(tk.END, f"归属地：{area}\n")
            self.id_result.insert(tk.END, f"出生日期：{birth_date}\n")
            self.id_result.insert(tk.END, f"性别：{sex}\n")
            self.id_result.insert(tk.END, f"校验码：{code[17]}")
            self.id_result.config(state='disabled')
            
        except Exception as e:
            messagebox.showerror("错误", f"解析失败：{str(e)}")

    # ================= 15. 车牌归属地 (数据扩充) =================
    def show_car_plate(self):
        self.clear_main()
        tk.Label(self.main_frame, text="🚗 车牌归属地查询", font=("Arial", 14)).pack(pady=10)
        tk.Label(self.main_frame, text="输入车牌（如：苏J）：").pack()
        self.plate_input = tk.Entry(self.main_frame, width=20)
        self.plate_input.pack()
        tk.Button(self.main_frame, text="查询", command=self.parse_plate).pack(pady=10)
        self.plate_result = tk.Label(self.main_frame, text="", font=("Arial", 12, "bold"))
        self.plate_result.pack()

    def parse_plate(self):
        plate = self.plate_input.get().upper().strip()
        if len(plate) < 2:
            messagebox.showwarning("提示", "请输入完整车牌")
            return
            
        province = plate[0]
        city_code = plate[1]
        
        # 省份映射
        provinces = {
            "京": "北京", "沪": "上海", "津": "天津", "渝": "重庆",
            "冀": "河北", "豫": "河南", "云": "云南", "辽": "辽宁",
            "黑": "黑龙江", "湘": "湖南", "皖": "安徽", "鲁": "山东",
            "新": "新疆", "苏": "江苏", "浙": "浙江", "赣": "江西",
            "鄂": "湖北", "桂": "广西", "甘": "甘肃", "晋": "山西",
            "蒙": "内蒙古", "陕": "陕西", "吉": "吉林", "闽": "福建",
            "贵": "贵州", "粤": "广东", "青": "青海", "藏": "西藏",
            "川": "四川", "宁": "宁夏", "琼": "海南"
        }
        
        # 江苏省城市代码 (扩充)
        jiangsu_cities = {
            "A": "南京市", "B": "无锡市", "C": "徐州市", "D": "常州市",
            "E": "苏州市", "F": "南通市", "G": "连云港市", "H": "淮安市",
            "J": "盐城市", "K": "扬州市", "L": "镇江市", "M": "泰州市", "N": "宿迁市"
        }
        
        # 浙江省城市代码
        zhejiang_cities = {
            "A": "杭州市", "B": "宁波市", "C": "温州市", "D": "绍兴市",
            "E": "湖州市", "F": "嘉兴市", "G": "金华市", "H": "衢州市",
            "J": "台州市", "K": "丽水市", "L": "舟山市"
        }

        if province not in provinces:
            self.plate_result.config(text="❓ 未知省份")
            return
            
        province_name = provinces[province]
        city_name = "未知城市"
        
        # 直辖市
        if province in ["京", "沪", "津", "渝"]:
            city_name = "市区"
        # 江苏省特判
        elif province == "苏":
            city_name = jiangsu_cities.get(city_code, "未知城市")
        # 浙江省特判
        elif province == "浙":
            city_name = zhejiang_cities.get(city_code, "未知城市")
        # 其他省份（简单示例，实际可继续扩充）
        else:
            city_name = f"{city_code}字头"
            
        self.plate_result.config(text=f"📍 {province}{city_code}：{province_name} {city_name}")

    # ================= 16. 课程表 (新增) =================
    def show_timetable(self):
        self.clear_main()
        tk.Label(self.main_frame, text="📅 我的课程表", font=("Arial", 14)).pack(pady=10)
        
        # 简单的表格布局
        days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
        periods = ["第1节", "第2节", "第3节", "第4节", "第5节", "第6节", "第7节", "第8节"]
        
        # 顶部表头
        header_frame = tk.Frame(self.main_frame)
        header_frame.pack(fill=tk.X)
        tk.Label(header_frame, text="时间", width=10, relief=tk.RIDGE).pack(side=tk.LEFT)
        for day in days:
            tk.Label(header_frame, text=day, width=12, relief=tk.RIDGE).pack(side=tk.LEFT)
            
        # 课程网格
        self.course_entries = []
        for period in periods:
            row_frame = tk.Frame(self.main_frame)
            row_frame.pack(fill=tk.X)
            tk.Label(row_frame, text=period, width=10, relief=tk.RIDGE).pack(side=tk.LEFT)
            
            row_entries = []
            for day in days:
                entry = tk.Entry(row_frame, width=12)
                entry.pack(side=tk.LEFT, padx=1, pady=1)
                row_entries.append(entry)
            self.course_entries.append(row_entries)
            
        # 保存/加载按钮
        btn_frame = tk.Frame(self.main_frame)
        btn_frame.pack(pady=10)
        tk.Button(btn_frame, text="保存课程表", command=self.save_timetable).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="加载课程表", command=self.load_timetable).pack(side=tk.LEFT, padx=5)

    def save_timetable(self):
        data = []
        for row in self.course_entries:
            row_data = [e.get() for e in row]
            data.append(row_data)
        
        with open("timetable.txt", "w", encoding="utf-8") as f:
            for row in data:
                f.write(",".join(row) + "\n")
        messagebox.showinfo("保存", "课程表已保存")

    def load_timetable(self):
        if not os.path.exists("timetable.txt"):
            return
        with open("timetable.txt", "r", encoding="utf-8") as f:
            lines = f.readlines()
        for i, line in enumerate(lines):
            if i < len(self.course_entries):
                cells = line.strip().split(",")
                for j, val in enumerate(cells):
                    if j < len(self.course_entries[i]):
                        self.course_entries[i][j].delete(0, tk.END)
                        self.course_entries[i][j].insert(0, val)

    # ================= 17. 任务清单 (新增) =================
    def show_todo(self):
        self.clear_main()
        tk.Label(self.main_frame, text="✅ 任务清单", font=("Arial", 14)).pack(pady=10)
        
        # 输入区
        input_frame = tk.Frame(self.main_frame)
        input_frame.pack(fill=tk.X, padx=10)
        self.todo_entry = tk.Entry(input_frame)
        self.todo_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
        tk.Button(input_frame, text="添加", command=self.add_todo).pack(side=tk.LEFT, padx=5)
        
        # 列表区
        self.todo_listbox = tk.Listbox(self.main_frame, height=15)
        self.todo_listbox.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 按钮区
        btn_frame = tk.Frame(self.main_frame)
        btn_frame.pack()
        tk.Button(btn_frame, text="完成/打勾", command=self.check_todo).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="删除", command=self.delete_todo).pack(side=tk.LEFT, padx=5)
        
        self.load_todos()

    def add_todo(self):
        task = self.todo_entry.get()
        if task:
            self.todo_listbox.insert(tk.END, task)
            self.todo_entry.delete(0, tk.END)
            self.save_todos()

    def check_todo(self):
        sel = self.todo_listbox.curselection()
        if sel:
            idx = sel[0]
            text = self.todo_listbox.get(idx)
            if not text.startswith("✅"):
                self.todo_listbox.delete(idx)
                self.todo_listbox.insert(idx, f"✅ {text}")
            self.save_todos()

    def delete_todo(self):
        sel = self.todo_listbox.curselection()
        if sel:
            self.todo_listbox.delete(sel[0])
            self.save_todos()

    def save_todos(self):
        tasks = self.todo_listbox.get(0, tk.END)
        with open("todos.txt", "w", encoding="utf-8") as f:
            for t in tasks:
                f.write(t + "\n")

    def load_todos(self):
        if not os.path.exists("todos.txt"): return
        with open("todos.txt", "r", encoding="utf-8") as f:
            for line in f:
                self.todo_listbox.insert(tk.END, line.strip())

    # ================= 18. 旅行计划 (新增) =================
    def show_travel(self):
        self.clear_main()
        tk.Label(self.main_frame, text="🧳 旅行计划本", font=("Arial", 14)).pack(pady=10)
        
        tk.Label(self.main_frame, text="目的地：").pack()
        self.travel_dest = tk.Entry(self.main_frame)
        self.travel_dest.pack()
        
        tk.Label(self.main_frame, text="日期：").pack()
        self.travel_date = tk.Entry(self.main_frame)
        self.travel_date.pack()
        
        tk.Label(self.main_frame, text="计划内容：").pack()
        self.travel_plan = tk.Text(self.main_frame, height=10)
        self.travel_plan.pack(fill=tk.BOTH, expand=True)
        
        btn_frame = tk.Frame(self.main_frame)
        btn_frame.pack(pady=10)
        tk.Button(btn_frame, text="保存计划", command=self.save_travel).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="打开计划", command=self.load_travel).pack(side=tk.LEFT, padx=5)

    def save_travel(self):
        dest = self.travel_dest.get()
        date = self.travel_date.get()
        plan = self.travel_plan.get(1.0, tk.END)
        
        filename = f"travel_{dest}.txt"
        with open(filename, "w", encoding="utf-8") as f:
            f.write(f"目的地：{dest}\n")
            f.write(f"日期：{date}\n")
            f.write(f"计划：\n{plan}")
        messagebox.showinfo("保存", f"计划已保存至 {filename}")

    def load_travel(self):
        dest = self.travel_dest.get()
        if not dest:
            messagebox.showwarning("提示", "请输入目的地名称以加载")
            return
        filename = f"travel_{dest}.txt"
        if os.path.exists(filename):
            with open(filename, "r", encoding="utf-8") as f:
                content = f.read()
            self.travel_dest.delete(0, tk.END)
            self.travel_dest.insert(0, dest)
            self.travel_date.delete(0, tk.END)
            # 简单的解析逻辑
            lines = content.split("\n")
            if len(lines) > 1:
                self.travel_date.insert(0, lines[1].replace("日期：", ""))
            self.travel_plan.delete(1.0, tk.END)
            self.travel_plan.insert(1.0, content)
        else:
            messagebox.showerror("错误", "未找到该目的地的计划")

    # ================= 19. 星座/生肖查询 (新增) =================
    def show_horoscope(self):
        self.clear_main()
        tk.Label(self.main_frame, text="♈ 星座与生肖查询", font=("Arial", 14)).pack(pady=10)
        
        # 星座查询
        zodiac_frame = tk.Frame(self.main_frame)
        zodiac_frame.pack(pady=10)
        tk.Label(zodiac_frame, text="生日（MMDD）：").pack(side=tk.LEFT)
        self.zodiac_input = tk.Entry(zodiac_frame, width=10)
        self.zodiac_input.pack(side=tk.LEFT)
        tk.Button(zodiac_frame, text="查星座", command=self.check_zodiac).pack(side=tk.LEFT, padx=5)
        self.zodiac_res = tk.Label(self.main_frame, text="", fg="purple")
        self.zodiac_res.pack()
        
        # 生肖查询
        animal_frame = tk.Frame(self.main_frame)
        animal_frame.pack(pady=10)
        tk.Label(animal_frame, text="年份（YYYY）：").pack(side=tk.LEFT)
        self.animal_input = tk.Entry(animal_frame, width=10)
        self.animal_input.pack(side=tk.LEFT)
        tk.Button(animal_frame, text="查生肖", command=self.check_animal).pack(side=tk.LEFT, padx=5)
        self.animal_res = tk.Label(self.main_frame, text="", fg="blue")
        self.animal_res.pack()

    def check_zodiac(self):
        try:
            bd = int(self.zodiac_input.get())
            m, d = bd // 100, bd % 100
            if (m == 3 and d >= 21) or (m == 4 and d <= 19): res = "白羊座"
            elif (m == 4 and d >= 20) or (m == 5 and d <= 20): res = "金牛座"
            elif (m == 5 and d >= 21) or (m == 6 and d <= 21): res = "双子座"
            elif (m == 6 and d >= 22) or (m == 7 and d <= 22): res = "巨蟹座"
            elif (m == 7 and d >= 23) or (m == 8 and d <= 22): res = "狮子座"
            elif (m == 8 and d >= 23) or (m == 9 and d <= 22): res = "处女座"
            elif (m == 9 and d >= 23) or (m == 10 and d <= 23): res = "天秤座"
            elif (m == 10 and d >= 24) or (m == 11 and d <= 22): res = "天蝎座"
            elif (m == 11 and d >= 23) or (m == 12 and d <= 21): res = "射手座"
            elif (m == 12 and d >= 22) or (m == 1 and d <= 19): res = "摩羯座"
            elif (m == 1 and d >= 20) or (m == 2 and d <= 18): res = "水瓶座"
            else: res = "双鱼座"
            self.zodiac_res.config(text=f"星座：{res}")
        except:
            messagebox.showerror("错误", "格式错误，如0520")

    def check_animal(self):
        try:
            year = int(self.animal_input.get())
            animals = ["猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"]
            res = animals[year % 12]
            self.animal_res.config(text=f"生肖：{res}")
        except:
            messagebox.showerror("错误", "年份无效")

# ================= 程序入口 =================
if __name__ == "__main__":
    root = tk.Tk()
    app = SuperApp(root)
    root.mainloop()