From 47fb017e211ccae6fd7eaaeed84c9c8cd7110a77 Mon Sep 17 00:00:00 2001 From: Jasery Date: Fri, 31 Oct 2025 13:41:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E6=A8=A1=E6=9D=BF=E5=88=9B=E5=BB=BA):?= =?UTF-8?q?=20=E9=87=8D=E6=9E=84=E6=A8=A1=E6=9D=BF=E6=A0=91=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 parentDirectory 类型从 string 改为 TreeNode 以直接引用节点 - 移除冗余的 TreeItem 接口和转换逻辑 - 简化文件/目录添加和更新逻辑,直接操作 TreeNode - 使用新的 generateUniqueId 工具函数生成唯一ID - 移除不必要的路径拼接和重复检查逻辑 --- src/renderer/components/DirectoryDialog.vue | 2 +- src/renderer/components/FileDialog.vue | 14 +- src/renderer/screens/CreateTemplateScreen.vue | 258 +++++------------- src/renderer/utils/index.ts | 11 + 4 files changed, 78 insertions(+), 207 deletions(-) diff --git a/src/renderer/components/DirectoryDialog.vue b/src/renderer/components/DirectoryDialog.vue index 9cb5f12..6bdd79a 100644 --- a/src/renderer/components/DirectoryDialog.vue +++ b/src/renderer/components/DirectoryDialog.vue @@ -44,7 +44,7 @@ import { TreeNode } from '@/renderer/store/template' interface Props { modelValue: boolean isEditMode?: boolean - parentDirectory?: string | null + parentDirectory?: TreeNode | null editingItem?: TreeNode | null } diff --git a/src/renderer/components/FileDialog.vue b/src/renderer/components/FileDialog.vue index 04d4435..2add1f5 100644 --- a/src/renderer/components/FileDialog.vue +++ b/src/renderer/components/FileDialog.vue @@ -70,13 +70,13 @@ import { TreeNode } from '@/renderer/store/template' interface Props { modelValue: boolean isEditMode?: boolean - parentDirectory?: string | null + parentDirectory?: TreeNode | null editingItem?: TreeNode | null } interface Emits { (e: 'update:modelValue', value: boolean): void - (e: 'confirm', data: { path: string; fullPath: string; sourceFilePath?: string }): void + (e: 'confirm', data: { path: string; sourceFilePath?: string }): void } const props = withDefaults(defineProps(), { @@ -137,19 +137,9 @@ const selectSourceFileOrFolder = async () => { const confirm = () => { if (!filePath.value.trim()) return - // Construct the full path if there's a parent directory - let fullPath = filePath.value - if (props.parentDirectory) { - // Make sure parent directory ends with a slash before appending - const parentPath = props.parentDirectory.endsWith('/') - ? props.parentDirectory - : props.parentDirectory + '/' - fullPath = parentPath + filePath.value - } emit('confirm', { path: filePath.value, - fullPath, sourceFilePath: selectedSourcePath.value || undefined }) diff --git a/src/renderer/screens/CreateTemplateScreen.vue b/src/renderer/screens/CreateTemplateScreen.vue index a6c0d09..5b607ad 100644 --- a/src/renderer/screens/CreateTemplateScreen.vue +++ b/src/renderer/screens/CreateTemplateScreen.vue @@ -111,7 +111,7 @@ (null) +const parentDirectoryForNewItems = ref(null) const currentEditingItem = ref(null) @@ -180,38 +181,15 @@ const currentEditingItem = ref(null) const expandedNodes = ref([]) const treeHeight = ref(600) -// Define type for tree items -interface TreeItem { - id: string - name: string - type: 'directory' | 'file' - children?: TreeItem[] -} + // Item state - 使用树状结构 const treeStructure = ref([]) // Computed const isEditMode = computed(() => !!route.params.id) -const treeItems = computed(() => { - // 直接返回树状结构 - return treeStructure.value.map((node) => convertToTreeItem(node)) -}) -// 转换 TreeNode 到 TreeItem 的辅助函数 -const convertToTreeItem = (node: TreeNode): TreeItem => { - const treeItem: TreeItem = { - id: node.id, - name: node.name, - type: node.type - } - if (node.children && node.children.length > 0) { - treeItem.children = node.children.map((child) => convertToTreeItem(child)) - } - - return treeItem -} // Validation rules const requiredRule = (fieldName: string) => (v: string | null | undefined) => @@ -278,49 +256,21 @@ const addRootFile = () => { // Add a file directly to a specific directory -const addFileToDirectory = (directoryItem: TreeItem) => { - parentDirectoryForNewItems.value = directoryItem.name // Store the directory as parent +const addFileToDirectory = (directoryItem: TreeNode) => { + parentDirectoryForNewItems.value = directoryItem // Store the directory node as parent currentEditingItem.value = null showFileDialog.value = true } -const addNewItemToCurrentDirectory = (directoryItem: TreeItem) => { - parentDirectoryForNewItems.value = directoryItem.name // Store parent context +const addNewItemToCurrentDirectory = (directoryItem: TreeNode) => { + parentDirectoryForNewItems.value = directoryItem // Store the directory node as parent currentEditingItem.value = null showDirectoryDialog.value = true } const handleDirectoryDialogConfirm = (data: { path: string }) => { const { path } = data - - // Check for duplicate names in the same parent directory - if (parentDirectoryForNewItems.value) { - // In the parent directory, check if a node with the same name already exists - const parentNode = findNodeInTreeByName( - treeStructure.value, - parentDirectoryForNewItems.value - ) - if (parentNode && parentNode.children) { - const duplicateExists = parentNode.children.some( - (child) => child.name === path - ) - if (duplicateExists) { - snackbar.error('当前目录下已存在同名节点!') - return - } - } - } else { - // Check at root level for duplicates - const duplicateExists = treeStructure.value.some( - (node) => node.name === path - ) - if (duplicateExists) { - snackbar.error('根目录下已存在同名节点!') - return - } - } - - const newId = `dir-${Date.now()}-${Math.random()}` + const newId = generateUniqueId('dir') // Check if we're editing an existing directory if ( @@ -329,16 +279,18 @@ const handleDirectoryDialogConfirm = (data: { path: string }) => { ) { // Find and update the existing directory in the tree const updatedNode: TreeNode = { - id: currentEditingItem.value.id, + ...currentEditingItem.value, name: path, path: path, type: 'directory' } + console.log('updatedNode', updatedNode) treeStructure.value = updateNodeInTree( treeStructure.value, currentEditingItem.value.path, updatedNode ) + console.log('update treeStructure', treeStructure.value) } else { // Create new directory node const newNode: TreeNode = { @@ -350,13 +302,29 @@ const handleDirectoryDialogConfirm = (data: { path: string }) => { // Add to tree structure if (parentDirectoryForNewItems.value) { + // In the parent directory, check if a node with the same name already exists + const parentNode = parentDirectoryForNewItems.value + if (parentNode.children) { + const duplicateExists = parentNode.children.some( + (child) => child.name === path + ) + if (duplicateExists) { + snackbar.error('当前目录下已存在同名节点!') + return + } + } // Add as child to the parent directory - treeStructure.value = addChildToNode( - treeStructure.value, - parentDirectoryForNewItems.value, - newNode - ) + parentNode.children = parentNode.children || [] + parentNode.children.push(newNode) } else { + // Check at root level for duplicates + const duplicateExists = treeStructure.value.some( + (node) => node.name === path + ) + if (duplicateExists) { + snackbar.error('根目录下已存在同名节点!') + return + } // Add as root node treeStructure.value.push(newNode) } @@ -372,45 +340,17 @@ const handleDirectoryDialogConfirm = (data: { path: string }) => { // 在树状结构中更新节点的辅助函数 const updateNodeInTree = ( nodes: TreeNode[], - oldPath: string, + oldId: string, updatedNode: TreeNode ): TreeNode[] => { return nodes.map((node) => { - if (node.path === oldPath) { + if (node.id === oldId) { return updatedNode } if (node.children) { return { ...node, - children: updateNodeInTree(node.children, oldPath, updatedNode) - } - } - return node - }) -} - -// 向节点添加子节点的辅助函数 -const addChildToNode = ( - nodes: TreeNode[], - parentName: string, - childNode: TreeNode -): TreeNode[] => { - return nodes.map((node) => { - if ( - node.name === parentName || - (node.path && node.path.endsWith('/' + parentName)) || - node.path === parentName - ) { - const children = node.children || [] - return { - ...node, - children: [...children, childNode] - } - } - if (node.children) { - return { - ...node, - children: addChildToNode(node.children, parentName, childNode) + children: updateNodeInTree(node.children, oldId, updatedNode) } } return node @@ -418,10 +358,12 @@ const addChildToNode = ( } -const handleFileDialogConfirm = (data: { path: string; fullPath: string; sourceFilePath?: string }) => { - const { path, fullPath, sourceFilePath } = data - const newId = `file-${Date.now()}-${Math.random()}` + +const handleFileDialogConfirm = (data: { path: string; sourceFilePath?: string }) => { + const { path, sourceFilePath } = data + + const newId = generateUniqueId('file') // Check if we're editing an existing file if (currentEditingItem.value && currentEditingItem.value.type === 'file') { @@ -429,24 +371,21 @@ const handleFileDialogConfirm = (data: { path: string; fullPath: string; sourceF const updatedNode: TreeNode = { id: currentEditingItem.value.id, name: path, - path: fullPath, + path: path, type: 'file', sourceFilePath: sourceFilePath } treeStructure.value = updateNodeInTree( treeStructure.value, - currentEditingItem.value.path, + currentEditingItem.value.id, updatedNode ) } else { // Check for duplicate names in the same parent directory if (parentDirectoryForNewItems.value) { // In the parent directory, check if a node with the same name already exists - const parentNode = findNodeInTreeByName( - treeStructure.value, - parentDirectoryForNewItems.value - ) - if (parentNode && parentNode.children) { + const parentNode = parentDirectoryForNewItems.value + if (parentNode.children) { const duplicateExists = parentNode.children.some( (child) => child.name === path ) @@ -466,65 +405,29 @@ const handleFileDialogConfirm = (data: { path: string; fullPath: string; sourceF } } - // Also check for duplicates using the full path (for backward compatibility) - const hasDuplicate = checkForDuplicateInTree(treeStructure.value, fullPath) - if (hasDuplicate) { - snackbar.error('该文件路径已存在!') - return + const newFileNode: TreeNode = { + id: newId, + name: path, + path: path, + type: 'file', + sourceFilePath } - // If we have a selected file, just add it - if (sourceFilePath) { - const newFileNode: TreeNode = { - id: newId, - name: path, - path: fullPath, - type: 'file', - sourceFilePath - } - - // Add to tree structure - if (parentDirectoryForNewItems.value) { - // Add as child to the parent directory - treeStructure.value = addChildToNode( - treeStructure.value, - parentDirectoryForNewItems.value, - newFileNode - ) - } else { - // Add as root node - treeStructure.value.push(newFileNode) - } + // Add to tree structure + if (parentDirectoryForNewItems.value) { + // Add as child to the parent directory + const parentNode = parentDirectoryForNewItems.value + parentNode.children = parentNode.children || [] + parentNode.children.push(newFileNode) } else { - // Otherwise, show warning - snackbar.warning('请先选择一个文件或文件夹') - return + // Add as root node + treeStructure.value.push(newFileNode) } } showFileDialog.value = false parentDirectoryForNewItems.value = null // Clear parent context after creation currentEditingItem.value = null - - -} - -// 检查树中是否有重复路径的辅助函数 -const checkForDuplicateInTree = ( - nodes: TreeNode[], - pathToCheck: string -): boolean => { - for (const node of nodes) { - if (node.path === pathToCheck) { - return true - } - if (node.children) { - if (checkForDuplicateInTree(node.children, pathToCheck)) { - return true - } - } - } - return false } const goBack = async () => { @@ -547,25 +450,11 @@ const goBack = async () => { // Unified method to edit items (both files and directories) -// This function needs to find the actual path of the item in our hierarchical tree -const editItem = (item: TreeItem) => { - // Find the node in the tree structure - const node = findNodeInTree(treeStructure.value, item.id) - if (node) { - const nodeData = { - id: node.id, - path: node.path, - type: node.type, - sourceFilePath: node.sourceFilePath, // For files - name: node.name - } - if (node.type === 'directory') { - showEditDirectoryDialog(nodeData) - } else { - showEditFileDialog(nodeData) - } +const editItem = (item: TreeNode) => { + if (item.type === 'directory') { + showEditDirectoryDialog(item) } else { - snackbar.error('无法找到对应的节点') + showEditFileDialog(item) } } @@ -585,25 +474,6 @@ const findNodeInTree = (nodes: TreeNode[], nodeId: string): TreeNode | null => { return null } -// 通过节点名称查找节点的辅助函数 -const findNodeInTreeByName = ( - nodes: TreeNode[], - nodeName: string -): TreeNode | null => { - for (const node of nodes) { - if (node.name === nodeName) { - return node - } - if (node.children) { - const found = findNodeInTreeByName(node.children, nodeName) - if (found) { - return found - } - } - } - return null -} - // Show dialog to edit directory const showEditDirectoryDialog = (directory: TreeNode) => { @@ -621,7 +491,7 @@ const showEditFileDialog = (file: TreeNode) => { showFileDialog.value = true } -const deleteItem = async (item: TreeItem) => { +const deleteItem = async (item: TreeNode) => { const confirmed = await ConfirmDialogService.confirm({ title: '删除确认', message: '确定要删除此项吗?', diff --git a/src/renderer/utils/index.ts b/src/renderer/utils/index.ts index a6a98c4..fe237af 100644 --- a/src/renderer/utils/index.ts +++ b/src/renderer/utils/index.ts @@ -9,3 +9,14 @@ export async function openExternal(url: string): Promise { export async function openFile(type: string): Promise { return window.mainApi.invoke('msgOpenFile', type) } + +/** + * 生成唯一ID + * @param prefix ID前缀,默认为空 + * @returns 唯一ID字符串 + */ +export function generateUniqueId(prefix: string = ''): string { + const timestamp = Date.now().toString(36) // 转换为36进制,更短 + const randomStr = Math.random().toString(36).substring(2, 9) // 7位随机字符 + return prefix ? `${prefix}-${timestamp}-${randomStr}` : `${timestamp}-${randomStr}` +}