feat: 益选 OCR 订单处理系统初始提交
- 智能供应商识别(蓉城易购/烟草/杨碧月/通用) - 百度 OCR 表格识别集成 - 规则引擎(列映射/数据清洗/单位转换/规格推断) - 条码映射管理与云端同步(Gitea REST API) - 云端同步支持:条码映射、供应商配置、商品资料、采购模板 - 拖拽一键处理(图片→OCR→Excel→合并) - 191 个单元测试 - 移除无用的模板管理功能 - 清理 IDE 产物目录 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""UI控件模块 - StatusBar、ProgressReporter、可折叠框架等"""
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
from .theme import THEMES, get_theme_mode
|
||||
|
||||
|
||||
class StatusBar(tk.Frame):
|
||||
"""状态栏,显示当前系统状态和进度"""
|
||||
|
||||
def __init__(self, master, **kwargs):
|
||||
super().__init__(master, **kwargs)
|
||||
self.configure(height=25, relief=tk.SUNKEN, borderwidth=1)
|
||||
|
||||
self.status_label = tk.Label(self, text="就绪", anchor=tk.W, padx=5)
|
||||
self.status_label.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
|
||||
self.progress = ttk.Progressbar(self, orient=tk.HORIZONTAL, length=200, mode='determinate')
|
||||
self.progress.pack(side=tk.RIGHT, padx=5, pady=2)
|
||||
|
||||
self.progress.pack_forget()
|
||||
|
||||
def set_status(self, text, progress=None):
|
||||
"""设置状态栏文本和进度"""
|
||||
self.status_label.config(text=text)
|
||||
|
||||
if progress is not None and 0 <= progress <= 100:
|
||||
self.progress.pack(side=tk.RIGHT, padx=5, pady=2)
|
||||
self.progress.config(value=progress)
|
||||
else:
|
||||
self.progress.pack_forget()
|
||||
|
||||
def set_running(self, is_running=True):
|
||||
"""设置运行状态"""
|
||||
theme = THEMES[get_theme_mode()]
|
||||
if is_running:
|
||||
self.status_label.config(text="处理中...", foreground=theme["info"])
|
||||
self.progress.pack(side=tk.RIGHT, padx=5, pady=2)
|
||||
self.progress.config(mode='indeterminate')
|
||||
self.progress.start()
|
||||
else:
|
||||
self.status_label.config(text="就绪", foreground=theme["fg"])
|
||||
self.progress.stop()
|
||||
self.progress.pack_forget()
|
||||
|
||||
|
||||
class ProgressReporter:
|
||||
def __init__(self, status_bar: StatusBar):
|
||||
self.status_bar = status_bar
|
||||
|
||||
def set(self, text: str, percent: int = None):
|
||||
try:
|
||||
if percent is not None:
|
||||
self.status_bar.set_status(text, percent)
|
||||
else:
|
||||
self.status_bar.set_status(text)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def running(self):
|
||||
try:
|
||||
self.status_bar.set_running(True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def done(self):
|
||||
try:
|
||||
self.status_bar.set_running(False)
|
||||
self.status_bar.set_status("就绪")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def create_collapsible_frame(parent, title, initial_state=True):
|
||||
"""创建可折叠的面板"""
|
||||
frame = tk.Frame(parent)
|
||||
frame.pack(fill=tk.X, pady=5)
|
||||
|
||||
title_frame = tk.Frame(frame)
|
||||
title_frame.pack(fill=tk.X)
|
||||
|
||||
state_var = tk.BooleanVar(value=initial_state)
|
||||
indicator = "▼" if initial_state else "►"
|
||||
state_label = tk.Label(title_frame, text=indicator, font=("Arial", 10, "bold"))
|
||||
state_label.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
title_label = tk.Label(title_frame, text=title, font=("Arial", 11, "bold"))
|
||||
title_label.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
content_frame = tk.Frame(frame)
|
||||
if initial_state:
|
||||
content_frame.pack(fill=tk.X, padx=20, pady=5)
|
||||
|
||||
def toggle_collapse(event=None):
|
||||
current_state = state_var.get()
|
||||
new_state = not current_state
|
||||
state_var.set(new_state)
|
||||
state_label.config(text="▼" if new_state else "►")
|
||||
if new_state:
|
||||
content_frame.pack(fill=tk.X, padx=20, pady=5)
|
||||
else:
|
||||
content_frame.pack_forget()
|
||||
|
||||
title_frame.bind("<Button-1>", toggle_collapse)
|
||||
state_label.bind("<Button-1>", toggle_collapse)
|
||||
title_label.bind("<Button-1>", toggle_collapse)
|
||||
|
||||
return content_frame, state_var
|
||||
|
||||
|
||||
def center_window(window):
|
||||
"""使窗口居中显示"""
|
||||
window.update_idletasks()
|
||||
width = window.winfo_width()
|
||||
height = window.winfo_height()
|
||||
x = (window.winfo_screenwidth() // 2) - (width // 2)
|
||||
y = (window.winfo_screenheight() // 2) - (height // 2)
|
||||
window.geometry('{}x{}+{}+{}'.format(width, height, x, y))
|
||||
Reference in New Issue
Block a user