mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-29 01:38:53 +08:00
refactor:重构路径输入组件
This commit is contained in:
@@ -3,6 +3,10 @@ import api from '@/api'
|
||||
import { FileItem } from '@/api/types'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '/',
|
||||
},
|
||||
root: {
|
||||
type: String,
|
||||
default: '/',
|
||||
@@ -16,7 +20,7 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const activedDirs = ref<Record<string, any>[]>([])
|
||||
const menuVisible = ref(false)
|
||||
|
||||
const treeItems = ref<FileItem[]>([
|
||||
{
|
||||
@@ -29,16 +33,70 @@ const treeItems = ref<FileItem[]>([
|
||||
},
|
||||
])
|
||||
|
||||
const activedDirs = ref<FileItem[]>([])
|
||||
|
||||
const openedDirs = ref<FileItem[]>([])
|
||||
|
||||
// 调用API查询子目录
|
||||
async function fetchDirs(item: any) {
|
||||
return api
|
||||
.post('/storage/list', item)
|
||||
.then((data: any) => {
|
||||
data = data.filter((i: any) => i.type === 'dir')
|
||||
item.children.push(...data)
|
||||
item.children?.push(...data)
|
||||
})
|
||||
.catch(err => console.warn(err))
|
||||
}
|
||||
|
||||
// 递归查询路径
|
||||
function findPath(item: FileItem, path: string): FileItem | null {
|
||||
if (item.path === path) {
|
||||
return item
|
||||
}
|
||||
if (item.children) {
|
||||
for (const child of item.children) {
|
||||
const res: FileItem | null = findPath(child, path)
|
||||
if (res) {
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 根据路径展开所有子目录
|
||||
async function expandDirs(path: string) {
|
||||
// 分割路径
|
||||
const paths = path.split('/').filter(i => i)
|
||||
// 展开根目录
|
||||
const root_item = treeItems.value[0]
|
||||
await fetchDirs(root_item)
|
||||
openedDirs.value.push(root_item)
|
||||
// 逐级展开
|
||||
let currentPath = '/'
|
||||
for (const p of paths) {
|
||||
currentPath += `${p}/`
|
||||
// 查询当前目录
|
||||
const item = findPath(root_item, currentPath)
|
||||
if (!item) {
|
||||
break
|
||||
}
|
||||
// 加载子目录
|
||||
if (item.children?.length === 0) {
|
||||
await fetchDirs(item)
|
||||
}
|
||||
// 打开当前目录
|
||||
if (!openedDirs.value.includes(item) && path != currentPath) {
|
||||
openedDirs.value.push(item)
|
||||
}
|
||||
// 选中当前目录
|
||||
if (path == currentPath) {
|
||||
activedDirs.value = [item]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 当前选中项
|
||||
const selectedPath = computed(() => {
|
||||
if (activedDirs.value.length > 0) {
|
||||
return activedDirs.value[0].path
|
||||
@@ -51,6 +109,27 @@ watch(activedDirs, newVal => {
|
||||
emit('update:modelValue', selectedPath.value)
|
||||
})
|
||||
|
||||
watch(
|
||||
() => menuVisible.value,
|
||||
async visible => {
|
||||
if (visible) {
|
||||
treeItems.value = [
|
||||
{
|
||||
name: '/',
|
||||
path: props.root,
|
||||
children: [],
|
||||
type: 'dir',
|
||||
basename: props.root,
|
||||
storage: props.storage,
|
||||
},
|
||||
]
|
||||
openedDirs.value = []
|
||||
activedDirs.value = []
|
||||
await expandDirs(props.modelValue)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.storage,
|
||||
async newVal => {
|
||||
@@ -65,18 +144,20 @@ watch(
|
||||
},
|
||||
]
|
||||
activedDirs.value = []
|
||||
openedDirs.value = []
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VMenu :close-on-content-click="false" content-class="cursor-default">
|
||||
<VMenu v-model="menuVisible" :close-on-content-click="false" content-class="cursor-default">
|
||||
<template v-slot:activator="{ props }">
|
||||
<slot name="activator" :menuprops="props" />
|
||||
</template>
|
||||
<VTreeview
|
||||
v-model:activated="activedDirs"
|
||||
v-model:opened="openedDirs"
|
||||
:items="treeItems"
|
||||
:load-children="fetchDirs"
|
||||
item-key="path"
|
||||
|
||||
Reference in New Issue
Block a user