mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-04 23:18:44 +08:00
fix FileManager
This commit is contained in:
@@ -903,6 +903,7 @@ export interface EndPoints {
|
|||||||
list: any
|
list: any
|
||||||
mkdir: any
|
mkdir: any
|
||||||
delete: any
|
delete: any
|
||||||
|
download: any
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文件浏览项目
|
// 文件浏览项目
|
||||||
|
|||||||
@@ -12,17 +12,12 @@ const props = defineProps({
|
|||||||
storages: String,
|
storages: String,
|
||||||
storage: String,
|
storage: String,
|
||||||
path: String,
|
path: String,
|
||||||
tree: String,
|
tree: Boolean,
|
||||||
endpoints: Object as PropType<EndPoints>,
|
endpoints: Object as PropType<EndPoints>,
|
||||||
axios: Object as PropType<Axios>,
|
axios: Object as PropType<Axios>,
|
||||||
axiosconfig: Object,
|
axiosconfig: Object,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 事件f
|
|
||||||
const emit = defineEmits(['change'])
|
|
||||||
|
|
||||||
console.log('FileBrowser Init Path', props.path)
|
|
||||||
|
|
||||||
const availableStorages = [
|
const availableStorages = [
|
||||||
{
|
{
|
||||||
name: '本地',
|
name: '本地',
|
||||||
@@ -53,14 +48,14 @@ const fileIcons = {
|
|||||||
other: 'mdi-file-outline',
|
other: 'mdi-file-outline',
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载次数
|
|
||||||
const loading = ref(0)
|
|
||||||
// 当前路径
|
// 当前路径
|
||||||
const path = ref(props.path)
|
const path = ref(props.path)
|
||||||
|
// 加载次数
|
||||||
|
const loading = ref(0)
|
||||||
// 当前存储
|
// 当前存储
|
||||||
const activeStorage = ref('local')
|
const activeStorage = ref('local')
|
||||||
// 刷新
|
// 刷新
|
||||||
const refreshPending = ref(true)
|
const refreshPending = ref(false)
|
||||||
// axios实例
|
// axios实例
|
||||||
const axiosInstance = ref<Axios>()
|
const axiosInstance = ref<Axios>()
|
||||||
|
|
||||||
@@ -84,8 +79,6 @@ 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ 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()
|
||||||
|
|
||||||
@@ -30,18 +28,12 @@ const axiosInstance = ref<Axios>(props.axios ?? axios)
|
|||||||
// 内容列表
|
// 内容列表
|
||||||
const items = ref<FileItem[]>([])
|
const items = ref<FileItem[]>([])
|
||||||
|
|
||||||
// 当前路径
|
|
||||||
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 dirs = computed(() =>
|
const dirs = computed(() =>
|
||||||
items.value.filter(item => item.type === 'dir' && item.basename.includes(filter.value)),
|
items.value.filter(item => item.type === 'dir' && item.basename.includes(filter.value)),
|
||||||
@@ -53,27 +45,27 @@ const files = computed(() =>
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 是否目录
|
// 是否目录
|
||||||
const isDir = computed(() => path.value?.endsWith('/'))
|
const isDir = computed(() => props.path?.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)
|
emit('loading', true)
|
||||||
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)
|
||||||
.replace(/{path}/g, path.value)
|
.replace(/{path}/g, props.path)
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
url,
|
url,
|
||||||
method: props.endpoints?.list.method || 'get',
|
method: props.endpoints?.list.method || 'get',
|
||||||
}
|
}
|
||||||
console.log('List load', url, config)
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
items.value = await axiosInstance.value.request(config) ?? []
|
items.value = await axiosInstance.value.request(config) ?? []
|
||||||
}
|
}
|
||||||
|
emit('loading', false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除项目
|
// 删除项目
|
||||||
@@ -104,23 +96,41 @@ async function deleteItem(item: FileItem) {
|
|||||||
await axiosInstance.value.request(config)
|
await axiosInstance.value.request(config)
|
||||||
emit('filedeleted')
|
emit('filedeleted')
|
||||||
emit('loading', false)
|
emit('loading', false)
|
||||||
|
// 重新加载
|
||||||
|
load()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换路径
|
// 切换路径
|
||||||
function changePath(_path: string) {
|
function changePath(_path: string) {
|
||||||
path.value = _path
|
emit('pathchanged', _path)
|
||||||
console.log('List changePath', path.value)
|
}
|
||||||
emit('pathchanged', path)
|
|
||||||
|
// 新窗口中下载文件
|
||||||
|
function download(path: string) {
|
||||||
|
if (!path)
|
||||||
|
return
|
||||||
|
const url = props.endpoints?.download.url
|
||||||
|
.replace(/{storage}/g, storage.value)
|
||||||
|
.replace(/{path}/g, path)
|
||||||
|
// FIXME 下载文件
|
||||||
|
window.open(url, '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听path变化
|
// 监听path变化
|
||||||
watch(
|
watch(
|
||||||
path,
|
() => props.path,
|
||||||
async () => {
|
async () => {
|
||||||
console.log('List pathChanged', path.value)
|
|
||||||
items.value = []
|
items.value = []
|
||||||
if (refreshPending.value) {
|
await load()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 监听refreshPending变化
|
||||||
|
watch(
|
||||||
|
() => props.refreshpending,
|
||||||
|
async () => {
|
||||||
|
if (props.refreshpending) {
|
||||||
await load()
|
await load()
|
||||||
emit('refreshed')
|
emit('refreshed')
|
||||||
}
|
}
|
||||||
@@ -147,7 +157,7 @@ onMounted(() => {
|
|||||||
文件: {{ path }}
|
文件: {{ path }}
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VCardText v-else-if="dirs.length || files.length" class="grow">
|
<VCardText v-else-if="dirs.length || files.length" class="grow">
|
||||||
<VList v-if="dirs.length" subheader>
|
<VList v-if="dirs.length" subheader max-height="300">
|
||||||
<VListSubheader>目录</VListSubheader>
|
<VListSubheader>目录</VListSubheader>
|
||||||
<VListItem
|
<VListItem
|
||||||
v-for="(item, index) in dirs"
|
v-for="(item, index) in dirs"
|
||||||
@@ -167,7 +177,7 @@ onMounted(() => {
|
|||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
<VDivider v-if="dirs.length && files.length" />
|
<VDivider v-if="dirs.length && files.length" />
|
||||||
<VList v-if="files.length" subheader>
|
<VList v-if="files.length" subheader max-height="300">
|
||||||
<VListSubheader>文件</VListSubheader>
|
<VListSubheader>文件</VListSubheader>
|
||||||
<VListItem
|
<VListItem
|
||||||
v-for="(item, index) in files"
|
v-for="(item, index) in files"
|
||||||
@@ -203,8 +213,9 @@ onMounted(() => {
|
|||||||
空目录
|
空目录
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VDivider v-if="path" />
|
<VDivider v-if="path" />
|
||||||
<VToolbar v-if="path && isFile" density="compact" flat color="gray">
|
<VToolbar density="compact" flat color="gray">
|
||||||
<VTextField
|
<VTextField
|
||||||
|
v-if="!isFile"
|
||||||
v-model="filter"
|
v-model="filter"
|
||||||
hide-details
|
hide-details
|
||||||
flat
|
flat
|
||||||
@@ -214,10 +225,11 @@ onMounted(() => {
|
|||||||
prepend-inner-icon="mdi-filter-outline"
|
prepend-inner-icon="mdi-filter-outline"
|
||||||
class="me-2"
|
class="me-2"
|
||||||
/>
|
/>
|
||||||
<VBtn icon>
|
<VSpacer v-if="isFile" />
|
||||||
|
<VBtn v-if="isFile" @click="download(props.path || '')">
|
||||||
<VIcon>mdi-download</VIcon>
|
<VIcon>mdi-download</VIcon>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn icon @click="load">
|
<VBtn v-if="!isFile" @click="load">
|
||||||
<VIcon>mdi-refresh</VIcon>
|
<VIcon>mdi-refresh</VIcon>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</VToolbar>
|
</VToolbar>
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ const inProps = defineProps({
|
|||||||
// 对外事件
|
// 对外事件
|
||||||
const emit = defineEmits(['storagechanged', 'pathchanged', 'loading', 'foldercreated'])
|
const emit = defineEmits(['storagechanged', 'pathchanged', 'loading', 'foldercreated'])
|
||||||
|
|
||||||
// 当前路径
|
|
||||||
const path = ref(inProps.path ?? '')
|
|
||||||
|
|
||||||
// 新建文件夹名称
|
// 新建文件夹名称
|
||||||
const newFolderPopper = ref(false)
|
const newFolderPopper = ref(false)
|
||||||
|
|
||||||
@@ -26,16 +23,16 @@ const newFolderName = ref('')
|
|||||||
// 计算PATH面包屑
|
// 计算PATH面包屑
|
||||||
const pathSegments = computed(() => {
|
const pathSegments = computed(() => {
|
||||||
let path_str = '/'
|
let path_str = '/'
|
||||||
const isFolder = path.value.endsWith('/')
|
const isFolder = inProps.path?.endsWith('/')
|
||||||
const segments = path.value.split('/').filter(item => item)
|
const segments = inProps.path?.split('/').filter(item => item)
|
||||||
|
|
||||||
return segments.map((item, index) => {
|
return segments?.map((item, index) => {
|
||||||
path_str += item + ((index < segments.length - 1 || isFolder) ? '/' : '')
|
path_str += item + ((index < segments.length - 1 || isFolder) ? '/' : '')
|
||||||
return {
|
return {
|
||||||
name: item,
|
name: item,
|
||||||
path: path_str,
|
path: path_str,
|
||||||
}
|
}
|
||||||
})
|
}) ?? []
|
||||||
})
|
})
|
||||||
|
|
||||||
const storageObject = computed(() => {
|
const storageObject = computed(() => {
|
||||||
@@ -52,15 +49,13 @@ function changeStorage(code: string) {
|
|||||||
|
|
||||||
// 路径变化
|
// 路径变化
|
||||||
function changePath(_path: string) {
|
function changePath(_path: string) {
|
||||||
path.value = _path
|
emit('pathchanged', _path)
|
||||||
console.log('Toolbar changePath', path.value)
|
|
||||||
emit('pathchanged', path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回上一级
|
// 返回上一级
|
||||||
function goUp() {
|
function goUp() {
|
||||||
const segments = pathSegments.value
|
const segments = pathSegments.value ?? []
|
||||||
const path = segments.length === 1 ? '/' : segments[segments.length - 2].path
|
const path = segments?.length === 1 ? '/' : segments[segments.length - 2].path
|
||||||
changePath(path)
|
changePath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,11 +71,15 @@ async function mkdir() {
|
|||||||
method: inProps.endpoints?.mkdir.method || 'post',
|
method: inProps.endpoints?.mkdir.method || 'post',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 调API
|
||||||
await inProps.axios?.request(config)
|
await inProps.axios?.request(config)
|
||||||
emit('foldercreated', newFolderName.value)
|
|
||||||
newFolderPopper.value = false
|
newFolderPopper.value = false
|
||||||
newFolderName.value = ''
|
newFolderName.value = ''
|
||||||
emit('loading', false)
|
emit('loading', false)
|
||||||
|
|
||||||
|
// 通知重新加载
|
||||||
|
emit('foldercreated')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ const props = defineProps({
|
|||||||
// 对外事件
|
// 对外事件
|
||||||
const emit = defineEmits(['pathchanged', 'loading', 'refreshed'])
|
const emit = defineEmits(['pathchanged', 'loading', 'refreshed'])
|
||||||
|
|
||||||
// 当前路径
|
|
||||||
const path = ref(props.path)
|
|
||||||
|
|
||||||
// 变量
|
// 变量
|
||||||
const open = ref<string[]>([])
|
const open = ref<string[]>([])
|
||||||
// 活跃的文件夹
|
// 活跃的文件夹
|
||||||
@@ -26,8 +23,6 @@ const active = ref<string[]>([])
|
|||||||
const items = ref<FileItem[]>([])
|
const items = ref<FileItem[]>([])
|
||||||
// 过滤
|
// 过滤
|
||||||
const filter = ref('')
|
const filter = ref('')
|
||||||
// 刷新状态
|
|
||||||
const refreshPending = ref(props.refreshpending || false)
|
|
||||||
|
|
||||||
// 方法
|
// 方法
|
||||||
function init() {
|
function init() {
|
||||||
@@ -69,8 +64,6 @@ async function readFolder(item: FileItem) {
|
|||||||
|
|
||||||
// 选中变化
|
// 选中变化
|
||||||
function activeChanged(_active: string[]) {
|
function activeChanged(_active: string[]) {
|
||||||
console.log('Tree changePath', _active)
|
|
||||||
active.value = _active
|
|
||||||
let path = ''
|
let path = ''
|
||||||
if (active.value.length)
|
if (active.value.length)
|
||||||
path = active.value[0]
|
path = active.value[0]
|
||||||
@@ -103,7 +96,7 @@ watch(() => props.storage, () => {
|
|||||||
|
|
||||||
// 监听路径变化
|
// 监听路径变化
|
||||||
watch(
|
watch(
|
||||||
path,
|
() => props.path,
|
||||||
() => {
|
() => {
|
||||||
if (props.path) {
|
if (props.path) {
|
||||||
active.value = [props.path]
|
active.value = [props.path]
|
||||||
@@ -114,9 +107,9 @@ watch(
|
|||||||
|
|
||||||
// 监听 refreshPending
|
// 监听 refreshPending
|
||||||
watch(
|
watch(
|
||||||
refreshPending,
|
() => props.refreshpending,
|
||||||
async () => {
|
async () => {
|
||||||
if (refreshPending.value && props.path) {
|
if (props.refreshpending && props.path) {
|
||||||
const item = findItem(props.path)
|
const item = findItem(props.path)
|
||||||
if (item) {
|
if (item) {
|
||||||
await readFolder(item)
|
await readFolder(item)
|
||||||
|
|||||||
@@ -2,17 +2,18 @@
|
|||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import FileBrowser from '@/components/FileBrowser.vue'
|
import FileBrowser from '@/components/FileBrowser.vue'
|
||||||
|
|
||||||
const initPath = ref('/Users/jxxghp/Downloads/爱情生活 (2020)/')
|
const initPath = '/Users/jxxghp/Downloads/爱情生活 (2020)/'
|
||||||
|
|
||||||
const endpoints = {
|
const endpoints = {
|
||||||
list: { url: '/filebrowser/list?path={path}', method: 'get' },
|
list: { url: '/filebrowser/list?path={path}', method: 'get' },
|
||||||
mkdir: { url: '/filebrowser/mkdir?path={path}', method: 'get' },
|
mkdir: { url: '/filebrowser/mkdir?path={path}', method: 'get' },
|
||||||
delete: { url: '/filebrowser/delete?path={path}', method: 'get' },
|
delete: { url: '/filebrowser/delete?path={path}', method: 'get' },
|
||||||
|
download: { url: '/filebrowser/download?path={path}', method: 'get' },
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<FileBrowser storages="local" tree="true" :path="initPath" :endpoints="endpoints" :axios="api" />
|
<FileBrowser storages="local" :tree="false" :path="initPath" :endpoints="endpoints" :axios="api" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user