- Standardize quote style (single to double quotes) - Improve code formatting consistency - Apply formatting to utilities, GUI components, and tools - Update imports and docstrings for consistency Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
327 lines
11 KiB
Python
327 lines
11 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
数据查询标签页
|
|
|
|
查询生产订单号等信息。
|
|
"""
|
|
|
|
import os
|
|
import threading
|
|
import tkinter as tk
|
|
from tkinter import ttk, messagebox, filedialog
|
|
from gui.widgets import LogText
|
|
from gui.config_manager import ConfigManager
|
|
import pandas as pd
|
|
|
|
|
|
class DataQueryTab(ttk.Frame):
|
|
"""数据查询标签页"""
|
|
|
|
def __init__(self, parent, config: ConfigManager):
|
|
"""
|
|
初始化数据查询标签页
|
|
|
|
Args:
|
|
parent: 父容器
|
|
config: 配置管理器
|
|
"""
|
|
super().__init__(parent)
|
|
self.config = config
|
|
self.query_results = None
|
|
self.querying = False
|
|
|
|
self.create_widgets()
|
|
|
|
# 稍后显示就绪消息
|
|
try:
|
|
self.log_text.info("数据查询标签页已就绪")
|
|
except:
|
|
pass # 如果窗口还未完全就绪,忽略错误
|
|
|
|
def create_widgets(self):
|
|
"""创建界面组件"""
|
|
# 主容器
|
|
main_container = ttk.Frame(self)
|
|
main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
|
|
# 上部:查询控制
|
|
control_frame = ttk.LabelFrame(main_container, text="查询条件", padding=10)
|
|
control_frame.pack(fill=tk.X, pady=(0, 10))
|
|
|
|
# 中部:结果表格
|
|
result_frame = ttk.LabelFrame(main_container, text="查询结果", padding=5)
|
|
result_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
|
|
|
|
# 下部:日志
|
|
log_frame = ttk.LabelFrame(main_container, text="日志", padding=5)
|
|
log_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
self._create_query_control(control_frame)
|
|
self._create_result_table(result_frame)
|
|
self._create_log_panel(log_frame)
|
|
|
|
def _create_query_control(self, parent):
|
|
"""创建查询控制面板"""
|
|
# 查询说明
|
|
info_label = ttk.Label(
|
|
parent,
|
|
text="输入总排号列表(每行一个),查询对应的生产订单号信息",
|
|
foreground="#666666",
|
|
)
|
|
info_label.pack(anchor=tk.W, pady=(0, 5))
|
|
|
|
# 输入区域
|
|
input_frame = ttk.Frame(parent)
|
|
input_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
# 左侧:文本输入框
|
|
text_frame = ttk.Frame(input_frame)
|
|
text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
|
|
|
|
self.input_text = tk.Text(text_frame, height=10, wrap=tk.WORD)
|
|
self.input_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
|
|
text_scrollbar = ttk.Scrollbar(
|
|
text_frame, orient=tk.VERTICAL, command=self.input_text.yview
|
|
)
|
|
text_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
self.input_text.configure(yscrollcommand=text_scrollbar.set)
|
|
|
|
# 右侧:示例和按钮
|
|
right_frame = ttk.Frame(input_frame, width=200)
|
|
right_frame.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
# 示例文本
|
|
example_label = ttk.Label(right_frame, text="示例格式:", foreground="#666666")
|
|
example_label.pack(anchor=tk.W, pady=(0, 5))
|
|
|
|
example_text = tk.Text(right_frame, height=8, width=25, wrap=tk.WORD)
|
|
example_text.pack(fill=tk.X)
|
|
example_text.insert("1.0", "24000001\n24000002\n24000003")
|
|
example_text.config(state=tk.DISABLED)
|
|
|
|
# 快捷按钮
|
|
ttk.Separator(right_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
|
|
|
|
ttk.Button(
|
|
right_frame, text="加载 ProductionID.txt", command=self._load_production_id
|
|
).pack(fill=tk.X, pady=2)
|
|
ttk.Button(right_frame, text="清空输入", command=self._clear_input).pack(
|
|
fill=tk.X, pady=2
|
|
)
|
|
|
|
# 查询按钮
|
|
button_frame = ttk.Frame(parent)
|
|
button_frame.pack(fill=tk.X, pady=(10, 0))
|
|
|
|
self.query_button = ttk.Button(
|
|
button_frame, text="执行查询", command=self.execute_query
|
|
)
|
|
self.query_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
self.export_button = ttk.Button(
|
|
button_frame,
|
|
text="导出结果",
|
|
command=self.export_results,
|
|
state=tk.DISABLED,
|
|
)
|
|
self.export_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
self.progress = ttk.Progressbar(parent, mode="indeterminate")
|
|
self.progress.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
|
|
|
|
def _create_result_table(self, parent):
|
|
"""创建结果表格"""
|
|
# 创建 Treeview
|
|
columns = ("总排号", "生产订单号", "订单状态")
|
|
self.tree = ttk.Treeview(parent, columns=columns, show="headings", height=12)
|
|
|
|
# 设置列标题和宽度
|
|
self.tree.heading("总排号", text="总排号")
|
|
self.tree.heading("生产订单号", text="生产订单号")
|
|
self.tree.heading("订单状态", text="订单状态")
|
|
|
|
self.tree.column("总排号", width=150)
|
|
self.tree.column("生产订单号", width=300)
|
|
self.tree.column("订单状态", width=150)
|
|
|
|
# 添加滚动条
|
|
scrollbar_y = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.tree.yview)
|
|
scrollbar_x = ttk.Scrollbar(
|
|
parent, orient=tk.HORIZONTAL, command=self.tree.xview
|
|
)
|
|
|
|
self.tree.configure(
|
|
yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set
|
|
)
|
|
|
|
# 布局
|
|
self.tree.grid(row=0, column=0, sticky="nsew")
|
|
scrollbar_y.grid(row=0, column=1, sticky="ns")
|
|
scrollbar_x.grid(row=1, column=0, sticky="ew")
|
|
|
|
parent.rowconfigure(0, weight=1)
|
|
parent.columnconfigure(0, weight=1)
|
|
|
|
def _create_log_panel(self, parent):
|
|
"""创建日志面板"""
|
|
self.log_text = LogText(parent, height=6, readonly=True)
|
|
self.log_text.pack(fill=tk.BOTH, expand=True)
|
|
|
|
def _load_production_id(self):
|
|
"""加载 ProductionID.txt 文件"""
|
|
default_path = self.config.get("paths.production_id_file", "ProductionID.txt")
|
|
|
|
# 检查默认路径
|
|
if os.path.exists(default_path):
|
|
file_path = default_path
|
|
else:
|
|
# 打开文件选择对话框
|
|
from tkinter import filedialog
|
|
|
|
file_path = filedialog.askopenfilename(
|
|
title="选择 ProductionID 文件",
|
|
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
|
|
)
|
|
|
|
if not file_path:
|
|
return
|
|
|
|
try:
|
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
content = f.read()
|
|
|
|
self.input_text.delete("1.0", tk.END)
|
|
self.input_text.insert("1.0", content)
|
|
self.log_text.info(f"已加载文件:{file_path}")
|
|
|
|
except Exception as e:
|
|
messagebox.showerror("错误", f"加载文件失败:{str(e)}")
|
|
self.log_text.error(f"加载文件失败:{str(e)}")
|
|
|
|
def _clear_input(self):
|
|
"""清空输入"""
|
|
self.input_text.delete("1.0", tk.END)
|
|
|
|
def execute_query(self):
|
|
"""执行查询"""
|
|
# 获取输入的总排号列表
|
|
input_text = self.input_text.get("1.0", tk.END).strip()
|
|
|
|
if not input_text:
|
|
messagebox.showwarning("警告", "请输入总排号列表")
|
|
return
|
|
|
|
# 解析总排号
|
|
production_ids = [
|
|
line.strip() for line in input_text.split("\n") if line.strip()
|
|
]
|
|
|
|
if not production_ids:
|
|
messagebox.showwarning("警告", "没有有效的总排号")
|
|
return
|
|
|
|
self.log_text.info(f"准备查询 {len(production_ids)} 个总排号...")
|
|
|
|
# 更新 UI 状态
|
|
self.querying = True
|
|
self.query_button.config(state=tk.DISABLED)
|
|
self.progress.start(10)
|
|
|
|
# 清空结果表格
|
|
for item in self.tree.get_children():
|
|
self.tree.delete(item)
|
|
|
|
# 在后台线程中执行查询
|
|
query_thread = threading.Thread(
|
|
target=self._query_worker, args=(production_ids,), daemon=True
|
|
)
|
|
query_thread.start()
|
|
|
|
def _query_worker(self, production_ids: list):
|
|
"""查询工作线程"""
|
|
try:
|
|
# 导入查询函数
|
|
from db.production_order_query import query_production_order_numbers
|
|
|
|
self._update_log("正在连接数据库...", "INFO")
|
|
|
|
# 执行查询
|
|
results = query_production_order_numbers(production_ids)
|
|
|
|
if results:
|
|
self._update_log(f"查询完成,共 {len(results)} 条结果", "SUCCESS")
|
|
self._display_results(results)
|
|
else:
|
|
self._update_log("查询完成,但没有找到匹配的结果", "WARNING")
|
|
|
|
except Exception as e:
|
|
self._update_log(f"查询过程中发生错误:{str(e)}", "ERROR")
|
|
messagebox.showerror("错误", f"查询失败:{str(e)}")
|
|
finally:
|
|
# 更新 UI 状态
|
|
self.after(0, self._query_complete)
|
|
|
|
def _query_complete(self):
|
|
"""查询完成后的 UI 更新"""
|
|
self.querying = False
|
|
self.query_button.config(state=tk.NORMAL)
|
|
self.progress.stop()
|
|
|
|
def _display_results(self, results: list):
|
|
"""在主线程中显示结果"""
|
|
|
|
def update():
|
|
for 总排号, 生产订单号 in results:
|
|
self.tree.insert("", tk.END, values=(总排号, 生产订单号, ""))
|
|
|
|
if len(results) > 0:
|
|
self.export_button.config(state=tk.NORMAL)
|
|
self.query_results = results
|
|
|
|
self.after(0, update)
|
|
|
|
def _update_log(self, message: str, level: str = "INFO"):
|
|
"""线程安全的日志更新"""
|
|
|
|
def update():
|
|
if level == "INFO":
|
|
self.log_text.info(message)
|
|
elif level == "SUCCESS":
|
|
self.log_text.success(message)
|
|
elif level == "WARNING":
|
|
self.log_text.warning(message)
|
|
elif level == "ERROR":
|
|
self.log_text.error(message)
|
|
|
|
self.after(0, update)
|
|
|
|
def export_results(self):
|
|
"""导出结果到 Excel"""
|
|
if not self.query_results:
|
|
messagebox.showwarning("警告", "没有结果可导出")
|
|
return
|
|
|
|
output_file = filedialog.asksaveasfilename(
|
|
title="导出查询结果",
|
|
defaultextension=".xlsx",
|
|
filetypes=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")],
|
|
initialfile="生产订单号查询结果.xlsx",
|
|
)
|
|
|
|
if not output_file:
|
|
return
|
|
|
|
try:
|
|
# 创建 DataFrame 并保存
|
|
df = pd.DataFrame(self.query_results, columns=["总排号", "生产订单号"])
|
|
df.to_excel(output_file, index=False)
|
|
|
|
messagebox.showinfo("成功", f"结果已导出到:{output_file}")
|
|
self.log_text.success(f"结果已导出到:{output_file}")
|
|
|
|
except Exception as e:
|
|
messagebox.showerror("错误", f"导出失败:{str(e)}")
|
|
self.log_text.error(f"导出失败:{str(e)}")
|