第九周总结

完成了一个Python实验(餐厅点餐子系统),以下是实验代码。
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import pymysql
from PIL import Image, ImageTk
import config
import io
import warnings

忽略图片处理警告

warnings.filterwarnings("ignore", message="iCCP: known incorrect sRGB profile")

class RestaurantApp:
"""餐厅点餐系统主应用"""

def __init__(self, root):
    self.root = root
    self.root.title("餐厅点餐系统")
    self.current_image = None

    # 数据库连接
    self.conn = pymysql.connect(**config.DB_CONFIG)
    self.cursor = self.conn.cursor()

    self.create_widgets()
    self.load_menu()

def create_widgets(self):
    """创建主界面"""
    self.notebook = ttk.Notebook(self.root)
    self.notebook.pack(fill='both', expand=True)

    # 创建三个功能标签页
    self.management_frame = ttk.Frame(self.notebook)
    self.notebook.add(self.management_frame, text='菜单管理')

    self.order_frame = ttk.Frame(self.notebook)
    self.notebook.add(self.order_frame, text='点餐')

    self.order_management_frame = ttk.Frame(self.notebook)
    self.notebook.add(self.order_management_frame, text='订单管理')

    # 初始化各标签页界面
    self.create_management_ui()
    self.create_order_ui()
    self.create_order_management_ui()

def create_management_ui(self):
    """创建菜单管理界面"""
    # 左侧控制按钮
    control_frame = ttk.Frame(self.management_frame, width=200)
    control_frame.pack(side='left', fill='y')

    ttk.Button(control_frame, text="添加菜品", command=self.add_dish).pack(pady=5, fill='x')
    ttk.Button(control_frame, text="删除菜品", command=self.delete_dish).pack(pady=5, fill='x')
    ttk.Button(control_frame, text="修改菜品", command=self.update_dish).pack(pady=5, fill='x')

    # 右侧显示区域
    display_frame = ttk.Frame(self.management_frame)
    display_frame.pack(side='right', fill='both', expand=True)

    # 菜品列表
    self.tree = ttk.Treeview(
        display_frame,
        columns=('id', 'name', 'price', 'cooking_time'),
        show='headings'
    )
    self.tree.heading('id', text='编号')
    self.tree.heading('name', text='菜名')
    self.tree.heading('price', text='价格')
    self.tree.heading('cooking_time', text='烹饪时间')
    self.tree.pack(fill='both', expand=True)

    # 图片显示区域
    self.image_frame = ttk.Frame(display_frame)
    self.image_frame.pack(pady=10)
    self.image_label = ttk.Label(self.image_frame)
    self.image_label.pack()

    # 绑定选择事件
    self.tree.bind("<<TreeviewSelect>>", self.show_selected_image)

def create_order_ui(self):
    """创建点餐界面"""
    # 左侧菜单列表
    menu_frame = ttk.Frame(self.order_frame)
    menu_frame.pack(side='left', fill='both', expand=True)

    # 菜品列表
    list_frame = ttk.Frame(menu_frame)
    list_frame.pack(fill='both', expand=True)
    self.order_tree = ttk.Treeview(
        list_frame,
        columns=('id', 'name', 'price'),
        show='headings',
        height=15
    )
    self.order_tree.heading('id', text='编号')
    self.order_tree.heading('name', text='菜名')
    self.order_tree.heading('price', text='价格')
    self.order_tree.pack(fill='both', expand=True)

    # 菜品图片预览
    self.order_image_frame = ttk.Frame(menu_frame)
    self.order_image_frame.pack(fill='both', expand=True)
    self.order_image_label = ttk.Label(self.order_image_frame)
    self.order_image_label.pack()

    # 绑定选择事件
    self.order_tree.bind("<<TreeviewSelect>>", self.show_order_image)

    # 右侧订单区域
    order_control_frame = ttk.Frame(self.order_frame)
    order_control_frame.pack(side='right', fill='both', expand=True)

    # 数量选择
    ttk.Label(order_control_frame, text="数量:").pack()
    self.quantity = ttk.Spinbox(order_control_frame, from_=1, to=10)
    self.quantity.pack()

    ttk.Button(order_control_frame, text="添加到订单", command=self.add_to_order).pack(pady=5)

    # 订单列表
    self.current_order = ttk.Treeview(
        order_control_frame,
        columns=('name', 'price', 'quantity', 'total'),
        show='headings'
    )
    self.current_order.heading('name', text='菜名')
    self.current_order.heading('price', text='单价')
    self.current_order.heading('quantity', text='数量')
    self.current_order.heading('total', text='小计')
    self.current_order.pack(fill='both', expand=True)

    # 总价显示
    self.total_label = ttk.Label(order_control_frame, text="总价:0.00元")
    self.total_label.pack()

    ttk.Button(order_control_frame, text="提交订单", command=self.submit_order).pack(pady=5)

