2026-03-06 15:27:09 +08:00
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
"""
|
|
|
|
|
|
管理员面板 - 管理异常工单
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
|
from tkinter import ttk, messagebox
|
|
|
|
|
|
import requests
|
|
|
|
|
|
import sys
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdminPanel:
|
|
|
|
|
|
"""管理员面板"""
|
|
|
|
|
|
|
2026-03-18 17:13:20 +08:00
|
|
|
|
@staticmethod
|
|
|
|
|
|
def translate_status(status):
|
|
|
|
|
|
"""将英文状态转换为中文"""
|
|
|
|
|
|
status_map = {
|
|
|
|
|
|
'pending': '待处理',
|
|
|
|
|
|
'claimed': '已认领',
|
|
|
|
|
|
'completed': '已完成'
|
|
|
|
|
|
}
|
|
|
|
|
|
return status_map.get(status, status)
|
|
|
|
|
|
|
2026-03-06 15:27:09 +08:00
|
|
|
|
def __init__(self, root, api_base_url):
|
|
|
|
|
|
self.root = root
|
|
|
|
|
|
self.root.title("管理员面板 - 工单管理")
|
|
|
|
|
|
self.root.geometry("900x600")
|
|
|
|
|
|
if isinstance(root, tk.Toplevel):
|
|
|
|
|
|
self.root.transient(root.master)
|
|
|
|
|
|
self.api_base_url = api_base_url
|
|
|
|
|
|
self.claimed_orders = []
|
|
|
|
|
|
|
|
|
|
|
|
self._create_widgets()
|
|
|
|
|
|
self.load_claimed_orders()
|
|
|
|
|
|
|
|
|
|
|
|
def _create_widgets(self):
|
|
|
|
|
|
"""创建界面"""
|
|
|
|
|
|
# 标题
|
|
|
|
|
|
title_frame = tk.Frame(self.root, bg="#2c3e50", height=60)
|
|
|
|
|
|
title_frame.pack(fill=tk.X)
|
|
|
|
|
|
title_frame.pack_propagate(False)
|
|
|
|
|
|
|
|
|
|
|
|
tk.Label(title_frame, text="管理员面板 - 已认领工单管理", font=("微软雅黑", 18, "bold"), fg="white", bg="#2c3e50").pack(pady=15)
|
|
|
|
|
|
|
|
|
|
|
|
# 工单列表
|
|
|
|
|
|
list_frame = tk.LabelFrame(self.root, text="已认领工单列表", font=("微软雅黑", 12), padx=10, pady=10)
|
|
|
|
|
|
list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
|
|
|
|
|
|
|
|
|
|
columns = ("追溯号", "工序号", "工序名称", "操作员", "认领时间", "状态")
|
|
|
|
|
|
self.tree = ttk.Treeview(list_frame, columns=columns, show="headings")
|
|
|
|
|
|
|
|
|
|
|
|
for col in columns:
|
|
|
|
|
|
self.tree.heading(col, text=col)
|
|
|
|
|
|
self.tree.column(col, width=150, anchor=tk.CENTER)
|
|
|
|
|
|
|
|
|
|
|
|
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview)
|
|
|
|
|
|
self.tree.configure(yscrollcommand=scrollbar.set)
|
|
|
|
|
|
self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
|
|
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
|
|
|
|
|
|
|
|
# 按钮
|
|
|
|
|
|
button_frame = tk.Frame(self.root, padx=10, pady=10)
|
|
|
|
|
|
button_frame.pack(fill=tk.X)
|
|
|
|
|
|
|
|
|
|
|
|
tk.Button(button_frame, text="刷新列表", font=("微软雅黑", 10), bg="#3498db", fg="white", width=12, command=self.load_claimed_orders).pack(side=tk.LEFT, padx=5)
|
|
|
|
|
|
tk.Button(button_frame, text="退领选中工单", font=("微软雅黑", 10), bg="#e67e22", fg="white", width=12, command=self.unclaim_selected).pack(side=tk.LEFT, padx=5)
|
|
|
|
|
|
tk.Button(button_frame, text="批量退领", font=("微软雅黑", 10), bg="#e74c3c", fg="white", width=12, command=self.unclaim_all).pack(side=tk.LEFT, padx=5)
|
|
|
|
|
|
|
|
|
|
|
|
def load_claimed_orders(self):
|
|
|
|
|
|
"""加载已认领工单"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
response = requests.get(f"{self.api_base_url}/work-orders/claimed", timeout=2)
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
|
|
|
data = response.json()
|
|
|
|
|
|
if data.get("success"):
|
|
|
|
|
|
self.claimed_orders = data.get("data", [])
|
|
|
|
|
|
self.update_list()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
messagebox.showerror("错误", f"加载失败: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
def update_list(self):
|
|
|
|
|
|
"""更新列表"""
|
|
|
|
|
|
self.tree.delete(*self.tree.get_children())
|
|
|
|
|
|
for order in self.claimed_orders:
|
2026-03-18 17:13:20 +08:00
|
|
|
|
status = order.get('status', 'claimed')
|
|
|
|
|
|
status_cn = self.translate_status(status)
|
2026-03-06 15:27:09 +08:00
|
|
|
|
self.tree.insert("", tk.END, values=(
|
|
|
|
|
|
order.get('trace_id'), order.get('process_id'), order.get('process_name', '--'),
|
2026-03-18 17:13:20 +08:00
|
|
|
|
order.get('operator', '--'), order.get('claimed_at', '--'), status_cn
|
2026-03-06 15:27:09 +08:00
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
|
def unclaim_selected(self):
|
|
|
|
|
|
"""退领选中工单"""
|
|
|
|
|
|
selected = self.tree.selection()
|
|
|
|
|
|
if not selected:
|
|
|
|
|
|
messagebox.showwarning("警告", "请选择要退领的工单")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
item = self.tree.item(selected[0])
|
|
|
|
|
|
values = item['values']
|
|
|
|
|
|
trace_id, process_id = values[0], values[1]
|
|
|
|
|
|
|
|
|
|
|
|
if not messagebox.askyesno("确认", f"确定退领工单 {trace_id} - {process_id}?"):
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
response = requests.post(f"{self.api_base_url}/work-orders/unclaim", json={"trace_id": trace_id, "process_id": process_id}, timeout=2)
|
|
|
|
|
|
if response.status_code == 200 and response.json().get("success"):
|
|
|
|
|
|
messagebox.showinfo("成功", "退领成功")
|
|
|
|
|
|
self.load_claimed_orders()
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
messagebox.showerror("错误", f"退领失败: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
def unclaim_all(self):
|
|
|
|
|
|
"""批量退领所有工单"""
|
|
|
|
|
|
if not self.claimed_orders:
|
|
|
|
|
|
messagebox.showinfo("提示", "没有需要退领的工单")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if not messagebox.askyesno("确认", f"确定退领所有 {len(self.claimed_orders)} 个工单?"):
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
success_count = 0
|
|
|
|
|
|
for order in self.claimed_orders:
|
|
|
|
|
|
try:
|
|
|
|
|
|
requests.post(f"{self.api_base_url}/work-orders/unclaim", json={"trace_id": order['trace_id'], "process_id": order['process_id']}, timeout=2)
|
|
|
|
|
|
success_count += 1
|
|
|
|
|
|
except:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
messagebox.showinfo("完成", f"成功退领 {success_count}/{len(self.claimed_orders)} 个工单")
|
|
|
|
|
|
self.load_claimed_orders()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
import json
|
|
|
|
|
|
api_url = "http://localhost:5000/api"
|
|
|
|
|
|
try:
|
|
|
|
|
|
config_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "config.json")
|
|
|
|
|
|
if os.path.exists(config_path):
|
|
|
|
|
|
with open(config_path, "r", encoding="utf-8") as f:
|
|
|
|
|
|
config = json.load(f)
|
|
|
|
|
|
api_url = config.get("api", {}).get("base_url", api_url)
|
|
|
|
|
|
if not api_url.endswith("/api"):
|
|
|
|
|
|
api_url = api_url.rstrip("/") + "/api"
|
|
|
|
|
|
except:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
root = tk.Tk()
|
|
|
|
|
|
AdminPanel(root, api_url)
|
|
|
|
|
|
root.mainloop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
main()
|