feat: 1.插件加载时会有全局提示。2.重命名miaoMessageProvider为miaoAlertTipProvider

This commit is contained in:
539943419 committed 2024-09-05 00:10:36 +08:00
1 parent 3a18bb3cbd
commit ec4ed10afd
16 files changed
+481 -465

No files matched your search

+13 -4
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { h, onMounted, reactive, ref, shallowRef } from 'vue'
import { h, onMounted, provide, reactive, ref, shallowRef, useTemplateRef } from 'vue'
import { NIcon, NScrollbar, NDropdown } from 'naive-ui'
import {
EyeOffOutline,
@@ -11,10 +11,12 @@ import {
} from '@vicons/ionicons5'
import VirtualDirectory, { VirtualFile } from './class/VirtualDirectory'
import MiaoMask from './components/miaoMask.vue'
import MiaoMessageProvider from './components/miaoAlertTipProvider.vue'
import config from './config'
import useVirtualPages from './hooks/useVirtualPages'
import init from './hooks/init'
import usePluginCenter from './hooks/usePluginCenter'
import PluginCenter from './class/PluginCenter'
const { baseUrl } = config
@@ -25,8 +27,10 @@ const modalData = shallowRef<{
props: any
}>()
const messageProviderRef = useTemplateRef('messageProviderRef')
const views = useVirtualPages()
const pluginCenter = usePluginCenter()
let pluginCenter: PluginCenter
const rootDirectory = reactive(
new VirtualDirectory({
@@ -105,14 +109,18 @@ const handleMenuSelect = async (key: string) => {
}
onMounted(async () => {
await init()
// @ts-ignore
await init(messageProviderRef.value?.alertTip)
pluginCenter = usePluginCenter()
pluginCenter.usePlugin('miaoDirectory', [rootDirectory], [])
// createView(miaoDirectory, [rootDirectory])
})
provide('globalAlertTip', messageProviderRef.value?.alertTip)
</script>
<template>
<div class="view">
<miao-message-provider ref="messageProviderRef">
<div class="view-controller">
<n-scrollbar x-scrollable>
<div class="tabs-container">
@@ -199,6 +207,7 @@ onMounted(async () => {
</div>
</transition-group>
</div>
</miao-message-provider>
</div>
<!-- 模态框展示,用来显示分享二维码,设置菜单之类的东西 -->
<MiaoMask v-model:show="showModal" @click="showModal = false">
+94 -109
View File
@@ -1,124 +1,109 @@
import useVirtualPages from '@/hooks/useVirtualPages'
import VirtualDirectory, { VirtualFile } from './VirtualDirectory'
import { ShallowRef, shallowRef } from 'vue'
import useVirtualPages from "@/hooks/useVirtualPages";
import VirtualDirectory, { VirtualFile } from "./VirtualDirectory";
import { ShallowRef, shallowRef } from "vue";
import { alertTipType } from "@/types/type";
export enum PluginGroup {
default = 'default',
mainMenu = 'mainMenu'
default = "default",
mainMenu = "mainMenu"
}
export interface registerComponentOption {
key: string
name: string
icon?: any
getComponent: () => Promise<any>
group?: PluginGroup[]
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean
disable?: boolean
exitConfirm?: boolean
key: string;
name: string;
icon?: any;
getComponent: () => Promise<any>;
group?: PluginGroup[];
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean;
disable?: boolean;
exitConfirm?: boolean;
}
type Plugin = {
// 用于显示的名字
name: string
// 代表插件的icon
icon?: ShallowRef<any>
// 是否禁用插件
disable: boolean
// 插件所属的group,用于区分插件使用的场合
group: PluginGroup[]
// 判断在未禁用时是否可以使用这个组件
// 使用组件即调用下面的func
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean
func: (
VDirectories: VirtualDirectory[],
VFiles: VirtualFile[],
...args: any[]
) => void
}
// 用于显示的名字
name: string;
// 代表插件的icon
icon?: ShallowRef<any>;
// 是否禁用插件
disable: boolean;
// 插件所属的group,用于区分插件使用的场合
group: PluginGroup[];
// 判断在未禁用时是否可以使用这个组件
// 使用组件即调用下面的func
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean;
func: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[], ...args: any[]) => void;
};
export default class PluginCenter {
constructor() {
this.pluginsMap = {}
}
pluginsMap: {
[key: string]: Plugin
}
constructor(globalAlertTip: alertTipType) {
this.pluginsMap = {};
this.globalAlertTip = globalAlertTip;
}
pluginsMap: {
[key: string]: Plugin;
};
register(key: string, plugin: Plugin) {
this.pluginsMap[key] = plugin
}
globalAlertTip: alertTipType;
/**
* 便捷地注册一个组件为插件,触发时直接用新页面打开
*/
registerComponent(option: registerComponentOption): void {
const {
key,
name,
getComponent,
icon,
filter,
group = [PluginGroup.default],
disable = false,
exitConfirm = false
} = option
let _component: any
const views = useVirtualPages()
this.register(key, {
name,
filter,
icon: shallowRef(icon),
group,
disable,
func: async (
VDirectories: VirtualDirectory[],
VFiles: VirtualFile[]
) => {
if (filter(VDirectories, VFiles) === false) {
return
}
if (_component === undefined) _component = await getComponent()
views.push(_component, VDirectories, VFiles, {
VirtualPageOption: {
exitConfirm
}
})
}
})
}
register(key: string, plugin: Plugin) {
this.pluginsMap[key] = plugin;
}
getUsablePlugin(
VDirectories: VirtualDirectory[],
VFiles: VirtualFile[],
option?: {
group?: PluginGroup[]
}
) {
const { group = [PluginGroup.default] } = option ?? {}
const usableList = []
for (let key of Object.keys(this.pluginsMap)) {
const _plugin = this.pluginsMap[key]
if (
!_plugin.disable &&
_plugin.group.filter((v) => group.includes(v)).length > 0 &&
_plugin.filter(VDirectories, VFiles)
) {
usableList.push(key)
}
}
return usableList.map((key) => ({
key,
...this.pluginsMap[key]
}))
}
/**
* 便捷地注册一个组件为插件,触发时直接用新页面打开
*/
registerComponent(option: registerComponentOption): void {
const { key, name, getComponent, icon, filter, group = [PluginGroup.default], disable = false, exitConfirm = false } = option;
let _component: any;
const views = useVirtualPages();
this.register(key, {
name,
filter,
icon: shallowRef(icon),
group,
disable,
func: async (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => {
if (filter(VDirectories, VFiles) === false) {
return;
}
usePlugin(
key: string,
VDirectories?: VirtualDirectory[],
VFiles?: VirtualFile[],
...args: any[]
) {
this.pluginsMap[key].func(VDirectories ?? [], VFiles ?? [], ...args)
}
const setAlertTip = key !== 'miaoDirectory' && this.globalAlertTip(`加载 ${name} 插件中`);
if (_component === undefined) _component = await getComponent();
setAlertTip && setAlertTip(`加载 ${name} 插件完成`, {
type: "success",
timeout: 2000
});
views.push(_component, VDirectories, VFiles, {
VirtualPageOption: {
exitConfirm
}
});
}
});
}
getUsablePlugin(
VDirectories: VirtualDirectory[],
VFiles: VirtualFile[],
option?: {
group?: PluginGroup[];
}
) {
const { group = [PluginGroup.default] } = option ?? {};
const usableList = [];
for (let key of Object.keys(this.pluginsMap)) {
const _plugin = this.pluginsMap[key];
if (!_plugin.disable && _plugin.group.filter(v => group.includes(v)).length > 0 && _plugin.filter(VDirectories, VFiles)) {
usableList.push(key);
}
}
return usableList.map(key => ({
key,
...this.pluginsMap[key]
}));
}
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]) {
this.pluginsMap[key].func(VDirectories ?? [], VFiles ?? [], ...args);
}
}
@@ -18,12 +18,7 @@ import generateId from '@/hooks/generateId';
import { NIcon } from 'naive-ui';
import { computed, onMounted, ref, shallowReactive } from 'vue';
import { InformationCircle, CheckmarkCircle, CloseCircle } from '@vicons/ionicons5'
interface MessageOptions {
type?: 'info' | 'success' | 'error'
timeout?: number
id?: number
}
import { AlertTipMessageOptions } from '@/types/type';
interface Message {
icon: any,
@@ -48,7 +43,7 @@ const messageList = computed(() => {
...messageMap[v],
}))
})
const message = (content: string, options?: MessageOptions) => {
const alertTip = (content: string, options?: AlertTipMessageOptions) => {
let timer: any
const { timeout = 0, type = 'info', id = generateId() } = options ?? {}
if (timeout > 0) {
@@ -63,10 +58,10 @@ const message = (content: string, options?: MessageOptions) => {
content,
timer
}
return (newContent: string, newOptions?: MessageOptions) => {
return (newContent: string, newOptions?: AlertTipMessageOptions) => {
newOptions = newOptions ?? {}
newOptions.id = id
message(newContent, newOptions)
alertTip(newContent, newOptions)
}
}
@@ -86,7 +81,7 @@ onMounted(async () => {
})
defineExpose({ message });
defineExpose({ alertTip });
</script>
<style scoped lang="scss">
@@ -105,6 +100,7 @@ defineExpose({ message });
flex-direction: column;
align-items: center;
overflow: visible;
z-index: 70582140539943419;
.miao-message {
display: flex;
+3 -2
View File
@@ -1,5 +1,6 @@
import { alertTipType } from "@/types/type";
import initPlugin from "./init/initPlugin";
export default async function init() {
await initPlugin()
export default async function init(globalAlertTip: alertTipType) {
await initPlugin(globalAlertTip)
}
+21 -14
View File
@@ -1,16 +1,23 @@
import usePluginCenter, { initPluginCenter } from "@/hooks/usePluginCenter";
import { registerComponentOption } from "@/class/PluginCenter";
import { alertTipType } from "@/types/type";
import usePluginCenter from '@/hooks/usePluginCenter'
import { registerComponentOption } from '@/class/PluginCenter'
const initPlugin = async (globalAlertTip: alertTipType) => {
initPluginCenter(globalAlertTip)
const modulesFiles = import.meta.glob("@/plugins/**/export.ts");
const pluginCenter = usePluginCenter();
const promiseArray = [];
for (let pluginConfig of Object.values(modulesFiles)) {
promiseArray.push(
new Promise(async resolve => {
const _config = pluginConfig as () => Promise<{
default: registerComponentOption;
}>;
resolve(pluginCenter.registerComponent((await _config()).default));
})
);
}
await Promise.all(promiseArray);
};
const initPlugin = async () => {
const modulesFiles = import.meta.glob('@/plugins/**/export.ts')
const pluginCenter = usePluginCenter()
for (let pluginConfig of Object.values(modulesFiles)) {
const _config = pluginConfig as () => Promise<{
default: registerComponentOption
}>
pluginCenter.registerComponent((await _config()).default)
}
}
export default initPlugin
export default initPlugin;
+252 -269
View File
@@ -1,291 +1,274 @@
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import VirtualDirectory, { VirtualFile } from "@/class/VirtualDirectory";
import {
getOption,
getResponse,
miaoFetchConfig,
deleteOption,
uploadOption,
queryOption,
renameOption,
cutOption,
mkdirOption
} from '@/types/fetch'
import Config from '@/config'
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
getOption,
getResponse,
miaoFetchConfig,
deleteOption,
uploadOption,
queryOption,
renameOption,
cutOption,
mkdirOption,
getFileOption
} from "@/types/fetch";
import Config from "@/config";
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
export const useMiaoFetch = (option?: miaoFetchConfig) => {
const retry = option?.retry ?? 0
const controller = new AbortController()
let flag = true
return {
miaoFetch: async (
config: AxiosRequestConfig<any>
): Promise<AxiosResponse<any, any>> => {
let counter = 0
let response: any
let errList = []
while (flag && counter <= retry) {
try {
response = await axios({
...config,
signal: controller.signal
})
return response
} catch (_e) {
errList.push(_e)
counter += 1
}
}
throw errList
},
/**
* 强制终止miaoFetch
*/
abortMiaoFetch: () => {
flag = false
controller.abort()
}
}
}
const retry = option?.retry ?? 0;
const controller = new AbortController();
let flag = true;
return {
miaoFetch: async (config: AxiosRequestConfig<any>): Promise<AxiosResponse<any, any>> => {
let counter = 0;
let response: any;
let errList = [];
while (flag && counter <= retry) {
try {
response = await axios({
...config,
signal: controller.signal
});
return response;
} catch (_e) {
errList.push(_e);
counter += 1;
}
}
throw errList;
},
/**
* 强制终止miaoFetch
*/
abortMiaoFetch: () => {
flag = false;
controller.abort();
}
};
};
const miaoFetchApi = {
/**
* 获取对应文件夹下的数据
*/
async get(
vDirectory: VirtualDirectory,
option?: getOption
): Promise<getResponse> {
const { baseUrl, api } = Config
const url = `${baseUrl}${api.get}${vDirectory.path}`
const retry = option?.retry ?? 0
/**
* 获取对应文件夹下的数据
*/
async get(vDirectory: VirtualDirectory, option?: getOption): Promise<getResponse> {
const { baseUrl, api } = Config;
const url = `${baseUrl}${api.get}${vDirectory.path}`;
const retry = option?.retry ?? 0;
const { miaoFetch } = useMiaoFetch({
retry
})
const response = await miaoFetch({
url
})
return response.data
},
const { miaoFetch } = useMiaoFetch({
retry
});
const response = await miaoFetch({
url
});
return response.data;
},
/**
* 获取对应文件下的数据
*/
async getFile(
vFile: VirtualFile,
option?: getOption
) {
// const { baseUrl, api } = Config
const url = vFile.url
const retry = option?.retry ?? 0
const axiosOption = option?.axiosOption ?? {}
/**
* 获取对应文件下的数据
*/
getFile(vFile: VirtualFile, option?: getFileOption) {
// const { baseUrl, api } = Config
const url = vFile.url;
const retry = option?.retry ?? 0;
const axiosOption = option?.axiosOption ?? {};
const { miaoFetch } = useMiaoFetch({
retry
})
const response = await miaoFetch({
url,
responseType: 'arraybuffer',
...axiosOption
})
return new Uint8Array(response.data)
},
const { miaoFetch, abortMiaoFetch: abort } = useMiaoFetch({
retry
});
const response = miaoFetch({
url,
responseType: "arraybuffer",
onDownloadProgress(progressEvent) {
option && option.onProcess && option.onProcess(progressEvent.total ? progressEvent.loaded / progressEvent.total : -1);
},
...axiosOption
});
return {
response: new Promise<Uint8Array>(async resolve => {
resolve(new Uint8Array((await response).data));
}),
abort
};
},
/**
* 上传单个文件到对应文件夹, 后续要将data类型改成buffer以支持分片上传
* 正常上传文件请使用uploadQueue
*/
upload(data: File, targetVDir: VirtualDirectory, option?: uploadOption) {
const { baseUrl, api } = Config
const url = `${baseUrl}${api.upload}${targetVDir.path}`
const retry = option?.retry ?? 0
const { miaoFetch, abortMiaoFetch } = useMiaoFetch({
retry
})
const sizeTotal = data.size
/**
* 上传单个文件到对应文件夹, 后续要将data类型改成buffer以支持分片上传
* 正常上传文件请使用uploadQueue
*/
upload(data: File, targetVDir: VirtualDirectory, option?: uploadOption) {
const { baseUrl, api } = Config;
const url = `${baseUrl}${api.upload}${targetVDir.path}`;
const retry = option?.retry ?? 0;
const { miaoFetch, abortMiaoFetch } = useMiaoFetch({
retry
});
const sizeTotal = data.size;
const opType = option?.type ?? 'write'
const opType = option?.type ?? "write";
const formData = new FormData()
const formData = new FormData();
formData.append('file', data)
// 必须这样传,不然中文乱码
formData.append('fileName', data.name)
formData.append('operateType', opType)
formData.append("file", data);
// 必须这样传,不然中文乱码
formData.append("fileName", data.name);
formData.append("operateType", opType);
return {
abort: () => abortMiaoFetch(),
response: new Promise<{
message: 'success' | 'failed'
error?: string
}>(async (resolve) => {
const response = await miaoFetch({
url,
method: 'post',
data: formData,
onUploadProgress(progressEvent) {
option &&
option.onProcess &&
option.onProcess(progressEvent.loaded / sizeTotal)
}
})
resolve(response.data)
})
}
},
return {
abort: () => abortMiaoFetch(),
response: new Promise<{
message: "success" | "failed";
error?: string;
}>(async resolve => {
const response = await miaoFetch({
url,
method: "post",
data: formData,
onUploadProgress(progressEvent) {
option && option.onProcess && option.onProcess(progressEvent.loaded / sizeTotal);
}
});
resolve(response.data);
})
};
},
/**
* 在目标文件夹下创建新的文件夹
*/
mkdir(
targetVDir: VirtualDirectory,
newFolderName: string,
option?: mkdirOption
) {
const { baseUrl, api } = Config
const url = `${baseUrl}${api.mkdir}${targetVDir.path}`
const { miaoFetch } = useMiaoFetch({
retry: option?.retry ?? 0
})
/**
* 在目标文件夹下创建新的文件夹
*/
mkdir(targetVDir: VirtualDirectory, newFolderName: string, option?: mkdirOption) {
const { baseUrl, api } = Config;
const url = `${baseUrl}${api.mkdir}${targetVDir.path}`;
const { miaoFetch } = useMiaoFetch({
retry: option?.retry ?? 0
});
return new Promise<{
message: 'success' | 'failed'
error?: string
}>(async (resolve) => {
const response = await miaoFetch({
url,
method: 'post',
data: {
folderName: newFolderName
}
})
resolve(response.data)
})
},
/**
* 在目标文件夹下创建新的空文件,实际上是通过upload空文件实现
*/
mkFile(
targetVDir: VirtualDirectory,
newFileName: string,
option?: uploadOption
) {
const emptyBlob = new Blob([])
const emptyFile = new File([emptyBlob], newFileName, {
type: 'text/plain'
})
return this.upload(emptyFile, targetVDir, option)
},
return new Promise<{
message: "success" | "failed";
error?: string;
}>(async resolve => {
const response = await miaoFetch({
url,
method: "post",
data: {
folderName: newFolderName
}
});
resolve(response.data);
});
},
/**
* 在目标文件夹下创建新的空文件,实际上是通过upload空文件实现
*/
mkFile(targetVDir: VirtualDirectory, newFileName: string, option?: uploadOption) {
const emptyBlob = new Blob([]);
const emptyFile = new File([emptyBlob], newFileName, {
type: "text/plain"
});
return this.upload(emptyFile, targetVDir, option);
},
/**
* 删除对应的文件或文件夹,若为文件夹会递归删除
*/
delete(target: VirtualFile | VirtualDirectory, option?: deleteOption) {
const { baseUrl, api } = Config
const url = `${baseUrl}${api.delete}${target.path}`
const retry = option?.retry ?? 0
const { miaoFetch } = useMiaoFetch({
retry
})
/**
* 删除对应的文件或文件夹,若为文件夹会递归删除
*/
delete(target: VirtualFile | VirtualDirectory, option?: deleteOption) {
const { baseUrl, api } = Config;
const url = `${baseUrl}${api.delete}${target.path}`;
const retry = option?.retry ?? 0;
const { miaoFetch } = useMiaoFetch({
retry
});
return {
response: new Promise<{
eventId: number
}>(async (resolve) => {
const response = await miaoFetch({
url,
method: 'post'
})
resolve(response.data)
})
}
},
/**
* 重命名对应的文件或文件夹
*/
rename(
target: VirtualFile | VirtualDirectory,
newName: string,
option?: renameOption
) {
const { baseUrl, api } = Config
const url = `${baseUrl}${api.rename}${target.path}`
const retry = option?.retry ?? 0
const { miaoFetch } = useMiaoFetch({
retry
})
return {
response: new Promise<{
eventId: number;
}>(async resolve => {
const response = await miaoFetch({
url,
method: "post"
});
resolve(response.data);
})
};
},
/**
* 重命名对应的文件或文件夹
*/
rename(target: VirtualFile | VirtualDirectory, newName: string, option?: renameOption) {
const { baseUrl, api } = Config;
const url = `${baseUrl}${api.rename}${target.path}`;
const retry = option?.retry ?? 0;
const { miaoFetch } = useMiaoFetch({
retry
});
return {
response: new Promise<{
eventId: number
}>(async (resolve) => {
const response = await miaoFetch({
url,
method: 'post',
data: { newName }
})
resolve(response.data)
})
}
},
/**
* 剪切文件或文件夹
*/
cut(
target: VirtualFile | VirtualDirectory,
to: VirtualDirectory,
option?: cutOption
) {
const newPath = to.path
const { baseUrl, api } = Config
const url = `${baseUrl}${api.cut}${target.path}`
const retry = option?.retry ?? 0
const { miaoFetch } = useMiaoFetch({
retry
})
return {
response: new Promise<{
eventId: number
}>(async (resolve) => {
const response = await miaoFetch({
url,
method: 'post',
data: { newPath }
})
resolve(response.data)
})
}
},
return {
response: new Promise<{
eventId: number;
}>(async resolve => {
const response = await miaoFetch({
url,
method: "post",
data: { newName }
});
resolve(response.data);
})
};
},
/**
* 剪切文件或文件夹
*/
cut(target: VirtualFile | VirtualDirectory, to: VirtualDirectory, option?: cutOption) {
const newPath = to.path;
const { baseUrl, api } = Config;
const url = `${baseUrl}${api.cut}${target.path}`;
const retry = option?.retry ?? 0;
const { miaoFetch } = useMiaoFetch({
retry
});
return {
response: new Promise<{
eventId: number;
}>(async resolve => {
const response = await miaoFetch({
url,
method: "post",
data: { newPath }
});
resolve(response.data);
})
};
},
/**
* 查询服务端操作事件的进展
*/
query(eventId: number, option?: queryOption) {
const { baseUrl, api } = Config
const url = `${baseUrl}${api.query}`
const retry = option?.retry ?? 0
const { miaoFetch } = useMiaoFetch({
retry
})
return {
response: new Promise<{
status: 'process' | 'success' | 'failed'
error?: unknown
}>(async (resolve) => {
const response = await miaoFetch({
url,
method: 'get',
params: {
id: eventId
}
})
resolve(response.data)
})
}
}
}
/**
* 查询服务端操作事件的进展
*/
query(eventId: number, option?: queryOption) {
const { baseUrl, api } = Config;
const url = `${baseUrl}${api.query}`;
const retry = option?.retry ?? 0;
const { miaoFetch } = useMiaoFetch({
retry
});
return {
response: new Promise<{
status: "process" | "success" | "failed";
error?: unknown;
}>(async resolve => {
const response = await miaoFetch({
url,
method: "get",
params: {
id: eventId
}
});
resolve(response.data);
})
};
}
};
export default function useMiaoFetchApi() {
return miaoFetchApi
return miaoFetchApi;
}
+6 -2
View File
@@ -1,11 +1,15 @@
import PluginCenter from "@/class/PluginCenter";
import { alertTipType } from "@/types/type";
import { reactive } from "vue";
let pluginCenter: PluginCenter
export default function usePluginCenter(){
export const initPluginCenter = (globalAlertTip: alertTipType) => {
if(!pluginCenter) {
pluginCenter = reactive(new PluginCenter())
pluginCenter = reactive(new PluginCenter(globalAlertTip))
}
}
export default function usePluginCenter(){
return pluginCenter
}
+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))]
+51 -28
View File
@@ -3,36 +3,29 @@
<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 +37,12 @@ import { computed } from 'vue'
const miaoFetchApi = useMiaoFetchApi()
interface workItem {
id: number
status: 'wait' | 'process' | 'finish'
buffer?: Uint8Array
getBuffer: () => Promise<Uint8Array>
getBufferProgress: number
getBufferAbort?: () => void
isGettingBuffer: boolean
name: string
}
@@ -55,14 +51,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]
@@ -78,7 +76,7 @@ class Work {
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]
@@ -94,12 +92,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 +136,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 +151,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 +168,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)
+3 -3
View File
@@ -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'
@@ -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}张图片`,
+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>
+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
})
+4 -4
View File
@@ -3,11 +3,11 @@
</template>
<script setup lang="ts">
import { VirtualFile } from '@/class/VirtualDirectory'
// import { VirtualFile } from '@/class/VirtualDirectory'
const currentFiles = defineModel<VirtualFile[]>('currentFiles', {
required: true
})
// const currentFiles = defineModel<VirtualFile[]>('currentFiles', {
// required: true
// })
</script>
+9 -1
View File
@@ -8,12 +8,20 @@ export type miaoFetchConfig = {
export type getOption = {} & miaoFetchConfig;
export type getFileOption = {
/**
* 下载进度回调函数
* @param {any} percent 进度百分比,float类型, 0-1
*/
onProcess?: (percent: number) => void;
} & miaoFetchConfig;
export type getResponse = (file | directory)[];
export type uploadOption = {
/**
* 上传进度回调函数
* @param {any} percent 进度百分比,float类型
* @param {any} percent 进度百分比,float类型, 0-1
*/
onProcess?: (percent: number) => void;
/**
+8
View File
@@ -20,3 +20,11 @@ export type directory = {
stats: stats;
parent?: directory;
};
export type alertTipType = ((content: string, options?: AlertTipMessageOptions) => (newContent: string, newOptions?: AlertTipMessageOptions) => void)
export interface AlertTipMessageOptions {
type?: 'info' | 'success' | 'error'
timeout?: number
id?: number
}