#!/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)}")