From cea49bb6857b99738d04bd9e73719751441dd896 Mon Sep 17 00:00:00 2001 From: "DESKTOP-72TV0V4\\caoxiaozhu" Date: Tue, 10 Mar 2026 23:21:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=88=A0=E9=99=A4=E6=97=A7?= =?UTF-8?q?=E7=9A=84=20skill=20composables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- web/src/views/skill/types.ts | 46 ---- web/src/views/skill/useFileTree.ts | 340 ------------------------- web/src/views/skill/useSkillChat.ts | 46 ---- web/src/views/skill/useSkillServers.ts | 114 --------- web/src/views/skill/useWorkflow.ts | 136 ---------- 5 files changed, 682 deletions(-) delete mode 100644 web/src/views/skill/types.ts delete mode 100644 web/src/views/skill/useFileTree.ts delete mode 100644 web/src/views/skill/useSkillChat.ts delete mode 100644 web/src/views/skill/useSkillServers.ts delete mode 100644 web/src/views/skill/useWorkflow.ts diff --git a/web/src/views/skill/types.ts b/web/src/views/skill/types.ts deleted file mode 100644 index 2d17789..0000000 --- a/web/src/views/skill/types.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Skill page types - -export interface MCPServer { - id: number - name: string - status: 'running' | 'stopped' | 'error' - type: string - port: number - createdAt: string - description: string -} - -export interface FileItem { - id: string - name: string - icon?: string - content?: string - type: 'file' -} - -export interface FolderItem { - id: string - name: string - icon?: string - type: 'folder' - expanded?: boolean - children: (FileItem | FolderItem)[] -} - -export interface WorkflowNode { - id: string - name: string - description: string - icon: string - color: string - bgColor: string - borderColor: string - status: 'pending' | 'processing' | 'completed' - expanded: boolean - children?: WorkflowNode[] -} - -export interface ChatMessage { - id: number - text: string -} diff --git a/web/src/views/skill/useFileTree.ts b/web/src/views/skill/useFileTree.ts deleted file mode 100644 index 0eeefda..0000000 --- a/web/src/views/skill/useFileTree.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { ref } from 'vue' -import type { FileItem, FolderItem } from './types' - -// 默认的 SKILL.md 内容 -const DEFAULT_SKILL_CONTENT = `# Skill Configuration - -## Overview -This skill is configured to process data and generate outputs. - -## Dependencies -- Python 3.8+ -- Node.js 16+ -` - -export function useFileTree() { - // 文件树数据 - const fileTree = ref([ - { - id: 'folder-1', - name: 'Data', - icon: 'fa-folder', - type: 'folder', - expanded: true, - children: [ - { id: 'file-1', name: 'user_data.csv', icon: 'fa-file', content: 'id,name,email,age\n1,John Doe,john@example.com,28\n2,Jane Smith,jane@example.com,32', type: 'file' }, - { id: 'file-2', name: 'config.json', icon: 'fa-code', content: '{\n "appName": "MyApp",\n "version": "1.0.0",\n "debug": true\n}', type: 'file' }, - ] - }, - { - id: 'folder-2', - name: 'Script', - icon: 'fa-folder', - type: 'folder', - expanded: true, - children: [ - { id: 'file-3', name: 'process.py', icon: 'fa-code', content: 'import pandas as pd\n\ndef process_data(data):\n """Process the input data"""\n return data.apply(lambda x: x.strip())\n\nif __name__ == "__main__":\n df = pd.read_csv("user_data.csv")\n processed = process_data(df)\n processed.to_csv("output.csv", index=False)', type: 'file' }, - { id: 'file-4', name: 'transform.js', icon: 'fa-code', content: 'function transformData(input) {\n return input.map(item => ({\n ...item,\n processed: true,\n timestamp: Date.now()\n }));\n}\n\nmodule.exports = { transformData };', type: 'file' }, - ] - }, - { - id: 'folder-3', - name: 'Reference', - icon: 'fa-folder', - type: 'folder', - expanded: true, - children: [ - { id: 'file-5', name: 'api_docs.md', icon: 'fa-code', content: '# API Documentation\n\n## Endpoints\n\n### GET /api/users\nReturns list of users.\n\n### POST /api/users\nCreate a new user.', type: 'file' }, - ] - }, - ]) - - // 根目录文件 - const rootFiles = ref([ - { id: 'file-root-1', name: 'SKILL.md', icon: 'fa-file', content: DEFAULT_SKILL_CONTENT, type: 'file' }, - ]) - - // 展开/收起文件夹 - const toggleFolder = (folder: FolderItem) => { - folder.expanded = !folder.expanded - } - - // 新建文件夹 - 内联输入模式 - const inlineNewFolderName = ref('') - const inlineCreatingFolderId = ref(null) - - const showInlineNewFolderInput = (parentId: string | null = null) => { - inlineNewFolderName.value = '' - inlineCreatingFolderId.value = parentId === null ? 'root' : parentId - } - - const confirmInlineCreateFolder = () => { - if (!inlineNewFolderName.value.trim()) { - inlineCreatingFolderId.value = null - return - } - - const newFolder: FolderItem = { - id: 'folder-' + Date.now(), - name: inlineNewFolderName.value, - icon: 'fa-folder', - type: 'folder', - expanded: true, - children: [] - } - - if (inlineCreatingFolderId.value && inlineCreatingFolderId.value !== 'root') { - const parentFolder = findFolderById(fileTree.value, inlineCreatingFolderId.value) - if (parentFolder && parentFolder.children) { - parentFolder.children.push(newFolder) - // 选中新创建的文件夹 - selectedFolder.value = newFolder.id - parentFolder.expanded = true - } - } else { - fileTree.value.push(newFolder) - // 选中新创建的文件夹 - selectedFolder.value = newFolder.id - } - inlineCreatingFolderId.value = null - inlineNewFolderName.value = '' - } - - const cancelInlineCreateFolder = () => { - inlineCreatingFolderId.value = null - inlineNewFolderName.value = '' - // 恢复选中之前选中的文件夹 - if (selectedFolder.value) { - const folder = findFolderById(fileTree.value, selectedFolder.value) - if (folder) { - folder.expanded = true - } - } - } - - // 递归查找文件夹 - const findFolderById = (folders: (FileItem | FolderItem)[], id: string): FolderItem | null => { - for (const folder of folders) { - if ('children' in folder && folder.id === id) return folder as FolderItem - if ('children' in folder && folder.children) { - const found = findFolderById(folder.children, id) - if (found) return found - } - } - return null - } - - // 新建文件 - 内联输入模式 - const inlineNewFileName = ref('') - const inlineCreatingFileId = ref(null) - - const showInlineNewFileInput = (folderId: string | null = null) => { - inlineNewFileName.value = '' - inlineCreatingFileId.value = folderId === null ? 'root' : folderId - } - - const confirmInlineCreateFile = () => { - if (!inlineNewFileName.value.trim()) { - inlineCreatingFileId.value = null - return - } - - const newFile: FileItem = { - id: 'file-' + Date.now(), - name: inlineNewFileName.value, - icon: getFileIconByName(inlineNewFileName.value), - content: '', - type: 'file' - } - - if (inlineCreatingFileId.value && inlineCreatingFileId.value !== 'root') { - const folder = findFolderById(fileTree.value, inlineCreatingFileId.value) - if (folder && folder.children) { - folder.children.push(newFile) - // 选中父文件夹 - selectedFolder.value = folder.id - folder.expanded = true - } - } else { - rootFiles.value.push(newFile) - } - - inlineCreatingFileId.value = null - inlineNewFileName.value = '' - } - - const cancelInlineCreateFile = () => { - inlineCreatingFileId.value = null - inlineNewFileName.value = '' - // 恢复选中之前选中的文件夹 - if (selectedFolder.value) { - const folder = findFolderById(fileTree.value, selectedFolder.value) - if (folder) { - folder.expanded = true - } - } - } - - // 根据文件名获取图标 - const getFileIconByName = (filename: string): string => { - const ext = filename.split('.').pop()?.toLowerCase() - const codeExtensions = ['js', 'ts', 'py', 'html', 'css', 'json', 'xml', 'yaml', 'yml', 'java', 'c', 'cpp', 'go', 'rs', 'php', 'rb', 'swift', 'kt', 'sql', 'sh', 'bash', 'md'] - if (codeExtensions.includes(ext || '')) { - return 'fa-code' - } - return 'fa-file' - } - - // 上传文件 - const handleFileUpload = (event: Event, folderId: string | null = null) => { - const input = event.target as HTMLInputElement - if (!input.files?.length) return - - Array.from(input.files).forEach(file => { - const reader = new FileReader() - reader.onload = (e) => { - const newFile: FileItem = { - id: 'file-' + Date.now() + Math.random(), - name: file.name, - icon: getFileIconByName(file.name), - content: e.target?.result as string || '', - type: 'file' - } - - if (folderId) { - const folder = findFolderById(fileTree.value, folderId) - if (folder && folder.children) { - folder.children.push(newFile) - } - } else { - rootFiles.value.push(newFile) - } - } - reader.readAsText(file) - }) - - input.value = '' - } - - // 递归查找文件 - const findFile = (items: (FileItem | FolderItem)[], fileId: string): FileItem | null => { - for (const item of items) { - if (item.type === 'file' && item.id === fileId) { - return item - } - if (item.type === 'folder' && item.children) { - const found = findFile(item.children, fileId) - if (found) return found - } - } - return null - } - - // 文件编辑相关状态 - const isEditingFile = ref(false) - const isEditingFileClosing = ref(false) - const editingFile = ref(null) - const editingFileName = ref('') - const editingFileContent = ref('') - const editingFileType = ref('') - - // 选中文件/文件夹状态 - const hoveringItem = ref(null) - const selectedFolder = ref(null) - - // 选中文件夹 - const selectFolder = (folderId: string) => { - if (selectedFolder.value === folderId) { - selectedFolder.value = null - } else { - selectedFolder.value = folderId - const folder = findFolderById(fileTree.value, folderId) - if (folder) { - folder.expanded = true - } - } - } - - // 删除文件 - const deleteFile = (file: FileItem, parentId: string | null) => { - if (!parentId) { - rootFiles.value = rootFiles.value.filter(f => f.id !== file.id) - } else { - const folder = fileTree.value.find(f => f.id === parentId) - if (folder && folder.children) { - folder.children = folder.children.filter(c => (c as FileItem).id !== file.id) - } - } - } - - // 删除文件夹 - const deleteFolder = (folder: FolderItem) => { - fileTree.value = fileTree.value.filter(f => f.id !== folder.id) - } - - // 打开文件编辑器 - const openFile = (file: FileItem) => { - editingFile.value = file - editingFileName.value = file.name - editingFileContent.value = file.content || '' - editingFileType.value = 'file' - isEditingFile.value = true - } - - const saveFileEdit = () => { - if (!editingFile.value) return - editingFile.value.content = editingFileContent.value - isEditingFileClosing.value = true - setTimeout(() => { - isEditingFile.value = false - isEditingFileClosing.value = false - editingFile.value = null - }, 300) - } - - const cancelFileEdit = () => { - isEditingFileClosing.value = true - setTimeout(() => { - isEditingFile.value = false - isEditingFileClosing.value = false - editingFile.value = null - }, 300) - } - - return { - // State - fileTree, - rootFiles, - inlineNewFolderName, - inlineCreatingFolderId, - inlineNewFileName, - inlineCreatingFileId, - isEditingFile, - isEditingFileClosing, - editingFile, - editingFileName, - editingFileContent, - editingFileType, - hoveringItem, - selectedFolder, - - // Methods - toggleFolder, - showInlineNewFolderInput, - confirmInlineCreateFolder, - cancelInlineCreateFolder, - findFolderById, - showInlineNewFileInput, - confirmInlineCreateFile, - cancelInlineCreateFile, - getFileIconByName, - handleFileUpload, - findFile, - selectFolder, - deleteFile, - deleteFolder, - openFile, - saveFileEdit, - cancelFileEdit, - } -} diff --git a/web/src/views/skill/useSkillChat.ts b/web/src/views/skill/useSkillChat.ts deleted file mode 100644 index d89f953..0000000 --- a/web/src/views/skill/useSkillChat.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ref } from 'vue' -import type { ChatMessage } from './types' - -export function useSkillChat() { - // AI 对话面板 - const isChatOpen = ref(false) - - // 对话相关 - const chatInput = ref('') - const chatMessages = ref([]) - - const toggleChat = () => { - isChatOpen.value = !isChatOpen.value - } - - const sendMessage = () => { - if (!chatInput.value.trim()) return - - chatMessages.value.push({ - id: Date.now(), - text: chatInput.value - }) - - const userInput = chatInput.value - chatInput.value = '' - - // 模拟 AI 回复 - setTimeout(() => { - chatMessages.value.push({ - id: Date.now(), - text: `I've updated the configuration based on your request: "${userInput}". The changes have been applied to your skill settings.` - }) - }, 1000) - } - - return { - // State - isChatOpen, - chatInput, - chatMessages, - - // Methods - toggleChat, - sendMessage, - } -} diff --git a/web/src/views/skill/useSkillServers.ts b/web/src/views/skill/useSkillServers.ts deleted file mode 100644 index eaacab3..0000000 --- a/web/src/views/skill/useSkillServers.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { ref } from 'vue' -import type { MCPServer } from './types' - -export function useSkillServers() { - // MCP Server 列表 - const mcpServers = ref([ - { id: 1, name: 'linear-demo', status: 'running', type: 'Linear', port: 3001, createdAt: '2025-04-10', description: 'Linear API integration for project management' }, - { id: 2, name: 'google-maps', status: 'running', type: 'Google Maps', port: 3002, createdAt: '2025-04-08', description: 'Google Maps API for location services' }, - { id: 3, name: 'explorer-mcp', status: 'error', type: 'File System', port: 3003, createdAt: '2025-04-05', description: 'File system explorer and editor' }, - { id: 4, name: 'postgres-mcp', status: 'running', type: 'PostgreSQL', port: 3004, createdAt: '2025-04-12', description: 'PostgreSQL database operations' }, - { id: 5, name: 'github-mcp', status: 'stopped', type: 'GitHub', port: 3005, createdAt: '2025-04-11', description: 'GitHub API integration' }, - ]) - - // 编辑状态 - const editingServer = ref(null) - const isEditing = ref(false) - - // 搜索和筛选 - const searchQuery = ref('') - const filterStatus = ref('all') - - // 编辑表单 - const editForm = ref({ - name: '', - type: '', - port: 3000, - description: '', - }) - - // 打开编辑弹窗 - const openEdit = (server: MCPServer) => { - editingServer.value = server - editForm.value = { - name: server.name, - type: server.type, - port: server.port, - description: server.description, - } - isEditing.value = true - } - - // 保存编辑 - const saveEdit = () => { - if (editingServer.value) { - const index = mcpServers.value.findIndex(s => s.id === editingServer.value!.id) - if (index !== -1) { - mcpServers.value[index] = { - ...mcpServers.value[index], - ...editForm.value, - } - } - } - isEditing.value = false - } - - // 取消编辑 - const cancelEdit = () => { - isEditing.value = false - editingServer.value = null - } - - // 切换状态 - const toggleStatus = (server: MCPServer) => { - if (server.status === 'running') { - server.status = 'stopped' - } else if (server.status === 'stopped') { - server.status = 'running' - } - } - - // 删除服务器 - const deleteServer = (id: number) => { - mcpServers.value = mcpServers.value.filter(s => s.id !== id) - } - - // 筛选服务器 - const filteredServers = () => { - return mcpServers.value.filter(server => { - const matchSearch = server.name.toLowerCase().includes(searchQuery.value.toLowerCase()) || - server.type.toLowerCase().includes(searchQuery.value.toLowerCase()) - const matchStatus = filterStatus.value === 'all' || server.status === filterStatus.value - return matchSearch && matchStatus - }) - } - - // 状态样式 - const statusClass = (status: string) => { - switch (status) { - case 'running': return 'bg-primary-success' - case 'stopped': return 'bg-gray-500' - case 'error': return 'bg-primary-danger' - default: return 'bg-gray-500' - } - } - - return { - // State - mcpServers, - editingServer, - isEditing, - searchQuery, - filterStatus, - editForm, - - // Methods - openEdit, - saveEdit, - cancelEdit, - toggleStatus, - deleteServer, - filteredServers, - statusClass, - } -} diff --git a/web/src/views/skill/useWorkflow.ts b/web/src/views/skill/useWorkflow.ts deleted file mode 100644 index 4d90bf7..0000000 --- a/web/src/views/skill/useWorkflow.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { ref } from 'vue' - -interface WorkflowNode { - id: string - name: string - description: string - icon: string - color: string - bgColor: string - borderColor: string - status: 'pending' | 'processing' | 'completed' - expanded: boolean - children?: WorkflowNode[] -} - -export function useWorkflow() { - // 流程生成相关 - const isGeneratingGraph = ref(false) - const isGraphGenerated = ref(false) - - const workflowData = ref([ - { - id: 'output', - name: '最终输出', - description: '生成最终结果返回给用户', - icon: 'fa-check-circle', - color: 'text-green-400', - bgColor: 'from-green-500/20 to-green-500/5', - borderColor: 'border-green-500/30', - status: 'pending', - expanded: false, - children: [ - { - id: 'generate', - name: '方案生成', - description: '基于分析结果构建解决方案', - icon: 'fa-lightbulb', - color: 'text-primary-orange', - bgColor: 'from-primary-orange/20 to-primary-orange/5', - borderColor: 'border-primary-orange/30', - status: 'pending', - expanded: false, - children: [ - { - id: 'analyze', - name: '问题分析', - description: '拆解问题、提取关键信息、理解用户意图', - icon: 'fa-microscope', - color: 'text-purple-400', - bgColor: 'from-purple-500/20 to-purple-500/5', - borderColor: 'border-purple-500/30', - status: 'pending', - expanded: false, - children: [ - { - id: 'question', - name: '用户问题', - description: '输入原始需求和问题描述', - icon: 'fa-question', - color: 'text-primary-cyan', - bgColor: 'from-primary-cyan/20 to-primary-cyan/5', - borderColor: 'border-primary-cyan/30', - status: 'pending', - expanded: false, - } - ] - }, - { - id: 'data', - name: '数据获取', - description: '从知识库、向量数据库获取相关信息', - icon: 'fa-database', - color: 'text-green-400', - bgColor: 'from-green-500/20 to-green-500/5', - borderColor: 'border-green-500/30', - status: 'pending', - expanded: false, - } - ] - }, - { - id: 'evaluate', - name: '方案评估', - description: '验证方案可行性和效果', - icon: 'fa-clipboard-check', - color: 'text-yellow-400', - bgColor: 'from-yellow-500/20 to-yellow-500/5', - borderColor: 'border-yellow-500/30', - status: 'pending', - expanded: false, - } - ] - } - ]) - - // 展开/收起节点 - const toggleNode = (node: WorkflowNode) => { - node.expanded = !node.expanded - } - - // 递归渲染节点 - const renderWorkflow = (nodes: WorkflowNode[], level: number = 0) => { - return nodes - } - - const generateGraph = () => { - isGeneratingGraph.value = true - setTimeout(() => { - isGeneratingGraph.value = false - isGraphGenerated.value = true - if (workflowData.value.length > 0) { - workflowData.value[0].expanded = true - if (workflowData.value[0].children) { - workflowData.value[0].children.forEach(child => { - child.expanded = false - if (child.children) { - child.children.forEach(gc => gc.expanded = false) - } - }) - } - } - }, 2500) - } - - return { - // State - workflowData, - isGeneratingGraph, - isGraphGenerated, - - // Methods - toggleNode, - renderWorkflow, - generateGraph, - } -}