mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-11 15:32:47 +08:00
feat:目录选择组件
This commit is contained in:
@@ -17,6 +17,9 @@ const props = defineProps({
|
|||||||
height: String,
|
height: String,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 路径
|
||||||
|
const path = ref<string>('')
|
||||||
|
|
||||||
// 类型下拉字典
|
// 类型下拉字典
|
||||||
const typeItems = [
|
const typeItems = [
|
||||||
{ title: '全部', value: '' },
|
{ title: '全部', value: '' },
|
||||||
@@ -25,13 +28,19 @@ const typeItems = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
// 定义触发的自定义事件
|
// 定义触发的自定义事件
|
||||||
const emit = defineEmits(['close', 'changed'])
|
const emit = defineEmits(['close', 'changed', 'update:modelValue'])
|
||||||
|
|
||||||
// 按钮点击
|
// 按钮点击
|
||||||
function onClose() {
|
function onClose() {
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 路径更新
|
||||||
|
function updatePath(value: string) {
|
||||||
|
path.value = value
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
}
|
||||||
|
|
||||||
// 根据选中的媒体类型,获取对应的媒体类别
|
// 根据选中的媒体类型,获取对应的媒体类别
|
||||||
const getCategories = computed(() => {
|
const getCategories = computed(() => {
|
||||||
const default_value = [{ title: '全部', value: '' }]
|
const default_value = [{ title: '全部', value: '' }]
|
||||||
@@ -60,7 +69,11 @@ const getCategories = computed(() => {
|
|||||||
<VForm>
|
<VForm>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol>
|
<VCol>
|
||||||
<VTextField v-model="props.directory.path" variant="underlined" label="路径" />
|
<VPathField @update:modelValue="updatePath">
|
||||||
|
<template #activator="{ menuprops }">
|
||||||
|
<VTextField v-model="props.directory.path" v-bind="menuprops" variant="underlined" label="路径" />
|
||||||
|
</template>
|
||||||
|
</VPathField>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
<VRow>
|
<VRow>
|
||||||
@@ -21,13 +21,10 @@ const activedDirs = ref<string[]>([])
|
|||||||
// 打开的目录
|
// 打开的目录
|
||||||
const openedDirs = ref<string[]>([])
|
const openedDirs = ref<string[]>([])
|
||||||
|
|
||||||
// 当前选中的目录
|
|
||||||
const selectedDir = ref<string>('')
|
|
||||||
|
|
||||||
// 目录列表
|
// 目录列表
|
||||||
const treeItems = ref<FileItem[]>([
|
const treeItems = ref<FileItem[]>([
|
||||||
{
|
{
|
||||||
name: props.root,
|
name: '/',
|
||||||
path: props.root,
|
path: props.root,
|
||||||
children: [],
|
children: [],
|
||||||
type: '',
|
type: '',
|
||||||
@@ -48,11 +45,18 @@ async function fetchDirs(item: any) {
|
|||||||
.catch(err => console.warn(err))
|
.catch(err => console.warn(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取选择的目录路径
|
||||||
|
const selectedPath = computed(() => {
|
||||||
|
if (activedDirs.value.length > 0) {
|
||||||
|
return activedDirs.value[0]
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
// 监听目录变化
|
// 监听目录变化
|
||||||
watch(activedDirs, newVal => {
|
watch(activedDirs, newVal => {
|
||||||
if (!newVal.length) return
|
if (!newVal.length) return
|
||||||
selectedDir.value = newVal[0]
|
emit('update:modelValue', selectedPath)
|
||||||
emit('update:modelValue', newVal[0])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -61,27 +65,24 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VMenu>
|
<VMenu :close-on-content-click="false" content-class="cursor-default">
|
||||||
<template v-slot:activator="{ props }">
|
<template v-slot:activator="{ props }">
|
||||||
<VTextField v-model="selectedDir" label="路径" variant="underlined" v-bind="props"></VTextField>
|
<slot name="activator" :menuprops="props" />
|
||||||
</template>
|
</template>
|
||||||
<VTreeview
|
<VTreeview
|
||||||
v-model:activated="activedDirs"
|
v-model:activated="activedDirs"
|
||||||
v-model:opened="openedDirs"
|
v-model:opened="openedDirs"
|
||||||
:items="treeItems"
|
:items="treeItems"
|
||||||
:load-children="fetchDirs"
|
:load-children="fetchDirs"
|
||||||
density="compact"
|
|
||||||
item-key="path"
|
item-key="path"
|
||||||
item-title="name"
|
item-title="name"
|
||||||
item-value="path"
|
item-value="path"
|
||||||
item-type="unknown"
|
item-type="unknown"
|
||||||
activatable
|
activatable
|
||||||
open-on-click
|
|
||||||
transition
|
|
||||||
return-object
|
return-object
|
||||||
max-height="20rem"
|
max-height="20rem"
|
||||||
selectable
|
expand-icon="mdi-folder"
|
||||||
class="cursor-pointer"
|
collapse-icon="mdi-folder-open"
|
||||||
>
|
>
|
||||||
</VTreeview>
|
</VTreeview>
|
||||||
</VMenu>
|
</VMenu>
|
||||||
@@ -26,6 +26,7 @@ import PersonCard from './components/cards/PersonCard.vue'
|
|||||||
import MediaInfoCard from './components/cards/MediaInfoCard.vue'
|
import MediaInfoCard from './components/cards/MediaInfoCard.vue'
|
||||||
import TorrentCard from './components/cards/TorrentCard.vue'
|
import TorrentCard from './components/cards/TorrentCard.vue'
|
||||||
import MediaIdSelector from './components/misc/MediaIdSelector.vue'
|
import MediaIdSelector from './components/misc/MediaIdSelector.vue'
|
||||||
|
import PathField from './components/input/PathField.vue'
|
||||||
import { fixArrayAt } from '@/@core/utils/compatibility'
|
import { fixArrayAt } from '@/@core/utils/compatibility'
|
||||||
|
|
||||||
// 修复低版本Safari等浏览器数组不支持at函数的问题
|
// 修复低版本Safari等浏览器数组不支持at函数的问题
|
||||||
@@ -50,6 +51,7 @@ app
|
|||||||
.component('VTorrentCard', TorrentCard)
|
.component('VTorrentCard', TorrentCard)
|
||||||
.component('VMediaIdSelector', MediaIdSelector)
|
.component('VMediaIdSelector', MediaIdSelector)
|
||||||
.component('VTreeview', VTreeview)
|
.component('VTreeview', VTreeview)
|
||||||
|
.component('VPathField', PathField)
|
||||||
|
|
||||||
// 注册插件
|
// 注册插件
|
||||||
app
|
app
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import draggable from 'vuedraggable'
|
|||||||
import { VRow } from 'vuetify/lib/components/index.mjs'
|
import { VRow } from 'vuetify/lib/components/index.mjs'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { MediaDirectory } from '@/api/types'
|
import { MediaDirectory } from '@/api/types'
|
||||||
import MediaDirectoryCard from '@/components/cards/MediaDirectoryCard.vue'
|
import DirectoryCard from '@/components/cards/DirectoryCard.vue'
|
||||||
|
|
||||||
// 媒体库设置项
|
// 媒体库设置项
|
||||||
const transferSettings = ref({
|
const transferSettings = ref({
|
||||||
@@ -223,10 +223,11 @@ onMounted(() => {
|
|||||||
:component-data="{ 'class': 'grid gap-3 grid-directory-card' }"
|
:component-data="{ 'class': 'grid gap-3 grid-directory-card' }"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<MediaDirectoryCard
|
<DirectoryCard
|
||||||
type="download"
|
type="download"
|
||||||
:directory="element"
|
:directory="element"
|
||||||
:categories="mediaCategories"
|
:categories="mediaCategories"
|
||||||
|
@update:modelValue="(value: string) => (element.path = value)"
|
||||||
@close="downloadCardClose(element.name)"
|
@close="downloadCardClose(element.name)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -256,7 +257,7 @@ onMounted(() => {
|
|||||||
:component-data="{ 'class': 'grid gap-3 grid-directory-card' }"
|
:component-data="{ 'class': 'grid gap-3 grid-directory-card' }"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<MediaDirectoryCard
|
<DirectoryCard
|
||||||
type="library"
|
type="library"
|
||||||
:directory="element"
|
:directory="element"
|
||||||
:categories="mediaCategories"
|
:categories="mediaCategories"
|
||||||
|
|||||||
Reference in New Issue
Block a user