feat: 也不知道改了啥

This commit is contained in:
539943419 committed 2024-09-29 11:50:39 +08:00
1 parent 9611e9f4ed
commit aec7fcabc9
2 files changed
+186 -117

No files matched your search

+118 -86
View File
@@ -1,51 +1,60 @@
import config from "@/config"; import config from '@/config'
import generateId from "@/hooks/generateId"; import generateId from '@/hooks/generateId'
import useMiaoFetchApi from "@/hooks/useMiaoFetchApi"; import useMiaoFetchApi from '@/hooks/useMiaoFetchApi'
import type { stats, file, directory } from "@/types/type.ts"; import type { stats, file, directory } from '@/types/type.ts'
import difference from 'lodash/difference'
const miaoFetchApi = useMiaoFetchApi(); const miaoFetchApi = useMiaoFetchApi()
const vItemMap = new Map(); // const vDirectoryMap = new Map<string, VirtualDirectory>()
// const vFileMap = new Map<string, VirtualFile>()
export interface Tree { export interface Tree {
name: string; name: string
type: "directory"; type: 'directory'
path: string; path: string
stats: stats; stats: stats
files?: { files?: {
name: string; name: string
type: "file"; type: 'file'
size: number; size: number
stats: stats; stats: stats
url: string; url: string
}[]; }[]
directories?: Tree[]; directories?: Tree[]
} }
export class VirtualFile { export class VirtualFile {
constructor(info: file, parent: VirtualDirectory) { constructor(info: file, parent: VirtualDirectory) {
this.name = info.name; this.name = info.name
this.size = info.size; this.size = info.size
this.stats = info.stats; this.stats = info.stats
this.parent = parent; this.parent = parent
this.type = "file"; this.type = 'file'
this.id = generateId(); this.id = generateId()
vItemMap.set(this.path, this); // if (vFileMap.get(this.path) !== undefined) {
// throw `${this.path} is already exist`
// }
// vFileMap.set(this.path, this)
} }
name: string; name: string
type: "file"; type: 'file'
size: number; size: number
stats: stats; stats: stats
parent: VirtualDirectory; parent: VirtualDirectory
id: number; id: number
storage: { [key: string]: any } = {}; storage: { [key: string]: any } = {}
get path() { get path() {
return `${this.parent.path}${this.name}`; return `${this.parent.path}${this.name}`
} }
get url() { get url() {
return `${config.api.get}${this.parent.path}${this.name}`; return `${config.api.get}${this.parent.path}${this.name}`
} }
// destroy() {
// vFileMap.delete(this.path)
// }
} }
class VirtualDirectory { class VirtualDirectory {
@@ -53,31 +62,34 @@ class VirtualDirectory {
* 除非为根节点,否则必须设置parent * 除非为根节点,否则必须设置parent
*/ */
constructor(info: directory, parent?: VirtualDirectory) { constructor(info: directory, parent?: VirtualDirectory) {
this.name = info.name; this.name = info.name
this.stats = info.stats; this.stats = info.stats
this.parent = parent ?? undefined; this.parent = parent ?? undefined
this.id = generateId(); this.id = generateId()
vItemMap.set(this.path, this); // if (vDirectoryMap.get(this.path) !== undefined) {
// throw `${this.path} is already exist`
// }
// vDirectoryMap.set(this.path, this)
} }
// 文件夹名 // 文件夹名
name: string; name: string
// 子文件 // 子文件
files?: VirtualFile[]; files: VirtualFile[] = []
// 子目录 // 子目录
directories?: VirtualDirectory[]; directories: VirtualDirectory[] = []
// 没啥意义,标注一下就是了 // 没啥意义,标注一下就是了
type: "directory" = "directory"; type: 'directory' = 'directory'
// 文件夹创建时间等杂项属性 // 文件夹创建时间等杂项属性
stats: stats; stats: stats
// 父文件夹 // 父文件夹
parent?: VirtualDirectory; parent?: VirtualDirectory
_isUpdated: boolean = false; _isUpdated: boolean = false
id: number; id: number
// 用来存储一些标记信息啥的 // 用来存储一些标记信息啥的
storage: { [key: string]: any } = {}; storage: { [key: string]: any } = {}
/** /**
* 获取相对于根目录的路径的层数 * 获取相对于根目录的路径的层数
@@ -85,7 +97,7 @@ class VirtualDirectory {
* @returns {string} * @returns {string}
*/ */
get layer(): number { get layer(): number {
return this.parent ? this.parent.layer + 1 : 0; return this.parent ? this.parent.layer + 1 : 0
} }
/** /**
* 相对于根目录的路径, 如: "/", "/123/321/" * 相对于根目录的路径, 如: "/", "/123/321/"
@@ -94,9 +106,9 @@ class VirtualDirectory {
*/ */
get path(): string { get path(): string {
if (!this.parent) { if (!this.parent) {
return "/"; return '/'
} }
return `${this.parent.path}${this.name}/`; return `${this.parent.path}${this.name}/`
} }
/** /**
@@ -105,16 +117,16 @@ class VirtualDirectory {
*/ */
get getParents(): VirtualDirectory[] { get getParents(): VirtualDirectory[] {
if (!this.parent) { if (!this.parent) {
return [this]; return [this]
} }
return [...this.parent.getParents, this]; return [...this.parent.getParents, this]
} }
/** /**
* 获取当前文件夹是否已经请求过至少一次数据 * 获取当前文件夹是否已经请求过至少一次数据
*/ */
get isUpdated() { get isUpdated() {
return this._isUpdated; return this._isUpdated
} }
/** /**
@@ -124,9 +136,9 @@ class VirtualDirectory {
*/ */
getParent(layer: number): VirtualDirectory { getParent(layer: number): VirtualDirectory {
if (layer <= 0 || !this.parent) { if (layer <= 0 || !this.parent) {
return this; return this
} }
return this.parent.getParent(layer - 1); return this.parent.getParent(layer - 1)
} }
get tree(): Tree { get tree(): Tree {
@@ -136,68 +148,88 @@ class VirtualDirectory {
path: this.path, path: this.path,
stats: this.stats, stats: this.stats,
files: files:
this.files?.map(v => ({ this.files?.map((v) => ({
name: v.name, name: v.name,
type: v.type, type: v.type,
size: v.size, size: v.size,
stats: v.stats, stats: v.stats,
url: v.url url: v.url
})) ?? [], })) ?? [],
directories: this.directories?.map(v => v.tree) ?? [] directories: this.directories?.map((v) => v.tree) ?? []
}; }
} }
// todo: 重构这个函数 // 时间复杂度大爆炸
updateContent(content: (file | directory)[]) { updateContent(content: (file | directory)[]) {
this._isUpdated = true; this._isUpdated = true
this.files = this.files ?? []; const itemNames: string[] = content.map((v) => v.name)
this.directories = this.directories ?? [];
const fileNames: string[] = this.files.map(v => v.name);
const dirNames: string[] = this.directories.map(v => v.name);
const itemNames: string[] = content.map(v => v.name);
// 删去远程端已不存在的文件与文件夹 // 删去远程端已不存在的文件与文件夹
const _delete = (target: (VirtualFile | VirtualDirectory)[]) => { const _delete = (target: (VirtualFile | VirtualDirectory)[]) => {
let index = 0; let index = 0
while (index < target.length) { while (index < target.length) {
if (!itemNames.includes(target[index].name)) { if (!itemNames.includes(target[index].name)) {
target.splice(index, 1); target.splice(index, 1)
} else { } else {
index += 1; index += 1
} }
} }
}; }
_delete(this.files); const _addFile = (item: file) => {
_delete(this.directories); const nvf =
// vFileMap.get(`${this.path}${item.name}`) ??
new VirtualFile(item, this)
this.files.push(nvf)
}
const _addDirectory = (item: directory) => {
const nvd =
// vDirectoryMap.get(`${this.path}${item.name}/`) ??
new VirtualDirectory(item, this)
this.directories.push(nvd)
}
const newFileNames: string[] = difference(
content.filter((v) => v.type === 'file').map((v) => v.name),
this.files.map((v) => v.name)
)
const newDirectoryNames: string[] = difference(
content.filter((v) => v.type === 'directory').map((v) => v.name),
this.files.map((v) => v.name)
)
_delete(this.files)
_delete(this.directories)
// 加入新的文件与文件夹 // 加入新的文件与文件夹
for (let item of content) { for (let item of content.filter((v) => newFileNames.includes(v.name))) {
if (item.type === "file") { _addFile(item as file)
if (!fileNames.includes(item.name)) {
this.files.push(new VirtualFile(item, this));
}
} else if (item.type === "directory") {
if (!dirNames.includes(item.name)) {
this.directories.push(new VirtualDirectory(item, this));
}
} }
for (let item of content.filter((v) =>
newDirectoryNames.includes(v.name)
)) {
_addDirectory(item as directory)
} }
} }
hasChild(item: VirtualDirectory | VirtualFile): boolean { hasChild(item: VirtualDirectory | VirtualFile): boolean {
if (item.type === "directory") { if (item.type === 'directory') {
return this.directories?.includes(item) ?? false; return this.directories?.includes(item) ?? false
} else { } else {
return this.files?.includes(item) ?? false; return this.files?.includes(item) ?? false
} }
} }
// destroy() {
// for(const item of [...this.files, ...this.directories]){
// item.destroy()
// }
// vDirectoryMap.delete(this.path)
// }
/** /**
* 调用后重新向远端拉取文件夹信息并进行更新 * 调用后重新向远端拉取文件夹信息并进行更新
* @returns {void} * @returns {void}
*/ */
async update(): Promise<void> { async update(): Promise<void> {
const data: (file | directory)[] = await miaoFetchApi.get(this); const data: (file | directory)[] = await miaoFetchApi.get(this)
this.updateContent(data); this.updateContent(data)
} }
} }
export default VirtualDirectory; export default VirtualDirectory
+68 -31
View File
@@ -1,28 +1,49 @@
<template> <template>
<miao-drop-handler @on-virtual-directory="handleDropVDirectory" @on-files="handleDropFiles" <miao-drop-handler
@on-virtual-directory="handleDropVDirectory"
@on-files="handleDropFiles"
@on-virtual-files="handleDropVirtualFiles"> @on-virtual-files="handleDropVirtualFiles">
<miaoAlertTipProvider ref="miaoAlertTip">
<div class="miao-directory-item-container" ref="rootDomRef"> <div class="miao-directory-item-container" ref="rootDomRef">
<!-- 顶部面包屑导航和工具栏 --> <!-- 顶部面包屑导航和工具栏 -->
<miao-directory-top :color="props.color" :current-directory="currentDirectory" @back="handleBack" <miao-directory-top
:open-menu-option="topBarMenuOption" @reload="handleReload" @exit="emit('exit')" :index="index" :color="props.color"
@set-current-directory="setCurrentDirectory" @search="handleSearch" :current-directory="currentDirectory"
@back="handleBack"
:open-menu-option="topBarMenuOption"
@reload="handleReload"
@exit="emit('exit')"
:index="index"
@set-current-directory="setCurrentDirectory"
@search="handleSearch"
@menu-select="handleTopBarMenuSelect" /> @menu-select="handleTopBarMenuSelect" />
<!-- 文件和文件夹列表 --> <!-- 文件和文件夹列表 -->
<miao-directory-items ref="miaoDirectoryItemRef" :color="props.color" <miao-directory-items
:showData_directory="showData_directory" :showData_files="showData_files" ref="miaoDirectoryItemRef"
:selected-item="selectedItem.value" :index="index" @item-click="handleItemClick" :color="props.color"
@item-download="handleItemDownload" @item-delete="handleItemDelete" :showData_directory="showData_directory"
@item-drag-start="handleItemDragStart" @item-rename="handleItemRename" :showData_files="showData_files"
:selected-item="selectedItem.value"
:index="index"
@item-click="handleItemClick"
@item-download="handleItemDownload"
@item-delete="handleItemDelete"
@item-drag-start="handleItemDragStart"
@item-rename="handleItemRename"
@item-select="handleItemSelect" /> @item-select="handleItemSelect" />
<!-- 底部工具栏 --> <!-- 底部工具栏 -->
<miao-directory-bottom :index="index" @add-new-item="handleAddNewItem" v-if="false" <miao-directory-bottom
:index="index"
@add-new-item="handleAddNewItem"
v-if="false"
@pick-files-upload="handlePickFilesUpload" /> @pick-files-upload="handlePickFilesUpload" />
<miao-mask v-model:show="showModel"></miao-mask> <miao-mask v-model:show="showModel"></miao-mask>
<miao-popup-input ref="popupInput"></miao-popup-input> <miao-popup-input ref="popupInput"></miao-popup-input>
</div> </div>
</miaoAlertTipProvider>
</miao-drop-handler> </miao-drop-handler>
</template> </template>
@@ -37,13 +58,13 @@ import useVirtualPages from '@/hooks/useVirtualPages'
import { filePicker, renderIcon } from '@/hooks/miaoTools' import { filePicker, renderIcon } from '@/hooks/miaoTools'
import uniq from 'lodash/uniq' import uniq from 'lodash/uniq'
// 导入子组件
import miaoDirectoryTop from './components/miaoDirectoryTop.vue' import miaoDirectoryTop from './components/miaoDirectoryTop.vue'
import MiaoDirectoryItems from './components/miaoDirectoryItemsContainer.vue' import MiaoDirectoryItems from './components/miaoDirectoryItemsContainer.vue'
import MiaoDirectoryBottom from './components/miaoDirectoryBottom.vue' import MiaoDirectoryBottom from './components/miaoDirectoryBottom.vue'
import MiaoMask from '@/components/miaoMask.vue' import MiaoMask from '@/components/miaoMask.vue'
import MiaoPopupInput from '@/components/miaoPopupInput.vue' import MiaoPopupInput from '@/components/miaoPopupInput.vue'
import MiaoDropHandler from '@/components/miaoDropHandler.vue' import MiaoDropHandler from '@/components/miaoDropHandler.vue'
import miaoAlertTipProvider from '@/components/miaoAlertTipProvider.vue'
import { import {
CloseOutline, CloseOutline,
SearchOutline, SearchOutline,
@@ -80,6 +101,7 @@ const searchText = ref<string>('')
const showDirs = ref<boolean>(true) const showDirs = ref<boolean>(true)
const showFiles = ref<boolean>(true) const showFiles = ref<boolean>(true)
const miaoDirectoryItemRef = ref() const miaoDirectoryItemRef = ref()
const miaoAlertTip = ref<InstanceType<typeof miaoAlertTipProvider>>()
class SelectedItem { class SelectedItem {
constructor() { constructor() {
@@ -227,13 +249,14 @@ const topBarMenuOption = computed(() => {
label: `反选`, label: `反选`,
key: 'multiSelect:inversion' key: 'multiSelect:inversion'
}, },
selectedItem.value.length === 2 ? selectedItem.value.length === 2
{ ? {
label: `区间内全选`, label: `区间内全选`,
key: 'multiSelect:range' key: 'multiSelect:range'
} : undefined }
: undefined
].filter((v) => v !== undefined), ].filter((v) => v !== undefined),
icon: renderIcon(CheckmarkDoneOutline), icon: renderIcon(CheckmarkDoneOutline)
}, },
{ {
label: '插件', label: '插件',
@@ -259,11 +282,9 @@ const topBarMenuOption = computed(() => {
// 设置显示的dir // 设置显示的dir
const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => { const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
try {
// 若没有缓存数据则同步刷新,有缓存数据则异步刷新 // 若没有缓存数据则同步刷新,有缓存数据则异步刷新
if ( if (!virtualDirectory.isUpdated) {
virtualDirectory.files === undefined ||
virtualDirectory.directories === undefined
) {
await virtualDirectory.update() await virtualDirectory.update()
} else { } else {
virtualDirectory.update() virtualDirectory.update()
@@ -279,6 +300,12 @@ const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
}) })
} }
currentDirectories.value[0] = virtualDirectory currentDirectories.value[0] = virtualDirectory
} catch(e) {
miaoAlertTip.value?.alertTip(`获取文件夹内容出错`, {
type: 'error',
timeout: 3000
})
}
} }
const reload = () => { const reload = () => {
@@ -315,10 +342,12 @@ const handleTopBarMenuSelect = (key: string) => {
// selectedItem.clear() // selectedItem.clear()
} else if (key === 'showDirs') { } else if (key === 'showDirs') {
showDirs.value = !showDirs.value showDirs.value = !showDirs.value
showDirs.value === false && selectedItem.clear(v => v.type !== 'directory') showDirs.value === false &&
selectedItem.clear((v) => v.type !== 'directory')
} else if (key === 'showFiles') { } else if (key === 'showFiles') {
showFiles.value = !showFiles.value showFiles.value = !showFiles.value
showFiles.value === false && selectedItem.clear(v => v.type !== 'file') showFiles.value === false &&
selectedItem.clear((v) => v.type !== 'file')
} else if (key.startsWith('plugin:')) { } else if (key.startsWith('plugin:')) {
const pluginName = key.split(':')[1] const pluginName = key.split(':')[1]
pluginCenter.usePlugin(pluginName, [currentDirectory.value], []) pluginCenter.usePlugin(pluginName, [currentDirectory.value], [])
@@ -326,20 +355,29 @@ const handleTopBarMenuSelect = (key: string) => {
const opName = key.split(':')[1] const opName = key.split(':')[1]
switch (opName) { switch (opName) {
case 'all': case 'all':
selectedItem.pushArray([...showData_directory.value, ...showData_files.value]) selectedItem.pushArray([
break; ...showData_directory.value,
...showData_files.value
])
break
case 'reset': case 'reset':
selectedItem.clear() selectedItem.clear()
break break
case 'inversion': case 'inversion':
const sArr = selectedItem.value const sArr = selectedItem.value
const arr = [...showData_directory.value, ...showData_files.value].filter(i => !sArr.includes(i)) const arr = [
...showData_directory.value,
...showData_files.value
].filter((i) => !sArr.includes(i))
selectedItem.clear() selectedItem.clear()
selectedItem.pushArray(arr) selectedItem.pushArray(arr)
break break
case "range": case 'range':
const _sArr = selectedItem.value const _sArr = selectedItem.value
const _arr = [...showData_directory.value, ...showData_files.value] const _arr = [
...showData_directory.value,
...showData_files.value
]
const _nArr = [] const _nArr = []
let _counter = 0 let _counter = 0
for (const i of _arr) { for (const i of _arr) {
@@ -357,7 +395,6 @@ const handleTopBarMenuSelect = (key: string) => {
selectedItem.pushArray(_nArr) selectedItem.pushArray(_nArr)
break break
} }
} }
} }
@@ -377,7 +414,7 @@ const handleItemClick = (item: VirtualDirectory | VirtualFile) => {
} else { } else {
if (item.type === 'file') { if (item.type === 'file') {
const useablePlugins = pluginCenter.getUsablePlugin([], [item]) const useablePlugins = pluginCenter.getUsablePlugin([], [item])
if(useablePlugins.length > 0){ if (useablePlugins.length > 0) {
pluginCenter.usePlugin(useablePlugins[0].key, [], [item]) pluginCenter.usePlugin(useablePlugins[0].key, [], [item])
} else { } else {
openUrl(`${baseUrl}${api.get}${item.path}`) openUrl(`${baseUrl}${api.get}${item.path}`)
@@ -396,7 +433,7 @@ const handleItemDownload = (item: VirtualFile) => {
const handleItemDelete = async (_item: VirtualDirectory | VirtualFile) => { const handleItemDelete = async (_item: VirtualDirectory | VirtualFile) => {
for (let item of uniq([...selectedItem.value, _item])) { for (let item of uniq([...selectedItem.value, _item])) {
; (async () => { ;(async () => {
const { response } = miaoFetchApi.delete(item, { const { response } = miaoFetchApi.delete(item, {
retry: 5 retry: 5
}) })
@@ -485,7 +522,7 @@ const handleDropVDirectory = async (vDirs: VirtualDirectory[]) => {
} }
} }
for (let dir of vDirs) { for (let dir of vDirs) {
; (async () => { ;(async () => {
const _from = dir.parent const _from = dir.parent
const { response } = miaoFetchApi.cut(dir, currentDirectory.value) const { response } = miaoFetchApi.cut(dir, currentDirectory.value)
const id = (await response).eventId const id = (await response).eventId
@@ -504,7 +541,7 @@ const handleDropVirtualFiles = (files: VirtualFile[]) => {
return return
} }
for (let file of files) { for (let file of files) {
; (async () => { ;(async () => {
const _from = file.parent const _from = file.parent
const { response } = miaoFetchApi.cut(file, currentDirectory.value) const { response } = miaoFetchApi.cut(file, currentDirectory.value)
const id = (await response).eventId const id = (await response).eventId