添加 Simple_Enterprise_Warehouse_Management.py
This commit is contained in:
commit
10c80df7e7
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()
|
Loading…
x
Reference in New Issue
Block a user