def create_order_management_ui(self):
    """创建订单管理界面"""
    main_frame = ttk.Frame(self.order_management_frame)
    main_frame.pack(fill='both', expand=True, padx=10, pady=10)

    # 订单列表
    self.orders_tree = ttk.Treeview(
        main_frame,
        columns=('order_id', 'total', 'time', 'items'),
        show='headings'
    )
    self.orders_tree.heading('order_id', text='订单号')
    self.orders_tree.heading('total', text='总金额')
    self.orders_tree.heading('time', text='下单时间')
    self.orders_tree.heading('items', text='菜品详情')
    self.orders_tree.pack(fill='both', expand=True)

    # 滚动条
    scrollbar = ttk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self.orders_tree.yview)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    self.orders_tree.configure(yscrollcommand=scrollbar.set)

    # 删除按钮
    ttk.Button(
        main_frame,
        text="删除选中订单",
        command=self.delete_order
    ).pack(pady=5)

    self.load_orders()

# ----------------- 数据库操作方法 -----------------
def load_menu(self):
    """加载菜单数据"""
    self.tree.delete(*self.tree.get_children())
    self.order_tree.delete(*self.order_tree.get_children())

    self.cursor.execute("SELECT id, name, price, cooking_time FROM menu")
    for row in self.cursor.fetchall():
        self.tree.insert('', 'end', values=row)
        self.order_tree.insert('', 'end', values=row[:3])

def show_selected_image(self, event):
    """显示选中菜品的图片"""
    selected = self.tree.selection()
    if selected:
        dish_id = self.tree.item(selected[0])['values'][0]
        self.show_image(dish_id)

def show_order_image(self, event):
    """在点餐界面显示选中菜品的图片"""
    selected = self.order_tree.selection()
    if selected:
        dish_id = self.order_tree.item(selected[0])['values'][0]
        self.show_image_in_label(dish_id, self.order_image_label)

def show_image(self, dish_id):
    """显示菜品图片"""
    self.show_image_in_label(dish_id, self.image_label)

def show_image_in_label(self, dish_id, label):
    """在指定标签中显示菜品图片"""
    self.cursor.execute("SELECT image FROM menu WHERE id=%s", (dish_id,))
    result = self.cursor.fetchone()

    if result and result[0]:
        try:
            image = Image.open(io.BytesIO(result[0]))
            image.thumbnail((300, 300))
            photo = ImageTk.PhotoImage(image)
            label.config(image=photo)
            label.image = photo
        except:
            label.config(image='')
    else:
        label.config(image='')

def add_dish(self):
    """打开添加菜品窗口"""
    AddDishWindow(self)

def delete_dish(self):
    """删除选中的菜品"""
    selected = self.tree.selection()
    if not selected:
        return

    dish_id = self.tree.item(selected[0])['values'][0]

    try:
        self.cursor.execute("DELETE FROM menu WHERE id=%s", (dish_id,))
        self.conn.commit()
        self.load_menu()
        messagebox.showinfo("提示", "删除成功!")
    except Exception as e:
        messagebox.showerror("错误", f"删除失败: {str(e)}")

def update_dish(self):
    """打开修改菜品窗口"""
    selected = self.tree.selection()
    if not selected:
        return

    values = self.tree.item(selected[0])['values']
    UpdateDishWindow(self, values)

