diff --git a/src/renderer/screens/CreateTemplateScreen.vue b/src/renderer/screens/CreateTemplateScreen.vue index a5e5a36..e7adfcb 100644 --- a/src/renderer/screens/CreateTemplateScreen.vue +++ b/src/renderer/screens/CreateTemplateScreen.vue @@ -2,7 +2,7 @@ @@ -158,7 +158,9 @@ max-width="500" > - {{ currentEditingItem ? '编辑目录' : '添加目录' }} + + {{ currentEditingItem ? '编辑目录' : '添加目录' }} + - - 取消 - + 取消 - {{ currentEditingItem ? '编辑文件' : '添加文件' }} + + {{ currentEditingItem ? '编辑文件' : '添加文件' }} +
选择文件会直接复制到目标位置 - 选择文件夹则会自动匹配该文件夹下的文件进行复制并且重命名 + + 选择文件夹则会自动匹配该文件夹下的文件进行复制并且重命名 +
- - 取消 - + 取消 {{ currentEditingItem ? '保存' : '添加' }} @@ -346,8 +346,6 @@ const fileFormValid = ref(false) const directoryInputRef = ref(null) const fileInputRef = ref(null) - - // Snackbar variables const snackbarVisible = ref(false) const snackbarMessage = ref('') @@ -360,7 +358,6 @@ const editingFile = ref<{ path: string; content: string } | null>(null) const editingFileContent = ref('') const parentDirectoryForNewItems = ref(null) // Track parent context const selectedSourcePath = ref('') // Track the selected source file or folder -const isAutoFindMode = ref(false) // Track if auto-find mode is enabled // Tree state const expandedNodes = ref([]) @@ -381,7 +378,7 @@ const treeStructure = ref([]) const isEditMode = computed(() => !!route.params.id) const treeItems = computed(() => { // 直接返回树状结构 - return treeStructure.value.map(node => convertToTreeItem(node)); + return treeStructure.value.map((node) => convertToTreeItem(node)) }) // 转换 TreeNode 到 TreeItem 的辅助函数 @@ -390,17 +387,18 @@ const convertToTreeItem = (node: TreeNode): 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; + 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) => !!v || `${fieldName}为必填项` +const requiredRule = (fieldName: string) => (v: string | null | undefined) => + !!v || `${fieldName}为必填项` // Watch for changes to detect unsaved changes watch( @@ -451,8 +449,6 @@ const updateTreeHeight = () => { treeHeight.value = window.innerHeight - 200 } - - const addRootDirectory = () => { newDirectoryPath.value = '' showDirectoryDialog.value = true @@ -510,39 +506,49 @@ const confirmAddDirectory = () => { // 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); + const parentNode = findNodeInTreeByName( + treeStructure.value, + parentDirectoryForNewItems.value + ) if (parentNode && parentNode.children) { - const duplicateExists = parentNode.children.some(child => - child.name === newDirectoryPath.value - ); + const duplicateExists = parentNode.children.some( + (child) => child.name === newDirectoryPath.value + ) if (duplicateExists) { - showSnackbar('当前目录下已存在同名节点!', 'error'); - return; + showSnackbar('当前目录下已存在同名节点!', 'error') + return } } } else { // Check at root level for duplicates - const duplicateExists = treeStructure.value.some(node => - node.name === newDirectoryPath.value - ); + const duplicateExists = treeStructure.value.some( + (node) => node.name === newDirectoryPath.value + ) if (duplicateExists) { - showSnackbar('根目录下已存在同名节点!', 'error'); - return; + showSnackbar('根目录下已存在同名节点!', 'error') + return } } const newId = `dir-${Date.now()}-${Math.random()}` // Check if we're editing an existing directory - if (currentEditingItem.value && currentEditingItem.value.type === 'directory') { + if ( + currentEditingItem.value && + currentEditingItem.value.type === 'directory' + ) { // Find and update the existing directory in the tree const updatedNode: TreeNode = { id: currentEditingItem.value.id, name: newDirectoryPath.value, path: fullPath, type: 'directory' - }; - treeStructure.value = updateNodeInTree(treeStructure.value, currentEditingItem.value.path, updatedNode) + } + treeStructure.value = updateNodeInTree( + treeStructure.value, + currentEditingItem.value.path, + updatedNode + ) } else { // Create new directory node const newNode: TreeNode = { @@ -555,7 +561,11 @@ const confirmAddDirectory = () => { // Add to tree structure if (parentDirectoryForNewItems.value) { // Add as child to the parent directory - treeStructure.value = addChildToNode(treeStructure.value, parentDirectoryForNewItems.value, newNode) + treeStructure.value = addChildToNode( + treeStructure.value, + parentDirectoryForNewItems.value, + newNode + ) } else { // Add as root node treeStructure.value.push(newNode) @@ -575,43 +585,53 @@ const confirmAddDirectory = () => { } // 在树状结构中更新节点的辅助函数 -const updateNodeInTree = (nodes: TreeNode[], oldPath: string, updatedNode: TreeNode): TreeNode[] => { - return nodes.map(node => { +const updateNodeInTree = ( + nodes: TreeNode[], + oldPath: string, + updatedNode: TreeNode +): TreeNode[] => { + return nodes.map((node) => { if (node.path === oldPath) { - return updatedNode; + return updatedNode } if (node.children) { return { ...node, children: updateNodeInTree(node.children, oldPath, updatedNode) - }; + } } - return node; - }); + 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 || []; +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) - }; + } } - return node; - }); + return node + }) } - - // Functions to close dialogs and reset state const closeDirectoryDialog = () => { showDirectoryDialog.value = false @@ -626,7 +646,6 @@ const closeFileDialog = () => { parentDirectoryForNewItems.value = null currentEditingItem.value = null selectedSourcePath.value = '' - isAutoFindMode.value = false } const selectAndAddFile = async () => { @@ -652,136 +671,72 @@ const selectAndAddFile = async () => { name: newFilePath.value, path: fullPath, type: 'file', - content: currentEditingItem.value.content, sourceFilePath: currentEditingItem.value.sourceFilePath - }; - treeStructure.value = updateNodeInTree(treeStructure.value, currentEditingItem.value.path, updatedNode) + } + treeStructure.value = updateNodeInTree( + treeStructure.value, + currentEditingItem.value.path, + 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); + const parentNode = findNodeInTreeByName( + treeStructure.value, + parentDirectoryForNewItems.value + ) if (parentNode && parentNode.children) { - const duplicateExists = parentNode.children.some(child => - child.name === newFilePath.value - ); + const duplicateExists = parentNode.children.some( + (child) => child.name === newFilePath.value + ) if (duplicateExists) { - showSnackbar('当前目录下已存在同名节点!', 'error'); - return; + showSnackbar('当前目录下已存在同名节点!', 'error') + return } } } else { // Check at root level for duplicates - const duplicateExists = treeStructure.value.some(node => - node.name === newFilePath.value - ); + const duplicateExists = treeStructure.value.some( + (node) => node.name === newFilePath.value + ) if (duplicateExists) { - showSnackbar('根目录下已存在同名节点!', 'error'); - return; + showSnackbar('根目录下已存在同名节点!', 'error') + return } } // Also check for duplicates using the full path (for backward compatibility) - const hasDuplicate = checkForDuplicateInTree(treeStructure.value, fullPath); + const hasDuplicate = checkForDuplicateInTree(treeStructure.value, fullPath) if (hasDuplicate) { showSnackbar('该文件路径已存在!') return } - // Check if we're in auto-find mode and have a selected folder - if (isAutoFindMode.value && selectedSourcePath.value) { - // Auto-find files in the selected folder - const foundFiles = await window.mainApi.invoke('msgFindFilesInFolder', selectedSourcePath.value) - - // Add all found files as template files - for (const foundFile of foundFiles) { - // Calculate relative path from selected folder to the found file - const relativePath = foundFile.replace(selectedSourcePath.value, '').substring(1) // Remove leading slash - const fullTargetPath = fullPath ? `${fullPath}/${relativePath}` : relativePath - - // Check for duplicates by full path - const hasDuplicateInTree = checkForDuplicateInTree(treeStructure.value, fullTargetPath); - if (!hasDuplicateInTree) { - const fileName = fullTargetPath.split('/').pop() || fullTargetPath; - - // Additionally, check for duplicate names in the same parent directory - let duplicateNameExists = false; - 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) { - duplicateNameExists = parentNode.children.some(child => - child.name === fileName - ); - } - } else { - // Check at root level for duplicates - duplicateNameExists = treeStructure.value.some(node => - node.name === fileName - ); - } - - if (duplicateNameExists) { - showSnackbar(`当前目录下已存在同名节点:${fileName}`, 'error'); - } else { - const newFileNode: TreeNode = { - id: `file-${Date.now()}-${Math.random()}`, - name: fileName, - path: fullTargetPath, - type: 'file', - sourceFilePath: foundFile - } - - // 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) - } - } - } - } - - // Reset selection state - selectedSourcePath.value = '' - isAutoFindMode.value = false - - showFileDialog.value = false - parentDirectoryForNewItems.value = null // Clear parent context after creation - currentEditingItem.value = null - - // After adding new files, expand all nodes to show the new structure - nextTick(() => { - expandAll() - }) - - newFilePath.value = '' - return - } - // If we have a selected file, just add it if (selectedSourcePath.value) { // Check for duplicate names in the same parent directory - let duplicateNameExists = false; + let duplicateNameExists = false if (parentDirectoryForNewItems.value) { // In the parent directory, check if a node with the same name already exists - const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value); + const parentNode = findNodeInTreeByName( + treeStructure.value, + parentDirectoryForNewItems.value + ) if (parentNode && parentNode.children) { - duplicateNameExists = parentNode.children.some(child => - child.name === newFilePath.value - ); + duplicateNameExists = parentNode.children.some( + (child) => child.name === newFilePath.value + ) } } else { // Check at root level for duplicates - duplicateNameExists = treeStructure.value.some(node => - node.name === newFilePath.value - ); + duplicateNameExists = treeStructure.value.some( + (node) => node.name === newFilePath.value + ) } if (duplicateNameExists) { - showSnackbar('当前目录下已存在同名节点!', 'error'); + showSnackbar('当前目录下已存在同名节点!', 'error') } else { const newFileNode: TreeNode = { id: newId, @@ -794,7 +749,11 @@ const selectAndAddFile = async () => { // Add to tree structure if (parentDirectoryForNewItems.value) { // Add as child to the parent directory - treeStructure.value = addChildToNode(treeStructure.value, parentDirectoryForNewItems.value, newFileNode) + treeStructure.value = addChildToNode( + treeStructure.value, + parentDirectoryForNewItems.value, + newFileNode + ) } else { // Add as root node treeStructure.value.push(newFileNode) @@ -803,7 +762,6 @@ const selectAndAddFile = async () => { // Reset selection state selectedSourcePath.value = '' - isAutoFindMode.value = false showFileDialog.value = false parentDirectoryForNewItems.value = null // Clear parent context after creation @@ -825,7 +783,6 @@ const selectAndAddFile = async () => { // Reset selection state after editing selectedSourcePath.value = '' - isAutoFindMode.value = false showFileDialog.value = false parentDirectoryForNewItems.value = null @@ -840,18 +797,21 @@ const selectAndAddFile = async () => { } // 检查树中是否有重复路径的辅助函数 -const checkForDuplicateInTree = (nodes: TreeNode[], pathToCheck: string): boolean => { +const checkForDuplicateInTree = ( + nodes: TreeNode[], + pathToCheck: string +): boolean => { for (const node of nodes) { if (node.path === pathToCheck) { - return true; + return true } if (node.children) { if (checkForDuplicateInTree(node.children, pathToCheck)) { - return true; + return true } } } - return false; + return false } const goBack = async () => { @@ -876,7 +836,7 @@ const expandAll = () => { const allIds: string[] = [] const collectIds = (items: TreeItem[]) => { - items.forEach(item => { + items.forEach((item) => { if (item.children && item.children.length > 0) { allIds.push(item.id) collectIds(item.children) @@ -901,16 +861,15 @@ const editFile = (item: TreeItem) => { // 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); + const node = findNodeInTree(treeStructure.value, item.id) if (node) { const nodeData = { id: node.id, path: node.path, type: node.type, - content: node.content, // For files sourceFilePath: node.sourceFilePath, // For files - name: node.name, - }; + name: node.name + } if (node.type === 'directory') { showEditDirectoryDialog(nodeData) } else { @@ -925,44 +884,50 @@ const editItem = (item: TreeItem) => { const findNodeInTree = (nodes: TreeNode[], nodeId: string): TreeNode | null => { for (const node of nodes) { if (node.id === nodeId) { - return node; + return node } if (node.children) { - const found = findNodeInTree(node.children, nodeId); + const found = findNodeInTree(node.children, nodeId) if (found) { - return found; + return found } } } - return null; + return null } // 通过节点名称查找节点的辅助函数 -const findNodeInTreeByName = (nodes: TreeNode[], nodeName: string): TreeNode | null => { +const findNodeInTreeByName = ( + nodes: TreeNode[], + nodeName: string +): TreeNode | null => { for (const node of nodes) { if (node.name === nodeName) { - return node; + return node } if (node.children) { - const found = findNodeInTreeByName(node.children, nodeName); + const found = findNodeInTreeByName(node.children, nodeName) if (found) { - return found; + return found } } } - return null; + return null } // 在指定节点中通过名称查找子节点的辅助函数 -const findChildNodeByName = (parentNode: TreeNode, childName: string): TreeNode | null => { +const findChildNodeByName = ( + parentNode: TreeNode, + childName: string +): TreeNode | null => { if (parentNode.children) { for (const child of parentNode.children) { if (child.name === childName) { - return child; + return child } } } - return null; + return null } // Show dialog to edit directory @@ -983,7 +948,6 @@ const showEditFileDialog = (file: TreeNode) => { // If the file has a source file path, set it in the selection state if (file.sourceFilePath) { selectedSourcePath.value = file.sourceFilePath - isAutoFindMode.value = false } showFileDialog.value = true @@ -1005,25 +969,24 @@ const deleteItem = async (item: TreeItem) => { if (!confirmed) return // 从树状结构中删除项目 - treeStructure.value = removeItemFromTree(treeStructure.value, item.id); + treeStructure.value = removeItemFromTree(treeStructure.value, item.id) } // 从树状结构中删除项目的辅助函数 const removeItemFromTree = (nodes: TreeNode[], itemId: string): TreeNode[] => { - return nodes.filter(node => node.id !== itemId) // 过滤掉要删除的节点 - .map(node => { + return nodes + .filter((node) => node.id !== itemId) // 过滤掉要删除的节点 + .map((node) => { if (node.children) { return { ...node, children: removeItemFromTree(node.children, itemId) - }; + } } - return node; - }); + return node + }) } - - // Show snackbar message const showSnackbar = (message: string, color: string = 'error') => { snackbarMessage.value = message @@ -1038,7 +1001,6 @@ const selectSourceFileOrFolder = async () => { if (result && result.filePath) { selectedSourcePath.value = result.filePath - isAutoFindMode.value = result.isDirectory // 如果是目录,则启用自动查找模式 } } diff --git a/src/renderer/store/template.ts b/src/renderer/store/template.ts index 6b019be..d130355 100644 --- a/src/renderer/store/template.ts +++ b/src/renderer/store/template.ts @@ -5,11 +5,9 @@ import { ref } from 'vue' export interface TreeNode { id: string name: string - path: string // 完整路径 + path: string // 完整路径 type: 'directory' | 'file' children?: TreeNode[] - // 文件特定属性 - content?: string sourceFilePath?: string }