定制化需求更新
parent
daeef833f8
commit
6d45d12656
|
|
@ -1,3 +1,6 @@
|
|||
__pycache__/
|
||||
backend/build/
|
||||
backend/dist/
|
||||
venv/
|
||||
frontend/build/
|
||||
frontend/dist/
|
||||
|
|
|
|||
|
|
@ -113,6 +113,45 @@ def claim_work_order():
|
|||
}), 500
|
||||
|
||||
|
||||
@app.route('/api/work-orders/unclaim', methods=['POST'])
|
||||
def unclaim_work_order():
|
||||
"""退领工单"""
|
||||
data = request.get_json()
|
||||
trace_id = data.get('trace_id')
|
||||
process_id = data.get('process_id')
|
||||
|
||||
if not trace_id or not process_id:
|
||||
return jsonify({"success": False, "message": "追溯号和工序号不能为空"}), 400
|
||||
|
||||
if db.unclaim_work_order(trace_id, process_id):
|
||||
return jsonify({"success": True, "message": "退领成功"})
|
||||
else:
|
||||
return jsonify({"success": False, "message": "退领失败"}), 500
|
||||
|
||||
|
||||
@app.route('/api/work-orders/delete', methods=['POST'])
|
||||
def delete_work_order():
|
||||
"""删除工单"""
|
||||
data = request.get_json()
|
||||
trace_id = data.get('trace_id')
|
||||
process_id = data.get('process_id')
|
||||
|
||||
if not trace_id or not process_id:
|
||||
return jsonify({"success": False, "message": "追溯号和工序号不能为空"}), 400
|
||||
|
||||
if db.delete_work_order(trace_id, process_id):
|
||||
return jsonify({"success": True, "message": "删除成功"})
|
||||
else:
|
||||
return jsonify({"success": False, "message": "删除失败"}), 500
|
||||
|
||||
|
||||
@app.route('/api/work-orders/claimed', methods=['GET'])
|
||||
def get_claimed_orders():
|
||||
"""获取所有已认领的工单"""
|
||||
orders = db.get_all_claimed_orders()
|
||||
return jsonify({"success": True, "data": orders})
|
||||
|
||||
|
||||
@app.route('/api/work-orders/submit', methods=['POST'])
|
||||
def submit_work_order():
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ class Database:
|
|||
|
||||
def get_connection(self):
|
||||
"""获取数据库连接"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
conn.row_factory = sqlite3.Row # 使查询结果可以按列名访问
|
||||
conn = sqlite3.connect(self.db_path, timeout=1.0, check_same_thread=False)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute('PRAGMA journal_mode=WAL')
|
||||
return conn
|
||||
|
||||
def init_database(self):
|
||||
|
|
@ -352,6 +353,19 @@ class Database:
|
|||
print(f"查询认领工单失败: {e}")
|
||||
return None
|
||||
|
||||
def get_all_claimed_orders(self) -> List[Dict]:
|
||||
"""获取所有已认领的工单"""
|
||||
try:
|
||||
conn = self.get_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT * FROM claimed_orders WHERE status = "claimed" ORDER BY claimed_at DESC')
|
||||
rows = cursor.fetchall()
|
||||
conn.close()
|
||||
return [dict(row) for row in rows]
|
||||
except Exception as e:
|
||||
print(f"获取已认领工单失败: {e}")
|
||||
return []
|
||||
|
||||
def claim_work_order(self, trace_id: str, process_id: str, operator: str) -> bool:
|
||||
"""
|
||||
认领工单
|
||||
|
|
@ -411,7 +425,25 @@ class Database:
|
|||
print(f"释放工单失败: {e}")
|
||||
return False
|
||||
|
||||
def submit_work_order(self, trace_id: str, process_id: str, bolts: List[Dict],
|
||||
def unclaim_work_order(self, trace_id: str, process_id: str) -> bool:
|
||||
"""退领工单"""
|
||||
return self.release_work_order(trace_id, process_id)
|
||||
|
||||
def delete_work_order(self, trace_id: str, process_id: str) -> bool:
|
||||
"""删除工单"""
|
||||
try:
|
||||
conn = self.get_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('DELETE FROM work_orders WHERE trace_id = ? AND process_id = ?', (trace_id, process_id))
|
||||
cursor.execute('DELETE FROM claimed_orders WHERE trace_id = ? AND process_id = ?', (trace_id, process_id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"删除工单失败: {e}")
|
||||
return False
|
||||
|
||||
def submit_work_order(self, trace_id: str, process_id: str, bolts: List[Dict],
|
||||
device_sn: str = None, device_name: str = None) -> bool:
|
||||
"""
|
||||
提交工单结果
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -4,7 +4,7 @@
|
|||
"description": "后端API服务地址,例如:http://localhost:5000 或 http://192.168.1.100:5000"
|
||||
},
|
||||
"wrench": {
|
||||
"host": "127.0.0.1",
|
||||
"host": "192.168.110.122",
|
||||
"port": 7888,
|
||||
"timeout": 30,
|
||||
"address": 1,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,148 @@
|
|||
#!/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:
|
||||
"""管理员面板"""
|
||||
|
||||
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:
|
||||
self.tree.insert("", tk.END, values=(
|
||||
order.get('trace_id'), order.get('process_id'), order.get('process_name', '--'),
|
||||
order.get('operator', '--'), order.get('claimed_at', '--'), order.get('status', '--')
|
||||
))
|
||||
|
||||
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()
|
||||
|
|
@ -195,7 +195,7 @@ class DeviceManagerWindow:
|
|||
|
||||
def add_device(self):
|
||||
"""添加设备"""
|
||||
DeviceEditDialog(self.window, self.api_base_url, None, self.load_devices)
|
||||
DeviceEditDialog(self.window, self.api_base_url, None, self.load_devices, self.refresh_callback)
|
||||
|
||||
def edit_device(self):
|
||||
"""编辑设备"""
|
||||
|
|
@ -209,7 +209,7 @@ class DeviceManagerWindow:
|
|||
break
|
||||
|
||||
if device:
|
||||
DeviceEditDialog(self.window, self.api_base_url, device, self.load_devices)
|
||||
DeviceEditDialog(self.window, self.api_base_url, device, self.load_devices, self.refresh_callback)
|
||||
|
||||
def delete_device(self):
|
||||
"""删除设备"""
|
||||
|
|
@ -299,11 +299,12 @@ class DeviceManagerWindow:
|
|||
class DeviceEditDialog:
|
||||
"""设备编辑对话框"""
|
||||
|
||||
def __init__(self, parent, api_base_url, device=None, callback=None):
|
||||
def __init__(self, parent, api_base_url, device=None, callback=None, parent_refresh_callback=None):
|
||||
self.parent = parent
|
||||
self.api_base_url = api_base_url
|
||||
self.device = device
|
||||
self.callback = callback
|
||||
self.parent_refresh_callback = parent_refresh_callback
|
||||
|
||||
self.dialog = tk.Toplevel(parent)
|
||||
self.dialog.title("添加设备" if not device else "编辑设备")
|
||||
|
|
@ -410,6 +411,8 @@ class DeviceEditDialog:
|
|||
self.dialog.destroy()
|
||||
if self.callback:
|
||||
self.callback()
|
||||
if self.parent_refresh_callback:
|
||||
self.parent_refresh_callback()
|
||||
else:
|
||||
messagebox.showerror("错误", data.get('message', '保存失败'))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
echo "========================================"
|
||||
echo "启动管理员面板"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
cd "$(dirname "$0")"
|
||||
python3 admin_panel.py
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo ========================================
|
||||
echo 启动管理员面板
|
||||
echo ========================================
|
||||
echo.
|
||||
cd /d %~dp0
|
||||
python admin_panel.py
|
||||
pause
|
||||
|
|
@ -199,9 +199,13 @@ class WrenchGUI:
|
|||
col1_frame.grid(row=0, column=0, padx=(0, 20), sticky=tk.W)
|
||||
|
||||
tk.Label(col1_frame, text="工单操作", font=("微软雅黑", 9, "bold"), fg="#2c3e50").pack(anchor=tk.W, pady=(0, 3))
|
||||
|
||||
order_buttons_frame = tk.Frame(col1_frame)
|
||||
order_buttons_frame.pack()
|
||||
|
||||
self.claim_button = tk.Button(
|
||||
col1_frame,
|
||||
text="认领工单",
|
||||
order_buttons_frame,
|
||||
text="认领工单",
|
||||
font=("微软雅黑", 10),
|
||||
bg="#f39c12",
|
||||
fg="white",
|
||||
|
|
@ -210,7 +214,47 @@ class WrenchGUI:
|
|||
cursor="hand2",
|
||||
command=self.claim_work_order
|
||||
)
|
||||
self.claim_button.pack()
|
||||
self.claim_button.pack(side=tk.LEFT, padx=(0, 5))
|
||||
|
||||
self.unclaim_button = tk.Button(
|
||||
order_buttons_frame,
|
||||
text="退领工单",
|
||||
font=("微软雅黑", 10),
|
||||
bg="#e67e22",
|
||||
fg="white",
|
||||
width=10,
|
||||
height=1,
|
||||
cursor="hand2",
|
||||
state=tk.DISABLED,
|
||||
command=self.unclaim_work_order
|
||||
)
|
||||
self.unclaim_button.pack(side=tk.LEFT, padx=(0, 5))
|
||||
|
||||
self.delete_button = tk.Button(
|
||||
order_buttons_frame,
|
||||
text="删除工单",
|
||||
font=("微软雅黑", 10),
|
||||
bg="#e74c3c",
|
||||
fg="white",
|
||||
width=10,
|
||||
height=1,
|
||||
cursor="hand2",
|
||||
command=self.delete_work_order
|
||||
)
|
||||
self.delete_button.pack(side=tk.LEFT, padx=(0, 5))
|
||||
|
||||
self.admin_button = tk.Button(
|
||||
order_buttons_frame,
|
||||
text="管理工单",
|
||||
font=("微软雅黑", 10),
|
||||
bg="#9b59b6",
|
||||
fg="white",
|
||||
width=10,
|
||||
height=1,
|
||||
cursor="hand2",
|
||||
command=self.open_admin_panel
|
||||
)
|
||||
self.admin_button.pack(side=tk.LEFT)
|
||||
|
||||
# 第二列:设备选择
|
||||
col2_frame = tk.Frame(button_frame)
|
||||
|
|
@ -478,7 +522,7 @@ class WrenchGUI:
|
|||
try:
|
||||
url = f"{self.api_base_url}/work-orders"
|
||||
# 不传参数,获取所有可用工单
|
||||
response = requests.get(url, timeout=5)
|
||||
response = requests.get(url, timeout=2)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
|
|
@ -584,16 +628,22 @@ class WrenchGUI:
|
|||
while self.is_polling:
|
||||
try:
|
||||
url = f"{self.api_base_url}/work-orders"
|
||||
# 不传参数,获取所有可用工单
|
||||
response = requests.get(url, timeout=5)
|
||||
response = requests.get(url, timeout=2)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get("success"):
|
||||
orders = data.get("data", [])
|
||||
# 只在数据变化时更新
|
||||
self.root.after(0, lambda o=orders: self.update_order_list(o))
|
||||
# 更新状态标签
|
||||
|
||||
# 检查当前认领的工单是否被退领
|
||||
if self.work_order:
|
||||
trace_id = self.work_order.get('trace_id')
|
||||
process_id = self.work_order.get('process_id')
|
||||
# 如果当前工单出现在可用列表中,说明被退领了
|
||||
if any(o.get('trace_id') == trace_id and o.get('process_id') == process_id for o in orders):
|
||||
self.root.after(0, self.clear_claimed_order)
|
||||
|
||||
if len(orders) > 0:
|
||||
self.root.after(0, lambda: self.poll_status_label.config(
|
||||
text=f"🔄 已找到 {len(orders)} 个可用工单", fg="#27ae60"
|
||||
|
|
@ -627,7 +677,7 @@ class WrenchGUI:
|
|||
"process_id": process_id,
|
||||
"operator": "操作员" # 可以从配置或输入获取
|
||||
}
|
||||
response = requests.post(url, json=data, timeout=5)
|
||||
response = requests.post(url, json=data, timeout=2)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
|
|
@ -636,7 +686,14 @@ class WrenchGUI:
|
|||
self.update_work_order_info()
|
||||
self.update_bolt_list()
|
||||
self.claim_button.config(state=tk.DISABLED)
|
||||
self.unclaim_button.config(state=tk.NORMAL)
|
||||
self.start_button.config(state=tk.NORMAL)
|
||||
# 从列表中移除已认领的工单
|
||||
for item in self.order_tree.get_children():
|
||||
values = self.order_tree.item(item)['values']
|
||||
if values[0] == trace_id and values[1] == process_id:
|
||||
self.order_tree.delete(item)
|
||||
break
|
||||
self.log(f"✅ 成功认领工单: {trace_id} - {process_id}", "SUCCESS")
|
||||
else:
|
||||
messagebox.showerror("错误", result.get("message", "认领失败"))
|
||||
|
|
@ -648,6 +705,89 @@ class WrenchGUI:
|
|||
messagebox.showerror("错误", f"无法连接到后端服务器\n\n错误: {e}")
|
||||
self.log(f"认领失败: {e}", "ERROR")
|
||||
|
||||
def unclaim_work_order(self):
|
||||
"""退领工单"""
|
||||
if not self.work_order:
|
||||
messagebox.showwarning("警告", "当前没有已认领的工单")
|
||||
return
|
||||
|
||||
if self.is_running:
|
||||
messagebox.showwarning("警告", "工单正在执行中,无法退领")
|
||||
return
|
||||
|
||||
trace_id = self.work_order.get('trace_id')
|
||||
process_id = self.work_order.get('process_id')
|
||||
|
||||
result = messagebox.askyesno("确认退领", f"确定要退领工单 {trace_id} - {process_id} 吗?")
|
||||
if not result:
|
||||
return
|
||||
|
||||
try:
|
||||
url = f"{self.api_base_url}/work-orders/unclaim"
|
||||
data = {"trace_id": trace_id, "process_id": process_id}
|
||||
response = requests.post(url, json=data, timeout=2)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("success"):
|
||||
self.work_order = None
|
||||
self.update_work_order_info()
|
||||
self.update_bolt_list()
|
||||
self.claim_button.config(state=tk.NORMAL)
|
||||
self.unclaim_button.config(state=tk.DISABLED)
|
||||
self.start_button.config(state=tk.DISABLED)
|
||||
self.log(f"✅ 成功退领工单: {trace_id} - {process_id}", "SUCCESS")
|
||||
self.query_work_orders()
|
||||
else:
|
||||
messagebox.showerror("错误", result.get("message", "退领失败"))
|
||||
else:
|
||||
messagebox.showerror("错误", f"退领失败: HTTP {response.status_code}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
messagebox.showerror("错误", f"无法连接到后端服务器\n\n错误: {e}")
|
||||
|
||||
def delete_work_order(self):
|
||||
"""删除工单"""
|
||||
selected = self.order_tree.selection()
|
||||
if not selected:
|
||||
messagebox.showwarning("警告", "请先选择要删除的工单")
|
||||
return
|
||||
|
||||
item = self.order_tree.item(selected[0])
|
||||
values = item['values']
|
||||
trace_id = values[0]
|
||||
process_id = values[1]
|
||||
|
||||
result = messagebox.askyesno("确认删除", f"确定要删除工单 {trace_id} - {process_id} 吗?\n此操作不可恢复!")
|
||||
if not result:
|
||||
return
|
||||
|
||||
try:
|
||||
url = f"{self.api_base_url}/work-orders/delete"
|
||||
data = {"trace_id": trace_id, "process_id": process_id}
|
||||
response = requests.post(url, json=data, timeout=2)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("success"):
|
||||
self.log(f"✅ 成功删除工单: {trace_id} - {process_id}", "SUCCESS")
|
||||
self.query_work_orders()
|
||||
else:
|
||||
messagebox.showerror("错误", result.get("message", "删除失败"))
|
||||
else:
|
||||
messagebox.showerror("错误", f"删除失败: HTTP {response.status_code}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
messagebox.showerror("错误", f"无法连接到后端服务器\n\n错误: {e}")
|
||||
|
||||
def clear_claimed_order(self):
|
||||
"""清空当前认领的工单"""
|
||||
self.work_order = None
|
||||
self.update_work_order_info()
|
||||
self.update_bolt_list()
|
||||
self.claim_button.config(state=tk.NORMAL)
|
||||
self.unclaim_button.config(state=tk.DISABLED)
|
||||
self.start_button.config(state=tk.DISABLED)
|
||||
self.log("⚠️ 当前工单已被管理员退领", "WARN")
|
||||
|
||||
def update_work_order_info(self):
|
||||
"""更新工单信息显示"""
|
||||
if self.work_order:
|
||||
|
|
@ -796,6 +936,10 @@ class WrenchGUI:
|
|||
|
||||
self.log("✅ 已启用远程控制", "SUCCESS")
|
||||
|
||||
# 等待扳手初始化完成
|
||||
time.sleep(0.5)
|
||||
self.log("扳手初始化完成,准备开始拧紧")
|
||||
|
||||
# 遍历所有螺栓
|
||||
bolts = self.work_order.get('bolts', [])
|
||||
bolt_results = []
|
||||
|
|
@ -1119,6 +1263,17 @@ class WrenchGUI:
|
|||
def open_device_manager(self):
|
||||
"""打开设备管理窗口"""
|
||||
DeviceManagerWindow(self.root, self.api_base_url, self.load_wrench_devices)
|
||||
|
||||
def open_admin_panel(self):
|
||||
"""打开管理员面板(需要密码)"""
|
||||
from tkinter import simpledialog
|
||||
password = simpledialog.askstring("管理员验证", "请输入管理员密码:", show='*')
|
||||
if password == "123":
|
||||
from admin_panel import AdminPanel
|
||||
admin_window = tk.Toplevel(self.root)
|
||||
AdminPanel(admin_window, self.api_base_url)
|
||||
elif password is not None:
|
||||
messagebox.showerror("错误", "密码错误")
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -1126,6 +1281,21 @@ def main():
|
|||
app = WrenchGUI(root)
|
||||
|
||||
def on_closing():
|
||||
# 如果有未完成的工单,提示用户
|
||||
if app.work_order:
|
||||
trace_id = app.work_order.get('trace_id')
|
||||
process_id = app.work_order.get('process_id')
|
||||
result = messagebox.askokcancel(
|
||||
"确认关闭",
|
||||
f"当前有工单 {trace_id} - {process_id} 未完成\n\n关闭程序将自动退领该工单"
|
||||
)
|
||||
if not result:
|
||||
return
|
||||
try:
|
||||
url = f"{app.api_base_url}/work-orders/unclaim"
|
||||
requests.post(url, json={"trace_id": trace_id, "process_id": process_id}, timeout=1)
|
||||
except:
|
||||
pass
|
||||
app.stop_polling()
|
||||
root.destroy()
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import socket
|
||||
import struct
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Tuple, Optional
|
||||
from pathlib import Path
|
||||
|
|
@ -439,7 +440,13 @@ class WrenchController:
|
|||
print(f" 报文: {data.hex(' ').upper()}")
|
||||
|
||||
# 发送命令
|
||||
self._send_command(bytes(data))
|
||||
if not self._send_command(bytes(data)):
|
||||
print("❌ 发送设定参数命令失败")
|
||||
return bytes(data)
|
||||
|
||||
# 等待扳手处理参数(0x10命令无响应,需要短暂延迟)
|
||||
time.sleep(1)
|
||||
print("✅ 参数设定命令已发送,等待扳手处理完成")
|
||||
|
||||
return bytes(data)
|
||||
|
||||
|
|
|
|||
|
|
@ -325,6 +325,10 @@ class WrenchGUI:
|
|||
|
||||
self.log("✅ 已启用远程控制", "SUCCESS")
|
||||
|
||||
# 等待扳手初始化完成
|
||||
time.sleep(0.5)
|
||||
self.log("扳手初始化完成,准备开始拧紧")
|
||||
|
||||
# 遍历所有螺栓
|
||||
bolts = self.work_order['bolts']
|
||||
for index, bolt in enumerate(bolts):
|
||||
|
|
|
|||
Loading…
Reference in New Issue