feat: 1.拆分miaoDirectory,右上角退出按钮改为小菜单,增加搜索,屏蔽文件夹等功能。2.更新readme

This commit is contained in:
539943419 committed 2024-08-30 23:29:28 +08:00
1 parent 3e24d4a363
commit c02f6743e3
7 files changed
+524 -313

No files matched your search

+13 -11
View File
@@ -1,11 +1,13 @@
todo: 标签页,miaoDirectory切换动画 [finish] ## TODO list:
todo: 重构virtualPage,所有page以插件形式使用 [finish]
todo: miaoDirectory插件化,为后续插件功能开发做准备 [finish] | 任务 | 状态 |
todo: miaoPopupInput, 弹出一个输入框 [finish] |---|---|
todo: miaoDirectory的重命名功能 [finish] | 拆分miaoDirectory | ✅ |
todo: miaoDirectory的剪切功能 [finish] | 完善视频插件 | ✅ |
todo: miaoDirectory的上传按钮 [finish] | 完善PDF插件 | ✅ |
todo: miaoDirectory的新建文件/文件夹功能 [finish] | 完善Code插件 | ✅ |
todo: miaoDirectory的多选功能 [finish] | 实现miaoDirectory的搜索功能 | ❌ |
todo: VirtualDirectory更新时更新文件信息 | 完善miaoDirectory的搜索功能 | ❌ |
todo: miaoDirectory的复制文件/文件夹功能 | 完善图片浏览插件 | ❌ |
| VirtualDirectory更新时更新文件信息 | ❌ |
| miaoDirectory的复制文件/文件夹功能 | ❌ |
@@ -0,0 +1,77 @@
<template>
<div class="miao-directory-container-bottom" :style="{
backgroundColor:
index % 2 === 1 ? 'rgb(61 61 61)' : 'rgb(162 162 162)'
}">
<div class="container-bottom-item">
<div class="container-bottom-item-icon">
<add-outline :style="{
color:
index % 2 === 0
? 'rgb(0 0 0)'
: 'rgb(255 255 255)'
}" @click="$emit('add-new-item')" />
</div>
</div>
<div class="container-bottom-item">
<div class="container-bottom-item-icon">
<cloud-upload-outline :style="{
color:
index % 2 === 0
? 'rgb(0 0 0)'
: 'rgb(255 255 255)'
}" @click="$emit('pick-files-upload')" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { AddOutline, CloudUploadOutline } from '@vicons/ionicons5'
defineProps<{
index: number
}>()
const emit = defineEmits<{
'add-new-item': []
'pick-files-upload': []
}>()
</script>
<style scoped lang="scss">
.miao-directory-container-bottom {
height: 60px;
background-color: bisque;
display: flex;
justify-content: space-around;
align-items: center;
user-select: none;
box-shadow: 0px 1px 10px #888888;
z-index: 2;
.container-bottom-item {
height: 40px;
width: 40px;
display: flex;
justify-content: center;
align-items: center;
.container-bottom-item-icon {
svg {
width: 30px;
height: 30px;
transition: width 0.3s ease;
transition: height 0.3s ease;
cursor: pointer;
}
&:hover {
svg {
width: 40px;
height: 40px;
}
}
}
}
}
</style>
@@ -138,6 +138,7 @@ const dropDownOptions = computed(() => {
}) })
// 是不是可以直接在这里面实现? // 是不是可以直接在这里面实现?
// 应该将所有事件emit出去才对
const handleDropdownSelect = (key: string) => { const handleDropdownSelect = (key: string) => {
if (key === 'rename') { if (key === 'rename') {
emit('rename') emit('rename')
@@ -0,0 +1,81 @@
<template>
<div class="miao-directory-container-items" :style="{
backgroundColor:
index % 2 === 0 ? '#f8f8f8' : 'rgb(240 240 240)'
}">
<n-scrollbar ref="scrollbarRef">
<transition-group name="dirItem">
<miao-lazy-div v-for="(dir, index) in showData_directory" :key="dir.uid" :disableLazy="index < 20"
min-height="50px">
<miaoDirectoryItem :item="dir" :color="props.color" :selectedItem="selectedItem"
@delete="handleItemDelete(dir)" @click="handleItemClick(dir)" @drag-start="handleItemDragStart"
@rename="handleItemRename(dir)" @on-selected="handleItemSelect(dir)" />
</miao-lazy-div>
</transition-group>
<transition-group name="dirItem">
<miao-lazy-div v-for="(file, index) in showData_files" :key="file.uid" :disableLazy="index < 20"
min-height="50px">
<miaoDirectoryItem :item="file" :color="props.color" :selectedItem="selectedItem"
@click="handleItemClick(file)" @download="handleItemDownload(file)"
@delete="handleItemDelete(file)" @drag-start="handleItemDragStart"
@rename="handleItemRename(file)" @on-selected="handleItemSelect(file)" />
</miao-lazy-div>
</transition-group>
</n-scrollbar>
</div>
</template>
<script setup lang="ts">
import { NScrollbar } from 'naive-ui'
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import miaoDirectoryItem from '@/components/miaoDirectory/miaoDirectoryItem.vue'
import miaoLazyDiv from '@/components/miaoLazyDiv.vue'
const props = defineProps<{
color: string
index: number
showData_directory: VirtualDirectory[]
showData_files: VirtualFile[]
selectedItem: (VirtualFile | VirtualDirectory)[]
}>()
const emit = defineEmits<{
'item-click': [item: VirtualDirectory | VirtualFile]
'item-download': [item: VirtualFile]
'item-delete': [item: VirtualDirectory | VirtualFile]
'item-drag-start': [_event: DragEvent, item: VirtualDirectory | VirtualFile]
'item-rename': [item: VirtualDirectory | VirtualFile]
'item-select': [item: VirtualDirectory | VirtualFile]
}>()
const handleItemClick = (item: VirtualDirectory | VirtualFile) => {
emit('item-click', item)
}
const handleItemDownload = (item: VirtualFile) => {
emit('item-download', item)
}
const handleItemDelete = (item: VirtualDirectory | VirtualFile) => {
emit('item-delete', item)
}
const handleItemDragStart = (_event: DragEvent, item: VirtualDirectory | VirtualFile) => {
emit('item-drag-start', _event, item)
}
const handleItemRename = (item: VirtualDirectory | VirtualFile) => {
emit('item-rename', item)
}
const handleItemSelect = (item: VirtualDirectory | VirtualFile) => {
emit('item-select', item)
}
</script>
<style scoped lang="scss">
.miao-directory-container-items {
width: 100%;
height: calc(100% - 30px - 60px);
}
</style>
@@ -0,0 +1,152 @@
<template>
<div class="miao-directory-container-top" :style="{
backgroundColor:
index % 2 === 0 ? '#f8f8f8' : 'rgb(240 240 240)'
}">
<div class="container-top-colorfulBar" :style="{ backgroundColor: props.color }"></div>
<div class="container-top-breadcrumb">
<div class="container-top-breadcrumb-container">
<n-breadcrumb separator=">" style="margin-left: 5px">
<n-breadcrumb-item :clickable="false">
<n-icon size="18">
<CloudOutline />
</n-icon>
</n-breadcrumb-item>
<n-breadcrumb-item v-for="dir in currentDirectory?.getParents"
@click="handleClickBreadcrumbItem(dir)" :clickable="true">
<div>{{ dir.name }}</div>
</n-breadcrumb-item>
</n-breadcrumb>
</div>
</div>
<div class="container-top-tools">
<n-icon class="container-top-tools-item" size="15" @click="$emit('back')">
<ChevronBackOutline />
</n-icon>
<n-icon class="container-top-tools-item" size="14" @click="$emit('reload')">
<ReloadOutline class="container-top-tools-item-reload" />
</n-icon>
<n-dropdown trigger="click" :options="openMenuOption" @select="(key: string) => emit('menuSelect', key)">
<n-icon class="container-top-tools-item" size="14">
<EllipsisVertical />
</n-icon>
</n-dropdown>
</div>
</div>
</template>
<script setup lang="ts">
import { NBreadcrumbItem, NBreadcrumb, NIcon, NDropdown } from 'naive-ui'
import {
CloudOutline,
ChevronBackOutline,
ReloadOutline,
EllipsisVertical,
} from '@vicons/ionicons5'
import VirtualDirectory from '@/class/VirtualDirectory'
const props = defineProps<{
color: string;
index: number
currentDirectory: VirtualDirectory | undefined;
openMenuOption: {
key: string,
label: string,
[key: string]: any,
}[]
}>()
const emit = defineEmits<{
back: [],
reload: [],
menuSelect: [key: string]
'set-current-directory': [virtualDirectory: VirtualDirectory]
}>()
const handleClickBreadcrumbItem = (virtualDirectory: VirtualDirectory) => {
emit('set-current-directory', virtualDirectory)
}
</script>
<style scoped lang="scss">
.miao-directory-container-top {
height: 30px;
width: 100%;
user-select: none;
position: relative;
display: flex;
align-items: center;
overflow: hidden;
background-color: #f1f1f1;
.container-top-colorfulBar {
height: 70%;
width: 5px;
margin-left: 10px;
border-radius: 3px 0 0 3px;
}
.container-top-breadcrumb {
position: relative;
height: 70%;
width: calc(100% - 95px);
display: flex;
justify-content: flex-start;
align-items: center;
// overflow: hidden;
overflow-y: hidden;
overflow-x: hidden;
background-color: #ffffff;
padding: 0 5px;
border-radius: 0 3px 3px 0;
.container-top-breadcrumb-container {
position: absolute;
height: 100%;
right: 0;
top: 0;
min-width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
}
}
.container-top-tools {
position: relative;
height: 100%;
// width: 70px;
padding: 0 5px;
display: flex;
justify-content: space-around;
align-items: center;
.container-top-tools-item {
width: 20px;
height: 20px;
margin: 0 1px;
display: flex;
justify-content: center;
align-items: center;
background-color: #ffffff00;
border-radius: 5px;
transition: background-color 0.3s;
cursor: pointer;
.container-top-tools-item-reload {
transition: transform 0.6s ease-in-out;
}
&:hover {
background-color: rgba(128, 128, 128, 0.4);
}
&:active .container-top-tools-item-reload {
transform: rotate(360deg);
}
}
}
}
</style>
+199 -300
View File
@@ -2,93 +2,21 @@
<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">
<div class="miao-directory-item-container" ref="rootDomRef"> <div class="miao-directory-item-container" ref="rootDomRef">
<div class="container-top" :style="{ <!-- 顶部面包屑导航和工具栏 -->
backgroundColor: <miao-directory-top :color="props.color" :current-directory="currentDirectory" @back="handleBack"
index % 2 === 0 ? '#f8f8f8' : 'rgb(240 240 240)' :open-menu-option="topBarMenuOption" @reload="handleReload" @exit="emit('exit')" :index="index"
}"> @set-current-directory="setCurrentDirectory" @search="handleSearch" @menu-select="handleTopBarMenuSelect" />
<div class="container-top-colorfulBar" :style="{ backgroundColor: props.color }"></div>
<div class="container-top-breadcrumb"> <!-- 文件和文件夹列表 -->
<!-- <n-scrollbar x-scrollable> --> <miao-directory-items :color="props.color" :showData_directory="showData_directory"
<div class="container-top-breadcrumb-container"> :showData_files="showData_files" :selected-item="selectedItem.value" :index="index"
<n-breadcrumb separator=">" style="margin-left: 5px"> @item-click="handleItemClick" @item-download="handleItemDownload" @item-delete="handleItemDelete"
<n-breadcrumb-item :clickable="false"> @item-drag-start="handleItemDragStart" @item-rename="handleItemRename" @item-select="handleItemSelect" />
<n-icon size="18">
<CloudOutline /> <!-- 底部工具栏 -->
</n-icon> <miao-directory-bottom :index="index" @add-new-item="handleAddNewItem"
</n-breadcrumb-item> @pick-files-upload="handlePickFilesUpload" />
<n-breadcrumb-item v-for="dir in currentDirectory?.getParents"
@click="setCurrentDirectory(dir)" :clickable="true">
<div>{{ dir.name }}</div>
</n-breadcrumb-item>
</n-breadcrumb>
</div>
<!-- </n-scrollbar> -->
</div>
<div class="container-top-tools">
<n-icon class="container-top-tools-item" size="15" @click="handleBack">
<ChevronBackOutline />
</n-icon>
<n-icon class="container-top-tools-item" size="14" @click="handleReload">
<ReloadOutline class="container-top-tools-item-reload" />
</n-icon>
<n-icon class="container-top-tools-item" size="20" @click="emit('exit')">
<CloseOutline />
</n-icon>
</div>
</div>
<div class="container-items" :style="{
backgroundColor:
index % 2 === 0 ? '#f8f8f8' : 'rgb(240 240 240)'
}">
<n-scrollbar ref="scrollbarRef">
<transition-group name="dirItem">
<miao-lazy-div v-for="(dir, index) in showData_directory" :key="dir.uid"
:disableLazy="index < 20" min-height="50px">
<miaoDirectoryItem :item="dir" :color="props.color" :selectedItem="selectedItem.value"
@delete="handleItemDelete(dir)" @click="handleItemClick(dir)"
@drag-start="handleItemDragStart" @rename="handleItemRename(dir)"
@on-selected="handleItemSelect(dir)" />
</miao-lazy-div>
</transition-group>
<transition-group name="dirItem">
<miao-lazy-div v-for="(file, index) in showData_files" :key="file.uid" :disableLazy="index < 20"
min-height="50px">
<miaoDirectoryItem :item="file" :color="props.color" :selectedItem="selectedItem.value"
@click="handleItemClick(file)" @download="handleItemDownload(file)"
@delete="handleItemDelete(file)" @drag-start="handleItemDragStart"
@rename="handleItemRename(file)" @on-selected="handleItemSelect(file)" />
</miao-lazy-div>
</transition-group>
<!-- <n-virtual-list :item="showData_all" :item-size="50">
</n-virtual-list> -->
</n-scrollbar>
</div>
<div class="container-bottom" :style="{
backgroundColor:
index % 2 === 1 ? 'rgb(61 61 61)' : 'rgb(162 162 162)'
}">
<div class="container-bottom-item">
<div class="container-bottom-item-icon">
<add-outline :style="{
color:
index % 2 === 0
? 'rgb(0 0 0)'
: 'rgb(255 255 255)'
}" @click="handleAddNewItem" />
</div>
</div>
<div class="container-bottom-item">
<div class="container-bottom-item-icon">
<cloud-upload-outline :style="{
color:
index % 2 === 0
? 'rgb(0 0 0)'
: 'rgb(255 255 255)'
}" @click="handlePickFilesUpload" />
</div>
</div>
</div>
<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>
@@ -96,35 +24,37 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { NBreadcrumbItem, NBreadcrumb, NIcon, NScrollbar } from 'naive-ui' import { computed, h, nextTick, onMounted, reactive, ref } from 'vue'
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory' import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import { computed, nextTick, onMounted, reactive, ref } from 'vue'
import Config from '@/config' import Config from '@/config'
import miaoMask from '@/components/miaoMask.vue'
import miaoDirectoryItem from '@/components/miaoDirectory/miaoDirectoryItem.vue'
import miaoLazyDiv from '@/components/miaoLazyDiv.vue'
import miaoPopupInput from '@/components/miaoPopupInput.vue'
import miaoDropHandler from '@/components/miaoDropHandler.vue'
import useMiaoFetchApi from '@/hooks/useMiaoFetchApi' import useMiaoFetchApi from '@/hooks/useMiaoFetchApi'
import useDataBus from '@/hooks/useDataBus' import useDataBus from '@/hooks/useDataBus'
import {
CloudOutline,
ChevronBackOutline,
ReloadOutline,
CloseOutline,
CloudUploadOutline,
AddOutline
} from '@vicons/ionicons5'
import useUploadQueue from '@/hooks/useUploadQueue' import useUploadQueue from '@/hooks/useUploadQueue'
import useVirtualPages from '@/hooks/useVirtualPages' import useVirtualPages from '@/hooks/useVirtualPages'
import { filePicker } from '@/hooks/miaoTools' import { filePicker } from '@/hooks/miaoTools'
import { uniq } from 'lodash' import { uniq } from 'lodash'
// 导入子组件
import MiaoDirectoryTop from '@/components/miaoDirectory/miaoDirectoryTop.vue'
import MiaoDirectoryItems from '@/components/miaoDirectory/miaoDirectoryItemsContainer.vue'
import MiaoDirectoryBottom from '@/components/miaoDirectory/miaoDirectoryBottom.vue'
import MiaoMask from '@/components/miaoMask.vue'
import MiaoPopupInput from '@/components/miaoPopupInput.vue'
import MiaoDropHandler from '@/components/miaoDropHandler.vue'
import { NIcon } from 'naive-ui'
import {
CloseOutline, SearchOutline, FilterOutline, CheckmarkDoneOutline,
DocumentText,
FileTray
} from '@vicons/ionicons5'
import usePluginCenter from '@/hooks/usePluginCenter'
const { baseUrl, api } = Config const { baseUrl, api } = Config
const dataBus = useDataBus() const dataBus = useDataBus()
const views = useVirtualPages() const views = useVirtualPages()
const uploadQueue = useUploadQueue()
const miaoFetchApi = useMiaoFetchApi() const miaoFetchApi = useMiaoFetchApi()
const pluginCenter = usePluginCenter()
const props = defineProps<{ const props = defineProps<{
color: string color: string
@@ -137,11 +67,14 @@ const emit = defineEmits<{
const popupInput = ref() const popupInput = ref()
const scrollbarRef = ref()
// 是否显示模态框 // 是否显示模态框
const showModel = ref(0) const showModel = ref(0)
const searchText = ref<string>('')
const showDirs = ref<boolean>(true)
const showFiles = ref<boolean>(true)
class SelectedItem { class SelectedItem {
constructor() { constructor() {
this._selectedItem = [] this._selectedItem = []
@@ -151,15 +84,18 @@ class SelectedItem {
this._selectedItem = [item, ...this._selectedItem] this._selectedItem = [item, ...this._selectedItem]
} }
remove(item: VirtualDirectory | VirtualFile) { remove(item: VirtualDirectory | VirtualFile) {
this._selectedItem = this._selectedItem.filter(v => v !== item) this._selectedItem = this._selectedItem.filter((v) => v !== item)
} }
clear() { clear() {
this._selectedItem = [] this._selectedItem = []
} }
// 保证内容仍然存在于dir中且各个元素不重复 // 保证内容仍然存在于dir中且各个元素不重复
get value() { get value() {
const _filterList = [...(currentDirectory.value?.directories ?? []), ...(currentDirectory.value?.files ?? [])] const _filterList = [
return uniq(this._selectedItem).filter(v => { ...(currentDirectory.value?.directories ?? []),
...(currentDirectory.value?.files ?? []),
]
return uniq(this._selectedItem).filter((v) => {
if (currentDirectory.value === undefined) { if (currentDirectory.value === undefined) {
return false return false
} }
@@ -172,7 +108,7 @@ class SelectedItem {
const selectedItem = reactive(new SelectedItem()) const selectedItem = reactive(new SelectedItem())
const currentDirectories = defineModel<VirtualDirectory[]>('currentDirectories', { const currentDirectories = defineModel<VirtualDirectory[]>('currentDirectories', {
required: true required: true,
}) })
// 目前展示的Dir // 目前展示的Dir
@@ -187,48 +123,99 @@ const index = computed(() => {
// 用于展示的数据,后续会增加排序等操作 // 用于展示的数据,后续会增加排序等操作
const showData_directory = computed<VirtualDirectory[]>(() => { const showData_directory = computed<VirtualDirectory[]>(() => {
const data = currentDirectory.value?.directories if (showDirs.value === false) {
return []
}
let data = currentDirectory.value?.directories
? [...currentDirectory.value?.directories] ? [...currentDirectory.value?.directories]
: [] : []
if (searchText.value !== '') {
data = data.filter(vd => vd.name.includes(searchText.value))
}
return data return data
}) })
const showData_files = computed<VirtualFile[]>(() => { const showData_files = computed<VirtualFile[]>(() => {
const data = currentDirectory.value?.files if (showFiles.value === false) {
? [...currentDirectory.value?.files] return []
: [] }
let data = currentDirectory.value?.files ? [...currentDirectory.value?.files] : []
if (searchText.value !== '') {
data = data.filter(vd => vd.name.includes(searchText.value))
}
return data return data
}) })
// const showData_all = computed<(VirtualDirectory | VirtualFile)[]>(() => {
// const data = currentDirectory.value?.directories
// ? [...currentDirectory.value?.directories]
// : []
// data.push(...currentDirectory.value?.files)
// return data
// })
// 用于监听拖拽文件事件 const topBarMenuOption = computed(() => {
const rootDomRef = ref<HTMLDivElement>() return [
{
label: '搜索',
key: 'search',
icon: renderIcon(SearchOutline)
},
searchText.value !== '' ? {
label: '重置搜索',
key: 'searchReset',
icon: renderIcon(SearchOutline)
} : undefined,
selectedItem.value.length !== 0 ? {
label: '重置多选',
key: 'selectedItemReset',
icon: renderIcon(CheckmarkDoneOutline)
} : undefined,
{
label: '筛选',
key: 'filter',
children: [
{
label: `${showDirs.value ? '隐藏' : '显示'}文件夹`,
key: 'showDirs',
icon: renderIcon(FileTray)
},
{
label: `${showFiles.value ? '隐藏' : '显示'}文件`,
key: 'showFiles',
icon: renderIcon(DocumentText)
},
],
icon: renderIcon(FilterOutline)
},
...pluginCenter.getUsablePlugin([currentDirectories.value[0]], []).map(v => ({
label: `插件:${v.name}`,
key: `plugin:${v.key}`
})),
{
label: '关闭',
key: 'close',
icon: renderIcon(CloseOutline)
},
].filter(v => v !== undefined)
})
const uploadQueue = useUploadQueue() const renderIcon = (icon: any) => {
return () => {
return h(NIcon, null, {
default: () => h(icon)
})
}
}
// 设置显示的dir // 设置显示的dir
const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => { const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
// 若没有缓存数据则同步刷新,有缓存数据则异步刷新 // 若没有缓存数据则同步刷新,有缓存数据则异步刷新
if ( if (virtualDirectory.files === undefined || virtualDirectory.directories === undefined) {
virtualDirectory.files === undefined ||
virtualDirectory.directories === undefined
) {
await virtualDirectory.update() await virtualDirectory.update()
} else { } else {
virtualDirectory.update() virtualDirectory.update()
} }
if (currentDirectories.value[0] !== virtualDirectory) { if (currentDirectories.value[0] !== virtualDirectory) {
selectedItem.clear() selectedItem.clear()
handleSearchReset()
nextTick(() => { nextTick(() => {
scrollbarRef.value.scrollTo({ // @ts-ignore
top: 0, const el = document.querySelector(
behavior: "instant" `.miao-virtual-page-container-item-${props.id} .n-scrollbar > .n-scrollbar-rail > .n-scrollbar-track`
}) )
el && (el.scrollTop = 0)
}) })
} }
currentDirectories.value[0] = virtualDirectory currentDirectories.value[0] = virtualDirectory
@@ -243,7 +230,7 @@ const openUrl = (
config?: { config?: {
download?: string download?: string
target?: string target?: string
} },
) => { ) => {
let { target, download } = config ?? {} let { target, download } = config ?? {}
const a = document.createElement('a') const a = document.createElement('a')
@@ -253,6 +240,25 @@ const openUrl = (
a.click() a.click()
} }
const handleTopBarMenuSelect = (key: string) => {
if (key === 'close') {
emit('exit')
} else if (key === 'search') {
handleSearch()
} else if (key === 'searchReset') {
handleSearchReset()
} else if (key === 'selectedItemReset') {
selectedItem.clear()
} else if (key === 'showDirs') {
showDirs.value = !showDirs.value
} else if (key === 'showFiles') {
showFiles.value = !showFiles.value
} else if (key.startsWith('plugin:')) {
const pluginName = key.split(':')[1]
pluginCenter.usePlugin(pluginName, [currentDirectory.value], [])
}
}
const handleBack = () => { const handleBack = () => {
if (currentDirectory.value?.parent) { if (currentDirectory.value?.parent) {
setCurrentDirectory(currentDirectory.value.parent) setCurrentDirectory(currentDirectory.value.parent)
@@ -277,7 +283,7 @@ const handleItemClick = (item: VirtualDirectory | VirtualFile) => {
const handleItemDownload = (item: VirtualFile) => { const handleItemDownload = (item: VirtualFile) => {
openUrl(`${baseUrl}${api.get}${item.path}`, { openUrl(`${baseUrl}${api.get}${item.path}`, {
download: item.name download: item.name,
}) })
} }
@@ -285,7 +291,7 @@ 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,
}) })
// todo: 将删除事件统一用一个事件管理中心管理 // todo: 将删除事件统一用一个事件管理中心管理
const id = (await response).eventId const id = (await response).eventId
@@ -304,27 +310,27 @@ const handleItemRename = async (item: VirtualDirectory | VirtualFile) => {
showInput: true, showInput: true,
inputValue: item.name, inputValue: item.name,
inputProps: { inputProps: {
placeholder: item.name placeholder: item.name,
}, },
options: [ options: [
{ {
label: '取消', label: '取消',
key: false, key: false,
type: 'error' type: 'error',
}, },
{ {
label: '确认', label: '确认',
key: true, key: true,
type: 'success' type: 'success',
} },
] ],
}) })
if (popupRes.key === false) { if (popupRes.key === false) {
return return
} }
const newName = popupRes.text const newName = popupRes.text
const { response } = miaoFetchApi.rename(item, newName, { const { response } = miaoFetchApi.rename(item, newName, {
retry: 5 retry: 5,
}) })
const id = (await response).eventId const id = (await response).eventId
const { response: res } = miaoFetchApi.query(id) const { response: res } = miaoFetchApi.query(id)
@@ -336,11 +342,11 @@ const handleItemRename = async (item: VirtualDirectory | VirtualFile) => {
const handleItemDragStart = async ( const handleItemDragStart = async (
_event: DragEvent, _event: DragEvent,
item: VirtualDirectory | VirtualFile item: VirtualDirectory | VirtualFile,
) => { ) => {
const items = uniq([item, ...selectedItem.value]) const items = uniq([item, ...selectedItem.value])
dataBus.set('dragData_vFiles', items.filter(v => v.type === 'file')) dataBus.set('dragData_vFiles', items.filter((v) => v.type === 'file'))
dataBus.set('dragData_vDirectory', items.filter(v => v.type === 'directory')) dataBus.set('dragData_vDirectory', items.filter((v) => v.type === 'directory'))
// selectedItem.clear() // selectedItem.clear()
} }
@@ -349,7 +355,7 @@ const handleDropFiles = async (files: File[]) => {
uploadQueue.push(files, currentDirectory.value, { uploadQueue.push(files, currentDirectory.value, {
onFinish() { onFinish() {
reload() reload()
} },
}) })
} }
@@ -359,6 +365,9 @@ const handleDropVDirectory = async (vDirs: VirtualDirectory[]) => {
if (currentDirectory.value.getParents.includes(vDir)) { if (currentDirectory.value.getParents.includes(vDir)) {
return return
} }
if(vDir.parent === currentDirectory.value) {
return
}
} }
for (let dir of vDirs) { for (let dir of vDirs) {
; (async () => { ; (async () => {
@@ -396,13 +405,13 @@ const handleDropVirtualFiles = (files: VirtualFile[]) => {
const handlePickFilesUpload = async () => { const handlePickFilesUpload = async () => {
const files = await filePicker({ const files = await filePicker({
multiple: true multiple: true,
}) })
const _currDir = currentDirectory.value const _currDir = currentDirectory.value
uploadQueue.push(files, _currDir, { uploadQueue.push(files, _currDir, {
onFinish() { onFinish() {
_currDir.update() _currDir.update()
} },
}) })
} }
@@ -411,25 +420,25 @@ const handleAddNewItem = async () => {
title: '新建文件/文件夹', title: '新建文件/文件夹',
showInput: true, showInput: true,
inputProps: { inputProps: {
placeholder: '' placeholder: '',
}, },
options: [ options: [
{ {
label: '取消', label: '取消',
key: 'cancel', key: 'cancel',
type: 'error' type: 'error',
}, },
{ {
label: '文件', label: '文件',
key: 'file', key: 'file',
type: 'success' type: 'success',
}, },
{ {
label: '文件夹', label: '文件夹',
key: 'dir', key: 'dir',
type: 'success' type: 'success',
} },
] ],
}) })
// todo: 上传前如重名文件夹等等的错误提前检查 // todo: 上传前如重名文件夹等等的错误提前检查
if (popupRes.key === 'cancel' || popupRes.text === '') { if (popupRes.key === 'cancel' || popupRes.text === '') {
@@ -459,6 +468,44 @@ const handleItemSelect = (item: VirtualDirectory | VirtualFile) => {
selectedItem.remove(item) selectedItem.remove(item)
} }
} }
const handleSearch = async () => {
const popupRes = await popupInput.value.popup({
title: '搜索当前文件夹',
showInput: true,
inputValue: searchText.value,
inputProps: {
placeholder: '',
},
options: [
{
label: '取消',
key: 'cancel',
type: 'default',
},
{
label: '重置',
key: 'reset',
type: 'default',
},
{
label: '搜索',
key: 'search',
type: 'success',
},
],
})
console.log(popupRes)
if (popupRes.key === 'search') {
searchText.value = popupRes.text
} else if (popupRes.key === 'reset') {
handleSearchReset()
}
}
const handleSearchReset = () => {
searchText.value = ''
}
onMounted(async () => { onMounted(async () => {
await setCurrentDirectory(currentDirectory.value) await setCurrentDirectory(currentDirectory.value)
}) })
@@ -477,153 +524,5 @@ $bottom-bar-height: 60px;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
min-width: 170px; min-width: 170px;
.container-top {
height: $top-height;
width: 100%;
user-select: none;
position: relative;
display: flex;
align-items: center;
overflow: hidden;
background-color: #f1f1f1;
.container-top-colorfulBar {
height: 70%;
width: 5px;
margin-left: 10px;
border-radius: 3px 0 0 3px;
}
.container-top-breadcrumb {
position: relative;
height: 70%;
width: calc(100% - 95px);
display: flex;
justify-content: flex-start;
align-items: center;
// overflow: hidden;
overflow-y: hidden;
overflow-x: hidden;
background-color: #ffffff;
padding: 0 5px;
border-radius: 0 3px 3px 0;
.container-top-breadcrumb-container {
position: absolute;
height: 100%;
right: 0;
top: 0;
min-width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
}
}
.container-top-tools {
position: relative;
height: 100%;
width: 70px;
padding: 0 5px;
display: flex;
justify-content: space-around;
align-items: center;
.container-top-tools-item {
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
background-color: #ffffff00;
border-radius: 5px;
transition: background-color 0.3s;
cursor: pointer;
.container-top-tools-item-reload {
transition: transform 0.6s ease-in-out;
}
&:hover {
background-color: rgba(128, 128, 128, 0.4);
}
&:active .container-top-tools-item-reload {
transform: rotate(360deg);
}
}
// &::after {
// content: '';
// height: 60%;
// position: absolute;
// right: -2px;
// width: 2px;
// background-color: #828282;
// }
}
}
.container-items {
width: 100%;
height: calc(100% - $top-height - $bottom-bar-height);
// flex: 1;
}
.container-bottom {
height: $bottom-bar-height;
background-color: bisque;
display: flex;
justify-content: space-around;
align-items: center;
user-select: none;
box-shadow: 0px 1px 10px #888888;
z-index: 2;
.container-bottom-item {
height: 40px;
width: 40px;
display: flex;
justify-content: center;
align-items: center;
.container-bottom-item-icon {
svg {
width: 30px;
height: 30px;
transition: all 0.3s ease;
cursor: pointer;
}
&:hover {
svg {
width: 40px;
height: 40px;
}
}
}
}
}
} }
</style>
// transition动画相关
// .miao-directory-item-container {
// .container-items {
// .dirItem-move {
// transition: all 0.2s ease;
// }
// .dirItem-leave-active {
// transition: none;
// }
// .dirItem-enter-from {
// opacity: 0;
// }
// .dirItem-leave-active {
// position: absolute;
// }
// }
// }</style>
+1 -2
View File
@@ -66,9 +66,8 @@ const activeImageIndex = ref(-1)
const scrollToActiveImage = () => { const scrollToActiveImage = () => {
const dom = rootRef.value?.querySelector('.miaoImage-container-row-image-active') const dom = rootRef.value?.querySelector('.miaoImage-container-row-image-active')
console.log({ dom })
NScrollbarRef.value.scrollTo({ NScrollbarRef.value.scrollTo({
top: dom?.offsetTop - 30 ?? 0, top: dom.offsetTop - 30,
behavior: "smooth" behavior: "smooth"
}) })
} }