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,371 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""处理结果预览对话框模块"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import datetime
|
||||
import tkinter as tk
|
||||
from tkinter import messagebox, scrolledtext
|
||||
|
||||
from .theme import THEMES, get_theme_mode, apply_theme
|
||||
from .ui_widgets import center_window
|
||||
from app.core.utils.file_utils import format_file_size
|
||||
|
||||
TOBACCO_PREVIEW_WINDOW = None
|
||||
|
||||
|
||||
def show_result_preview(command, output):
|
||||
"""显示处理结果预览"""
|
||||
if "ocr" in command:
|
||||
show_ocr_result_preview(output)
|
||||
elif "excel" in command:
|
||||
show_excel_result_preview(output)
|
||||
elif "merge" in command:
|
||||
show_merge_result_preview(output)
|
||||
elif "pipeline" in command:
|
||||
show_pipeline_result_preview(output)
|
||||
else:
|
||||
messagebox.showinfo("处理完成", "操作已成功完成!\n请在data/output目录查看结果。")
|
||||
|
||||
|
||||
def show_ocr_result_preview(output):
|
||||
"""显示OCR处理结果预览"""
|
||||
files_match = re.search(r'找到 (\d+) 个图片文件,其中 (\d+) 个未处理', output)
|
||||
processed_match = re.search(r'所有图片处理完成, 总计: (\d+), 成功: (\d+)', output)
|
||||
|
||||
if processed_match:
|
||||
total = int(processed_match.group(1))
|
||||
success = int(processed_match.group(2))
|
||||
|
||||
preview = tk.Toplevel()
|
||||
preview.title("OCR处理结果")
|
||||
preview.geometry("400x300")
|
||||
preview.resizable(False, False)
|
||||
center_window(preview)
|
||||
|
||||
tk.Label(preview, text="OCR处理完成", font=("Arial", 16, "bold")).pack(pady=10)
|
||||
|
||||
result_frame = tk.Frame(preview)
|
||||
result_frame.pack(pady=10, fill=tk.BOTH, expand=True)
|
||||
|
||||
tk.Label(result_frame, text=f"总共处理: {total} 个文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text=f"成功处理: {success} 个文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text=f"失败数量: {total - success} 个文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
|
||||
if success == total:
|
||||
result_text = "全部处理成功!"
|
||||
result_color = "#28a745"
|
||||
elif success > total * 0.8:
|
||||
result_text = "大部分处理成功。"
|
||||
result_color = "#ffc107"
|
||||
else:
|
||||
result_text = "处理失败较多,请检查日志。"
|
||||
result_color = "#dc3545"
|
||||
|
||||
tk.Label(result_frame, text=result_text, font=("Arial", 12, "bold"), fg=result_color).pack(pady=10)
|
||||
|
||||
button_frame = tk.Frame(preview)
|
||||
button_frame.pack(pady=10)
|
||||
|
||||
tk.Button(button_frame, text="查看输出文件", command=lambda: os.startfile(os.path.abspath("data/output"))).pack(side=tk.LEFT, padx=10)
|
||||
tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=10)
|
||||
else:
|
||||
messagebox.showinfo("OCR处理完成", "OCR处理已完成,请在data/output目录查看结果。")
|
||||
|
||||
|
||||
def show_excel_result_preview(output):
|
||||
"""显示Excel处理结果预览"""
|
||||
extract_match = re.search(r'提取到 (\d+) 个商品信息', output)
|
||||
file_match = re.search(r'采购单已保存到: (.+?)(?:\n|$)', output)
|
||||
|
||||
if extract_match and file_match:
|
||||
products_count = int(extract_match.group(1))
|
||||
output_file = file_match.group(1)
|
||||
|
||||
preview = tk.Toplevel()
|
||||
preview.title("Excel处理结果")
|
||||
preview.geometry("450x320")
|
||||
preview.resizable(False, False)
|
||||
center_window(preview)
|
||||
|
||||
tk.Label(preview, text="Excel处理完成", font=("Arial", 16, "bold")).pack(pady=10)
|
||||
|
||||
result_frame = tk.Frame(preview)
|
||||
result_frame.pack(pady=10, fill=tk.BOTH, expand=True)
|
||||
|
||||
tk.Label(result_frame, text=f"提取商品数量: {products_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text=f"输出文件: {os.path.basename(output_file)}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
|
||||
tk.Label(result_frame, text="采购单已成功生成!", font=("Arial", 12, "bold"), fg="#28a745").pack(pady=10)
|
||||
|
||||
file_frame = tk.Frame(result_frame, relief=tk.GROOVE, borderwidth=1)
|
||||
file_frame.pack(fill=tk.X, padx=15, pady=5)
|
||||
|
||||
tk.Label(file_frame, text="文件信息", font=("Arial", 10, "bold")).pack(anchor=tk.W, padx=10, pady=5)
|
||||
|
||||
try:
|
||||
file_size = os.path.getsize(output_file)
|
||||
file_time = datetime.datetime.fromtimestamp(os.path.getmtime(output_file))
|
||||
size_text = format_file_size(file_size)
|
||||
tk.Label(file_frame, text=f"文件大小: {size_text}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2)
|
||||
tk.Label(file_frame, text=f"创建时间: {file_time.strftime('%Y-%m-%d %H:%M:%S')}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2)
|
||||
except Exception:
|
||||
tk.Label(file_frame, text="无法获取文件信息", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2)
|
||||
|
||||
button_frame = tk.Frame(preview)
|
||||
button_frame.pack(pady=10)
|
||||
|
||||
tk.Button(button_frame, text="打开文件", command=lambda: os.startfile(output_file)).pack(side=tk.LEFT, padx=5)
|
||||
tk.Button(button_frame, text="打开所在文件夹", command=lambda: os.startfile(os.path.dirname(output_file))).pack(side=tk.LEFT, padx=5)
|
||||
tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=5)
|
||||
else:
|
||||
messagebox.showinfo("Excel处理完成", "Excel处理已完成,请在data/output目录查看结果。")
|
||||
|
||||
|
||||
def show_merge_result_preview(output):
|
||||
"""显示合并结果预览"""
|
||||
merged_match = re.search(r'合并了 (\d+) 个采购单', output)
|
||||
product_match = re.search(r'共处理 (\d+) 个商品', output)
|
||||
output_match = re.search(r'已保存到: (.+?)(?:\n|$)', output)
|
||||
|
||||
if merged_match and output_match:
|
||||
merged_count = int(merged_match.group(1))
|
||||
product_count = int(product_match.group(1)) if product_match else 0
|
||||
output_file = output_match.group(1)
|
||||
|
||||
preview = tk.Toplevel()
|
||||
preview.title("采购单合并结果")
|
||||
preview.geometry("450x300")
|
||||
preview.resizable(False, False)
|
||||
apply_theme(preview)
|
||||
|
||||
tk.Label(preview, text="采购单合并完成", font=("Arial", 16, "bold")).pack(pady=10)
|
||||
|
||||
result_frame = tk.Frame(preview)
|
||||
result_frame.pack(pady=10, fill=tk.BOTH, expand=True)
|
||||
|
||||
tk.Label(result_frame, text=f"合并采购单数量: {merged_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text=f"处理商品数量: {product_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text=f"输出文件: {os.path.basename(output_file)}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
|
||||
theme = THEMES[get_theme_mode()]
|
||||
tk.Label(result_frame, text="采购单已成功合并!", font=("Arial", 12, "bold"), fg=theme["success"]).pack(pady=10)
|
||||
|
||||
button_frame = tk.Frame(preview)
|
||||
button_frame.pack(pady=10)
|
||||
|
||||
tk.Button(button_frame, text="打开文件", command=lambda: os.startfile(output_file)).pack(side=tk.LEFT, padx=10)
|
||||
tk.Button(button_frame, text="打开所在文件夹", command=lambda: os.startfile(os.path.dirname(output_file))).pack(side=tk.LEFT, padx=10)
|
||||
tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=10)
|
||||
else:
|
||||
messagebox.showinfo("采购单合并完成", "采购单合并已完成,请在data/output目录查看结果。")
|
||||
|
||||
|
||||
def show_pipeline_result_preview(output):
|
||||
"""显示完整流程结果预览"""
|
||||
ocr_match = re.search(r'所有图片处理完成, 总计: (\d+), 成功: (\d+)', output)
|
||||
excel_match = re.search(r'提取到 (\d+) 个商品信息', output)
|
||||
output_file_match = re.search(r'采购单已保存到: (.+?)(?:\n|$)', output)
|
||||
|
||||
preview = tk.Toplevel()
|
||||
preview.title("完整流程处理结果")
|
||||
preview.geometry("500x400")
|
||||
preview.resizable(False, False)
|
||||
center_window(preview)
|
||||
|
||||
tk.Label(preview, text="完整处理流程已完成", font=("Arial", 16, "bold")).pack(pady=10)
|
||||
|
||||
no_files_match = re.search(r'未找到可合并的文件', output)
|
||||
if no_files_match:
|
||||
tk.Label(preview, text="未找到可合并的文件,但其他步骤已成功执行", font=("Arial", 12)).pack(pady=0)
|
||||
|
||||
result_frame = tk.Frame(preview)
|
||||
result_frame.pack(pady=10, fill=tk.BOTH, expand=True)
|
||||
|
||||
result_text = scrolledtext.ScrolledText(result_frame, wrap=tk.WORD, height=15, width=60)
|
||||
result_text.pack(fill=tk.BOTH, expand=True, padx=15, pady=5)
|
||||
result_text.configure(state=tk.NORMAL)
|
||||
|
||||
result_text.insert(tk.END, "===== 流程执行结果 =====\n\n", "title")
|
||||
|
||||
result_text.insert(tk.END, "步骤1: OCR识别\n", "step")
|
||||
if ocr_match:
|
||||
total = int(ocr_match.group(1))
|
||||
success = int(ocr_match.group(2))
|
||||
result_text.insert(tk.END, f" 处理图片: {total} 个\n", "info")
|
||||
result_text.insert(tk.END, f" 成功识别: {success} 个\n", "info")
|
||||
if success == total:
|
||||
result_text.insert(tk.END, " 结果: 全部识别成功\n", "success")
|
||||
else:
|
||||
result_text.insert(tk.END, f" 结果: 部分识别成功 ({success}/{total})\n", "warning")
|
||||
else:
|
||||
result_text.insert(tk.END, " 结果: 无OCR处理或处理信息不完整\n", "warning")
|
||||
|
||||
result_text.insert(tk.END, "\n步骤2: Excel处理\n", "step")
|
||||
if excel_match:
|
||||
products = int(excel_match.group(1))
|
||||
result_text.insert(tk.END, f" 提取商品: {products} 个\n", "info")
|
||||
result_text.insert(tk.END, " 结果: 成功生成采购单\n", "success")
|
||||
if output_file_match:
|
||||
output_file = output_file_match.group(1)
|
||||
result_text.insert(tk.END, f" 输出文件: {os.path.basename(output_file)}\n", "info")
|
||||
else:
|
||||
result_text.insert(tk.END, " 结果: 无Excel处理或处理信息不完整\n", "warning")
|
||||
|
||||
result_text.insert(tk.END, "\n===== 整体评估 =====\n", "title")
|
||||
|
||||
has_errors = "错误" in output or "失败" in output
|
||||
|
||||
no_files_match2 = re.search(r'未找到采购单文件', output)
|
||||
single_file_match = re.search(r'只有1个采购单文件', output)
|
||||
|
||||
if no_files_match2:
|
||||
result_text.insert(tk.END, "没有找到可合并的文件,但处理流程已成功完成。\n", "warning")
|
||||
result_text.insert(tk.END, "可以选择打开Excel文件或查看输出文件夹。\n", "info")
|
||||
elif single_file_match:
|
||||
result_text.insert(tk.END, "只有一个采购单文件,无需合并,处理流程已成功完成。\n", "warning")
|
||||
result_text.insert(tk.END, "可以选择打开生成的Excel文件。\n", "info")
|
||||
elif ocr_match and excel_match and not has_errors:
|
||||
result_text.insert(tk.END, "流程完整执行成功!\n", "success")
|
||||
elif ocr_match or excel_match:
|
||||
result_text.insert(tk.END, "流程部分执行成功,请检查日志获取详情。\n", "warning")
|
||||
else:
|
||||
result_text.insert(tk.END, "流程执行可能存在问题,请查看详细日志。\n", "error")
|
||||
|
||||
result_text.tag_configure("title", font=("Arial", 12, "bold"))
|
||||
result_text.tag_configure("step", font=("Arial", 11, "bold"))
|
||||
result_text.tag_configure("info", font=("Arial", 10))
|
||||
result_text.tag_configure("success", font=("Arial", 10, "bold"), foreground="#28a745")
|
||||
result_text.tag_configure("warning", font=("Arial", 10, "bold"), foreground="#ffc107")
|
||||
result_text.tag_configure("error", font=("Arial", 10, "bold"), foreground="#dc3545")
|
||||
|
||||
result_text.configure(state=tk.DISABLED)
|
||||
|
||||
button_frame = tk.Frame(preview)
|
||||
button_frame.pack(pady=10)
|
||||
|
||||
if output_file_match:
|
||||
output_file = output_file_match.group(1)
|
||||
tk.Button(button_frame, text="打开Excel文件", command=lambda: os.startfile(output_file)).pack(side=tk.LEFT, padx=10)
|
||||
else:
|
||||
if excel_match or no_files_match or single_file_match:
|
||||
output_dir = os.path.abspath("data/output")
|
||||
excel_files = [f for f in os.listdir(output_dir) if f.startswith('采购单_') and (f.endswith('.xls') or f.endswith('.xlsx'))]
|
||||
if excel_files:
|
||||
excel_files.sort(key=lambda x: os.path.getmtime(os.path.join(output_dir, x)), reverse=True)
|
||||
latest_file = os.path.join(output_dir, excel_files[0])
|
||||
tk.Button(button_frame, text="打开最新Excel文件",
|
||||
command=lambda: os.startfile(latest_file)).pack(side=tk.LEFT, padx=10)
|
||||
|
||||
tk.Button(button_frame, text="查看输出文件夹", command=lambda: os.startfile(os.path.abspath("data/output"))).pack(side=tk.LEFT, padx=10)
|
||||
tk.Button(button_frame, text="关闭", command=preview.destroy).pack(side=tk.LEFT, padx=10)
|
||||
|
||||
|
||||
def show_tobacco_result_preview(returncode, output):
|
||||
"""显示烟草订单处理结果预览"""
|
||||
global TOBACCO_PREVIEW_WINDOW
|
||||
if returncode != 0:
|
||||
return
|
||||
|
||||
try:
|
||||
try:
|
||||
if TOBACCO_PREVIEW_WINDOW and TOBACCO_PREVIEW_WINDOW.winfo_exists():
|
||||
TOBACCO_PREVIEW_WINDOW.lift()
|
||||
return
|
||||
except Exception:
|
||||
TOBACCO_PREVIEW_WINDOW = None
|
||||
|
||||
result_file = None
|
||||
order_time = "(未知)"
|
||||
total_amount = "(未知)"
|
||||
items_count = 0
|
||||
|
||||
abs_path_match = re.search(r'烟草订单处理完成,绝对路径: (.+)(?:\n|$)', output)
|
||||
if abs_path_match:
|
||||
result_file = abs_path_match.group(1).strip()
|
||||
|
||||
for line in output.split('\n'):
|
||||
if "烟草公司订单处理成功" in line and "订单时间" in line:
|
||||
time_match = re.search(r'订单时间: ([^,]+)', line)
|
||||
amount_match = re.search(r'总金额: ([^,]+)', line)
|
||||
items_match = re.search(r'处理条目: (\d+)', line)
|
||||
|
||||
if time_match:
|
||||
order_time = time_match.group(1).strip()
|
||||
if amount_match:
|
||||
total_amount = amount_match.group(1).strip()
|
||||
if items_match:
|
||||
items_count = int(items_match.group(1).strip())
|
||||
|
||||
if not result_file or not os.path.exists(result_file):
|
||||
default_path = os.path.abspath("data/output/银豹采购单_烟草公司.xls")
|
||||
if os.path.exists(default_path):
|
||||
result_file = default_path
|
||||
|
||||
preview = tk.Toplevel()
|
||||
preview.title("烟草订单处理结果")
|
||||
preview.geometry("450x320")
|
||||
preview.resizable(False, False)
|
||||
TOBACCO_PREVIEW_WINDOW = preview
|
||||
|
||||
def _close_preview():
|
||||
global TOBACCO_PREVIEW_WINDOW
|
||||
TOBACCO_PREVIEW_WINDOW = None
|
||||
try:
|
||||
preview.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
preview.protocol("WM_DELETE_WINDOW", _close_preview)
|
||||
center_window(preview)
|
||||
|
||||
tk.Label(preview, text="烟草订单处理完成", font=("Arial", 16, "bold")).pack(pady=10)
|
||||
|
||||
result_frame = tk.Frame(preview)
|
||||
result_frame.pack(pady=10, fill=tk.BOTH, expand=True)
|
||||
|
||||
tk.Label(result_frame, text=f"订单时间: {order_time}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text=f"订单总金额: {total_amount}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text=f"处理商品数量: {items_count} 个", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
|
||||
if result_file and os.path.exists(result_file):
|
||||
tk.Label(result_frame, text=f"输出文件: {os.path.basename(result_file)}", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text="银豹采购单已成功生成!", font=("Arial", 12, "bold"), fg="#28a745").pack(pady=10)
|
||||
|
||||
file_frame = tk.Frame(result_frame, relief=tk.GROOVE, borderwidth=1)
|
||||
file_frame.pack(fill=tk.X, padx=15, pady=5)
|
||||
tk.Label(file_frame, text="文件信息", font=("Arial", 10, "bold")).pack(anchor=tk.W, padx=10, pady=5)
|
||||
|
||||
try:
|
||||
file_size = os.path.getsize(result_file)
|
||||
file_time = datetime.datetime.fromtimestamp(os.path.getmtime(result_file))
|
||||
size_text = format_file_size(file_size)
|
||||
tk.Label(file_frame, text=f"文件大小: {size_text}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2)
|
||||
tk.Label(file_frame, text=f"创建时间: {file_time.strftime('%Y-%m-%d %H:%M:%S')}", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2)
|
||||
except Exception:
|
||||
tk.Label(file_frame, text="无法获取文件信息", font=("Arial", 10)).pack(anchor=tk.W, padx=10, pady=2)
|
||||
|
||||
button_frame = tk.Frame(preview)
|
||||
button_frame.pack(pady=10)
|
||||
tk.Button(button_frame, text="打开文件", command=lambda: os.startfile(result_file)).pack(side=tk.LEFT, padx=5)
|
||||
tk.Button(button_frame, text="打开所在文件夹", command=lambda: os.startfile(os.path.dirname(result_file))).pack(side=tk.LEFT, padx=5)
|
||||
tk.Button(button_frame, text="关闭", command=_close_preview).pack(side=tk.LEFT, padx=5)
|
||||
else:
|
||||
tk.Label(result_frame, text="未找到输出文件", font=("Arial", 12)).pack(anchor=tk.W, padx=20, pady=5)
|
||||
tk.Label(result_frame, text="请检查data/output目录", font=("Arial", 12, "bold"), fg="#dc3545").pack(pady=10)
|
||||
|
||||
button_frame = tk.Frame(preview)
|
||||
button_frame.pack(pady=10)
|
||||
tk.Button(button_frame, text="打开输出目录", command=lambda: os.startfile(os.path.abspath("data/output"))).pack(side=tk.LEFT, padx=5)
|
||||
tk.Button(button_frame, text="关闭", command=_close_preview).pack(side=tk.LEFT, padx=5)
|
||||
|
||||
preview.lift()
|
||||
preview.attributes('-topmost', True)
|
||||
preview.after_idle(lambda: preview.attributes('-topmost', False))
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror(
|
||||
"处理异常",
|
||||
f"显示预览时发生错误: {e}\n请检查日志了解详细信息。"
|
||||
)
|
||||
Reference in New Issue
Block a user