{installedPlugins.map((plugin) => (
-
{
+ try {
+ if (plugin.enabled) {
+ await invoke("disable_plugin", { name: plugin.id });
+ toast.success("插件已禁用");
+ } else {
+ await invoke("enable_plugin", { name: plugin.id });
+ toast.success("插件已启用");
+ }
+ fetchData();
+ } catch (_err) {
+ toast.error("操作失败");
+ }
+ }}
onUninstall={() => setPluginToUninstall(plugin)}
- />
+ >
+
+ setPluginToUninstall(plugin)}
+ />
+
+
))}
diff --git a/src/components/plugins/README.md b/src/components/plugins/README.md
index a748926a0..24c26e149 100644
--- a/src/components/plugins/README.md
+++ b/src/components/plugins/README.md
@@ -11,6 +11,7 @@
| `PluginInstallDialog.tsx` | 插件安装对话框,支持本地文件和 URL 安装 |
| `PluginUninstallDialog.tsx` | 插件卸载确认对话框 |
| `PluginUIRenderer.tsx` | 插件 UI 渲染器,根据 pluginId 渲染对应的插件 UI |
+| `PluginItemContextMenu.tsx` | 插件项右键菜单,支持启用/禁用、打开目录、卸载等操作 |
| `index.ts` | 模块导出 |
## 功能说明
@@ -38,6 +39,12 @@
- 显示友好的错误提示(插件未找到、加载失败)
- 导出 Page 类型定义,支持动态插件路由
+### PluginItemContextMenu
+- 为已安装插件列表提供右键菜单
+- 支持启用/禁用插件
+- 支持打开插件目录
+- 支持卸载插件(带确认对话框)
+
## 相关需求
- 需求 1.1: 本地文件安装
diff --git a/src/components/provider-pool/CredentialCardContextMenu.tsx b/src/components/provider-pool/CredentialCardContextMenu.tsx
new file mode 100644
index 000000000..fb4af4069
--- /dev/null
+++ b/src/components/provider-pool/CredentialCardContextMenu.tsx
@@ -0,0 +1,149 @@
+/**
+ * 凭证卡片右键菜单组件
+ *
+ * 为凭证池的凭证卡片提供右键菜单功能
+ * 支持复制 ID、刷新 Token、查看详情、启用/禁用、删除等操作
+ *
+ * @module components/provider-pool/CredentialCardContextMenu
+ */
+
+import React, { useState } from "react";
+import { Copy, RefreshCw, Info, Power, PowerOff, Trash2 } from "lucide-react";
+import {
+ ContextMenu,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuShortcut,
+ ContextMenuTrigger,
+} from "@/components/ui/context-menu";
+import { ConfirmDialog } from "@/components/ConfirmDialog";
+import { toast } from "sonner";
+import type { CredentialDisplay } from "@/lib/api/providerPool";
+
+interface CredentialCardContextMenuProps {
+ /** 凭证数据 */
+ credential: CredentialDisplay;
+ /** 子元素 */
+ children: React.ReactNode;
+ /** 刷新 Token 回调 */
+ onRefreshToken?: () => void;
+ /** 切换启用状态回调 */
+ onToggle: () => void;
+ /** 删除回调 */
+ onDelete: () => void;
+ /** 是否为 OAuth 凭证 */
+ isOAuth?: boolean;
+}
+
+export function CredentialCardContextMenu({
+ credential,
+ children,
+ onRefreshToken,
+ onToggle,
+ onDelete,
+ isOAuth = false,
+}: CredentialCardContextMenuProps) {
+ const [showDeleteDialog, setShowDeleteDialog] = useState(false);
+
+ // 复制凭证 ID
+ const handleCopyId = async () => {
+ try {
+ await navigator.clipboard.writeText(credential.uuid);
+ toast.success("已复制凭证 ID");
+ } catch (error) {
+ console.error("复制失败:", error);
+ toast.error("复制失败");
+ }
+ };
+
+ // 刷新 Token
+ const handleRefreshToken = () => {
+ if (onRefreshToken) {
+ onRefreshToken();
+ toast.info("正在刷新 Token...");
+ }
+ };
+
+ // 查看详情(展开卡片详情)
+ const handleViewDetail = () => {
+ // 触发卡片展开,这里通过复制 ID 并提示用户点击卡片查看
+ toast.info("请点击卡片查看详细信息");
+ };
+
+ // 确认删除
+ const handleConfirmDelete = () => {
+ onDelete();
+ setShowDeleteDialog(false);
+ };
+
+ return (
+ <>
+