diff --git a/desktop/activation_dialog.py b/desktop/activation_dialog.py index 4a39f2a..f692e61 100644 --- a/desktop/activation_dialog.py +++ b/desktop/activation_dialog.py @@ -4,74 +4,113 @@ from __future__ import annotations import tkinter as tk from tkinter import messagebox, ttk +from typing import Optional import hub_client -from device_store import is_activated, load_device, machine_fingerprint, save_device +from device_store import load_device, machine_fingerprint -def ensure_activated(root: tk.Tk) -> bool: +def _bring_front(win: tk.Misc) -> None: + """确保对话框在 Windows 上可见(避免挂在 withdraw 根窗后不显示)。""" + try: + win.update_idletasks() + win.deiconify() + win.lift() + win.focus_force() + win.attributes("-topmost", True) + win.after(200, lambda: win.attributes("-topmost", False)) + except Exception: + pass + + +def ensure_activated(parent: Optional[tk.Misc] = None) -> bool: """已激活且能 ping 通则通过;否则弹出激活窗。返回是否可继续。""" device = load_device() - if device.get("token") and device.get("server"): - if hub_client.ping(): - return True - # token 失效时允许重新激活 - if not messagebox.askyesno( - "激活校验", - "无法连接中控或令牌失效,是否重新激活?\n选「否」将以离线模式继续(不上报复盘)。", - parent=root, - ): - return True + owns_root = False + root: tk.Misc + if parent is not None: + root = parent + else: + root = tk.Tk() + root.title("黄金市价辅助") + root.geometry("360x80") + ttk.Label(root, text="正在启动…").pack(expand=True, padx=16, pady=16) + root.update() + owns_root = True - win = tk.Toplevel(root) - win.title("激活黄金辅助") - win.geometry("460x280") - win.transient(root) - win.grab_set() - result = {"ok": False} + try: + if device.get("token") and device.get("server"): + if hub_client.ping(): + return True + _bring_front(root) + if not messagebox.askyesno( + "激活校验", + "无法连接中控或令牌失效,是否重新激活?\n选「否」将以离线模式继续(不上报复盘)。", + parent=root, + ): + return True - frm = ttk.Frame(win, padding=16) - frm.pack(fill=tk.BOTH, expand=True) + win = tk.Toplevel(root) + win.title("激活黄金辅助") + win.geometry("480x300") + win.resizable(False, False) + # 不要 transient 到已隐藏的父窗,否则 Windows 上常不显示 + result = {"ok": False} - ttk.Label(frm, text="首次使用请输入中控地址与激活码(网页下载中心生成)").pack(anchor="w") - ttk.Label(frm, text="服务器地址(例:http://192.168.1.10:5800)").pack(anchor="w", pady=(12, 4)) - var_server = tk.StringVar(value=device.get("server") or "http://127.0.0.1:5800") - ttk.Entry(frm, textvariable=var_server, width=48).pack(fill=tk.X) + frm = ttk.Frame(win, padding=16) + frm.pack(fill=tk.BOTH, expand=True) - ttk.Label(frm, text="激活码").pack(anchor="w", pady=(12, 4)) - var_code = tk.StringVar() - ttk.Entry(frm, textvariable=var_code, width=48).pack(fill=tk.X) + ttk.Label(frm, text="首次使用请输入中控地址与激活码(网页下载中心生成)").pack(anchor="w") + ttk.Label(frm, text="服务器地址(例:http://192.168.1.10:5800)").pack(anchor="w", pady=(12, 4)) + var_server = tk.StringVar(value=device.get("server") or "http://127.0.0.1:5800") + ttk.Entry(frm, textvariable=var_server, width=48).pack(fill=tk.X) - ttk.Label(frm, text="本机名称(可改)").pack(anchor="w", pady=(12, 4)) - var_name = tk.StringVar(value=device.get("machine_name") or "") - ttk.Entry(frm, textvariable=var_name, width=48).pack(fill=tk.X) + ttk.Label(frm, text="激活码").pack(anchor="w", pady=(12, 4)) + var_code = tk.StringVar() + ttk.Entry(frm, textvariable=var_code, width=48).pack(fill=tk.X) - status = ttk.Label(frm, text="", foreground="#888") - status.pack(anchor="w", pady=(10, 0)) + ttk.Label(frm, text="本机名称(可改)").pack(anchor="w", pady=(12, 4)) + var_name = tk.StringVar(value=device.get("machine_name") or "") + ttk.Entry(frm, textvariable=var_name, width=48).pack(fill=tk.X) - def do_skip(): - result["ok"] = True - win.destroy() + status = ttk.Label(frm, text="", foreground="#888") + status.pack(anchor="w", pady=(10, 0)) - def do_ok(): - server = var_server.get().strip() - code = var_code.get().strip() - if not server or not code: - status.configure(text="请填写服务器与激活码", foreground="#f6465d") - return - try: - hub_client.activate(server, code, machine_fingerprint(), var_name.get().strip() or "PC") + def do_skip(): result["ok"] = True - messagebox.showinfo("激活成功", "已绑定账户与机器,成交将上报复盘中心。", parent=win) win.destroy() - except hub_client.HubError as exc: - status.configure(text=str(exc), foreground="#f6465d") - btns = ttk.Frame(frm) - btns.pack(fill=tk.X, pady=(16, 0)) - ttk.Button(btns, text="离线使用", command=do_skip).pack(side=tk.LEFT) - ttk.Button(btns, text="激活", command=do_ok).pack(side=tk.RIGHT) + def do_ok(): + server = var_server.get().strip() + code = var_code.get().strip() + if not server or not code: + status.configure(text="请填写服务器与激活码", foreground="#f6465d") + return + try: + hub_client.activate( + server, code, machine_fingerprint(), var_name.get().strip() or "PC" + ) + result["ok"] = True + messagebox.showinfo( + "激活成功", "已绑定账户与机器,成交将上报复盘中心。", parent=win + ) + win.destroy() + except hub_client.HubError as exc: + status.configure(text=str(exc), foreground="#f6465d") - win.protocol("WM_DELETE_WINDOW", do_skip) - root.wait_window(win) - return result["ok"] + btns = ttk.Frame(frm) + btns.pack(fill=tk.X, pady=(16, 0)) + ttk.Button(btns, text="离线使用", command=do_skip).pack(side=tk.LEFT) + ttk.Button(btns, text="激活", command=do_ok).pack(side=tk.RIGHT) + + win.protocol("WM_DELETE_WINDOW", do_skip) + _bring_front(win) + win.grab_set() + root.wait_window(win) + return result["ok"] + finally: + if owns_root: + try: + root.destroy() + except Exception: + pass diff --git a/desktop/gold_order_app.py b/desktop/gold_order_app.py index 1cc0bff..2e9bce0 100644 --- a/desktop/gold_order_app.py +++ b/desktop/gold_order_app.py @@ -1472,14 +1472,10 @@ class OrderApp(tk.Tk): def main() -> None: enable_dpi_awareness() - # 先建隐藏根窗完成激活,再开主界面 - boot = tk.Tk() - boot.withdraw() + # 激活窗自管可见性(勿对隐藏根窗挂 Toplevel,Windows 上会双击无界面) if ensure_activated is not None: - if not ensure_activated(boot): - boot.destroy() + if not ensure_activated(): return - boot.destroy() app = OrderApp() if is_activated(): @@ -1495,4 +1491,23 @@ def main() -> None: if __name__ == "__main__": - main() + try: + main() + except Exception as exc: + try: + import traceback + from pathlib import Path + + log = Path.home() / ".gold_monitor" / "crash.log" + log.parent.mkdir(parents=True, exist_ok=True) + log.write_text(traceback.format_exc(), encoding="utf-8") + except Exception: + pass + try: + root = tk.Tk() + root.withdraw() + messagebox.showerror("黄金市价辅助", f"启动失败:{exc}\n详情见 %USERPROFILE%\\.gold_monitor\\crash.log") + root.destroy() + except Exception: + pass + raise diff --git a/releases/黄金市价辅助.exe b/releases/黄金市价辅助.exe index b0f7c81..df0aff9 100644 Binary files a/releases/黄金市价辅助.exe and b/releases/黄金市价辅助.exe differ