diff --git a/QWEN.md b/QWEN.md index a28acea..0cc7f30 100644 --- a/QWEN.md +++ b/QWEN.md @@ -64,6 +64,9 @@ pnpm dev:debug # Force reinstall dependencies and start development pnpm dev:debug:force + +# run Typescript Type check +pnpm typecheck ``` ### Building @@ -103,11 +106,6 @@ pnpm lint # Fix linting issues automatically pnpm lint:fix -# Format code with Prettier -pnpm format - -# Format and fix code automatically -pnpm format:fix ``` ## Key Features @@ -231,4 +229,6 @@ Building creates different distribution formats based on the platform: Artifacts are named with the format `${productName} ${version}_${arch}.${ext}` and stored in the `release/${version}` directory. +run `pnpm typecheck` before finish the task + Always respond in 中文 diff --git a/package.json b/package.json index 4cbe0a0..7e3d8c8 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "dev": "vite", "dev:debug": "vite -d", "dev:debug:force": "vite -d --force", + "typecheck": "vue-tsc --noEmit", "build": "npm run build:pre && electron-builder --config=buildAssets/builder/config.js", "build:pre": "vue-tsc --noEmit && vite build", "build:all": "npm run build:pre && electron-builder --config=buildAssets/builder/config.js -wml", @@ -33,8 +34,6 @@ "build:win": "npm run build:pre && electron-builder --config=buildAssets/builder/config.js --windows", "lint": "eslint . --ext .js,.ts,.vue .", "lint:fix": "eslint . --ext .js,.ts,.vue --fix .", - "format": "prettier .", - "format:fix": "prettier . --write", "test": "npm run build:pre && playwright test", "test:linux": "npm run build:pre && xvfb-run --auto-servernum --server-args='-screen 0, 1280x960x24' -- playwright test" }, diff --git a/src/renderer/components/TemplateTree.vue b/src/renderer/components/TemplateTree.vue index b3527f9..3ea3b49 100644 --- a/src/renderer/components/TemplateTree.vue +++ b/src/renderer/components/TemplateTree.vue @@ -3,7 +3,6 @@ variant="outlined" class="pa-2" :height="height" - @contextmenu.prevent="emit('showContextMenu', $event, null)" > {{ item.name }} - - mdi-plus - - 添加到目录 - - @@ -61,23 +42,24 @@ class="d-flex align-center ga-1" > - mdi-pencil + mdi-folder-plus - {{ item.type === 'file' ? '编辑文件' : '编辑目录' }} + 添加到目录 + + mdi-pencil + + {{ item.type === 'file' ? '编辑文件' : '编辑目录' }} + + + @@ -133,39 +129,12 @@ v-if="!readOnly" class="text-caption" > - 右键点击空白区域添加根目录或文件 + 点击上方按钮添加根目录或文件

