添加 Simple_Enterprise_Warehouse_Management.py
This commit is contained in:
		
							
								
								
									
										999
									
								
								Simple_Enterprise_Warehouse_Management.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										999
									
								
								Simple_Enterprise_Warehouse_Management.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,999 @@
 | 
			
		||||
#本产品含AI量高达98%
 | 
			
		||||
import tkinter as tk
 | 
			
		||||
from tkinter import ttk, messagebox
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
import json
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
class InventoryApp:
 | 
			
		||||
    def __init__(self, root):
 | 
			
		||||
        self.root = root
 | 
			
		||||
        self.root.title("出入库管理系统")
 | 
			
		||||
        self.root.geometry("800x600")
 | 
			
		||||
        
 | 
			
		||||
        # 数据存储
 | 
			
		||||
        self.data_file = "inventory_data.json"
 | 
			
		||||
        self.load_data()
 | 
			
		||||
        
 | 
			
		||||
        # 当前页面状态
 | 
			
		||||
        self.current_page = "main"
 | 
			
		||||
        self.current_product = None
 | 
			
		||||
        self.current_main_page = 1
 | 
			
		||||
        self.current_detail_page = 1
 | 
			
		||||
        self.current_query_page = 1
 | 
			
		||||
        self.items_per_page = 14
 | 
			
		||||
        self.query_results = []
 | 
			
		||||
        
 | 
			
		||||
        # 窗口大小相关
 | 
			
		||||
        self.last_window_height = 600
 | 
			
		||||
        
 | 
			
		||||
        # 创建主框架
 | 
			
		||||
        self.main_frame = tk.Frame(root)
 | 
			
		||||
        self.main_frame.pack(fill=tk.BOTH, expand=True)
 | 
			
		||||
        
 | 
			
		||||
        # 绑定窗口大小变化事件
 | 
			
		||||
        self.root.bind('<Configure>', self.on_window_resize)
 | 
			
		||||
        
 | 
			
		||||
        # 显示主页面
 | 
			
		||||
        self.show_main_page()
 | 
			
		||||
    
 | 
			
		||||
    def load_data(self):
 | 
			
		||||
        """加载数据"""
 | 
			
		||||
        if os.path.exists(self.data_file):
 | 
			
		||||
            try:
 | 
			
		||||
                with open(self.data_file, 'r', encoding='utf-8') as f:
 | 
			
		||||
                    self.data = json.load(f)
 | 
			
		||||
            except:
 | 
			
		||||
                self.data = {"products": {}, "transactions": []}
 | 
			
		||||
        else:
 | 
			
		||||
            # 初始化空数据结构
 | 
			
		||||
            self.data = {"products": {}, "transactions": []}
 | 
			
		||||
    
 | 
			
		||||
    def save_data(self):
 | 
			
		||||
        """保存数据"""
 | 
			
		||||
        with open(self.data_file, 'w', encoding='utf-8') as f:
 | 
			
		||||
            json.dump(self.data, f, ensure_ascii=False, indent=2)
 | 
			
		||||
    
 | 
			
		||||
    def clear_frame(self):
 | 
			
		||||
        """清空当前框架"""
 | 
			
		||||
        for widget in self.main_frame.winfo_children():
 | 
			
		||||
            widget.destroy()
 | 
			
		||||
    
 | 
			
		||||
    def calculate_items_per_page(self):
 | 
			
		||||
        """根据窗口高度动态计算每页显示的条目数"""
 | 
			
		||||
        window_height = self.root.winfo_height()
 | 
			
		||||
        # 减去顶部搜索区域(约60px)、表头(约30px)、底部分页区域(约50px)的高度
 | 
			
		||||
        available_height = window_height - 140
 | 
			
		||||
        # 每个条目大约占用35px高度
 | 
			
		||||
        item_height = 35
 | 
			
		||||
        # 计算可显示的条目数,最少5个,最多20个
 | 
			
		||||
        items_count = max(5, min(20, available_height // item_height))
 | 
			
		||||
        return items_count
 | 
			
		||||
    
 | 
			
		||||
    def on_window_resize(self, event):
 | 
			
		||||
        """窗口大小变化时的处理"""
 | 
			
		||||
        # 只处理主窗口的大小变化事件
 | 
			
		||||
        if event.widget == self.root:
 | 
			
		||||
            current_height = self.root.winfo_height()
 | 
			
		||||
            # 如果高度变化超过50px,重新计算每页条目数
 | 
			
		||||
            if abs(current_height - self.last_window_height) > 50:
 | 
			
		||||
                self.last_window_height = current_height
 | 
			
		||||
                new_items_per_page = self.calculate_items_per_page()
 | 
			
		||||
                if new_items_per_page != self.items_per_page:
 | 
			
		||||
                    self.items_per_page = new_items_per_page
 | 
			
		||||
                    # 重新刷新当前页面的列表
 | 
			
		||||
                    if self.current_page == "main":
 | 
			
		||||
                        self.update_product_list()
 | 
			
		||||
                        # 更新页码标签
 | 
			
		||||
                        total_products = len(self.data["products"])
 | 
			
		||||
                        max_pages = (total_products + self.items_per_page - 1) // self.items_per_page
 | 
			
		||||
                        if self.current_main_page > max_pages and max_pages > 0:
 | 
			
		||||
                            self.current_main_page = max_pages
 | 
			
		||||
                        self.main_page_label.config(text=f"第 {self.current_main_page} 页 / 共 {max_pages} 页")
 | 
			
		||||
                    elif self.current_page == "detail":
 | 
			
		||||
                        self.update_detail_list()
 | 
			
		||||
                        # 更新页码标签
 | 
			
		||||
                        product_transactions = [t for t in self.data["transactions"] if t["product"] == self.current_product]
 | 
			
		||||
                        max_pages = (len(product_transactions) + self.items_per_page - 1) // self.items_per_page
 | 
			
		||||
                        if self.current_detail_page > max_pages and max_pages > 0:
 | 
			
		||||
                            self.current_detail_page = max_pages
 | 
			
		||||
                        self.detail_page_label.config(text=f"第 {self.current_detail_page} 页 / 共 {max_pages} 页")
 | 
			
		||||
    
 | 
			
		||||
    def show_main_page(self):
 | 
			
		||||
        """显示主页面"""
 | 
			
		||||
        self.current_page = "main"
 | 
			
		||||
        self.clear_frame()
 | 
			
		||||
        
 | 
			
		||||
        # 如果是首次显示主页面,保持默认的14条,否则根据窗口大小计算
 | 
			
		||||
        if not hasattr(self, 'main_page_initialized'):
 | 
			
		||||
            self.main_page_initialized = True
 | 
			
		||||
        else:
 | 
			
		||||
            self.items_per_page = self.calculate_items_per_page()
 | 
			
		||||
        
 | 
			
		||||
        # 顶部搜索功能和添加产品按钮
 | 
			
		||||
        search_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        search_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(search_frame, text="搜索产品:", font=("Arial", 12)).pack(side=tk.LEFT)
 | 
			
		||||
        self.search_var = tk.StringVar()
 | 
			
		||||
        search_entry = tk.Entry(search_frame, textvariable=self.search_var, font=("Arial", 12))
 | 
			
		||||
        search_entry.pack(side=tk.LEFT, padx=(10, 5), fill=tk.X, expand=True)
 | 
			
		||||
        
 | 
			
		||||
        tk.Button(search_frame, text="搜索", command=self.search_products).pack(side=tk.LEFT, padx=2)
 | 
			
		||||
        tk.Button(search_frame, text="清空", command=self.clear_search).pack(side=tk.LEFT, padx=2)
 | 
			
		||||
        tk.Button(search_frame, text="添加产品分类", command=self.show_add_category_page, bg="lightblue", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        tk.Button(search_frame, text="查询", command=self.show_query_page, bg="lightcyan", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        
 | 
			
		||||
        # 产品列表
 | 
			
		||||
        list_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 表头
 | 
			
		||||
        header_frame = tk.Frame(list_frame)
 | 
			
		||||
        header_frame.pack(fill=tk.X)
 | 
			
		||||
        tk.Label(header_frame, text="产品名", width=15, relief=tk.RIDGE, font=("Arial", 12, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="当前剩余重量(kg)", width=15, relief=tk.RIDGE, font=("Arial", 12, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="平均价格(元/kg)", width=15, relief=tk.RIDGE, font=("Arial", 12, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="操作", width=15, relief=tk.RIDGE, font=("Arial", 12, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        # 产品条目
 | 
			
		||||
        self.product_list_frame = tk.Frame(list_frame)
 | 
			
		||||
        self.product_list_frame.pack(fill=tk.BOTH, expand=True)
 | 
			
		||||
        
 | 
			
		||||
        self.update_product_list()
 | 
			
		||||
        
 | 
			
		||||
        # 页数控制
 | 
			
		||||
        page_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        page_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        tk.Button(page_frame, text="上一页", command=self.prev_main_page).pack(side=tk.LEFT)
 | 
			
		||||
        total_products = len(self.data["products"])
 | 
			
		||||
        max_pages = max(1, (total_products + self.items_per_page - 1) // self.items_per_page)
 | 
			
		||||
        self.main_page_label = tk.Label(page_frame, text=f"第 {self.current_main_page} 页 / 共 {max_pages} 页")
 | 
			
		||||
        self.main_page_label.pack(side=tk.LEFT, padx=20)
 | 
			
		||||
        tk.Button(page_frame, text="下一页", command=self.next_main_page).pack(side=tk.LEFT)
 | 
			
		||||
    
 | 
			
		||||
    def search_products(self):
 | 
			
		||||
        """搜索产品"""
 | 
			
		||||
        # 重置到第一页
 | 
			
		||||
        self.current_main_page = 1
 | 
			
		||||
        self.update_product_list()
 | 
			
		||||
    
 | 
			
		||||
    def clear_search(self):
 | 
			
		||||
        """清空搜索"""
 | 
			
		||||
        self.search_var.set("")
 | 
			
		||||
        self.current_main_page = 1
 | 
			
		||||
        self.update_product_list()
 | 
			
		||||
    
 | 
			
		||||
    def update_product_list(self):
 | 
			
		||||
        """更新产品列表"""
 | 
			
		||||
        for widget in self.product_list_frame.winfo_children():
 | 
			
		||||
            widget.destroy()
 | 
			
		||||
        
 | 
			
		||||
        # 获取搜索词并过滤产品
 | 
			
		||||
        search_term = self.search_var.get().strip().lower()
 | 
			
		||||
        all_products = list(self.data["products"].items())
 | 
			
		||||
        
 | 
			
		||||
        if search_term:
 | 
			
		||||
            # 模糊搜索:产品名包含搜索词
 | 
			
		||||
            filtered_products = [(name, data) for name, data in all_products 
 | 
			
		||||
                               if search_term in name.lower()]
 | 
			
		||||
        else:
 | 
			
		||||
            filtered_products = all_products
 | 
			
		||||
        
 | 
			
		||||
        # 分页处理
 | 
			
		||||
        start_idx = (self.current_main_page - 1) * self.items_per_page
 | 
			
		||||
        end_idx = start_idx + self.items_per_page
 | 
			
		||||
        page_products = filtered_products[start_idx:end_idx]
 | 
			
		||||
        
 | 
			
		||||
        # 显示产品列表
 | 
			
		||||
        for product_name, product_data in page_products:
 | 
			
		||||
            row_frame = tk.Frame(self.product_list_frame)
 | 
			
		||||
            row_frame.pack(fill=tk.X, pady=1)
 | 
			
		||||
            
 | 
			
		||||
            tk.Label(row_frame, text=product_name, width=21, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=f"{product_data['total_weight']:.1f}", width=22, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=f"{product_data['avg_price']:.2f}", width=21, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Button(row_frame, text="详情", width=21, 
 | 
			
		||||
                     command=lambda p=product_name: self.show_detail_page(p)).pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        # 更新分页信息
 | 
			
		||||
        total_products = len(filtered_products)
 | 
			
		||||
        max_pages = max(1, (total_products + self.items_per_page - 1) // self.items_per_page)
 | 
			
		||||
        if hasattr(self, 'main_page_label') and self.main_page_label.winfo_exists():
 | 
			
		||||
            try:
 | 
			
		||||
                if search_term:
 | 
			
		||||
                    self.main_page_label.config(text=f"第 {self.current_main_page} 页 / 共 {max_pages} 页 (找到 {total_products} 个结果)")
 | 
			
		||||
                else:
 | 
			
		||||
                    self.main_page_label.config(text=f"第 {self.current_main_page} 页 / 共 {max_pages} 页")
 | 
			
		||||
            except tk.TclError:
 | 
			
		||||
                pass  # 忽略已销毁的组件错误
 | 
			
		||||
        
 | 
			
		||||
        # 如果没有搜索结果,显示提示
 | 
			
		||||
        if not page_products and search_term:
 | 
			
		||||
            no_result_frame = tk.Frame(self.product_list_frame)
 | 
			
		||||
            no_result_frame.pack(fill=tk.X, pady=20)
 | 
			
		||||
            tk.Label(no_result_frame, text=f"未找到包含 '{search_term}' 的产品", 
 | 
			
		||||
                    font=("Arial", 12), fg="gray").pack()
 | 
			
		||||
    
 | 
			
		||||
    def prev_main_page(self):
 | 
			
		||||
        """上一页"""
 | 
			
		||||
        if self.current_main_page > 1:
 | 
			
		||||
            self.current_main_page -= 1
 | 
			
		||||
            self.update_product_list()
 | 
			
		||||
    
 | 
			
		||||
    def next_main_page(self):
 | 
			
		||||
        """下一页"""
 | 
			
		||||
        # 获取当前过滤后的产品数量
 | 
			
		||||
        search_term = self.search_var.get().strip().lower()
 | 
			
		||||
        all_products = list(self.data["products"].items())
 | 
			
		||||
        
 | 
			
		||||
        if search_term:
 | 
			
		||||
            filtered_products = [(name, data) for name, data in all_products 
 | 
			
		||||
                               if search_term in name.lower()]
 | 
			
		||||
        else:
 | 
			
		||||
            filtered_products = all_products
 | 
			
		||||
        
 | 
			
		||||
        total_products = len(filtered_products)
 | 
			
		||||
        max_pages = max(1, (total_products + self.items_per_page - 1) // self.items_per_page)
 | 
			
		||||
        
 | 
			
		||||
        if self.current_main_page < max_pages:
 | 
			
		||||
            self.current_main_page += 1
 | 
			
		||||
            self.update_product_list()
 | 
			
		||||
    
 | 
			
		||||
    def show_detail_page(self, product_name):
 | 
			
		||||
        """显示详细条目页面"""
 | 
			
		||||
        self.current_page = "detail"
 | 
			
		||||
        self.current_product = product_name
 | 
			
		||||
        self.current_detail_page = 1
 | 
			
		||||
        self.clear_frame()
 | 
			
		||||
        
 | 
			
		||||
        # 如果是首次显示详情页面,保持默认的14条,否则根据窗口大小计算
 | 
			
		||||
        if not hasattr(self, 'detail_page_initialized'):
 | 
			
		||||
            self.detail_page_initialized = True
 | 
			
		||||
        else:
 | 
			
		||||
            self.items_per_page = self.calculate_items_per_page()
 | 
			
		||||
        
 | 
			
		||||
        # 顶部产品名和按钮
 | 
			
		||||
        top_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        top_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(top_frame, text=f"产品: {product_name}", font=("Arial", 16, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        button_frame = tk.Frame(top_frame)
 | 
			
		||||
        button_frame.pack(side=tk.RIGHT)
 | 
			
		||||
        tk.Button(button_frame, text="入库", command=self.show_inbound_page, bg="lightgreen").pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        tk.Button(button_frame, text="出库", command=self.show_outbound_page, bg="lightcoral").pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        tk.Button(button_frame, text="删除产品", command=self.delete_product_category, bg="darkred", fg="white").pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        tk.Button(button_frame, text="返回主页", command=self.show_main_page).pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        # 详细条目列表
 | 
			
		||||
        detail_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        detail_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 表头
 | 
			
		||||
        header_frame = tk.Frame(detail_frame)
 | 
			
		||||
        header_frame.pack(fill=tk.X)
 | 
			
		||||
        tk.Label(header_frame, text="时间", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="类型", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="重量(kg)", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="价格(元/kg)", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="总价(元)", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="备注", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="操作", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        # 交易记录
 | 
			
		||||
        self.detail_list_frame = tk.Frame(detail_frame)
 | 
			
		||||
        self.detail_list_frame.pack(fill=tk.BOTH, expand=True)
 | 
			
		||||
        
 | 
			
		||||
        self.update_detail_list()
 | 
			
		||||
        
 | 
			
		||||
        # 页数控制
 | 
			
		||||
        page_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        page_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        tk.Button(page_frame, text="上一页", command=self.prev_detail_page).pack(side=tk.LEFT)
 | 
			
		||||
        product_transactions = [t for t in self.data["transactions"] if t["product"] == self.current_product]
 | 
			
		||||
        max_pages = max(1, (len(product_transactions) + self.items_per_page - 1) // self.items_per_page)
 | 
			
		||||
        self.detail_page_label = tk.Label(page_frame, text=f"第 {self.current_detail_page} 页 / 共 {max_pages} 页")
 | 
			
		||||
        self.detail_page_label.pack(side=tk.LEFT, padx=20)
 | 
			
		||||
        tk.Button(page_frame, text="下一页", command=self.next_detail_page).pack(side=tk.LEFT)
 | 
			
		||||
    
 | 
			
		||||
    def update_detail_list(self):
 | 
			
		||||
        """更新详细条目列表"""
 | 
			
		||||
        for widget in self.detail_list_frame.winfo_children():
 | 
			
		||||
            widget.destroy()
 | 
			
		||||
        
 | 
			
		||||
        # 筛选当前产品的交易记录
 | 
			
		||||
        product_transactions = [t for t in self.data["transactions"] if t["product"] == self.current_product]
 | 
			
		||||
        product_transactions.sort(key=lambda x: x["time"], reverse=True)
 | 
			
		||||
        
 | 
			
		||||
        start_idx = (self.current_detail_page - 1) * self.items_per_page
 | 
			
		||||
        end_idx = start_idx + self.items_per_page
 | 
			
		||||
        page_transactions = product_transactions[start_idx:end_idx]
 | 
			
		||||
        
 | 
			
		||||
        for i, transaction in enumerate(page_transactions):
 | 
			
		||||
            row_frame = tk.Frame(self.detail_list_frame)
 | 
			
		||||
            row_frame.pack(fill=tk.X, pady=1)
 | 
			
		||||
            
 | 
			
		||||
            total_price = transaction['weight'] * transaction['price']
 | 
			
		||||
            
 | 
			
		||||
            tk.Label(row_frame, text=transaction["time"], width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            color = "lightgreen" if transaction["type"] == "入库" else "lightcoral"
 | 
			
		||||
            tk.Label(row_frame, text=transaction["type"], width=15, relief=tk.RIDGE, bg=color).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=f"{transaction['weight']:.1f}", width=14, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=f"{transaction['price']:.2f}", width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=f"{total_price:.2f}", width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=transaction["note"], width=14, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Button(row_frame, text="删除", width=15, bg="red", fg="white",
 | 
			
		||||
                     command=lambda t=transaction: self.delete_transaction(t)).pack(side=tk.LEFT)
 | 
			
		||||
    
 | 
			
		||||
    def prev_detail_page(self):
 | 
			
		||||
        """上一页"""
 | 
			
		||||
        if self.current_detail_page > 1:
 | 
			
		||||
            self.current_detail_page -= 1
 | 
			
		||||
            self.update_detail_list()
 | 
			
		||||
            product_transactions = [t for t in self.data["transactions"] if t["product"] == self.current_product]
 | 
			
		||||
            max_pages = max(1, (len(product_transactions) + self.items_per_page - 1) // self.items_per_page)
 | 
			
		||||
            self.detail_page_label.config(text=f"第 {self.current_detail_page} 页 / 共 {max_pages} 页")
 | 
			
		||||
    
 | 
			
		||||
    def next_detail_page(self):
 | 
			
		||||
        """详情页下一页"""
 | 
			
		||||
        product_transactions = [t for t in self.data["transactions"] if t["product"] == self.current_product]
 | 
			
		||||
        max_pages = (len(product_transactions) + self.items_per_page - 1) // self.items_per_page
 | 
			
		||||
        if self.current_detail_page < max_pages:
 | 
			
		||||
            self.current_detail_page += 1
 | 
			
		||||
            self.update_detail_list()
 | 
			
		||||
            self.detail_page_label.config(text=f"第 {self.current_detail_page} 页 / 共 {max_pages} 页")
 | 
			
		||||
    
 | 
			
		||||
    def show_inbound_page(self):
 | 
			
		||||
        """显示入库页面"""
 | 
			
		||||
        self.current_page = "inbound"
 | 
			
		||||
        self.clear_frame()
 | 
			
		||||
        
 | 
			
		||||
        # 标题
 | 
			
		||||
        title_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        title_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        tk.Label(title_frame, text=f"入库 - {self.current_product}", font=("Arial", 16, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Button(title_frame, text="返回详情", command=lambda: self.show_detail_page(self.current_product)).pack(side=tk.RIGHT)
 | 
			
		||||
        
 | 
			
		||||
        # 输入表单
 | 
			
		||||
        form_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        form_frame.pack(fill=tk.X, padx=50, pady=50)
 | 
			
		||||
        
 | 
			
		||||
        # 入库重量
 | 
			
		||||
        tk.Label(form_frame, text="入库重量(kg):", font=("Arial", 12)).grid(row=0, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.inbound_weight_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.inbound_weight_var, font=("Arial", 12), width=20).grid(row=0, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 入库价格
 | 
			
		||||
        tk.Label(form_frame, text="入库价格(元/kg):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.inbound_price_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.inbound_price_var, font=("Arial", 12), width=20).grid(row=1, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 入库日期
 | 
			
		||||
        tk.Label(form_frame, text="入库日期:", font=("Arial", 12)).grid(row=2, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.inbound_date_var = tk.StringVar(value=datetime.now().strftime("%Y-%m-%d"))
 | 
			
		||||
        date_entry = tk.Entry(form_frame, textvariable=self.inbound_date_var, font=("Arial", 12), width=20)
 | 
			
		||||
        date_entry.grid(row=2, column=1, padx=10, pady=10)
 | 
			
		||||
        tk.Label(form_frame, text="(格式: 2024-01-01)", font=("Arial", 8), fg="gray").grid(row=2, column=2, sticky="w", padx=5)
 | 
			
		||||
        
 | 
			
		||||
        # 备注
 | 
			
		||||
        tk.Label(form_frame, text="备注:", font=("Arial", 12)).grid(row=3, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.inbound_note_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.inbound_note_var, font=("Arial", 12), width=20).grid(row=3, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 提交按钮
 | 
			
		||||
        button_frame = tk.Frame(form_frame)
 | 
			
		||||
        button_frame.grid(row=4, column=0, columnspan=2, pady=20)
 | 
			
		||||
        tk.Button(button_frame, text="确认入库", command=self.process_inbound, bg="lightgreen", font=("Arial", 12)).pack(side=tk.LEFT, padx=10)
 | 
			
		||||
        tk.Button(button_frame, text="取消", command=lambda: self.show_detail_page(self.current_product), font=("Arial", 12)).pack(side=tk.LEFT, padx=10)
 | 
			
		||||
    
 | 
			
		||||
    def show_outbound_page(self):
 | 
			
		||||
        """显示出库页面"""
 | 
			
		||||
        self.current_page = "outbound"
 | 
			
		||||
        self.clear_frame()
 | 
			
		||||
        
 | 
			
		||||
        # 标题
 | 
			
		||||
        title_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        title_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        tk.Label(title_frame, text=f"出库 - {self.current_product}", font=("Arial", 16, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Button(title_frame, text="返回详情", command=lambda: self.show_detail_page(self.current_product)).pack(side=tk.RIGHT)
 | 
			
		||||
        
 | 
			
		||||
        # 输入表单
 | 
			
		||||
        form_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        form_frame.pack(fill=tk.X, padx=50, pady=50)
 | 
			
		||||
        
 | 
			
		||||
        # 出库重量
 | 
			
		||||
        tk.Label(form_frame, text="出库重量(kg):", font=("Arial", 12)).grid(row=0, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.outbound_weight_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.outbound_weight_var, font=("Arial", 12), width=20).grid(row=0, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 出库价格(自动计算)
 | 
			
		||||
        tk.Label(form_frame, text="出库价格(元/kg):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", pady=10)
 | 
			
		||||
        current_price = self.data["products"][self.current_product]["avg_price"]
 | 
			
		||||
        self.outbound_price_var = tk.StringVar(value=str(current_price))
 | 
			
		||||
        price_entry = tk.Entry(form_frame, textvariable=self.outbound_price_var, font=("Arial", 12), width=20, state="readonly")
 | 
			
		||||
        price_entry.grid(row=1, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 出库日期
 | 
			
		||||
        tk.Label(form_frame, text="出库日期:", font=("Arial", 12)).grid(row=2, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.outbound_date_var = tk.StringVar(value=datetime.now().strftime("%Y-%m-%d"))
 | 
			
		||||
        date_entry = tk.Entry(form_frame, textvariable=self.outbound_date_var, font=("Arial", 12), width=20)
 | 
			
		||||
        date_entry.grid(row=2, column=1, padx=10, pady=10)
 | 
			
		||||
        tk.Label(form_frame, text="(格式: 2024-01-01)", font=("Arial", 8), fg="gray").grid(row=2, column=2, sticky="w", padx=5)
 | 
			
		||||
        
 | 
			
		||||
        # 备注
 | 
			
		||||
        tk.Label(form_frame, text="备注:", font=("Arial", 12)).grid(row=3, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.outbound_note_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.outbound_note_var, font=("Arial", 12), width=20).grid(row=3, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 提交按钮
 | 
			
		||||
        button_frame = tk.Frame(form_frame)
 | 
			
		||||
        button_frame.grid(row=4, column=0, columnspan=2, pady=20)
 | 
			
		||||
        tk.Button(button_frame, text="确认出库", command=self.process_outbound, bg="lightcoral", font=("Arial", 12)).pack(side=tk.LEFT, padx=10)
 | 
			
		||||
        tk.Button(button_frame, text="取消", command=lambda: self.show_detail_page(self.current_product), font=("Arial", 12)).pack(side=tk.LEFT, padx=10)
 | 
			
		||||
    
 | 
			
		||||
    def process_inbound(self):
 | 
			
		||||
        """处理入库"""
 | 
			
		||||
        try:
 | 
			
		||||
            weight = float(self.inbound_weight_var.get())
 | 
			
		||||
            price = float(self.inbound_price_var.get())
 | 
			
		||||
            note = self.inbound_note_var.get().strip()
 | 
			
		||||
            date_str = self.inbound_date_var.get().strip()
 | 
			
		||||
            
 | 
			
		||||
            if weight <= 0 or price <= 0:
 | 
			
		||||
                messagebox.showerror("错误", "重量和价格必须大于0")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            # 验证日期格式
 | 
			
		||||
            try:
 | 
			
		||||
                datetime.strptime(date_str, "%Y-%m-%d")
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                messagebox.showerror("错误", "请输入正确的日期格式 (YYYY-MM-DD)")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            # 更新产品数据
 | 
			
		||||
            if self.current_product not in self.data["products"]:
 | 
			
		||||
                self.data["products"][self.current_product] = {"total_weight": 0, "avg_price": 0}
 | 
			
		||||
            
 | 
			
		||||
            product_data = self.data["products"][self.current_product]
 | 
			
		||||
            old_total_weight = product_data["total_weight"]
 | 
			
		||||
            old_avg_price = product_data["avg_price"]
 | 
			
		||||
            
 | 
			
		||||
            # 计算新的平均价格
 | 
			
		||||
            new_total_weight = old_total_weight + weight
 | 
			
		||||
            new_avg_price = (old_total_weight * old_avg_price + weight * price) / new_total_weight
 | 
			
		||||
            
 | 
			
		||||
            product_data["total_weight"] = new_total_weight
 | 
			
		||||
            product_data["avg_price"] = new_avg_price
 | 
			
		||||
            
 | 
			
		||||
            # 添加交易记录
 | 
			
		||||
            transaction = {
 | 
			
		||||
                "product": self.current_product,
 | 
			
		||||
                "type": "入库",
 | 
			
		||||
                "weight": weight,
 | 
			
		||||
                "price": price,
 | 
			
		||||
                "note": note,
 | 
			
		||||
                "time": date_str
 | 
			
		||||
            }
 | 
			
		||||
            self.data["transactions"].append(transaction)
 | 
			
		||||
            
 | 
			
		||||
            # 保存数据
 | 
			
		||||
            self.save_data()
 | 
			
		||||
            
 | 
			
		||||
            messagebox.showinfo("成功", "入库成功!")
 | 
			
		||||
            self.show_detail_page(self.current_product)
 | 
			
		||||
            
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            messagebox.showerror("错误", "请输入有效的数字")
 | 
			
		||||
    
 | 
			
		||||
    def process_outbound(self):
 | 
			
		||||
        """处理出库"""
 | 
			
		||||
        try:
 | 
			
		||||
            weight = float(self.outbound_weight_var.get())
 | 
			
		||||
            price = float(self.outbound_price_var.get())
 | 
			
		||||
            note = self.outbound_note_var.get().strip()
 | 
			
		||||
            date_str = self.outbound_date_var.get().strip()
 | 
			
		||||
            
 | 
			
		||||
            if weight <= 0:
 | 
			
		||||
                messagebox.showerror("错误", "重量必须大于0")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            # 验证日期格式
 | 
			
		||||
            try:
 | 
			
		||||
                datetime.strptime(date_str, "%Y-%m-%d")
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                messagebox.showerror("错误", "请输入正确的日期格式 (YYYY-MM-DD)")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            # 检查库存是否足够
 | 
			
		||||
            current_weight = self.data["products"][self.current_product]["total_weight"]
 | 
			
		||||
            if weight > current_weight:
 | 
			
		||||
                messagebox.showerror("错误", f"库存不足!当前库存: {current_weight:.1f}kg")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            # 更新产品数据
 | 
			
		||||
            self.data["products"][self.current_product]["total_weight"] -= weight
 | 
			
		||||
            
 | 
			
		||||
            # 添加交易记录
 | 
			
		||||
            transaction = {
 | 
			
		||||
                "product": self.current_product,
 | 
			
		||||
                "type": "出库",
 | 
			
		||||
                "weight": weight,
 | 
			
		||||
                "price": price,
 | 
			
		||||
                "note": note,
 | 
			
		||||
                "time": date_str
 | 
			
		||||
            }
 | 
			
		||||
            self.data["transactions"].append(transaction)
 | 
			
		||||
            
 | 
			
		||||
            # 保存数据
 | 
			
		||||
            self.save_data()
 | 
			
		||||
            
 | 
			
		||||
            messagebox.showinfo("成功", "出库成功!")
 | 
			
		||||
            self.show_detail_page(self.current_product)
 | 
			
		||||
            
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            messagebox.showerror("错误", "请输入有效的数字")
 | 
			
		||||
    
 | 
			
		||||
    def show_add_category_page(self):
 | 
			
		||||
        """显示添加产品大类页面"""
 | 
			
		||||
        self.current_page = "add_category"
 | 
			
		||||
        self.clear_frame()
 | 
			
		||||
        
 | 
			
		||||
        # 标题
 | 
			
		||||
        title_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        title_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        tk.Label(title_frame, text="添加产品大类", font=("Arial", 16, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Button(title_frame, text="返回主页", command=self.show_main_page).pack(side=tk.RIGHT)
 | 
			
		||||
        
 | 
			
		||||
        # 输入表单
 | 
			
		||||
        form_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        form_frame.pack(fill=tk.X, padx=50, pady=50)
 | 
			
		||||
        
 | 
			
		||||
        # 产品名称
 | 
			
		||||
        tk.Label(form_frame, text="产品名称:", font=("Arial", 12)).grid(row=0, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.category_name_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.category_name_var, font=("Arial", 12), width=30).grid(row=0, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 初始重量
 | 
			
		||||
        tk.Label(form_frame, text="初始重量(kg):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.category_weight_var = tk.StringVar(value="0")
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.category_weight_var, font=("Arial", 12), width=30).grid(row=1, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 初始价格
 | 
			
		||||
        tk.Label(form_frame, text="初始价格(元/kg):", font=("Arial", 12)).grid(row=2, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.category_price_var = tk.StringVar(value="0")
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.category_price_var, font=("Arial", 12), width=30).grid(row=2, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 产品描述
 | 
			
		||||
        tk.Label(form_frame, text="产品描述:", font=("Arial", 12)).grid(row=3, column=0, sticky="w", pady=10)
 | 
			
		||||
        self.category_desc_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(form_frame, textvariable=self.category_desc_var, font=("Arial", 12), width=30).grid(row=3, column=1, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 提交按钮
 | 
			
		||||
        button_frame = tk.Frame(form_frame)
 | 
			
		||||
        button_frame.grid(row=4, column=0, columnspan=2, pady=20)
 | 
			
		||||
        tk.Button(button_frame, text="确认添加", command=self.process_add_category, bg="lightblue", font=("Arial", 12)).pack(side=tk.LEFT, padx=10)
 | 
			
		||||
        tk.Button(button_frame, text="取消", command=self.show_main_page, font=("Arial", 12)).pack(side=tk.LEFT, padx=10)
 | 
			
		||||
        
 | 
			
		||||
        # 说明文字
 | 
			
		||||
        info_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        info_frame.pack(fill=tk.X, padx=50, pady=10)
 | 
			
		||||
        info_text = "说明:\n• 产品名称不能为空且不能与现有产品重复\n• 初始重量和价格可以设为0,后续通过入库操作添加\n• 产品描述为可选项"
 | 
			
		||||
        tk.Label(info_frame, text=info_text, font=("Arial", 10), justify=tk.LEFT, fg="gray").pack(anchor="w")
 | 
			
		||||
    
 | 
			
		||||
    def process_add_category(self):
 | 
			
		||||
        """处理添加产品大类"""
 | 
			
		||||
        try:
 | 
			
		||||
            name = self.category_name_var.get().strip()
 | 
			
		||||
            weight = float(self.category_weight_var.get())
 | 
			
		||||
            price = float(self.category_price_var.get())
 | 
			
		||||
            description = self.category_desc_var.get().strip()
 | 
			
		||||
            
 | 
			
		||||
            # 验证输入
 | 
			
		||||
            if not name:
 | 
			
		||||
                messagebox.showerror("错误", "产品名称不能为空")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            if name in self.data["products"]:
 | 
			
		||||
                messagebox.showerror("错误", f"产品 '{name}' 已存在,请使用其他名称")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            if weight < 0 or price < 0:
 | 
			
		||||
                messagebox.showerror("错误", "重量和价格不能为负数")
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
            # 添加新产品
 | 
			
		||||
            self.data["products"][name] = {
 | 
			
		||||
                "total_weight": weight,
 | 
			
		||||
                "avg_price": price
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            # 如果有初始重量和价格,添加初始入库记录
 | 
			
		||||
            if weight > 0 and price > 0:
 | 
			
		||||
                transaction = {
 | 
			
		||||
                    "product": name,
 | 
			
		||||
                    "type": "入库",
 | 
			
		||||
                    "weight": weight,
 | 
			
		||||
                    "price": price,
 | 
			
		||||
                    "note": f"初始库存 - {description}" if description else "初始库存",
 | 
			
		||||
                    "time": datetime.now().strftime("%Y-%m-%d %H:%M")
 | 
			
		||||
                }
 | 
			
		||||
                self.data["transactions"].append(transaction)
 | 
			
		||||
            
 | 
			
		||||
            # 保存数据
 | 
			
		||||
            self.save_data()
 | 
			
		||||
            
 | 
			
		||||
            messagebox.showinfo("成功", f"产品大类 '{name}' 添加成功!")
 | 
			
		||||
            self.show_main_page()
 | 
			
		||||
            
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            messagebox.showerror("错误", "请输入有效的数字")
 | 
			
		||||
    
 | 
			
		||||
    def show_query_page(self):
 | 
			
		||||
        """显示查询页面"""
 | 
			
		||||
        self.current_page = "query"
 | 
			
		||||
        self.current_query_page = 1
 | 
			
		||||
        self.clear_frame()
 | 
			
		||||
        
 | 
			
		||||
        # 标题
 | 
			
		||||
        title_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        title_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        tk.Label(title_frame, text="订单查询", font=("Arial", 16, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Button(title_frame, text="返回主页", command=self.show_main_page).pack(side=tk.RIGHT)
 | 
			
		||||
        
 | 
			
		||||
        # 查询条件
 | 
			
		||||
        query_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        query_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 第一行:产品名称和交易类型
 | 
			
		||||
        row1_frame = tk.Frame(query_frame)
 | 
			
		||||
        row1_frame.pack(fill=tk.X, pady=5)
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(row1_frame, text="产品名称:", font=("Arial", 10)).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_product_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(row1_frame, textvariable=self.query_product_var, font=("Arial", 10), width=15).pack(side=tk.LEFT, padx=(5, 20))
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(row1_frame, text="交易类型:", font=("Arial", 10)).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_type_var = tk.StringVar()
 | 
			
		||||
        type_combo = tk.OptionMenu(row1_frame, self.query_type_var, "全部", "入库", "出库")
 | 
			
		||||
        type_combo.config(font=("Arial", 10))
 | 
			
		||||
        self.query_type_var.set("全部")
 | 
			
		||||
        type_combo.pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        
 | 
			
		||||
        # 第二行:时间范围
 | 
			
		||||
        row2_frame = tk.Frame(query_frame)
 | 
			
		||||
        row2_frame.pack(fill=tk.X, pady=5)
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(row2_frame, text="开始时间:", font=("Arial", 10)).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_start_date_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(row2_frame, textvariable=self.query_start_date_var, font=("Arial", 10), width=12).pack(side=tk.LEFT, padx=(5, 10))
 | 
			
		||||
        tk.Label(row2_frame, text="(格式: 2024-01-01)", font=("Arial", 8), fg="gray").pack(side=tk.LEFT, padx=(0, 20))
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(row2_frame, text="结束时间:", font=("Arial", 10)).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_end_date_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(row2_frame, textvariable=self.query_end_date_var, font=("Arial", 10), width=12).pack(side=tk.LEFT, padx=(5, 10))
 | 
			
		||||
        tk.Label(row2_frame, text="(格式: 2024-12-31)", font=("Arial", 8), fg="gray").pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        # 第三行:重量和价格范围
 | 
			
		||||
        row3_frame = tk.Frame(query_frame)
 | 
			
		||||
        row3_frame.pack(fill=tk.X, pady=5)
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(row3_frame, text="最小重量:", font=("Arial", 10)).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_min_weight_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(row3_frame, textvariable=self.query_min_weight_var, font=("Arial", 10), width=10).pack(side=tk.LEFT, padx=(5, 20))
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(row3_frame, text="最大重量:", font=("Arial", 10)).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_max_weight_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(row3_frame, textvariable=self.query_max_weight_var, font=("Arial", 10), width=10).pack(side=tk.LEFT, padx=(5, 20))
 | 
			
		||||
        
 | 
			
		||||
        tk.Label(row3_frame, text="备注关键词:", font=("Arial", 10)).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_note_var = tk.StringVar()
 | 
			
		||||
        tk.Entry(row3_frame, textvariable=self.query_note_var, font=("Arial", 10), width=15).pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        
 | 
			
		||||
        # 查询按钮
 | 
			
		||||
        button_frame = tk.Frame(query_frame)
 | 
			
		||||
        button_frame.pack(fill=tk.X, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        tk.Button(button_frame, text="查询", command=self.execute_query, bg="lightgreen", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        tk.Button(button_frame, text="清空条件", command=self.clear_query_conditions, font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
 | 
			
		||||
        
 | 
			
		||||
        # 查询结果列表
 | 
			
		||||
        result_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        result_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        # 表头
 | 
			
		||||
        header_frame = tk.Frame(result_frame)
 | 
			
		||||
        header_frame.pack(fill=tk.X)
 | 
			
		||||
        tk.Label(header_frame, text="时间", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="产品名", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="类型", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="重量(kg)", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="价格(元/kg)", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="总价(元)", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        tk.Label(header_frame, text="备注", width=13, relief=tk.RIDGE, font=("Arial", 10, "bold")).pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        # 查询结果
 | 
			
		||||
        self.query_result_frame = tk.Frame(result_frame)
 | 
			
		||||
        self.query_result_frame.pack(fill=tk.BOTH, expand=True)
 | 
			
		||||
        
 | 
			
		||||
        # 分页控制
 | 
			
		||||
        self.query_page_frame = tk.Frame(self.main_frame)
 | 
			
		||||
        self.query_page_frame.pack(fill=tk.X, padx=10, pady=10)
 | 
			
		||||
        
 | 
			
		||||
        tk.Button(self.query_page_frame, text="上一页", command=self.prev_query_page).pack(side=tk.LEFT)
 | 
			
		||||
        self.query_page_label = tk.Label(self.query_page_frame, text="第 1 页 / 共 1 页")
 | 
			
		||||
        self.query_page_label.pack(side=tk.LEFT, padx=20)
 | 
			
		||||
        tk.Button(self.query_page_frame, text="下一页", command=self.next_query_page).pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        # 设置默认查询条件:最近一个月
 | 
			
		||||
        from datetime import datetime, timedelta
 | 
			
		||||
        today = datetime.now()
 | 
			
		||||
        one_month_ago = today - timedelta(days=30)
 | 
			
		||||
        self.query_start_date_var.set(one_month_ago.strftime("%Y-%m-%d"))
 | 
			
		||||
        self.query_end_date_var.set(today.strftime("%Y-%m-%d"))
 | 
			
		||||
        
 | 
			
		||||
        # 初始显示最近一个月的交易记录
 | 
			
		||||
        self.execute_query()
 | 
			
		||||
    
 | 
			
		||||
    def execute_query(self):
 | 
			
		||||
        """执行查询"""
 | 
			
		||||
        # 获取查询条件
 | 
			
		||||
        product_name = self.query_product_var.get().strip().lower()
 | 
			
		||||
        transaction_type = self.query_type_var.get()
 | 
			
		||||
        start_date = self.query_start_date_var.get().strip()
 | 
			
		||||
        end_date = self.query_end_date_var.get().strip()
 | 
			
		||||
        min_weight = self.query_min_weight_var.get().strip()
 | 
			
		||||
        max_weight = self.query_max_weight_var.get().strip()
 | 
			
		||||
        note_keyword = self.query_note_var.get().strip().lower()
 | 
			
		||||
        
 | 
			
		||||
        # 过滤交易记录
 | 
			
		||||
        filtered_transactions = []
 | 
			
		||||
        
 | 
			
		||||
        for transaction in self.data["transactions"]:
 | 
			
		||||
            # 产品名称过滤
 | 
			
		||||
            if product_name and product_name not in transaction["product"].lower():
 | 
			
		||||
                continue
 | 
			
		||||
            
 | 
			
		||||
            # 交易类型过滤
 | 
			
		||||
            if transaction_type != "全部" and transaction["type"] != transaction_type:
 | 
			
		||||
                continue
 | 
			
		||||
            
 | 
			
		||||
            # 时间范围过滤
 | 
			
		||||
            if start_date:
 | 
			
		||||
                try:
 | 
			
		||||
                    trans_date = transaction["time"][:10]  # 取日期部分
 | 
			
		||||
                    if trans_date < start_date:
 | 
			
		||||
                        continue
 | 
			
		||||
                except:
 | 
			
		||||
                    pass
 | 
			
		||||
            
 | 
			
		||||
            if end_date:
 | 
			
		||||
                try:
 | 
			
		||||
                    trans_date = transaction["time"][:10]  # 取日期部分
 | 
			
		||||
                    if trans_date > end_date:
 | 
			
		||||
                        continue
 | 
			
		||||
                except:
 | 
			
		||||
                    pass
 | 
			
		||||
            
 | 
			
		||||
            # 重量范围过滤
 | 
			
		||||
            if min_weight:
 | 
			
		||||
                try:
 | 
			
		||||
                    if transaction["weight"] < float(min_weight):
 | 
			
		||||
                        continue
 | 
			
		||||
                except ValueError:
 | 
			
		||||
                    pass
 | 
			
		||||
            
 | 
			
		||||
            if max_weight:
 | 
			
		||||
                try:
 | 
			
		||||
                    if transaction["weight"] > float(max_weight):
 | 
			
		||||
                        continue
 | 
			
		||||
                except ValueError:
 | 
			
		||||
                    pass
 | 
			
		||||
            
 | 
			
		||||
            # 备注关键词过滤
 | 
			
		||||
            if note_keyword and note_keyword not in transaction["note"].lower():
 | 
			
		||||
                continue
 | 
			
		||||
            
 | 
			
		||||
            filtered_transactions.append(transaction)
 | 
			
		||||
        
 | 
			
		||||
        # 按时间倒序排列
 | 
			
		||||
        filtered_transactions.sort(key=lambda x: x["time"], reverse=True)
 | 
			
		||||
        
 | 
			
		||||
        # 保存查询结果
 | 
			
		||||
        self.query_results = filtered_transactions
 | 
			
		||||
        
 | 
			
		||||
        # 重置到第一页
 | 
			
		||||
        self.current_query_page = 1
 | 
			
		||||
        
 | 
			
		||||
        # 更新查询结果显示
 | 
			
		||||
        self.update_query_results()
 | 
			
		||||
    
 | 
			
		||||
    def update_query_results(self):
 | 
			
		||||
        """更新查询结果显示"""
 | 
			
		||||
        for widget in self.query_result_frame.winfo_children():
 | 
			
		||||
            widget.destroy()
 | 
			
		||||
        
 | 
			
		||||
        # 分页处理
 | 
			
		||||
        start_idx = (self.current_query_page - 1) * self.items_per_page
 | 
			
		||||
        end_idx = start_idx + self.items_per_page
 | 
			
		||||
        page_results = self.query_results[start_idx:end_idx]
 | 
			
		||||
        
 | 
			
		||||
        # 显示查询结果
 | 
			
		||||
        for transaction in page_results:
 | 
			
		||||
            row_frame = tk.Frame(self.query_result_frame)
 | 
			
		||||
            row_frame.pack(fill=tk.X, pady=1)
 | 
			
		||||
            
 | 
			
		||||
            # 计算总价
 | 
			
		||||
            total_price = transaction["weight"] * transaction["price"]
 | 
			
		||||
            
 | 
			
		||||
            tk.Label(row_frame, text=transaction["time"], width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=transaction["product"], width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            
 | 
			
		||||
            color = "lightgreen" if transaction["type"] == "入库" else "lightcoral"
 | 
			
		||||
            tk.Label(row_frame, text=transaction["type"], width=14, relief=tk.RIDGE, bg=color).pack(side=tk.LEFT)
 | 
			
		||||
            
 | 
			
		||||
            tk.Label(row_frame, text=f"{transaction['weight']:.1f}", width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=f"{transaction['price']:.2f}", width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=f"{total_price:.2f}", width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
            tk.Label(row_frame, text=transaction["note"], width=15, relief=tk.RIDGE).pack(side=tk.LEFT)
 | 
			
		||||
        
 | 
			
		||||
        # 更新分页信息
 | 
			
		||||
        total_results = len(self.query_results)
 | 
			
		||||
        max_pages = max(1, (total_results + self.items_per_page - 1) // self.items_per_page)
 | 
			
		||||
        self.query_page_label.config(text=f"第 {self.current_query_page} 页 / 共 {max_pages} 页 (共 {total_results} 条记录)")
 | 
			
		||||
        
 | 
			
		||||
        # 计算统计信息
 | 
			
		||||
        total_weight = 0
 | 
			
		||||
        total_price = 0
 | 
			
		||||
        for transaction in self.query_results:
 | 
			
		||||
            total_weight += transaction["weight"]
 | 
			
		||||
            total_price += transaction["weight"] * transaction["price"]
 | 
			
		||||
        
 | 
			
		||||
        # 在分页信息右侧显示统计信息
 | 
			
		||||
        stats_text = f"总重量: {total_weight:.2f}kg    总价: {total_price:.2f}元"
 | 
			
		||||
        if hasattr(self, 'query_stats_label') and self.query_stats_label.winfo_exists():
 | 
			
		||||
            try:
 | 
			
		||||
                self.query_stats_label.config(text=stats_text)
 | 
			
		||||
            except tk.TclError:
 | 
			
		||||
                # 如果标签已被销毁,重新创建
 | 
			
		||||
                self.query_stats_label = tk.Label(self.query_page_frame, text=stats_text, font=("Arial", 10, "bold"), fg="blue")
 | 
			
		||||
                self.query_stats_label.pack(side=tk.RIGHT)
 | 
			
		||||
        else:
 | 
			
		||||
            self.query_stats_label = tk.Label(self.query_page_frame, text=stats_text, font=("Arial", 10, "bold"), fg="blue")
 | 
			
		||||
            self.query_stats_label.pack(side=tk.RIGHT)
 | 
			
		||||
        
 | 
			
		||||
        # 如果没有查询结果,显示提示
 | 
			
		||||
        if not page_results:
 | 
			
		||||
            no_result_frame = tk.Frame(self.query_result_frame)
 | 
			
		||||
            no_result_frame.pack(fill=tk.X, pady=20)
 | 
			
		||||
            tk.Label(no_result_frame, text="未找到符合条件的记录", 
 | 
			
		||||
                    font=("Arial", 12), fg="gray").pack()
 | 
			
		||||
    
 | 
			
		||||
    def clear_query_conditions(self):
 | 
			
		||||
        """清空查询条件"""
 | 
			
		||||
        self.query_product_var.set("")
 | 
			
		||||
        self.query_type_var.set("全部")
 | 
			
		||||
        self.query_start_date_var.set("")
 | 
			
		||||
        self.query_end_date_var.set("")
 | 
			
		||||
        self.query_min_weight_var.set("")
 | 
			
		||||
        self.query_max_weight_var.set("")
 | 
			
		||||
        self.query_note_var.set("")
 | 
			
		||||
        self.execute_query()
 | 
			
		||||
    
 | 
			
		||||
    def prev_query_page(self):
 | 
			
		||||
        """查询结果上一页"""
 | 
			
		||||
        if self.current_query_page > 1:
 | 
			
		||||
            self.current_query_page -= 1
 | 
			
		||||
            self.update_query_results()
 | 
			
		||||
    
 | 
			
		||||
    def next_query_page(self):
 | 
			
		||||
        """查询结果下一页"""
 | 
			
		||||
        total_results = len(self.query_results)
 | 
			
		||||
        max_pages = max(1, (total_results + self.items_per_page - 1) // self.items_per_page)
 | 
			
		||||
        
 | 
			
		||||
        if self.current_query_page < max_pages:
 | 
			
		||||
            self.current_query_page += 1
 | 
			
		||||
            self.update_query_results()
 | 
			
		||||
    
 | 
			
		||||
    def delete_transaction(self, transaction):
 | 
			
		||||
        """删除交易记录"""
 | 
			
		||||
        # 确认删除
 | 
			
		||||
        result = messagebox.askyesno("确认删除", 
 | 
			
		||||
                                   f"确定要删除这条交易记录吗?\n\n时间: {transaction['time']}\n类型: {transaction['type']}\n重量: {transaction['weight']:.1f}kg\n价格: {transaction['price']:.2f}元/kg")
 | 
			
		||||
        
 | 
			
		||||
        if not result:
 | 
			
		||||
            return
 | 
			
		||||
        
 | 
			
		||||
        try:
 | 
			
		||||
            # 从交易记录中移除
 | 
			
		||||
            self.data["transactions"].remove(transaction)
 | 
			
		||||
            
 | 
			
		||||
            # 重新计算产品数据
 | 
			
		||||
            self.recalculate_product_data(self.current_product)
 | 
			
		||||
            
 | 
			
		||||
            # 保存数据
 | 
			
		||||
            self.save_data()
 | 
			
		||||
            
 | 
			
		||||
            messagebox.showinfo("成功", "交易记录删除成功!")
 | 
			
		||||
            
 | 
			
		||||
            # 刷新详情页面
 | 
			
		||||
            self.show_detail_page(self.current_product)
 | 
			
		||||
            
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            messagebox.showerror("错误", "删除失败,请重试")
 | 
			
		||||
    
 | 
			
		||||
    def recalculate_product_data(self, product_name):
 | 
			
		||||
        """重新计算产品数据"""
 | 
			
		||||
        # 获取该产品的所有交易记录
 | 
			
		||||
        product_transactions = [t for t in self.data["transactions"] if t["product"] == product_name]
 | 
			
		||||
        
 | 
			
		||||
        if not product_transactions:
 | 
			
		||||
            # 如果没有交易记录,重置产品数据
 | 
			
		||||
            self.data["products"][product_name] = {"total_weight": 0, "avg_price": 0}
 | 
			
		||||
            return
 | 
			
		||||
        
 | 
			
		||||
        # 重新计算总重量和平均价格
 | 
			
		||||
        total_weight = 0
 | 
			
		||||
        total_value = 0
 | 
			
		||||
        
 | 
			
		||||
        for transaction in product_transactions:
 | 
			
		||||
            if transaction["type"] == "入库":
 | 
			
		||||
                total_weight += transaction["weight"]
 | 
			
		||||
                total_value += transaction["weight"] * transaction["price"]
 | 
			
		||||
            else:  # 出库
 | 
			
		||||
                total_weight -= transaction["weight"]
 | 
			
		||||
        
 | 
			
		||||
        # 计算平均价格(只考虑入库记录)
 | 
			
		||||
        inbound_transactions = [t for t in product_transactions if t["type"] == "入库"]
 | 
			
		||||
        if inbound_transactions:
 | 
			
		||||
            total_inbound_weight = sum(t["weight"] for t in inbound_transactions)
 | 
			
		||||
            total_inbound_value = sum(t["weight"] * t["price"] for t in inbound_transactions)
 | 
			
		||||
            avg_price = total_inbound_value / total_inbound_weight if total_inbound_weight > 0 else 0
 | 
			
		||||
        else:
 | 
			
		||||
            avg_price = 0
 | 
			
		||||
        
 | 
			
		||||
        # 更新产品数据
 | 
			
		||||
        self.data["products"][product_name] = {
 | 
			
		||||
            "total_weight": max(0, total_weight),  # 确保重量不为负
 | 
			
		||||
            "avg_price": avg_price
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
    def delete_product_category(self):
 | 
			
		||||
        """删除整个产品分类"""
 | 
			
		||||
        # 确认删除
 | 
			
		||||
        result = messagebox.askyesno("确认删除", 
 | 
			
		||||
                                   f"确定要删除产品分类 '{self.current_product}' 吗?\n\n这将删除该产品的所有交易记录,此操作不可撤销!")
 | 
			
		||||
        
 | 
			
		||||
        if not result:
 | 
			
		||||
            return
 | 
			
		||||
        
 | 
			
		||||
        try:
 | 
			
		||||
            # 删除该产品的所有交易记录
 | 
			
		||||
            self.data["transactions"] = [t for t in self.data["transactions"] if t["product"] != self.current_product]
 | 
			
		||||
            
 | 
			
		||||
            # 删除产品数据
 | 
			
		||||
            if self.current_product in self.data["products"]:
 | 
			
		||||
                del self.data["products"][self.current_product]
 | 
			
		||||
            
 | 
			
		||||
            # 保存数据
 | 
			
		||||
            self.save_data()
 | 
			
		||||
            
 | 
			
		||||
            messagebox.showinfo("成功", f"产品分类 '{self.current_product}' 已删除!")
 | 
			
		||||
            
 | 
			
		||||
            # 返回主页
 | 
			
		||||
            self.show_main_page()
 | 
			
		||||
            
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            messagebox.showerror("错误", f"删除失败:{str(e)}")
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    root = tk.Tk()
 | 
			
		||||
    app = InventoryApp(root)
 | 
			
		||||
    root.mainloop()
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
		Reference in New Issue
	
	Block a user