# ----------------- 点餐功能方法 -----------------
def add_to_order(self):
    """添加菜品到订单"""
    selected = self.order_tree.selection()
    if not selected:
        return

    dish_id = self.order_tree.item(selected[0])['values'][0]

    try:
        quantity = int(self.quantity.get())
        if quantity < 1:
            raise ValueError
    except:
        messagebox.showerror("错误", "请输入有效数量(1-10)")
        return

    try:
        self.cursor.execute("SELECT name, price FROM menu WHERE id=%s", (dish_id,))
        name, price = self.cursor.fetchone()
        price = float(price)
        total = price * quantity

        # 检查是否已存在相同菜品
        exists = False
        for child in self.current_order.get_children():
            values = self.current_order.item(child)['values']
            if values[0] == name:
                exists = True
                new_quantity = values[2] + quantity
                new_total = new_quantity * price
                self.current_order.item(child, values=(name, price, new_quantity, new_total))
                break

        if not exists:
            self.current_order.insert('', 'end', values=(name, price, quantity, total))

        self.update_total()
    except Exception as e:
        messagebox.showerror("错误", f"添加失败: {str(e)}")

def update_total(self):
    """更新订单总价"""
    total = 0.0
    for child in self.current_order.get_children():
        total += float(self.current_order.item(child)['values'][3])
    self.total_label.config(text=f"总价:{total:.2f}元")

def submit_order(self):
    """提交订单"""
    if not self.current_order.get_children():
        messagebox.showwarning("提示", "订单为空!")
        return

    try:
        self.conn.begin()

        # 插入主订单
        total = float(self.total_label.cget("text")[3:-1])
        self.cursor.execute("INSERT INTO orders (total) VALUES (%s)", (total,))
        order_id = self.cursor.lastrowid

        # 插入订单详情
        for child in self.current_order.get_children():
            values = self.current_order.item(child)['values']
            dish_id = self.get_dish_id_by_name(values[0])
            quantity = values[2]
            price = values[1]

            self.cursor.execute(
                "INSERT INTO order_details (order_id, dish_id, quantity, price) VALUES (%s, %s, %s, %s)",
                (order_id, dish_id, quantity, price)
            )

        self.conn.commit()
        messagebox.showinfo("成功", f"订单提交成功!订单号:{order_id},总金额:¥{total:.2f}")
        self.current_order.delete(*self.current_order.get_children())
        self.total_label.config(text="总价:0.00元")
        self.load_orders()
    except Exception as e:
        self.conn.rollback()
        messagebox.showerror("错误", f"提交失败: {str(e)}")

def get_dish_id_by_name(self, dish_name):
    """根据菜品名称获取ID"""
    self.cursor.execute("SELECT id FROM menu WHERE name = %s", (dish_name,))
    result = self.cursor.fetchone()
    return result[0] if result else None

# ----------------- 订单管理方法 -----------------
def load_orders(self):
    """加载历史订单"""
    self.orders_tree.delete(*self.orders_tree.get_children())

    try:
        self.cursor.execute("""
            SELECT o.order_id, o.total, o.order_time, 
                   GROUP_CONCAT(CONCAT(m.name, ' × ', od.quantity)) 
            FROM orders o
            JOIN order_details od ON o.order_id = od.order_id
            JOIN menu m ON od.dish_id = m.id
            GROUP BY o.order_id
            ORDER BY o.order_time DESC
        """)

        for row in self.cursor.fetchall():
            order_id, total, time, items = row
            self.orders_tree.insert('', 'end', values=(
                order_id, f"¥{total:.2f}", time.strftime("%Y-%m-%d %H:%M:%S"), items
            ))
    except Exception as e:
        messagebox.showerror("错误", f"加载订单失败: {str(e)}")

def delete_order(self):
    """删除选中的订单"""
    selected = self.orders_tree.selection()
    if not selected:
        return

    order_id = self.orders_tree.item(selected[0])['values'][0]

    if messagebox.askyesno("确认", f"确定要删除订单 {order_id} 吗?"):
        try:
            self.cursor.execute("DELETE FROM orders WHERE order_id = %s", (order_id,))
            self.conn.commit()
            self.load_orders()
            messagebox.showinfo("成功", "订单已删除")
        except Exception as e:
            self.conn.rollback()
            messagebox.showerror("错误", f"删除失败: {str(e)}")

class AddDishWindow(tk.Toplevel):
"""添加菜品窗口"""

