feat: 添加父目录跟踪功能,优化目录和文件的路径构建逻辑
This commit is contained in:
1 parent
6431049d05
commit
de7af2f650
2 files changed
+146
-21
No files matched your search
@@ -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>
|
||||||
@@ -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 = {
|
||||||
// Add directories
|
id: 'root',
|
||||||
directories.value.forEach((dir) => {
|
name: 'root',
|
||||||
items.push({
|
|
||||||
id: `dir-${dir.path}`,
|
|
||||||
name: dir.path,
|
|
||||||
type: 'directory',
|
type: 'directory',
|
||||||
children: []
|
children: []
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// Process each directory
|
||||||
|
directories.value.forEach((dir) => {
|
||||||
|
const pathParts = dir.path.split('/').filter(part => part !== '') // Split path and remove empty parts
|
||||||
|
let currentLevel = root.children || []
|
||||||
|
|
||||||
|
// Navigate/create the directory structure
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user