Files
playwrite/gui/data_query_tab.py
Misaka_Company 2ca53f6a55 style: normalize code formatting across the codebase
- 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>
2026-02-05 14:56:35 +08:00

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)}")