This commit is contained in:
539943419 committed 2024-09-26 17:02:41 +08:00
commit 96ca8fcf4c
32 files changed
+834 -601

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
import { VirtualFile } from "@/class/VirtualDirectory"
import config from "@/config"
import { usePluginHooksType } from "@/types/type"
import copy2Clipboard from 'copy-to-clipboard'
const copy = (__: any, vFiles: VirtualFile[], hooks: usePluginHooksType) => {
const { globalAlertTip } = hooks
const vFile = vFiles[0]
console.log(vFile.url)
copy2Clipboard(`${config.baseUrl}${vFile.url}`)
globalAlertTip(`${vFile.name}的链接已复制至剪切板`, {
type: 'info',
timeout: 2000
})
}
export default copy
@@ -0,0 +1,26 @@
import { Plugin, PluginGroup } from "@/class/PluginCenter";
import Copy from "./copy";
import { CopyOutline } from "@vicons/ionicons5";
import { PluginExportType } from "@/types/type";
import { shallowRef } from "vue";
const pluginConfig: Plugin = {
name: "复制链接",
icon: shallowRef(CopyOutline),
filter: (vDirs, vFiles) => {
if (vDirs.length !== 0) {
return false;
}
if (vFiles.length !== 1) {
return false;
}
return true;
},
disable: false,
group: [PluginGroup.default],
func: Copy
};
export default pluginConfig;
export const type = PluginExportType.default;
+3
View File
@@ -1,5 +1,6 @@
import { registerComponentOption } from '@/class/PluginCenter'
import { CodeOutline } from '@vicons/ionicons5'
import { PluginExportType } from '@/types/type'
const pluginConfig: registerComponentOption = {
key: 'miaoCodeMirror',
@@ -40,3 +41,5 @@ const pluginConfig: registerComponentOption = {
}
export default pluginConfig
export const type = PluginExportType.component
+8 -15
View File
@@ -1,18 +1,11 @@
<template>
<miao-message-provider ref="miaoMessage">
<div
class="codemirror-container"
ref="rootRef"
:class="`codemirror-container-${theme}`">
<div class="codemirror-container" ref="rootRef" :class="`codemirror-container-${theme}`">
<div class="codemirror-container-top">
<div
class="codemirror-container-btn codemirror-container-btn-save"
@click="handleSave">
<div class="codemirror-container-btn codemirror-container-btn-save" @click="handleSave">
保存
</div>
<div
class="codemirror-container-btn codemirror-container-btn-save"
@click="handleReset">
<div class="codemirror-container-btn codemirror-container-btn-save" @click="handleReset">
恢复到上次保存
</div>
</div>
@@ -26,7 +19,7 @@
</template>
<script setup lang="ts">
import miaoMessageProvider from '@/components/miaoMessageProvider.vue'
import miaoMessageProvider from '@/components/miaoAlertTipProvider.vue'
import { VirtualFile } from '@/class/VirtualDirectory'
import useMiaoFetchApi from '@/hooks/useMiaoFetchApi'
import { onMounted, ref } from 'vue'
@@ -53,7 +46,7 @@ const theme = ref<'light' | 'dark'>('light')
const handleSave = async () => {
if (bakData.value === codeData.value || !vFile.value) {
miaoMessage.value?.message('内容未改动', {
miaoMessage.value?.alertTip('内容未改动', {
timeout: 3000,
type: 'info'
})
@@ -69,7 +62,7 @@ const handleSave = async () => {
const { response } = miaoFetchApi.upload(file, parentDir)
false && miaoFetchApi.upload(file_bak, parentDir)
await response
miaoMessage.value?.message('保存成功', {
miaoMessage.value?.alertTip('保存成功', {
timeout: 5000,
type: 'success'
})
@@ -152,13 +145,13 @@ onMounted(async () => {
vFile.value = currentFiles.value[0]
const fileName = currentFiles.value[0].name
codeData.value = decoder.decode(
await miaoFetchApi.getFile(currentFiles.value[0], {
await (miaoFetchApi.getFile(currentFiles.value[0], {
axiosOption: {
headers: {
'Cache-Control': 'no-cache'
}
}
})
}).response)
)
bakData.value = codeData.value
extensions.value = [...(await getLangExtensions(fileName))]
+4
View File
@@ -1,5 +1,6 @@
// @ts-nocheck
import { registerComponentOption } from '@/class/PluginCenter'
import { PluginExportType } from '@/types/type'
const pluginConfig: registerComponentOption = {
key: 'miaoCrypto',
@@ -16,6 +17,9 @@ const pluginConfig: registerComponentOption = {
}
return vFiles[0].name.endsWith('txt')
},
disable: true,
}
export default pluginConfig
export const type = PluginExportType.component
+64 -32
View File
@@ -2,37 +2,31 @@
<miao-drop-handler @on-virtual-files="handleDropVirtualFiles">
<div class="miaoCrypto-container">
<div class="miaoCrypto-container-encrypt miaoCrypto-container-item">
<n-scrollbar style="max-height: 100%">
<div
v-for="item of workItemList"
class="miaoCrypto-container-item-item">
<div
class="miaoCrypto-container-item-percentBar"
:style="{
zIndex: 0,
width: item.buffer ? `100%` : `0%`,
backgroundColor: 'blue'
}"></div>
<div
class="miaoCrypto-container-item-percentBar"
:style="{
zIndex: 1,
width: item.status === 'finish' ? `100%` : `0%`,
backgroundColor: 'green'
}"></div>
<div v-for="item of workItemList" :key="item.id" class="miaoCrypto-container-item-item">
<div class="miaoCrypto-container-item-percentBar" :style="{
zIndex: 0,
width: item.getBufferProgress !== -1 ? `${item.getBufferProgress * 100}%` : `0%`,
backgroundColor: 'blue'
}"></div>
<div class="miaoCrypto-container-item-percentBar" :style="{
zIndex: 1,
width: item.status === 'finish' ? `100%` : `0%`,
backgroundColor: 'green'
}"></div>
<span class="miaoCrypto-container-item-content">{{ item.name }}{{ item.status }}</span>
</div>
</n-scrollbar>
</div>
<div
class="miaoCrypto-container-decrypt miaoCrypto-container-item"></div>
<!-- <div class="miaoCrypto-container-decrypt miaoCrypto-container-item"></div> -->
</div>
</miao-drop-handler>
</template>
<script setup lang="ts">
import { NScrollbar } from 'naive-ui'
import { ref } from 'vue'
import { onUnmounted, ref, shallowReactive } from 'vue'
import aes_ctr_worker from './hooks/AES'
import { VirtualFile } from '@/class/VirtualDirectory'
import miaoDropHandler from '@/components/miaoDropHandler.vue'
@@ -44,9 +38,12 @@ import { computed } from 'vue'
const miaoFetchApi = useMiaoFetchApi()
interface workItem {
status: 'wait' | 'process' | 'finish'
id: number
status: 'wait' | 'process' | 'finish' | 'error'
buffer?: Uint8Array
getBuffer: () => Promise<Uint8Array>
getBufferProgress: number
getBufferAbort?: () => void
isGettingBuffer: boolean
name: string
}
@@ -55,14 +52,16 @@ class Work {
constructor(func: (key: string, data: Uint8Array) => Promise<Uint8Array>) {
this.queue = []
this.func = func
this.abortLoop = false
}
queue: workItem[]
func: (key: string, data: Uint8Array) => Promise<Uint8Array>
abortLoop: boolean
get isBusy() {
return this.queue.filter((v) => v.status === 'process').length > 0
}
async funcLoop() {
if (this.isBusy) {
if (this.isBusy || this.abortLoop) {
return
}
const currentItem = this.queue.filter((v) => v.status === 'wait')[0]
@@ -70,20 +69,28 @@ class Work {
return
}
currentItem.status = 'process'
currentItem.buffer = await this.func(key.value, currentItem.buffer)
currentItem.status = 'finish'
try {
currentItem.buffer = await this.func(key.value, currentItem.buffer)
currentItem.status = 'finish'
} catch (e) {
currentItem.status = 'error'
}
this.funcLoop()
}
async getBufferLoop() {
const _list = this.queue.filter(
(v) => v.isGettingBuffer === false && v.buffer === undefined
)
if (_list.length === 0) {
if (_list.length === 0 || this.abortLoop) {
return
}
const item = _list[0]
item.isGettingBuffer = true
item.buffer = await item.getBuffer()
try {
item.buffer = await item.getBuffer()
} catch(e) {
item.status = 'error'
}
item.isGettingBuffer = false
this.funcLoop()
this.getBufferLoop()
@@ -94,12 +101,25 @@ class Work {
}
pushVFiles(itemList: VirtualFile[]) {
this.push(
itemList.map((v) => ({
name: v.name,
getBuffer: () => miaoFetchApi.getFile(v),
status: 'wait',
isGettingBuffer: false
}))
itemList.map((v) => {
const item: workItem = shallowReactive({
id: Math.random(),
status: 'wait',
name: v.name,
getBuffer: () => {
const { response, abort } = miaoFetchApi.getFile(v, {
onProcess(percent) {
item.getBufferProgress = percent
}
})
item.getBufferAbort = abort
return response
},
isGettingBuffer: false,
getBufferProgress: 0
})
return item
})
)
}
}
@@ -125,6 +145,13 @@ const handleDropVirtualFiles = (vFiles: VirtualFile[]) => {
onMounted(() => {
encryptWork.pushVFiles(currentFiles.value)
})
onUnmounted(() => {
encryptWork.abortLoop = true
encryptWork.queue.forEach(item => {
item.getBufferAbort && item.getBufferAbort()
})
})
</script>
<style scoped lang="scss">
@@ -133,12 +160,14 @@ onMounted(() => {
height: 100%;
display: flex;
flex-direction: column;
&-item {
max-height: 100%;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
&-item {
margin: 10px auto;
width: 95%;
@@ -148,12 +177,15 @@ onMounted(() => {
0 0 3px 1px #43434359;
border-radius: 5px;
position: relative;
.miaoCrypto-container-item-percentBar {
height: 100%;
position: absolute;
top: 0;
left: 0;
border-radius: 5px;
}
.miaoCrypto-container-item-content {
position: relative;
z-index: 3
@@ -3,7 +3,6 @@ import aesJs from 'aes-js'
self.onmessage = async function (event) {
const data = event.data.data as Uint8Array
const key = event.data.key as Uint8Array
console.log(event)
var aesCtr = new aesJs.ModeOfOperation.ctr(key, new aesJs.Counter(7058))
const encryptData = aesCtr.encrypt(data)
self.postMessage(encryptData)
+4
View File
@@ -17,3 +17,7 @@ const pluginConfig: registerComponentOption = {
}
export default pluginConfig
import { PluginExportType } from '@/types/type'
export const type = PluginExportType.component
+98 -48
View File
@@ -1,42 +1,23 @@
<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">
<div class="miao-directory-item-container" ref="rootDomRef">
<!-- 顶部面包屑导航和工具栏 -->
<miao-directory-top
:color="props.color"
:current-directory="currentDirectory"
@back="handleBack"
:open-menu-option="topBarMenuOption"
@reload="handleReload"
@exit="emit('exit')"
:index="index"
@set-current-directory="setCurrentDirectory"
@search="handleSearch"
<miao-directory-top :color="props.color" :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" />
<!-- 文件和文件夹列表 -->
<miao-directory-items
ref="miaoDirectoryItemRef"
:color="props.color"
:showData_directory="showData_directory"
: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"
<miao-directory-items ref="miaoDirectoryItemRef" :color="props.color"
:showData_directory="showData_directory" :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" />
<!-- 底部工具栏 -->
<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" />
<miao-mask v-model:show="showModel"></miao-mask>
@@ -106,13 +87,20 @@ class SelectedItem {
}
_selectedItem: (VirtualDirectory | VirtualFile)[]
push(item: VirtualDirectory | VirtualFile) {
this._selectedItem = [item, ...this._selectedItem]
this._selectedItem = uniq([item, ...this._selectedItem])
}
pushArray(items: (VirtualDirectory | VirtualFile)[]) {
this._selectedItem = uniq([...items, ...this._selectedItem])
}
remove(item: VirtualDirectory | VirtualFile) {
this._selectedItem = this._selectedItem.filter((v) => v !== item)
}
clear() {
this._selectedItem = []
/**
* 仅保留filter为true的元素, filter默认为()=>false
*/
clear(filter?: (item: VirtualDirectory | VirtualFile) => boolean) {
filter || (filter = (__) => false)
this._selectedItem = this.value.filter(filter)
}
// 保证内容仍然存在于dir中且各个元素不重复
get value() {
@@ -194,18 +182,18 @@ const topBarMenuOption = computed(() => {
},
searchText.value !== ''
? {
label: '重置搜索',
key: 'searchReset',
icon: renderIcon(SearchOutline)
}
: undefined,
selectedItem.value.length !== 0
? {
label: '重置多选',
key: 'selectedItemReset',
icon: renderIcon(CheckmarkDoneOutline)
}
label: '重置搜索',
key: 'searchReset',
icon: renderIcon(SearchOutline)
}
: undefined,
// selectedItem.value.length !== 0
// ? {
// label: '重置多选',
// key: 'selectedItemReset',
// icon: renderIcon(CheckmarkDoneOutline)
// }
// : undefined,
{
label: '筛选',
key: 'filter',
@@ -223,6 +211,30 @@ const topBarMenuOption = computed(() => {
],
icon: renderIcon(FilterOutline)
},
{
label: '多选',
key: 'multiSelect',
children: [
{
label: `全选`,
key: 'multiSelect:all'
},
{
label: `全不选`,
key: 'multiSelect:reset'
},
{
label: `反选`,
key: 'multiSelect:inversion'
},
selectedItem.value.length === 2 ?
{
label: `区间内全选`,
key: 'multiSelect:range'
} : undefined
].filter((v) => v !== undefined),
icon: renderIcon(CheckmarkDoneOutline),
},
{
label: '插件',
key: 'plugin',
@@ -299,15 +311,53 @@ const handleTopBarMenuSelect = (key: string) => {
handleAddNewItem()
} else if (key === 'searchReset') {
handleSearchReset()
} else if (key === 'selectedItemReset') {
selectedItem.clear()
// } else if (key === 'selectedItemReset') {
// selectedItem.clear()
} else if (key === 'showDirs') {
showDirs.value = !showDirs.value
showDirs.value === false && selectedItem.clear(v => v.type !== 'directory')
} else if (key === 'showFiles') {
showFiles.value = !showFiles.value
showFiles.value === false && selectedItem.clear(v => v.type !== 'file')
} else if (key.startsWith('plugin:')) {
const pluginName = key.split(':')[1]
pluginCenter.usePlugin(pluginName, [currentDirectory.value], [])
} else if (key.startsWith('multiSelect:')) {
const opName = key.split(':')[1]
switch (opName) {
case 'all':
selectedItem.pushArray([...showData_directory.value, ...showData_files.value])
break;
case 'reset':
selectedItem.clear()
break
case 'inversion':
const sArr = selectedItem.value
const arr = [...showData_directory.value, ...showData_files.value].filter(i => !sArr.includes(i))
selectedItem.clear()
selectedItem.pushArray(arr)
break
case "range":
const _sArr = selectedItem.value
const _arr = [...showData_directory.value, ...showData_files.value]
const _nArr = []
let _counter = 0
for (const i of _arr) {
if (_sArr.includes(i)) {
_counter++
}
if (_counter === 1) {
_nArr.push(i)
} else if (_counter === 2) {
_nArr.push(i)
break
}
}
selectedItem.clear()
selectedItem.pushArray(_nArr)
break
}
}
}
@@ -341,7 +391,7 @@ const handleItemDownload = (item: VirtualFile) => {
const handleItemDelete = async (_item: VirtualDirectory | VirtualFile) => {
for (let item of uniq([...selectedItem.value, _item])) {
;(async () => {
; (async () => {
const { response } = miaoFetchApi.delete(item, {
retry: 5
})
@@ -430,7 +480,7 @@ const handleDropVDirectory = async (vDirs: VirtualDirectory[]) => {
}
}
for (let dir of vDirs) {
;(async () => {
; (async () => {
const _from = dir.parent
const { response } = miaoFetchApi.cut(dir, currentDirectory.value)
const id = (await response).eventId
@@ -449,7 +499,7 @@ const handleDropVirtualFiles = (files: VirtualFile[]) => {
return
}
for (let file of files) {
;(async () => {
; (async () => {
const _from = file.parent
const { response } = miaoFetchApi.cut(file, currentDirectory.value)
const id = (await response).eventId
+5 -1
View File
@@ -18,4 +18,8 @@ const pluginConfig: registerComponentOption = {
}
}
export default pluginConfig
export default pluginConfig
import { PluginExportType } from '@/types/type'
export const type = PluginExportType.component
+19 -2
View File
@@ -1,6 +1,7 @@
<template>
<div class="miao-markdown-container-miaomiaomiao">
<iframe
ref="iframeRef"
:src="iframeSrc"
frameborder="0"
class="iframe-container-iframe"></iframe>
@@ -8,17 +9,33 @@
</template>
<script setup lang="ts">
import { VirtualFile } from '@/class/VirtualDirectory'
import { onMounted, ref } from 'vue'
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import { cloneDeep } from 'lodash';
import { inject, onMounted, ref } from 'vue'
import buildFromTree from '../../hooks/buildFromTree';
const root = inject('rootDirectory') as VirtualDirectory
const currentFiles = defineModel<VirtualFile[]>('currentFiles', {
required: true
})
const iframeSrc = ref<string>()
const iframeRef = ref<HTMLIFrameElement>();
const sendRootTree = () => {
iframeRef.value?.contentWindow && iframeRef.value.contentWindow.postMessage(cloneDeep(root.tree), "*");
}
const handleIframeMessage = (e: MessageEvent<any>) => {
// const data = e.data;
sendRootTree()
}
onMounted(() => {
iframeSrc.value = currentFiles.value[0].url
if (typeof window.addEventListener != "undefined") {
window.addEventListener("message", handleIframeMessage, false);
}
console.log(buildFromTree(cloneDeep(root.tree)))
})
</script>
+4
View File
@@ -43,3 +43,7 @@ const pluginConfig: registerComponentOption = {
}
export default pluginConfig
import { PluginExportType } from '@/types/type'
export const type = PluginExportType.component
+5 -5
View File
@@ -4,7 +4,7 @@
@on-virtual-files="handleDrop">
<miao-message-provider ref="miaoMessageRef">
<div class="miaoImage" ref="rootRef">
<n-scrollbar ref="NScrollbarRef">
<n-scrollbar ref="NScrollbarRef" style="max-height: 100%;">
<div
class="miaoImage-container"
v-for="imageGroup in imageGroupList">
@@ -62,7 +62,7 @@
<script setup lang="ts">
import miaoMask from '@/components/miaoMask.vue'
import miaoDropHandler from '@/components/miaoDropHandler.vue'
import miaoMessageProvider from '@/components/miaoMessageProvider.vue'
import miaoMessageProvider from '@/components/miaoAlertTipProvider.vue'
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import { uniq } from 'lodash'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
@@ -152,7 +152,7 @@ const scrollToActiveImage = () => {
const dom = rootRef.value?.querySelector(
'.miaoImage-container-row-image-active'
)
NScrollbarRef.value.scrollTo({
dom && NScrollbarRef.value.scrollTo({
top: dom.offsetTop - 30,
behavior: 'smooth'
})
@@ -199,7 +199,7 @@ const handleDrop = async (vItems: (VirtualFile | VirtualDirectory)[]) => {
// @ts-ignore
await updateImageSrcList(vItems)
}
miaoMessageRef.value?.message(
miaoMessageRef.value?.alertTip(
length_before === imageFileList.value.length
? '未发现任何可添加图片'
: `导入${imageFileList.value.length - length_before}张图片`,
@@ -247,7 +247,7 @@ onMounted(async () => {
for (const i of [currentFiles.value, ...currentDirectories.value]) {
await updateImageSrcList(i)
}
miaoMessageRef.value?.message(
miaoMessageRef.value?.alertTip(
length_before === imageFileList.value.length
? '未发现任何新增图片'
: `导入${imageFileList.value.length - length_before}张图片`,
+4
View File
@@ -19,3 +19,7 @@ const pluginConfig: registerComponentOption = {
}
export default pluginConfig
import { PluginExportType } from '@/types/type'
export const type = PluginExportType.component
+1 -1
View File
@@ -28,7 +28,7 @@ const md = new MarkdownIt()
onMounted(async () => {
markdownSrc.value = currentFiles.value[0].url
const text = decoder.decode(await miaoFetchApi.getFile(currentFiles.value[0]))
const text = decoder.decode(await(miaoFetchApi.getFile(currentFiles.value[0])).response)
renderedMarkdown.value = md.render(text)
})
</script>
+4
View File
@@ -19,3 +19,7 @@ const pluginConfig: registerComponentOption = {
}
export default pluginConfig
import { PluginExportType } from '@/types/type'
export const type = PluginExportType.component
+2 -2
View File
@@ -52,7 +52,7 @@
</template>
<script setup lang="ts">
import miaoMessageProvider from '@/components/miaoMessageProvider.vue'
import miaoMessageProvider from '@/components/miaoAlertTipProvider.vue'
import { onMounted, ref, shallowReactive } from 'vue'
import PdfjsWorker from 'pdfjs-dist/build/pdf.worker.mjs?worker'
import { VirtualFile } from '@/class/VirtualDirectory'
@@ -89,7 +89,7 @@ const handleResetMargin = () => {
}
onMounted(async () => {
const setLoadingMessage = miaoMessageRef.value?.message('加载PDF插件中', {
const setLoadingMessage = miaoMessageRef.value?.alertTip('加载PDF插件中', {
type: 'info',
timeout: -1
})
@@ -20,3 +20,7 @@ const pluginConfig: registerComponentOption = {
}
export default pluginConfig
import { PluginExportType } from '@/types/type'
export const type = PluginExportType.component
+4
View File
@@ -26,3 +26,7 @@ const pluginConfig: registerComponentOption = {
}
export default pluginConfig
import { PluginExportType } from '@/types/type'
export const type = PluginExportType.component