jb/script_manager.py
2025-06-05 17:08:26 +08:00

657 lines
28 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import sqlite3
import os
import datetime
import json
import importlib.util
from typing import List, Dict
import pyperclip
class ScriptManager:
def __init__(self, db_path="scripts.db", scripts_dir="scripts"):
self.db_path = db_path
self.scripts_dir = scripts_dir
self._init_db()
self._init_scripts_dir()
self.tag_library = {
"文本": ["string", "text", "format", "generate"],
"转换": ["convert", "transform", "format"],
"处理": ["process", "handle", "manipulate"],
"生成": ["create", "generate", "make"],
"解析": ["parse", "extract", "analyze"]
}
def _init_db(self):
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
# 修改 scripts 表,添加 status 和 type 字段,移除 abbreviation
cursor.execute("""
CREATE TABLE IF NOT EXISTS scripts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
path TEXT NOT NULL,
ui_path TEXT NOT NULL,
created_at TEXT NOT NULL,
tags TEXT,
usage_count INTEGER DEFAULT 0,
status INTEGER DEFAULT 1,
type TEXT DEFAULT 'complex'
)
""")
# 创建 tags 表
cursor.execute("""
CREATE TABLE IF NOT EXISTS tags (
script_id INTEGER,
tag TEXT,
PRIMARY KEY (script_id, tag),
FOREIGN KEY (script_id) REFERENCES scripts(id)
)
""")
# 为 tags 字段创建索引
cursor.execute("CREATE INDEX IF NOT EXISTS idx_scripts_tags ON scripts(tags)")
cursor.execute("CREATE INDEX IF NOT EXISTS idx_tags_tag ON tags(tag)")
conn.commit()
def _init_scripts_dir(self):
os.makedirs(self.scripts_dir, exist_ok=True)
def _suggest_tags(self, script_name: str) -> List[str]:
name = script_name.lower()
suggested_tags = []
for category, keywords in self.tag_library.items():
if any(keyword in name for keyword in keywords):
suggested_tags.append(category)
return suggested_tags
def add_script(self, script_name: str, script_content: str = None, script_path: str = None,
ui_content: str = None, script_type: str = "complex") -> Dict:
script_name_clean = script_name.replace(" ", "_").replace("/", "_").replace("\\", "_")
script_path = os.path.join(self.scripts_dir, f"{script_name_clean}.py")
ui_path = os.path.join(self.scripts_dir, f"{script_name_clean}.ui.py")
if not script_content:
script_content = '''def process(input_strings: list) -> list:
"""处理输入字符串并返回结果"""
return [s.upper() for s in input_strings]
'''
if not ui_content and script_type == "simple":
ui_content = '''import tkinter as tk
from tkinter import ttk
import pyperclip
def create_ui(parent, run_callback):
"""创建简单脚本前端界面:单一输入输出"""
frame = ttk.Frame(parent)
frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
frame.columnconfigure(1, weight=1)
ttk.Label(frame, text="输入字符串:").grid(row=0, column=0, sticky=tk.W, pady=2)
input_entry = ttk.Entry(frame)
input_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2)
ttk.Label(frame, text="输出结果:").grid(row=1, column=0, sticky=tk.W, pady=2)
output_entry = ttk.Entry(frame, state="readonly")
output_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=2)
def copy_output(event):
output = output_entry.get()
if output:
pyperclip.copy(output)
tk.messagebox.showinfo("提示", "输出已复制到剪贴板")
output_entry.bind("<Button-1>", copy_output)
def run():
input_text = input_entry.get().strip()
if not input_text:
tk.messagebox.showerror("错误", "请输入字符串")
return
result = run_callback([input_text])
output_entry.configure(state="normal")
output_entry.delete(0, tk.END)
output_entry.insert(0, result[0] if result else "")
output_entry.configure(state="readonly")
ttk.Button(frame, text="运行脚本", command=run).grid(row=2, column=0, columnspan=2, pady=5)
return frame
'''
elif not ui_content:
ui_content = '''import tkinter as tk
from tkinter import ttk
import pyperclip
def create_ui(parent, run_callback):
"""创建前端界面"""
frame = ttk.Frame(parent)
frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
frame.columnconfigure(1, weight=1)
ttk.Label(frame, text="输入字符串 1").grid(row=0, column=0, sticky=tk.W, pady=2)
input_entry = ttk.Entry(frame)
input_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2)
ttk.Label(frame, text="输出结果 1").grid(row=1, column=0, sticky=tk.W, pady=2)
output_entry = ttk.Entry(frame, state="readonly")
output_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=2)
def copy_output(event):
output = output_entry.get()
if output:
pyperclip.copy(output)
tk.messagebox.showinfo("提示", "输出已复制到剪贴板")
output_entry.bind("<Button-1>", copy_output)
def run():
input_text = input_entry.get().strip()
if not input_text:
tk.messagebox.showerror("错误", "请输入字符串")
return
result = run_callback([input_text])
output_entry.configure(state="normal")
output_entry.delete(0, tk.END)
output_entry.insert(0, result[0] if result else "")
output_entry.configure(state="readonly")
ttk.Button(frame, text="运行脚本", command=run).grid(row=2, column=0, columnspan=2, pady=5)
return frame
'''
with open(script_path, 'w', encoding='utf-8') as f:
f.write(script_content)
with open(ui_path, 'w', encoding='utf-8') as f:
f.write(ui_content)
suggested_tags = self._suggest_tags(script_name)
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute("""
INSERT INTO scripts (name, path, ui_path, created_at, tags, usage_count, status, type)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (
script_name,
script_path,
ui_path,
datetime.datetime.now().strftime("%Y年%m月%d%H:%M:%S"),
json.dumps(suggested_tags),
0,
1,
script_type
))
script_id = cursor.lastrowid
for tag in suggested_tags:
cursor.execute("INSERT OR IGNORE INTO tags (script_id, tag) VALUES (?, ?)", (script_id, tag))
conn.commit()
return {
"id": script_id,
"name": script_name,
"path": script_path,
"ui_path": ui_path,
"suggested_tags": suggested_tags,
"type": script_type
}
def update_script(self, script_id: int, new_name: str, new_tags: List[str]) -> None:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute("SELECT name, path, ui_path FROM scripts WHERE id = ? AND status = 1", (script_id,))
result = cursor.fetchone()
if not result:
raise ValueError("脚本未找到或已删除")
old_name, old_path, old_ui_path = result
new_name_clean = new_name.replace(" ", "_").replace("/", "_").replace("\\", "_")
new_path = os.path.join(self.scripts_dir, f"{new_name_clean}.py")
new_ui_path = os.path.join(self.scripts_dir, f"{new_name_clean}.ui.py")
# 重命名文件
if old_name != new_name:
os.rename(old_path, new_path)
os.rename(old_ui_path, new_ui_path)
# 更新 scripts 表
cursor.execute("""
UPDATE scripts SET name = ?, path = ?, ui_path = ?, tags = ?
WHERE id = ? AND status = 1
""", (new_name, new_path, new_ui_path, json.dumps(new_tags), script_id))
# 更新 tags 表
cursor.execute("DELETE FROM tags WHERE script_id = ?", (script_id,))
for tag in new_tags:
cursor.execute("INSERT OR IGNORE INTO tags (script_id, tag) VALUES (?, ?)", (script_id, tag))
conn.commit()
def delete_script(self, script_id: int) -> None:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute("UPDATE scripts SET status = 0 WHERE id = ? AND status = 1", (script_id,))
if cursor.rowcount == 0:
raise ValueError("脚本未找到或已删除")
conn.commit()
def list_scripts(self, tag: str = None, name: str = None) -> List[Dict]:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
query = "SELECT s.id, s.name, s.path, s.created_at, s.tags, s.usage_count, s.ui_path, s.type " \
"FROM scripts s WHERE s.status = 1"
params = []
conditions = []
if tag:
query += " AND EXISTS (SELECT 1 FROM tags t WHERE t.script_id = s.id AND t.tag LIKE ?)"
params.append(f'%{tag}%')
if name:
conditions.append("s.name LIKE ?")
params.append(f'%{name}%')
if conditions:
query += " AND " + " AND ".join(conditions)
cursor.execute(query, params)
scripts = []
for row in cursor.fetchall():
try:
tags = json.loads(row[4]) if row[4] and row[4].strip() else []
except json.JSONDecodeError:
tags = []
scripts.append({
"id": row[0],
"name": row[1],
"path": row[2],
"created_at": row[3],
"tags": tags,
"usage_count": row[5],
"ui_path": row[6],
"type": row[7]
})
return scripts
def run_script(self, script_id: int, input_strings: List[str]) -> List[str]:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute("SELECT path FROM scripts WHERE id = ? AND status = 1", (script_id,))
result = cursor.fetchone()
if not result:
raise ValueError("脚本未找到或已删除")
script_path = result[0]
cursor.execute("UPDATE scripts SET usage_count = usage_count + 1 WHERE id = ?", (script_id,))
conn.commit()
spec = importlib.util.spec_from_file_location("script_module", script_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module.process(input_strings)
def load_ui_module(self, ui_path: str):
if not ui_path or not os.path.isfile(ui_path):
raise ValueError(f"前端界面文件不存在或路径无效:{ui_path}")
try:
spec = importlib.util.spec_from_file_location("ui_module", ui_path)
if spec is None:
raise ValueError(f"无法加载前端界面模块:{ui_path} (模块规格无效)")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
except Exception as e:
raise ValueError(f"加载前端界面失败:{str(e)}")
class ScriptManagerGUI:
def __init__(self, root):
self.root = root
self.root.title("脚本管理器")
self.manager = ScriptManager()
self.selected_script_id = None
self.current_ui_frame = None
self.text_editor_content = ""
self.create_widgets()
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
def create_widgets(self):
self.notebook = ttk.Notebook(self.root)
self.notebook.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=10, pady=5)
self.notebook.columnconfigure(0, weight=1)
self.notebook.rowconfigure(0, weight=1)
# 添加脚本选项卡
self.create_add_tab()
# 修改脚本选项卡
self.create_edit_tab()
# 索引运行脚本选项卡
self.create_run_tab()
# 文本编辑选项卡
self.create_text_editor_tab()
# 绑定选项卡切换事件
self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_changed)
def create_text_editor_tab(self):
"""创建文本编辑选项卡"""
text_editor_frame = ttk.Frame(self.notebook, padding="10")
self.notebook.add(text_editor_frame, text="文本【text】")
text_editor_frame.columnconfigure(0, weight=1)
text_editor_frame.rowconfigure(0, weight=1)
self.text_editor = tk.Text(text_editor_frame, height=20, width=50)
self.text_editor.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
text_scroll = ttk.Scrollbar(text_editor_frame, orient=tk.VERTICAL, command=self.text_editor.yview)
text_scroll.grid(row=0, column=1, sticky=(tk.N, tk.S))
self.text_editor["yscrollcommand"] = text_scroll.set
# 恢复之前的内容(如果有)
self.text_editor.insert("1.0", self.text_editor_content)
def on_tab_changed(self, event):
"""选项卡切换时保存文本编辑内容"""
selected_tab = self.notebook.select()
tab_name = self.notebook.tab(selected_tab, "text")
# 如果离开文本编辑选项卡,保存内容
if hasattr(self, "text_editor") and tab_name != "文本编辑":
self.text_editor_content = self.text_editor.get("1.0", tk.END).strip()
# 如果切换到文本编辑选项卡,恢复内容
if tab_name == "文本编辑" and hasattr(self, "text_editor"):
self.text_editor.delete("1.0", tk.END)
self.text_editor.insert("1.0", self.text_editor_content)
def create_add_tab(self):
add_frame = ttk.Frame(self.notebook, padding="10")
self.notebook.add(add_frame, text="添加【Add】")
add_frame.columnconfigure(1, weight=1)
add_frame.rowconfigure(3, weight=1)
ttk.Label(add_frame, text="脚本名称:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.script_name_var = tk.StringVar()
ttk.Entry(add_frame, textvariable=self.script_name_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5)
ttk.Label(add_frame, text="脚本类型:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.script_type_var = tk.StringVar(value="simple")
ttk.OptionMenu(add_frame, self.script_type_var, "simple", "simple", "complex").grid(row=1, column=1, sticky=tk.W, pady=5)
ttk.Label(add_frame, text="脚本路径(可选):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.script_path_var = tk.StringVar()
ttk.Entry(add_frame, textvariable=self.script_path_var).grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5)
ttk.Button(add_frame, text="选择文件", command=self.browse_file).grid(row=2, column=2, padx=5)
ttk.Label(add_frame, text="标签(逗号分隔,可选):").grid(row=3, column=0, sticky=tk.W, pady=5)
self.tags_var = tk.StringVar()
ttk.Entry(add_frame, textvariable=self.tags_var).grid(row=3, column=1, sticky=(tk.W, tk.E), pady=5)
ttk.Label(add_frame, text="脚本内容(可选):").grid(row=4, column=0, sticky=tk.W, pady=5)
self.script_content_text = tk.Text(add_frame, height=5)
self.script_content_text.grid(row=4, column=1, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
ttk.Label(add_frame, text="前端界面内容(复杂脚本可选):").grid(row=5, column=0, sticky=tk.W, pady=5)
self.ui_content_text = tk.Text(add_frame, height=5)
self.ui_content_text.grid(row=5, column=1, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
ttk.Button(add_frame, text="添加脚本", command=self.add_script).grid(row=6, column=0, columnspan=3, pady=5)
def create_edit_tab(self):
edit_frame = ttk.Frame(self.notebook, padding="10")
self.notebook.add(edit_frame, text="修改【Modify】")
edit_frame.columnconfigure(0, weight=1)
edit_frame.rowconfigure(1, weight=1)
# 搜索和脚本列表
ttk.Label(edit_frame, text="搜索(名称或标签):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.edit_search_var = tk.StringVar()
ttk.Entry(edit_frame, textvariable=self.edit_search_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5)
ttk.Button(edit_frame, text="搜索", command=self.refresh_edit_list).grid(row=0, column=2, padx=5)
self.edit_tree = ttk.Treeview(edit_frame, columns=("ID", "名称", "标签", "使用次数", "创建时间", "类型"),
show="headings")
self.edit_tree.heading("ID", text="ID")
self.edit_tree.heading("名称", text="名称")
self.edit_tree.heading("标签", text="标签")
self.edit_tree.heading("使用次数", text="使用次数")
self.edit_tree.heading("创建时间", text="创建时间")
self.edit_tree.heading("类型", text="类型")
self.edit_tree.column("ID", width=25, minwidth=25, stretch=False)
self.edit_tree.column("名称", width=150, minwidth=100, stretch=True)
self.edit_tree.column("标签", width=100, minwidth=80, stretch=True)
self.edit_tree.column("使用次数", width=80, minwidth=60, stretch=False)
self.edit_tree.column("创建时间", width=120, minwidth=100, stretch=True)
self.edit_tree.column("类型", width=80, minwidth=60, stretch=False)
self.edit_tree.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S))
self.edit_tree.bind("<<TreeviewSelect>>", self.on_edit_script_select)
# 修改区域
edit_input_frame = ttk.Frame(edit_frame)
edit_input_frame.grid(row=2, column=0, columnspan=3, pady=5, sticky=(tk.W, tk.E))
edit_input_frame.columnconfigure(1, weight=1)
ttk.Label(edit_input_frame, text="脚本名称:").grid(row=0, column=0, sticky=tk.W, pady=2)
self.edit_name_var = tk.StringVar()
ttk.Entry(edit_input_frame, textvariable=self.edit_name_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2)
ttk.Label(edit_input_frame, text="标签(逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=2)
self.edit_tags_var = tk.StringVar()
ttk.Entry(edit_input_frame, textvariable=self.edit_tags_var).grid(row=1, column=1, sticky=(tk.W, tk.E), pady=2)
ttk.Button(edit_input_frame, text="修改脚本", command=self.update_script).grid(row=2, column=0, pady=5)
ttk.Button(edit_input_frame, text="删除脚本", command=self.delete_script).grid(row=2, column=1, sticky=tk.W, pady=5)
self.refresh_edit_list()
def create_run_tab(self):
run_frame = ttk.Frame(self.notebook, padding="10")
self.notebook.add(run_frame, text="运行【Run】")
run_frame.columnconfigure(0, weight=1)
run_frame.columnconfigure(2, weight=1)
run_frame.rowconfigure(0, weight=1)
left_frame = ttk.Frame(run_frame)
left_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 5))
left_frame.columnconfigure(0, weight=1)
left_frame.rowconfigure(1, weight=1)
ttk.Label(left_frame, text="搜索(名称或标签):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.search_var = tk.StringVar()
ttk.Entry(left_frame, textvariable=self.search_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5)
ttk.Button(left_frame, text="搜索", command=self.search_scripts).grid(row=0, column=2, padx=5)
self.tree = ttk.Treeview(left_frame, columns=("ID", "名称", "标签", "使用次数", "创建时间", "类型"),
show="headings")
self.tree.heading("ID", text="ID")
self.tree.heading("名称", text="名称")
self.tree.heading("标签", text="标签")
self.tree.heading("使用次数", text="使用次数")
self.tree.heading("创建时间", text="创建时间")
self.tree.heading("类型", text="类型")
self.tree.column("ID", width=25, minwidth=25, stretch=False)
self.tree.column("名称", width=150, minwidth=100, stretch=True)
self.tree.column("标签", width=100, minwidth=80, stretch=True)
self.tree.column("使用次数", width=80, minwidth=60, stretch=False)
self.tree.column("创建时间", width=120, minwidth=100, stretch=True)
self.tree.column("类型", width=80, minwidth=60, stretch=False)
self.tree.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S))
self.tree.bind("<<TreeviewSelect>>", self.on_script_select)
ttk.Separator(run_frame, orient=tk.VERTICAL).grid(row=0, column=1, sticky=(tk.N, tk.S), padx=5)
self.io_frame = ttk.Frame(run_frame)
self.io_frame.grid(row=0, column=2, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(5, 0))
self.io_frame.columnconfigure(0, weight=1)
self.io_frame.rowconfigure(0, weight=1)
self.refresh_script_list()
def browse_file(self):
file_path = filedialog.askopenfilename(filetypes=[("Python files", "*.py")])
if file_path:
self.script_path_var.set(file_path)
def refresh_script_list(self, search_term: str = None):
for item in self.tree.get_children():
self.tree.delete(item)
scripts = self.manager.list_scripts(tag=search_term, name=search_term)
for script in scripts:
self.tree.insert("", tk.END, values=(
script["id"],
script["name"],
", ".join(script["tags"]),
script["usage_count"],
script["created_at"],
script["type"]
))
def refresh_edit_list(self, search_term: str = None):
for item in self.edit_tree.get_children():
self.edit_tree.delete(item)
scripts = self.manager.list_scripts(tag=search_term, name=search_term)
for script in scripts:
self.edit_tree.insert("", tk.END, values=(
script["id"],
script["name"],
", ".join(script["tags"]),
script["usage_count"],
script["created_at"],
script["type"]
))
def add_script(self):
script_name = self.script_name_var.get().strip()
script_path = self.script_path_var.get().strip()
script_content = self.script_content_text.get("1.0", tk.END).strip()
ui_content = self.ui_content_text.get("1.0", tk.END).strip()
tags = [t.strip() for t in self.tags_var.get().split(",") if t.strip()]
script_type = self.script_type_var.get()
if not script_name and not script_path:
messagebox.showerror("错误", "脚本名称和脚本路径不能同时为空")
return
if not script_path and not script_content:
messagebox.showerror("错误", "脚本路径和脚本内容不能同时为空")
return
if not script_name and script_path:
script_name = os.path.splitext(os.path.basename(script_path))[0]
try:
result = self.manager.add_script(script_name, script_content or None, script_path or None,
ui_content or None, script_type)
if tags:
self.manager.update_script(result["id"], script_name, tags)
messagebox.showinfo("成功", f"脚本 '{script_name}' 已添加!\n建议标签:{', '.join(result['suggested_tags'])}")
self.script_name_var.set("")
self.script_path_var.set("")
self.script_content_text.delete("1.0", tk.END)
self.ui_content_text.delete("1.0", tk.END)
self.tags_var.set(", ".join(result["suggested_tags"]))
self.refresh_script_list()
self.refresh_edit_list()
except Exception as e:
messagebox.showerror("错误", f"添加脚本失败:{str(e)}")
def on_script_select(self, event):
selection = self.tree.selection()
if selection:
item = self.tree.item(selection[0])
self.selected_script_id = int(item["values"][0])
script = next(s for s in self.manager.list_scripts() if s["id"] == self.selected_script_id)
self.refresh_io_frame(script["ui_path"], script["path"])
self.refresh_script_list() # 实时更新使用次数
def on_edit_script_select(self, event):
selection = self.edit_tree.selection()
if selection:
item = self.edit_tree.item(selection[0])
self.selected_script_id = int(item["values"][0])
script = next(s for s in self.manager.list_scripts() if s["id"] == self.selected_script_id)
self.edit_name_var.set(script["name"])
self.edit_tags_var.set(", ".join(script["tags"]))
def update_script(self):
if not self.selected_script_id:
messagebox.showerror("错误", "请先选择一个脚本")
return
new_name = self.edit_name_var.get().strip()
new_tags = [t.strip() for t in self.edit_tags_var.get().split(",") if t.strip()]
if not new_name:
messagebox.showerror("错误", "脚本名称不能为空")
return
try:
self.manager.update_script(self.selected_script_id, new_name, new_tags)
messagebox.showinfo("成功", f"脚本 '{new_name}' 已更新")
self.edit_name_var.set("")
self.edit_tags_var.set("")
self.refresh_edit_list()
self.refresh_script_list()
except Exception as e:
messagebox.showerror("错误", f"更新脚本失败:{str(e)}")
def delete_script(self):
if not self.selected_script_id:
messagebox.showerror("错误", "请先选择一个脚本")
return
if messagebox.askyesno("确认", "确定要删除此脚本吗?"):
try:
self.manager.delete_script(self.selected_script_id)
messagebox.showinfo("成功", "脚本已删除")
self.edit_name_var.set("")
self.edit_tags_var.set("")
self.refresh_edit_list()
self.refresh_script_list()
except Exception as e:
messagebox.showerror("错误", f"删除脚本失败:{str(e)}")
def search_scripts(self):
search_term = self.search_var.get().strip()
self.refresh_script_list(search_term)
def refresh_io_frame(self, ui_path: str = None, script_path: str = None):
if self.current_ui_frame:
self.current_ui_frame.destroy()
if not ui_path or not script_path:
self.current_ui_frame = ttk.Label(
self.io_frame,
text="请选择一个脚本",
wraplength=int(self.io_frame.winfo_width() * 0.9) or 300
)
self.current_ui_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
return
try:
ui_module = self.manager.load_ui_module(ui_path)
def run_callback(input_strings):
result = self.manager.run_script(self.selected_script_id, input_strings)
self.refresh_script_list() # 实时更新使用次数
return result
self.current_ui_frame = ui_module.create_ui(self.io_frame, run_callback)
self.current_ui_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
except Exception as e:
frame_width = self.io_frame.winfo_width() or 300
self.current_ui_frame = ttk.Label(
self.io_frame,
text=f"加载前端界面失败:{str(e)}",
wraplength=int(frame_width * 0.9),
padding=(5, 5),
foreground="red"
)
self.current_ui_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
if __name__ == "__main__":
root = tk.Tk()
root.geometry("800x600")
app = ScriptManagerGUI(root)
root.mainloop()