- web/ → frontend/ 目录重命名(Wails v3 标准结构) - main.go: Middleware 修复 custom.js 404 + DevTools 延迟启动 - Sidebar: 收藏夹内部独立滚动 + 帮助区块固定底部 - useFavorites.ts: longPressTimer const→let 修复 TypeError - App.vue: Arco Tabs padding-top 覆盖 - build: config.yml / Taskfile.yml 对齐官方模板,devtools build tag - 新增 v3 bindings、vite.config.js、跨平台构建配置 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
248 lines
5.5 KiB
TypeScript
248 lines
5.5 KiB
TypeScript
/**
|
|
* 路径导航 Composable
|
|
* 提供路径输入、历史记录、前进/后退等功能
|
|
*/
|
|
|
|
import { ref, watch, computed } from 'vue'
|
|
import { STORAGE_KEYS } from '@/utils/constants'
|
|
import { normalizePathSeparators } from '@/utils/fileUtils'
|
|
import type { PathHistory } from '@/types/file-system'
|
|
|
|
export interface UsePathNavigationOptions {
|
|
onListDirectory?: (path: string) => Promise<void>
|
|
initialPath?: string
|
|
}
|
|
|
|
/**
|
|
* 从 localStorage 恢复上次的路径
|
|
*/
|
|
const restoreLastPath = (): string | null => {
|
|
try {
|
|
const lastPath = localStorage.getItem(STORAGE_KEYS.FILESYSTEM.FILE_PATH)
|
|
if (lastPath) {
|
|
// 规范化旧路径(可能包含反斜杠)
|
|
return normalizePathSeparators(lastPath)
|
|
}
|
|
return lastPath
|
|
} catch (error) {
|
|
console.error('恢复路径失败:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存路径到 localStorage
|
|
*/
|
|
const saveLastPath = (path: string) => {
|
|
try {
|
|
localStorage.setItem(STORAGE_KEYS.FILESYSTEM.FILE_PATH, path)
|
|
} catch (error) {
|
|
console.error('保存路径失败:', error)
|
|
}
|
|
}
|
|
|
|
export function usePathNavigation(options: UsePathNavigationOptions = {}) {
|
|
const { onListDirectory, initialPath = '' } = options
|
|
|
|
// 尝试恢复上次的路径,如果没有则使用初始路径
|
|
const savedPath = restoreLastPath()
|
|
const filePath = ref(savedPath || initialPath)
|
|
|
|
// 历史记录
|
|
const history = ref<PathHistory>({
|
|
paths: [],
|
|
currentIndex: -1
|
|
})
|
|
|
|
/**
|
|
* 导航到指定路径(带错误处理)
|
|
*/
|
|
const navigate = async (path: string) => {
|
|
if (!path || path === filePath.value) return
|
|
|
|
try {
|
|
// 路径规范化(处理反斜杠并统一为正斜杠)
|
|
const normalizedPath = normalizePathSeparators(path)
|
|
filePath.value = normalizedPath
|
|
|
|
// 添加到历史记录
|
|
addToHistory(normalizedPath)
|
|
|
|
// 触发目录列出
|
|
if (onListDirectory) {
|
|
await onListDirectory(normalizedPath)
|
|
}
|
|
} catch (error) {
|
|
console.error('导航失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加到历史记录
|
|
*/
|
|
const addToHistory = (path: string) => {
|
|
const { paths, currentIndex } = history.value
|
|
|
|
// 如果当前不在历史记录末尾,删除当前位置之后的所有记录
|
|
if (currentIndex < paths.length - 1) {
|
|
history.value.paths = paths.slice(0, currentIndex + 1)
|
|
}
|
|
|
|
// 避免重复添加相同路径
|
|
const lastPath = history.value.paths[history.value.paths.length - 1]
|
|
if (lastPath !== path) {
|
|
history.value.paths.push(path)
|
|
history.value.currentIndex = history.value.paths.length - 1
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 后退(带错误处理)
|
|
*/
|
|
const back = async () => {
|
|
const { paths, currentIndex } = history.value
|
|
|
|
if (currentIndex <= 0) return
|
|
|
|
try {
|
|
const newIndex = currentIndex - 1
|
|
history.value.currentIndex = newIndex
|
|
filePath.value = paths[newIndex]
|
|
|
|
if (onListDirectory) {
|
|
await onListDirectory(paths[newIndex])
|
|
}
|
|
} catch (error) {
|
|
console.error('后退失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 前进(带错误处理)
|
|
*/
|
|
const forward = async () => {
|
|
const { paths, currentIndex } = history.value
|
|
|
|
if (currentIndex >= paths.length - 1) return
|
|
|
|
try {
|
|
const newIndex = currentIndex + 1
|
|
history.value.currentIndex = newIndex
|
|
filePath.value = paths[newIndex]
|
|
|
|
if (onListDirectory) {
|
|
await onListDirectory(paths[newIndex])
|
|
}
|
|
} catch (error) {
|
|
console.error('前进失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 路径输入选择
|
|
*/
|
|
const onPathSelect = (value: string) => {
|
|
navigate(value)
|
|
}
|
|
|
|
/**
|
|
* 路径输入回车
|
|
*/
|
|
const onPathEnter = (value: string) => {
|
|
navigate(value)
|
|
}
|
|
|
|
/**
|
|
* 浏览目录(双击或回车)
|
|
*/
|
|
const browseDirectory = async (path: string) => {
|
|
await navigate(path)
|
|
}
|
|
|
|
/**
|
|
* 获取父目录路径
|
|
*/
|
|
const getParentPath = (path: string): string => {
|
|
const separator = path.includes('\\') ? '\\' : '/'
|
|
const lastSeparator = path.lastIndexOf(separator)
|
|
return lastSeparator > 0 ? path.substring(0, lastSeparator) : path
|
|
}
|
|
|
|
/**
|
|
* 上级目录
|
|
*/
|
|
const goUp = async () => {
|
|
const parentPath = getParentPath(filePath.value)
|
|
if (parentPath !== filePath.value) {
|
|
await navigate(parentPath)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 路径规范化(统一为正斜杠)
|
|
*/
|
|
const normalizePath = (path: string): string => {
|
|
return normalizePathSeparators(path)
|
|
}
|
|
|
|
/**
|
|
* 判断是否可以后退
|
|
*/
|
|
const canGoBack = computed(() => {
|
|
return history.value.currentIndex > 0
|
|
})
|
|
|
|
/**
|
|
* 判断是否可以前进
|
|
*/
|
|
const canGoForward = computed(() => {
|
|
return history.value.currentIndex < history.value.paths.length - 1
|
|
})
|
|
|
|
/**
|
|
* 获取历史记录列表(用于自动完成)
|
|
*/
|
|
const getPathHistory = computed(() => {
|
|
return history.value.paths.slice().reverse() // 最新的在前
|
|
})
|
|
|
|
// 监听路径变化,自动保存到 localStorage
|
|
watch(filePath, (newPath) => {
|
|
if (newPath) {
|
|
saveLastPath(newPath)
|
|
}
|
|
})
|
|
|
|
return {
|
|
// 状态
|
|
filePath,
|
|
history,
|
|
|
|
// 导航方法
|
|
navigate,
|
|
back,
|
|
forward,
|
|
goUp,
|
|
browseDirectory,
|
|
|
|
// 事件处理
|
|
onPathSelect,
|
|
onPathEnter,
|
|
|
|
// 工具方法
|
|
getParentPath,
|
|
normalizePath,
|
|
|
|
// 计算属性
|
|
canGoBack,
|
|
canGoForward,
|
|
getPathHistory
|
|
}
|
|
}
|
|
|
|
// 导出类型(用于外部使用)
|
|
export type { PathHistory }
|