From c7a76ac2cd657586fdc3025ba2afe48895c8f93b Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Fri, 15 May 2026 23:18:55 +0800 Subject: [PATCH] feat: improve simadmin config list actions --- plugins/simadmin/README.md | 64 ++++++++++++-- plugins/simadmin/simadmin_multi.py | 137 +++++++++++++++++++++++++---- 2 files changed, 179 insertions(+), 22 deletions(-) diff --git a/plugins/simadmin/README.md b/plugins/simadmin/README.md index 4571a8e..02b747d 100644 --- a/plugins/simadmin/README.md +++ b/plugins/simadmin/README.md @@ -74,11 +74,65 @@ SimAdmin 配置管理(多级菜单) q. 退出 ``` +### 实例列表页快捷操作 + +菜单选择 `1. 查看实例列表` 后,不再只是展示文本,而是进入实例列表操作页: + +```text +SimAdmin 实例列表: +1. 主卡 [启用] + http://192.168.68.1:3000 timeout=10s token=未设置 +2. 副卡 [禁用] + http://192.168.68.2:3000 timeout=10s token=abc***xyz + +列表操作: +输入实例编号:进入该实例操作菜单 +a. 新增实例 +e <编号>. 编辑实例,例如 e 1 +d <编号>. 删除实例,例如 d 1 +t <编号>. 测试状态,例如 t 1 +on <编号> / off <编号>. 启用或禁用 +r. 刷新列表 +b. 返回上级菜单 +q. 退出配置管理 +``` + +也就是说,查看列表后可以直接继续操作: + +```text +1 # 进入 1 号实例操作菜单 +e 1 # 直接编辑 1 号实例 +d 2 # 直接删除 2 号实例 +t 1 # 直接测试 1 号实例 +on 2 # 启用 2 号实例 +a # 新增实例 +``` + +### 单实例操作菜单 + +在列表页输入实例编号后,进入该实例的二级操作菜单: + +```text +实例操作:【主卡】 +主卡 [启用] + http://192.168.68.1:3000 timeout=10s token=未设置 +1. 测试状态 +2. 编辑实例 +3. 删除实例 +4. 启用/禁用 +5. 复制/新增一个实例 +b. 返回实例列表 +q. 退出配置管理 +``` + ### 添加实例流程 +可从主菜单选择 `2. 添加实例`,也可在列表页输入 `a`: + ```text sim配置 -2 +1 +a 请输入实例名称,例如:主卡 主卡 请输入 SimAdmin 地址,例如:http://192.168.68.1:3000 @@ -95,7 +149,7 @@ yes ### 编辑实例流程 -菜单选择 `3. 编辑实例` 后,选择实例编号,再进入二级菜单: +可从主菜单选择 `3. 编辑实例`,也可在列表页输入 `e 1`,或输入实例编号后选择 `2. 编辑实例`。编辑二级菜单: ```text 编辑【主卡】 @@ -110,15 +164,15 @@ q. 放弃返回 ### 删除实例流程 -菜单选择 `4. 删除实例`,选择编号后,需要输入 `yes` 二次确认。 +可从主菜单选择 `4. 删除实例`,也可在列表页输入 `d 1`,或进入单实例操作菜单选择 `3. 删除实例`。删除前需要输入 `yes` 二次确认。 ### 启用/禁用实例 -菜单选择 `5. 启用/禁用实例`,选择编号后立即切换。 +可从主菜单选择 `5. 启用/禁用实例`,也可在列表页输入 `on 1` / `off 1`,或进入单实例操作菜单选择 `4. 启用/禁用`。 ### 测试状态查询 -菜单选择 `6. 测试状态查询`,选择编号后会调用该实例的状态接口并返回摘要。 +可从主菜单选择 `6. 测试状态查询`,也可在列表页输入 `t 1`,或进入单实例操作菜单选择 `1. 测试状态`。 ### 导出配置 diff --git a/plugins/simadmin/simadmin_multi.py b/plugins/simadmin/simadmin_multi.py index f925aa5..e6f5e2c 100644 --- a/plugins/simadmin/simadmin_multi.py +++ b/plugins/simadmin/simadmin_multi.py @@ -10,7 +10,7 @@ # [rule: ^sim短信\s+\S+\s+\S+\s+[\s\S]+$] # [platform: qq,wx,tg,tb,fs] # [open_source: true] -# [version: 1.1.0] +# [version: 1.2.0] # [public: false] # [price: 0] # [description: 管理员专用:兼容多个 SimAdmin 实例,支持多级菜单配置管理、状态查询和短信发送。配置桶 otto/simadmin_instances。] @@ -366,11 +366,66 @@ def choose_instance_by_menu(sender, instances, prompt="请选择实例编号"): def menu_list(sender): - instances = load_instances(include_disabled=True, allow_empty=True) - if not instances: - reply(sender, "当前没有 SimAdmin 实例。") - return - reply(sender, "SimAdmin 实例列表:\n" + "\n".join(instance_brief(item, idx) for idx, item in enumerate(instances, 1))) + """实例列表页本身就是二级操作页:看完列表后可直接编辑/新增/删除/测试。""" + while True: + instances = load_instances(include_disabled=True, allow_empty=True) + lines = ["SimAdmin 实例列表:"] + if instances: + lines.extend(instance_brief(item, idx) for idx, item in enumerate(instances, 1)) + else: + lines.append("当前没有 SimAdmin 实例。") + lines.extend([ + "", + "列表操作:", + "输入实例编号:进入该实例操作菜单", + "a. 新增实例", + "e <编号>. 编辑实例,例如 e 1", + "d <编号>. 删除实例,例如 d 1", + "t <编号>. 测试状态,例如 t 1", + "on <编号> / off <编号>. 启用或禁用", + "r. 刷新列表", + "b. 返回上级菜单", + "q. 退出配置管理", + ]) + choice = listen_text(sender, "\n".join(lines), allow_empty=True, default="r").strip() + lower = choice.lower() + if lower in ("r", "刷新"): + continue + if lower in ("b", "back", "返回"): + return "back" + if lower in ("q", "quit", "exit", "退出"): + return "quit" + if lower in ("a", "add", "新增", "添加"): + menu_add(sender) + continue + if choice.isdigit(): + idx = int(choice) - 1 + if 0 <= idx < len(instances): + action = instance_action_menu(sender, idx) + if action == "quit": + return "quit" + continue + reply(sender, "编号超出范围") + continue + m = re.match(r"^(e|edit|编辑|d|del|delete|删除|t|test|测试|on|启用|off|禁用)\s+(\d+)$", lower) + if not m: + reply(sender, "无法识别的列表操作,请重新输入") + continue + op, idx_text = m.group(1), m.group(2) + idx = int(idx_text) - 1 + if idx < 0 or idx >= len(instances): + reply(sender, "编号超出范围") + continue + if op in ("e", "edit", "编辑"): + menu_edit(sender, idx) + elif op in ("d", "del", "delete", "删除"): + menu_delete(sender, idx) + elif op in ("t", "test", "测试"): + menu_test(sender, idx) + elif op in ("on", "启用"): + menu_set_enabled(sender, idx, True) + elif op in ("off", "禁用"): + menu_set_enabled(sender, idx, False) def menu_add(sender): @@ -398,9 +453,10 @@ def menu_add(sender): reply(sender, "已添加 SimAdmin 实例:" + item["name"]) -def menu_delete(sender): +def menu_delete(sender, idx=None): instances = load_instances(include_disabled=True, allow_empty=True) - idx = choose_instance_by_menu(sender, instances, "请选择要删除的实例编号") + if idx is None: + idx = choose_instance_by_menu(sender, instances, "请选择要删除的实例编号") item = instances[idx] if not confirm(sender, "确认删除【%s】?输入 yes 确认" % item["name"]): reply(sender, "已取消删除") @@ -410,9 +466,10 @@ def menu_delete(sender): reply(sender, "已删除 SimAdmin 实例:" + removed["name"]) -def menu_edit(sender): +def menu_edit(sender, idx=None): instances = load_instances(include_disabled=True, allow_empty=True) - idx = choose_instance_by_menu(sender, instances, "请选择要编辑的实例编号") + if idx is None: + idx = choose_instance_by_menu(sender, instances, "请选择要编辑的实例编号") item = dict(instances[idx]) while True: reply(sender, "\n".join([ @@ -451,21 +508,64 @@ def menu_edit(sender): return -def menu_toggle(sender): +def menu_set_enabled(sender, idx, enabled): instances = load_instances(include_disabled=True, allow_empty=True) - idx = choose_instance_by_menu(sender, instances, "请选择要启用/禁用的实例编号") - instances[idx]["enabled"] = not instances[idx].get("enabled") + instances[idx]["enabled"] = bool(enabled) save_instances(instances) - reply(sender, "已将【%s】切换为:%s" % (instances[idx]["name"], "启用" if instances[idx]["enabled"] else "禁用")) + reply(sender, "已将【%s】设置为:%s" % (instances[idx]["name"], "启用" if instances[idx]["enabled"] else "禁用")) -def menu_test(sender): +def menu_toggle(sender, idx=None): instances = load_instances(include_disabled=True, allow_empty=True) - idx = choose_instance_by_menu(sender, instances, "请选择要测试连通性的实例编号") + if idx is None: + idx = choose_instance_by_menu(sender, instances, "请选择要启用/禁用的实例编号") + menu_set_enabled(sender, idx, not instances[idx].get("enabled")) + + +def menu_test(sender, idx=None): + instances = load_instances(include_disabled=True, allow_empty=True) + if idx is None: + idx = choose_instance_by_menu(sender, instances, "请选择要测试连通性的实例编号") item = instances[idx] reply(sender, format_instance_status(item)) +def instance_action_menu(sender, idx): + while True: + instances = load_instances(include_disabled=True, allow_empty=True) + if idx < 0 or idx >= len(instances): + reply(sender, "实例已不存在,返回列表") + return "back" + item = instances[idx] + reply(sender, "\n".join([ + "实例操作:【%s】" % item["name"], + instance_brief(item), + "1. 测试状态", + "2. 编辑实例", + "3. 删除实例", + "4. 启用/禁用", + "5. 复制/新增一个实例", + "b. 返回实例列表", + "q. 退出配置管理", + ])) + choice = listen_text(sender, "请输入操作编号") + if choice == "1": + menu_test(sender, idx) + elif choice == "2": + menu_edit(sender, idx) + elif choice == "3": + menu_delete(sender, idx) + return "back" + elif choice == "4": + menu_toggle(sender, idx) + elif choice == "5": + menu_add(sender) + elif choice.lower() in ("b", "back", "返回"): + return "back" + else: + return "quit" + + def menu_export(sender): instances = load_instances(include_disabled=True, allow_empty=True) reply(sender, "当前配置 JSON:\n" + json.dumps(instances, ensure_ascii=False, indent=2)) @@ -488,7 +588,10 @@ def handle_config_menu(sender): ])) choice = listen_text(sender, "请输入菜单编号") if choice == "1": - menu_list(sender) + action = menu_list(sender) + if action == "quit": + reply(sender, "已退出 SimAdmin 配置管理") + return elif choice == "2": menu_add(sender) elif choice == "3":