diff --git a/web/src/views/Tools.vue b/web/src/views/Tools.vue index 7266b01..e2891d6 100644 --- a/web/src/views/Tools.vue +++ b/web/src/views/Tools.vue @@ -28,7 +28,7 @@ import { useTools } from './tools/useTools' import '@/views/database/database.css' // 使用工具 composable -const { tools, toolsLoading, fetchTools, syncTools, deleteTool: deleteToolApi } = useTools() +const { tools, toolsLoading, fetchTools, syncTools, deleteTool: deleteToolApi, createTool } = useTools() // 图标组件映射 const iconComponents: Record = { @@ -65,7 +65,8 @@ interface Tool { parameters: string status: string type: 'built-in' | 'mcp' - createdAt?: string + icon?: string + created_at?: string } // 页面加载时获取工具列表 @@ -92,6 +93,7 @@ const editForm = ref({ name: '', description: '', provider: '', + icon: '', }) // Statistics @@ -123,7 +125,7 @@ const tabCounts = computed(() => ({ const openEdit = (tool: any) => { editingTool.value = tool - editForm.value = { name: tool.name, description: tool.description, provider: tool.provider || '' } + editForm.value = { name: tool.name, description: tool.description, provider: tool.provider || '', icon: tool.icon || '' } isEditing.value = true } @@ -133,9 +135,32 @@ const saveEdit = () => { const cancelEdit = () => { isEditing.value = false; editingTool.value = null } -const toggleStatus = async (tool: any) => { +// 状态切换确认弹窗 +const showStatusConfirm = ref(false) +const toolToToggle = ref(null) + +const confirmToggleStatus = (tool: any) => { + toolToToggle.value = tool + showStatusConfirm.value = true +} + +const toggleStatus = async () => { + if (!toolToToggle.value) return + + const tool = toolToToggle.value const newStatus = tool.status === 'active' ? 'inactive' : 'active' + const action = newStatus === 'active' ? 'activate' : 'deactivate' + // TODO: 调用 API 更新状态 + console.log(`${action} tool:`, tool.name) + + showStatusConfirm.value = false + toolToToggle.value = null +} + +const cancelToggleStatus = () => { + showStatusConfirm.value = false + toolToToggle.value = null } const handleDeleteTool = async (id: string) => { @@ -148,6 +173,67 @@ const handleDeleteTool = async (id: string) => { const handleSyncTools = async () => { await syncTools() } + +// Add MCP 弹窗 +const showAddMcp = ref(false) +const mcpForm = ref({ + name: '', + description: '', + description_cn: '', + transport: 'stdio', + command: '', + args: '', + env: '', +}) + +const openAddMcp = () => { + mcpForm.value = { + name: '', + description: '', + description_cn: '', + transport: 'stdio', + command: '', + args: '', + env: '', + } + showAddMcp.value = true +} + +const closeAddMcp = () => { + showAddMcp.value = false +} + +const submitMcp = async () => { + try { + // 组装参数 + const argsArray = mcpForm.value.args ? mcpForm.value.args.split('\n').filter((a: string) => a.trim()) : [] + const envObj: Record = {} + if (mcpForm.value.env) { + mcpForm.value.env.split('\n').forEach((line: string) => { + const [key, ...valueParts] = line.split('=') + if (key && valueParts.length > 0) { + envObj[key.trim()] = valueParts.join('=').trim() + } + }) + } + + await createTool({ + name: mcpForm.value.name, + description: mcpForm.value.description, + description_cn: mcpForm.value.description_cn, + category: 'mcp', + provider: 'mcp', + transport: mcpForm.value.transport, + command: mcpForm.value.command, + args: JSON.stringify(argsArray), + env: JSON.stringify(envObj), + status: 'active', + }) + closeAddMcp() + } catch (error) { + console.error('Failed to add MCP:', error) + } +}