mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-11 07:21:41 +08:00
fix
This commit is contained in:
@@ -913,5 +913,5 @@ export interface FileItem {
|
|||||||
path: string
|
path: string
|
||||||
extension: string
|
extension: string
|
||||||
size: number
|
size: number
|
||||||
children: []
|
children: FileItem[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import axios from 'axios'
|
|||||||
import Toolbar from './filebrowser/Toolbar.vue'
|
import Toolbar from './filebrowser/Toolbar.vue'
|
||||||
import Tree from './filebrowser/Tree.vue'
|
import Tree from './filebrowser/Tree.vue'
|
||||||
import List from './filebrowser/List.vue'
|
import List from './filebrowser/List.vue'
|
||||||
|
import type { EndPoints } from '@/api/types'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -12,16 +13,16 @@ const props = defineProps({
|
|||||||
storage: String,
|
storage: String,
|
||||||
path: String,
|
path: String,
|
||||||
tree: String,
|
tree: String,
|
||||||
endpoints: Object,
|
endpoints: Object as PropType<EndPoints>,
|
||||||
axios: Object as PropType<Axios>,
|
axios: Object as PropType<Axios>,
|
||||||
axiosConfig: Object,
|
axiosconfig: Object,
|
||||||
maxUploadFilesCount: Number,
|
|
||||||
maxUploadFileSize: Number,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 事件
|
// 事件f
|
||||||
const emit = defineEmits(['change'])
|
const emit = defineEmits(['change'])
|
||||||
|
|
||||||
|
console.log('FileBrowser Init Path', props.path)
|
||||||
|
|
||||||
const availableStorages = [
|
const availableStorages = [
|
||||||
{
|
{
|
||||||
name: '本地',
|
name: '本地',
|
||||||
@@ -30,12 +31,6 @@ const availableStorages = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const endpoints = {
|
|
||||||
list: { url: '/filebrowser/list?path={path}', method: 'get' },
|
|
||||||
mkdir: { url: '/filebrowser/mkdir?path={path}', method: 'post' },
|
|
||||||
delete: { url: '/filebrowser/delete?path={path}', method: 'post' },
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileIcons = {
|
const fileIcons = {
|
||||||
zip: 'mdi-folder-zip-outline',
|
zip: 'mdi-folder-zip-outline',
|
||||||
rar: 'mdi-folder-zip-outline',
|
rar: 'mdi-folder-zip-outline',
|
||||||
@@ -65,7 +60,7 @@ const path = ref(props.path)
|
|||||||
// 当前存储
|
// 当前存储
|
||||||
const activeStorage = ref('local')
|
const activeStorage = ref('local')
|
||||||
// 刷新
|
// 刷新
|
||||||
const refreshPending = ref(false)
|
const refreshPending = ref(true)
|
||||||
// axios实例
|
// axios实例
|
||||||
const axiosInstance = ref<Axios>()
|
const axiosInstance = ref<Axios>()
|
||||||
|
|
||||||
@@ -89,13 +84,14 @@ function storageChanged(storage: string) {
|
|||||||
|
|
||||||
function pathChanged(_path: string) {
|
function pathChanged(_path: string) {
|
||||||
path.value = _path
|
path.value = _path
|
||||||
|
console.log('Browser changePath', path.value)
|
||||||
emit('change', path)
|
emit('change', path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(() => {
|
onBeforeMount(() => {
|
||||||
activeStorage.value = props.storage ?? 'local'
|
activeStorage.value = props.storage ?? 'local'
|
||||||
axiosInstance.value = props.axios ?? axios.create(props.axiosConfig)
|
axiosInstance.value = props.axios ?? axios.create(props.axiosconfig)
|
||||||
if (!path.value)
|
if (!path.value)
|
||||||
pathChanged('/')
|
pathChanged('/')
|
||||||
})
|
})
|
||||||
@@ -107,7 +103,7 @@ onMounted(() => {
|
|||||||
:path="path"
|
:path="path"
|
||||||
:storages="storagesArray"
|
:storages="storagesArray"
|
||||||
:storage="activeStorage"
|
:storage="activeStorage"
|
||||||
:endpoints="endpoints"
|
:endpoints="props.endpoints"
|
||||||
:axios="axiosInstance"
|
:axios="axiosInstance"
|
||||||
@storagechanged="storageChanged"
|
@storagechanged="storageChanged"
|
||||||
@pathchanged="pathChanged"
|
@pathchanged="pathChanged"
|
||||||
@@ -136,10 +132,10 @@ onMounted(() => {
|
|||||||
:endpoints="endpoints"
|
:endpoints="endpoints"
|
||||||
:axios="axiosInstance"
|
:axios="axiosInstance"
|
||||||
:refreshpending="refreshPending"
|
:refreshpending="refreshPending"
|
||||||
@path-changed="pathChanged"
|
@pathchanged="pathChanged"
|
||||||
@loading="loadingChanged"
|
@loading="loadingChanged"
|
||||||
@refreshed="refreshPending = false"
|
@refreshed="refreshPending = false"
|
||||||
@file-deleted="refreshPending = true"
|
@filedeleted="refreshPending = true"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import type { Axios } from 'axios'
|
import type { Axios } from 'axios'
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { useConfirm } from 'vuetify-use-dialog'
|
import { useConfirm } from 'vuetify-use-dialog'
|
||||||
|
import axios from 'axios'
|
||||||
import { formatBytes } from '@core/utils/formatters'
|
import { formatBytes } from '@core/utils/formatters'
|
||||||
import type { EndPoints, FileItem } from '@/api/types'
|
import type { EndPoints, FileItem } from '@/api/types'
|
||||||
|
|
||||||
@@ -18,20 +19,25 @@ const props = defineProps({
|
|||||||
// 对外事件
|
// 对外事件
|
||||||
const emit = defineEmits(['loading', 'pathchanged', 'refreshed', 'filedeleted'])
|
const emit = defineEmits(['loading', 'pathchanged', 'refreshed', 'filedeleted'])
|
||||||
|
|
||||||
|
console.log('List Init Path', props.path)
|
||||||
|
|
||||||
// 确认框
|
// 确认框
|
||||||
const createConfirm = useConfirm()
|
const createConfirm = useConfirm()
|
||||||
|
|
||||||
|
// axios实例
|
||||||
|
const axiosInstance = ref<Axios>(props.axios ?? axios)
|
||||||
|
|
||||||
// 内容列表
|
// 内容列表
|
||||||
const items = ref<FileItem[]>([])
|
const items = ref<FileItem[]>([])
|
||||||
|
|
||||||
// 当前路径
|
// 当前路径
|
||||||
const path = ref(props.path ?? '')
|
const path = ref(props.path)
|
||||||
|
|
||||||
// 过滤条件
|
// 过滤条件
|
||||||
const filter = ref('')
|
const filter = ref('')
|
||||||
|
|
||||||
// 存储空间类型
|
// 存储空间类型
|
||||||
const storage = ref(props.storage || '')
|
const storage = ref(props.storage ?? '')
|
||||||
|
|
||||||
// 是否正在加载
|
// 是否正在加载
|
||||||
const refreshPending = ref(props.refreshpending || false)
|
const refreshPending = ref(props.refreshpending || false)
|
||||||
@@ -47,13 +53,14 @@ const files = computed(() =>
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 是否目录
|
// 是否目录
|
||||||
const isDir = computed(() => path.value.endsWith('/'))
|
const isDir = computed(() => path.value?.endsWith('/'))
|
||||||
|
|
||||||
// 是否文件
|
// 是否文件
|
||||||
const isFile = computed(() => !isDir.value)
|
const isFile = computed(() => !isDir.value)
|
||||||
|
|
||||||
// 调API加载内容
|
// 调API加载内容
|
||||||
async function load() {
|
async function load() {
|
||||||
|
console.log('List load', path.value, isDir.value)
|
||||||
if (isDir.value) {
|
if (isDir.value) {
|
||||||
const url = props.endpoints?.list.url
|
const url = props.endpoints?.list.url
|
||||||
.replace(/{storage}/g, storage.value)
|
.replace(/{storage}/g, storage.value)
|
||||||
@@ -63,9 +70,9 @@ async function load() {
|
|||||||
url,
|
url,
|
||||||
method: props.endpoints?.list.method || 'get',
|
method: props.endpoints?.list.method || 'get',
|
||||||
}
|
}
|
||||||
|
console.log('List load', url, config)
|
||||||
const response = await props.axios?.request(config)
|
// 加载数据
|
||||||
items.value = response?.data
|
items.value = await axiosInstance.value.request(config) ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +82,7 @@ async function deleteItem(item: FileItem) {
|
|||||||
title: '确认',
|
title: '确认',
|
||||||
content: `是否确认删除${
|
content: `是否确认删除${
|
||||||
item.type === 'dir' ? '目录' : '文件'
|
item.type === 'dir' ? '目录' : '文件'
|
||||||
}?<br><em>${item.basename}</em>?`,
|
} ${item.basename}?`,
|
||||||
confirmationText: '确认',
|
confirmationText: '确认',
|
||||||
cancellationText: '取消',
|
cancellationText: '取消',
|
||||||
dialogProps: {
|
dialogProps: {
|
||||||
@@ -94,7 +101,7 @@ async function deleteItem(item: FileItem) {
|
|||||||
method: props.endpoints?.delete.method || 'post',
|
method: props.endpoints?.delete.method || 'post',
|
||||||
}
|
}
|
||||||
|
|
||||||
await props.axios?.request(config)
|
await axiosInstance.value.request(config)
|
||||||
emit('filedeleted')
|
emit('filedeleted')
|
||||||
emit('loading', false)
|
emit('loading', false)
|
||||||
}
|
}
|
||||||
@@ -102,21 +109,26 @@ async function deleteItem(item: FileItem) {
|
|||||||
|
|
||||||
// 切换路径
|
// 切换路径
|
||||||
function changePath(path: string) {
|
function changePath(path: string) {
|
||||||
|
console.log('List changePath', path)
|
||||||
emit('pathchanged', path)
|
emit('pathchanged', path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听path变化
|
// 监听path变化
|
||||||
watch(
|
watch(
|
||||||
() => path.value,
|
path,
|
||||||
async () => {
|
async () => {
|
||||||
|
console.log('List pathChanged', path.value)
|
||||||
items.value = []
|
items.value = []
|
||||||
await load()
|
|
||||||
if (refreshPending.value) {
|
if (refreshPending.value) {
|
||||||
await load()
|
await load()
|
||||||
emit('refreshed')
|
emit('refreshed')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
load()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -139,19 +151,17 @@ watch(
|
|||||||
<VListItem
|
<VListItem
|
||||||
v-for="(item, index) in dirs"
|
v-for="(item, index) in dirs"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="pl-0"
|
class="pl-2"
|
||||||
@click="changePath(item.path)"
|
@click="changePath(item.path)"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VIcon icon="mdi-folder-outline" />
|
<VIcon icon="mdi-folder-outline" />
|
||||||
</template>
|
</template>
|
||||||
<VListItemTitle v-text="item.basename" />
|
<VListItemTitle v-text="item.name" />
|
||||||
<template #append>
|
<template #append>
|
||||||
<VBtn icon @click.stop="deleteItem(item)">
|
<IconBtn @click.stop="deleteItem(item)">
|
||||||
<VIcon color="grey lighten-1">
|
<VIcon icon="mdi-delete-outline" />
|
||||||
mdi-delete-outline
|
</IconBtn>
|
||||||
</VIcon>
|
|
||||||
</VBtn>
|
|
||||||
</template>
|
</template>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
@@ -161,22 +171,20 @@ watch(
|
|||||||
<VListItem
|
<VListItem
|
||||||
v-for="(item, index) in files"
|
v-for="(item, index) in files"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="pl-0"
|
class="pl-2"
|
||||||
@click="changePath(item.path)"
|
@click="changePath(item.path)"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VIcon v-if="props.icons" :icon="props.icons[item.extension.toLowerCase()] || props.icons?.other" />
|
<VIcon v-if="props.icons" :icon="props.icons[item.extension.toLowerCase()] || props.icons?.other" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<VListItemTitle v-text="item.basename" />
|
<VListItemTitle v-text="item.name" />
|
||||||
<VListItemSubtitle> {{ formatBytes(item.size) }}</VListItemSubtitle>
|
<VListItemSubtitle> {{ formatBytes(item.size) }}</VListItemSubtitle>
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<VBtn icon @click.stop="deleteItem(item)">
|
<IconBtn @click.stop="deleteItem(item)">
|
||||||
<VIcon color="grey lighten-1">
|
<VIcon icon="mdi-delete-outline" />
|
||||||
mdi-delete-outline
|
</IconBtn>
|
||||||
</VIcon>
|
|
||||||
</VBtn>
|
|
||||||
</template>
|
</template>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ function changeStorage(code: string) {
|
|||||||
|
|
||||||
// 路径变化
|
// 路径变化
|
||||||
function changePath(path: string) {
|
function changePath(path: string) {
|
||||||
|
console.log('Toolbar changePath', path)
|
||||||
emit('pathchanged', path)
|
emit('pathchanged', path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ function init() {
|
|||||||
children: [],
|
children: [],
|
||||||
size: 0,
|
size: 0,
|
||||||
}]
|
}]
|
||||||
if (props.path !== '')
|
|
||||||
emit('pathchanged', '')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用API读取文件夹
|
// 调用API读取文件夹
|
||||||
@@ -54,9 +52,9 @@ async function readFolder(item: FileItem) {
|
|||||||
method: props.endpoints?.list.method || 'get',
|
method: props.endpoints?.list.method || 'get',
|
||||||
}
|
}
|
||||||
|
|
||||||
const response: any = await props.axios?.request(config)
|
const response: FileItem[] = await props.axios?.request(config) ?? []
|
||||||
|
|
||||||
item.children = response.data.map((item: FileItem) => {
|
item.children = response.map((item: FileItem) => {
|
||||||
if (item.type === 'dir')
|
if (item.type === 'dir')
|
||||||
item.children = []
|
item.children = []
|
||||||
|
|
||||||
@@ -68,6 +66,7 @@ async function readFolder(item: FileItem) {
|
|||||||
|
|
||||||
// 选中变化
|
// 选中变化
|
||||||
function activeChanged(_active: string[]) {
|
function activeChanged(_active: string[]) {
|
||||||
|
console.log('Tree changePath', _active)
|
||||||
active.value = _active
|
active.value = _active
|
||||||
let path = ''
|
let path = ''
|
||||||
if (active.value.length)
|
if (active.value.length)
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import api from '@/api'
|
||||||
import FileBrowser from '@/components/FileBrowser.vue'
|
import FileBrowser from '@/components/FileBrowser.vue'
|
||||||
|
|
||||||
|
const initPath = ref('/Users/jxxghp/Downloads/爱情生活 (2020)/')
|
||||||
|
|
||||||
|
const endpoints = {
|
||||||
|
list: { url: '/filebrowser/list?path={path}', method: 'get' },
|
||||||
|
mkdir: { url: '/filebrowser/mkdir?path={path}', method: 'get' },
|
||||||
|
delete: { url: '/filebrowser/delete?path={path}', method: 'get' },
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<FileBrowser storages="local" tree="true" path="/Users/jxxghp/Downloads/public" />
|
<FileBrowser storages="local" tree="true" :path="initPath" :endpoints="endpoints" :axios="api" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user