def __init__(self, parent):
    super().__init__(parent.root)
    self.parent = parent
    self.title("添加菜品")
    self.temp_image = None
    self.image_data = None

    # 创建UI元素
    ttk.Label(self, text="菜名:").grid(row=0, column=0)
    self.name = ttk.Entry(self)
    self.name.grid(row=0, column=1)

    ttk.Label(self, text="价格:").grid(row=1, column=0)
    self.price = ttk.Entry(self)
    self.price.grid(row=1, column=1)

    ttk.Label(self, text="烹饪时间:").grid(row=2, column=0)
    self.cooking_time = ttk.Entry(self)
    self.cooking_time.grid(row=2, column=1)

    ttk.Label(self, text="图片:").grid(row=3, column=0)
    ttk.Button(self, text="选择图片", command=self.select_image).grid(row=3, column=1)

    # 图片预览区域
    self.preview_frame = ttk.Frame(self)
    self.preview_frame.grid(row=4, columnspan=2, pady=10)
    self.preview_label = ttk.Label(self.preview_frame)
    self.preview_label.pack()

    ttk.Button(self, text="提交", command=self.submit).grid(row=5, columnspan=2)

def select_image(self):
    """选择并处理图片"""
    path = filedialog.askopenfilename()
    if path:
        try:
            img = Image.open(path)

            # 处理图片格式问题
            if "icc_profile" in img.info:
                del img.info["icc_profile"]

            if img.mode in ("RGBA", "P"):
                img = img.convert("RGB")

            # 生成预览
            preview_img = img.copy()
            preview_img.thumbnail((200, 200))
            self.temp_image = ImageTk.PhotoImage(preview_img)
            self.preview_label.config(image=self.temp_image)

            # 保存图片数据
            img_byte_arr = io.BytesIO()
            img.save(img_byte_arr, format='PNG' if path.lower().endswith('.png') else 'JPEG')
            self.image_data = img_byte_arr.getvalue()

        except Exception as e:
            messagebox.showerror("错误", f"图片处理失败: {str(e)}")
            self.image_data = None

def submit(self):
    """提交菜品数据"""
    if not self.image_data:
        messagebox.showerror("错误", "请选择菜品图片")
        return

    try:
        self.parent.cursor.execute(
            "INSERT INTO menu (name, price, image, cooking_time) VALUES (%s, %s, %s, %s)",
            (self.name.get(), float(self.price.get()), self.image_data, int(self.cooking_time.get()))
        )
        self.parent.conn.commit()
        self.parent.load_menu()
        self.destroy()
    except Exception as e:
        messagebox.showerror("错误", str(e))

class UpdateDishWindow(AddDishWindow):
"""修改菜品窗口"""

def __init__(self, parent, values):
    super().__init__(parent)
    self.title("修改菜品")
    self.dish_id = values[0]

    # 填充现有数据
    self.name.insert(0, values[1])
    self.price.insert(0, values[2])
    self.cooking_time.insert(0, values[3])

    # 加载现有图片
    self.parent.cursor.execute("SELECT image FROM menu WHERE id=%s", (self.dish_id,))
    image_data = self.parent.cursor.fetchone()[0]
    if image_data:
        try:
            image = Image.open(io.BytesIO(image_data))
            image.thumbnail((200, 200))
            self.temp_image = ImageTk.PhotoImage(image)
            self.preview_label.config(image=self.temp_image)
        except:
            pass

def submit(self):
    """提交修改"""
    try:
        # 如果未选择新图片,则使用原有图片
        if not self.image_data:
            self.parent.cursor.execute("SELECT image FROM menu WHERE id=%s", (self.dish_id,))
            self.image_data = self.parent.cursor.fetchone()[0]

        self.parent.cursor.execute(
            "UPDATE menu SET name=%s, price=%s, image=%s, cooking_time=%s WHERE id=%s",
            (self.name.get(), float(self.price.get()), self.image_data, int(self.cooking_time.get()), self.dish_id)
        )
        self.parent.conn.commit()
        self.parent.load_menu()
        self.destroy()
    except Exception as e:
        messagebox.showerror("错误", str(e))

if name == "main":
root = tk.Tk()
app = RestaurantApp(root)
root.mainloop()
app.conn.close()

posted @ 2025-05-17 23:52  离璨霂  阅读(10)  评论(0)    收藏  举报