feat: 添加父目录跟踪功能,优化目录和文件的路径构建逻辑

This commit is contained in:
zhanggy committed 2025-10-28 13:46:54 +08:00
1 parent 6431049d05
commit de7af2f650
2 files changed
+146 -21

No files matched your search

+44 -1
View File
@@ -14,6 +14,7 @@
activatable activatable
open-on-click open-on-click
:return-object="false" :return-object="false"
:hoverable="true"
> >
<template #prepend="{ item }"> <template #prepend="{ item }">
<v-icon <v-icon
@@ -202,12 +203,14 @@ const emit = defineEmits([
cursor: pointer; cursor: pointer;
} }
/* Tree node styling */
:deep(.v-treeview-node__root), :deep(.v-treeview-node__root),
:deep(.v-treeview-node__children .v-treeview-node__root) { :deep(.v-treeview-node__children .v-treeview-node__root) {
padding: 4px; padding: 4px;
margin: 2px 0; margin: 2px 0;
border-radius: 4px; border-radius: 4px;
transition: background-color 0.2s; transition: background-color 0.2s;
position: relative;
} }
:deep(.v-treeview-node__root:hover), :deep(.v-treeview-node__root:hover),
@@ -215,7 +218,47 @@ const emit = defineEmits([
background-color: rgba(0, 0, 0, 0.04); background-color: rgba(0, 0, 0, 0.04);
} }
/* Indentation guides to show hierarchy */
:deep(.v-treeview-node__level) { :deep(.v-treeview-node__level) {
margin-right: 4px; margin-right: 8px;
position: relative;
}
/* Vertical connector lines */
:deep(.v-treeview-node) {
position: relative;
}
/* Add connector lines */
:deep(.v-treeview-node::before) {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 12px;
width: 1px;
background: rgba(0, 0, 0, 0.12);
z-index: 1;
}
/* Horizontal connector lines for children */
:deep(.v-treeview-node__children) {
position: relative;
}
:deep(.v-treeview-node__children::before) {
content: '';
position: absolute;
top: 0;
left: -16px;
width: 16px;
height: 1px;
background: rgba(0, 0, 0, 0.12);
}
/* Hide connector for root level */
:deep(.v-treeview > .v-treeview-node > .v-treeview-node__root::before),
:deep(.v-treeview > .v-treeview-node > .v-treeview-node__children::before) {
display: none;
} }
</style> </style>
+102 -20
View File
@@ -336,6 +336,7 @@ const newDirectoryPath = ref('')
const newFilePath = ref('') const newFilePath = ref('')
const editingFile = ref<{ path: string; content: string } | null>(null) const editingFile = ref<{ path: string; content: string } | null>(null)
const editingFileContent = ref('') const editingFileContent = ref('')
const parentDirectoryForNewItems = ref<string | null>(null) // Track parent context
// Tree state // Tree state
const expandedNodes = ref<string[]>([]) const expandedNodes = ref<string[]>([])
@@ -356,28 +357,84 @@ const files = ref<{ path: string; content: string }[]>([])
// Computed // Computed
const isEditMode = computed(() => !!route.params.id) const isEditMode = computed(() => !!route.params.id)
const treeItems = computed<TreeItem[]>(() => { const treeItems = computed<TreeItem[]>(() => {
const items: TreeItem[] = [] // Create root structure
const root: TreeItem = {
id: 'root',
name: 'root',
type: 'directory',
children: []
}
// Add directories // Process each directory
directories.value.forEach((dir) => { directories.value.forEach((dir) => {
items.push({ const pathParts = dir.path.split('/').filter(part => part !== '') // Split path and remove empty parts
id: `dir-${dir.path}`, let currentLevel = root.children || []
name: dir.path,
type: 'directory', // Navigate/create the directory structure
children: [] 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 = {
id: `dir-${part}-${Date.now()}-${Math.random()}`, // Unique ID
name: part,
type: 'directory',
children: []
}
currentLevel.push(newDir)
existingItem = newDir
}
// Move to the next level if not the last part
if (!isLastPart && existingItem.children) {
currentLevel = existingItem.children
}
}
}) })
// Add files // Process each file and add to the appropriate directory
files.value.forEach((file) => { files.value.forEach((file) => {
items.push({ const pathParts = file.path.split('/').filter(part => part !== '')
id: `file-${file.path}`, const fileName = pathParts.pop() // Get the last part as filename
name: file.path,
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 {
// If the directory doesn't exist, create it
const newDir: TreeItem = {
id: `dir-${part}-${Date.now()}-${Math.random()}`,
name: part,
type: 'directory',
children: []
}
currentLevel.push(newDir)
currentLevel = newDir.children || []
}
}
// Add the file to the current level
currentLevel.push({
id: `file-${fileName}-${Date.now()}-${Math.random()}`,
name: fileName,
type: 'file' type: 'file'
}) })
}) })
return items return root.children || []
}) })
// Validation rules // Validation rules
@@ -459,21 +516,24 @@ const addRootFile = () => {
const addDirectory = (parentItem: TreeItem | null = null) => { const addDirectory = (parentItem: TreeItem | null = null) => {
showContextMenuVar.value = false showContextMenuVar.value = false
currentContextItem.value = parentItem currentContextItem.value = parentItem
newDirectoryPath.value = parentItem ? `${parentItem.name}/` : '' parentDirectoryForNewItems.value = parentItem ? parentItem.name : null // Store parent context
newDirectoryPath.value = '' // Don't pre-fill the path
showDirectoryDialog.value = true showDirectoryDialog.value = true
autoFocusDirectoryInput() autoFocusDirectoryInput()
} }
const addFile = (parentItem: TreeItem | null = null) => { const addFile = (parentItem: TreeItem | null = null) => {
showContextMenuVar.value = false showContextMenuVar.value = false
newFilePath.value = parentItem ? `${parentItem.name}/` : '' parentDirectoryForNewItems.value = parentItem ? parentItem.name : null // Store parent context
newFilePath.value = '' // Don't pre-fill the path
showFileDialog.value = true showFileDialog.value = true
autoFocusFileInput() autoFocusFileInput()
} }
const addNewItemToCurrentDirectory = (directoryItem: TreeItem) => { const addNewItemToCurrentDirectory = (directoryItem: TreeItem) => {
currentContextItem.value = directoryItem currentContextItem.value = directoryItem
newDirectoryPath.value = directoryItem ? `${directoryItem.name}/` : '' parentDirectoryForNewItems.value = directoryItem.name // Store parent context
newDirectoryPath.value = '' // Don't pre-fill the path
showDirectoryDialog.value = true showDirectoryDialog.value = true
autoFocusDirectoryInput() autoFocusDirectoryInput()
} }
@@ -481,9 +541,19 @@ const addNewItemToCurrentDirectory = (directoryItem: TreeItem) => {
const confirmAddDirectory = () => { const confirmAddDirectory = () => {
if (!newDirectoryPath.value.trim()) return if (!newDirectoryPath.value.trim()) return
// Construct the full path if there's a parent directory
let fullPath = newDirectoryPath.value
if (parentDirectoryForNewItems.value) {
// Make sure parent directory ends with a slash before appending
const parentPath = parentDirectoryForNewItems.value.endsWith('/')
? parentDirectoryForNewItems.value
: parentDirectoryForNewItems.value + '/'
fullPath = parentPath + newDirectoryPath.value
}
// Check for duplicates // Check for duplicates
const exists = directories.value.some( const exists = directories.value.some(
(d) => d.path === newDirectoryPath.value (d) => d.path === fullPath
) )
if (exists) { if (exists) {
showSnackbar('该目录路径已存在!') showSnackbar('该目录路径已存在!')
@@ -491,26 +561,37 @@ const confirmAddDirectory = () => {
} }
directories.value.push({ directories.value.push({
path: newDirectoryPath.value path: fullPath
}) })
showDirectoryDialog.value = false showDirectoryDialog.value = false
newDirectoryPath.value = '' newDirectoryPath.value = ''
parentDirectoryForNewItems.value = null // Clear parent context after creation
currentContextItem.value = null currentContextItem.value = null
} }
const confirmAddFile = () => { const confirmAddFile = () => {
if (!newFilePath.value.trim()) return if (!newFilePath.value.trim()) return
// Construct the full path if there's a parent directory
let fullPath = newFilePath.value
if (parentDirectoryForNewItems.value) {
// Make sure parent directory ends with a slash before appending
const parentPath = parentDirectoryForNewItems.value.endsWith('/')
? parentDirectoryForNewItems.value
: parentDirectoryForNewItems.value + '/'
fullPath = parentPath + newFilePath.value
}
// Check for duplicates // Check for duplicates
const exists = files.value.some((f) => f.path === newFilePath.value) const exists = files.value.some((f) => f.path === fullPath)
if (exists) { if (exists) {
showSnackbar('该文件路径已存在!') showSnackbar('该文件路径已存在!')
return return
} }
const newFile = { const newFile = {
path: newFilePath.value, path: fullPath,
content: '' content: ''
} }
@@ -521,6 +602,7 @@ const confirmAddFile = () => {
showFileDialog.value = false showFileDialog.value = false
newFilePath.value = '' newFilePath.value = ''
parentDirectoryForNewItems.value = null // Clear parent context after creation
currentContextItem.value = null currentContextItem.value = null
} }