- - - - - - - {{ currentContextItem ? '添加子目录' : '添加根目录' }} - - - - - - {{ currentContextItem ? '添加子文件' : '添加根文件' }} - - - - diff --git a/src/renderer/screens/CreateTemplateScreen.vue b/src/renderer/screens/CreateTemplateScreen.vue index 2f663b0..a7a29f7 100644 --- a/src/renderer/screens/CreateTemplateScreen.vue +++ b/src/renderer/screens/CreateTemplateScreen.vue @@ -142,19 +142,12 @@ :items="treeItems" :height="treeHeight" v-model:expanded="expandedNodes" - v-model:showContextMenuVar="showContextMenuVar" - :context-menu-x="contextMenuX" - :context-menu-y="contextMenuY" - :current-context-item="currentContextItem" :empty-text="'暂无文件或目录'" :read-only="false" - @showContextMenu="showContextMenu" @add-new-item-to-current-directory="addNewItemToCurrentDirectory" @edit-file="editFile" @edit-item="editItem" @delete-item="deleteItem" - @add-directory="addDirectory" - @add-file="addFile" @add-file-to-directory="addFileToDirectory" /> @@ -183,10 +176,10 @@ - - 取消 + > + 取消 - +
- +
@@ -245,7 +238,7 @@ {{ selectedSourcePath }}
- + 自动寻找文件夹内的文件 - + - - 取消 + > + 取消 (null) const fileInputRef = ref(null) -// Context menu -const showContextMenuVar = ref(false) -const contextMenuX = ref(0) -const contextMenuY = ref(0) -const currentContextItem = ref(null) + // Snackbar variables const snackbarVisible = ref(false) @@ -440,10 +429,10 @@ const treeItems = computed(() => { for (let i = 0; i < pathParts.length; i++) { const part = pathParts[i] const isLastPart = i === pathParts.length - 1 - + // Check if this part already exists in the current level let existingItem = currentLevel.find(item => item.name === part) - + if (!existingItem) { // Create new directory item const newDir: TreeItem = { @@ -455,7 +444,7 @@ const treeItems = computed(() => { currentLevel.push(newDir) existingItem = newDir } - + // Move to the next level if not the last part if (!isLastPart && existingItem.children) { currentLevel = existingItem.children @@ -467,16 +456,16 @@ const treeItems = computed(() => { files.value.forEach((file) => { const pathParts = file.path.split('/').filter(part => part !== '') const fileName = pathParts.pop() // Get the last part as filename - + if (!fileName) return // Skip if no filename - + let currentLevel = root.children || [] - + // Navigate to the appropriate directory for the file for (let i = 0; i < pathParts.length; i++) { const part = pathParts[i] const dirItem = currentLevel.find(item => item.name === part && item.type === 'directory') - + if (dirItem && dirItem.children) { currentLevel = dirItem.children } else { @@ -491,7 +480,7 @@ const treeItems = computed(() => { currentLevel = newDir.children || [] } } - + // Add the file to the current level currentLevel.push({ id: `file-${fileName}-${Date.now()}-${Math.random()}`, @@ -554,18 +543,7 @@ const updateTreeHeight = () => { treeHeight.value = window.innerHeight - 200 } -const showContextMenu = (event: MouseEvent, item: TreeItem | null) => { - event.preventDefault() - contextMenuX.value = event.clientX - contextMenuY.value = event.clientY - currentContextItem.value = item - showContextMenuVar.value = false // Close first to reset position - nextTick(() => { - contextMenuX.value = event.clientX - contextMenuY.value = event.clientY - showContextMenuVar.value = true - }) -} + const addRootDirectory = () => { newDirectoryPath.value = '' @@ -580,8 +558,6 @@ const addRootFile = () => { } const addDirectory = (parentItem: TreeItem | null = null) => { - showContextMenuVar.value = false - currentContextItem.value = parentItem parentDirectoryForNewItems.value = parentItem ? parentItem.name : null // Store parent context newDirectoryPath.value = '' // Don't pre-fill the path showDirectoryDialog.value = true @@ -589,7 +565,6 @@ const addDirectory = (parentItem: TreeItem | null = null) => { } const addFile = (parentItem: TreeItem | null = null) => { - showContextMenuVar.value = false parentDirectoryForNewItems.value = parentItem ? parentItem.name : null // Store parent context newFilePath.value = '' // Don't pre-fill the path showFileDialog.value = true @@ -598,7 +573,6 @@ const addFile = (parentItem: TreeItem | null = null) => { // Add a file directly to a specific directory const addFileToDirectory = (directoryItem: TreeItem) => { - showContextMenuVar.value = false parentDirectoryForNewItems.value = directoryItem.name // Store the directory as parent newFilePath.value = '' // Don't pre-fill the path showFileDialog.value = true @@ -606,7 +580,6 @@ const addFileToDirectory = (directoryItem: TreeItem) => { } const addNewItemToCurrentDirectory = (directoryItem: TreeItem) => { - currentContextItem.value = directoryItem parentDirectoryForNewItems.value = directoryItem.name // Store parent context newDirectoryPath.value = '' // Don't pre-fill the path showDirectoryDialog.value = true @@ -620,8 +593,8 @@ const confirmAddDirectory = () => { let fullPath = newDirectoryPath.value if (parentDirectoryForNewItems.value) { // Make sure parent directory ends with a slash before appending - const parentPath = parentDirectoryForNewItems.value.endsWith('/') - ? parentDirectoryForNewItems.value + const parentPath = parentDirectoryForNewItems.value.endsWith('/') + ? parentDirectoryForNewItems.value : parentDirectoryForNewItems.value + '/' fullPath = parentPath + newDirectoryPath.value } @@ -632,7 +605,7 @@ const confirmAddDirectory = () => { if (index !== -1) { // Update the existing directory path directories.value[index].path = fullPath - + // If the directory path changes, update any files/dirs that were inside it updatePathsForRenamedDirectory(currentEditingItem.value.path, fullPath) } @@ -654,9 +627,8 @@ const confirmAddDirectory = () => { showDirectoryDialog.value = false newDirectoryPath.value = '' parentDirectoryForNewItems.value = null // Clear parent context after creation - currentContextItem.value = null currentEditingItem.value = null - + // If we added to a parent directory, make sure it's expanded if (parentDirectoryForNewItems.value) { if (!expandedNodes.value.includes(`dir-${parentDirectoryForNewItems.value}`)) { @@ -677,7 +649,7 @@ const updatePathsForRenamedDirectory = (oldPath: string, newPath: string) => { } return file }) - + // Update all directories that were under the old directory directories.value = directories.value.map(dir => { if (dir.path.startsWith(oldPath + '/') || dir.path === oldPath) { @@ -695,7 +667,6 @@ const closeDirectoryDialog = () => { showDirectoryDialog.value = false newDirectoryPath.value = '' parentDirectoryForNewItems.value = null - currentContextItem.value = null currentEditingItem.value = null } @@ -703,7 +674,6 @@ const closeFileDialog = () => { showFileDialog.value = false newFilePath.value = '' parentDirectoryForNewItems.value = null - currentContextItem.value = null currentEditingItem.value = null selectedSourcePath.value = '' isAutoFindMode.value = false @@ -716,8 +686,8 @@ const selectAndAddFile = async () => { let fullPath = newFilePath.value if (parentDirectoryForNewItems.value) { // Make sure parent directory ends with a slash before appending - const parentPath = parentDirectoryForNewItems.value.endsWith('/') - ? parentDirectoryForNewItems.value + const parentPath = parentDirectoryForNewItems.value.endsWith('/') + ? parentDirectoryForNewItems.value : parentDirectoryForNewItems.value + '/' fullPath = parentPath + newFilePath.value } @@ -744,13 +714,13 @@ const selectAndAddFile = async () => { 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 const duplicate = files.value.some(f => f.path === fullTargetPath) if (!duplicate) { @@ -761,19 +731,18 @@ const selectAndAddFile = async () => { files.value.push(newFile) } } - + // Reset selection state selectedSourcePath.value = '' isAutoFindMode.value = false - + showFileDialog.value = false newFilePath.value = '' parentDirectoryForNewItems.value = null // Clear parent context after creation - currentContextItem.value = null currentEditingItem.value = null return } - + // If we have a selected file, just add it if (selectedSourcePath.value) { const newFile = { @@ -790,11 +759,10 @@ const selectAndAddFile = async () => { showFileDialog.value = false newFilePath.value = '' parentDirectoryForNewItems.value = null // Clear parent context after creation - currentContextItem.value = null currentEditingItem.value = null return } - + // Otherwise, show file selection dialog showSnackbar('请先选择一个文件或文件夹', 'warning') return @@ -803,11 +771,10 @@ const selectAndAddFile = async () => { // Reset selection state after editing selectedSourcePath.value = '' isAutoFindMode.value = false - + showFileDialog.value = false newFilePath.value = '' parentDirectoryForNewItems.value = null - currentContextItem.value = null currentEditingItem.value = null } @@ -820,7 +787,7 @@ const goBack = async () => { cancelText: '取消', confirmColor: 'warning' }) - + if (confirmed) { router.push('/templates') } @@ -831,7 +798,7 @@ const goBack = async () => { const expandAll = () => { const allIds: string[] = [] - + const collectIds = (items: TreeItem[]) => { items.forEach(item => { if (item.children && item.children.length > 0) { @@ -840,7 +807,7 @@ const expandAll = () => { } }) } - + collectIds(treeItems.value) expandedNodes.value = allIds } @@ -899,13 +866,13 @@ const showEditFileDialog = (file: { path: string; content?: string; sourceFilePa // Set up for editing an existing file currentEditingItem.value = { ...file, type: 'file' } newFilePath.value = file.path // Set the current path for editing - + // 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 autoFocusFileInput() } @@ -921,7 +888,7 @@ const deleteItem = async (item: TreeItem) => { cancelText: '取消', confirmColor: 'error' }) - + if (!confirmed) return if (item.type === 'directory') { @@ -931,7 +898,7 @@ const deleteItem = async (item: TreeItem) => { // Exclude if exact match or it's a subdirectory return !isSubPath(d.path, item.name); }); - + // Also remove files that are inside this directory files.value = files.value.filter(f => { // Exclude if it's inside the directory being deleted