Compare commits
2
Commits
1d4feb471c
...
4f477c99d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f477c99d1 | ||
|
|
e840e4eb5a |
No files matched your search
@@ -5,20 +5,24 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev:host": "vite --host 0.0.0.0",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vicons/ionicons5": "^0.12.0",
|
||||
"axios": "^1.7.3",
|
||||
"naive-ui": "^2.39.0",
|
||||
"sass": "^1.77.8",
|
||||
"vue": "^3.4.35"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/node": "^22.1.0",
|
||||
"@vitejs/plugin-vue": "^5.1.2",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^5.4.0",
|
||||
"vite-plugin-singlefile": "^2.0.2",
|
||||
"vue-tsc": "^2.0.29"
|
||||
}
|
||||
}
|
||||
Generated
+101
@@ -11,6 +11,9 @@ importers:
|
||||
'@vicons/ionicons5':
|
||||
specifier: ^0.12.0
|
||||
version: 0.12.0
|
||||
axios:
|
||||
specifier: ^1.7.3
|
||||
version: 1.7.3
|
||||
naive-ui:
|
||||
specifier: ^2.39.0
|
||||
version: 2.39.0(vue@3.4.37(typescript@5.5.4))
|
||||
@@ -21,6 +24,9 @@ importers:
|
||||
specifier: ^3.4.35
|
||||
version: 3.4.37(typescript@5.5.4)
|
||||
devDependencies:
|
||||
'@types/lodash':
|
||||
specifier: ^4.17.7
|
||||
version: 4.17.7
|
||||
'@types/node':
|
||||
specifier: ^22.1.0
|
||||
version: 22.1.0
|
||||
@@ -33,6 +39,9 @@ importers:
|
||||
vite:
|
||||
specifier: ^5.4.0
|
||||
version: 5.4.0(@types/node@22.1.0)(sass@1.77.8)
|
||||
vite-plugin-singlefile:
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2(rollup@4.20.0)(vite@5.4.0(@types/node@22.1.0)(sass@1.77.8))
|
||||
vue-tsc:
|
||||
specifier: ^2.0.29
|
||||
version: 2.0.29(typescript@5.5.4)
|
||||
@@ -387,6 +396,12 @@ packages:
|
||||
async-validator@4.2.5:
|
||||
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
|
||||
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
axios@1.7.3:
|
||||
resolution: {integrity: sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
@@ -405,6 +420,10 @@ packages:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
computeds@0.0.1:
|
||||
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
|
||||
|
||||
@@ -429,6 +448,10 @@ packages:
|
||||
de-indent@1.0.2:
|
||||
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
|
||||
|
||||
delayed-stream@1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
entities@5.0.0:
|
||||
resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==}
|
||||
engines: {node: '>=0.12'}
|
||||
@@ -448,6 +471,19 @@ packages:
|
||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
follow-redirects@1.15.6:
|
||||
resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
|
||||
form-data@4.0.0:
|
||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
@@ -493,6 +529,18 @@ packages:
|
||||
magic-string@0.30.11:
|
||||
resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
|
||||
|
||||
micromatch@4.0.7:
|
||||
resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
mime-db@1.52.0:
|
||||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
mime-types@2.1.35:
|
||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
@@ -528,6 +576,9 @@ packages:
|
||||
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
|
||||
readdirp@3.6.0:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
engines: {node: '>=8.10.0'}
|
||||
@@ -581,6 +632,13 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.0.11
|
||||
|
||||
vite-plugin-singlefile@2.0.2:
|
||||
resolution: {integrity: sha512-Z2ou6HcvED5CF0hM+vcFSaFa+klyS8RyyLxW0PbMRLnMbvzTI6ueWyxdYNFhpuXZgz/aj6+E/dHFTdEcw6gb9w==}
|
||||
engines: {node: '>18.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^4.18.0
|
||||
vite: ^5.3.1
|
||||
|
||||
vite@5.4.0:
|
||||
resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
@@ -902,6 +960,16 @@ snapshots:
|
||||
|
||||
async-validator@4.2.5: {}
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
axios@1.7.3:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.6
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
binary-extensions@2.3.0: {}
|
||||
@@ -926,6 +994,10 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
combined-stream@1.0.8:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
computeds@0.0.1: {}
|
||||
|
||||
css-render@0.15.14:
|
||||
@@ -947,6 +1019,8 @@ snapshots:
|
||||
|
||||
de-indent@1.0.2: {}
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
entities@5.0.0: {}
|
||||
|
||||
esbuild@0.21.5:
|
||||
@@ -983,6 +1057,14 @@ snapshots:
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
|
||||
follow-redirects@1.15.6: {}
|
||||
|
||||
form-data@4.0.0:
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
@@ -1016,6 +1098,17 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
|
||||
micromatch@4.0.7:
|
||||
dependencies:
|
||||
braces: 3.0.3
|
||||
picomatch: 2.3.1
|
||||
|
||||
mime-db@1.52.0: {}
|
||||
|
||||
mime-types@2.1.35:
|
||||
dependencies:
|
||||
mime-db: 1.52.0
|
||||
|
||||
minimatch@9.0.5:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
@@ -1061,6 +1154,8 @@ snapshots:
|
||||
picocolors: 1.0.1
|
||||
source-map-js: 1.2.0
|
||||
|
||||
proxy-from-env@1.1.0: {}
|
||||
|
||||
readdirp@3.6.0:
|
||||
dependencies:
|
||||
picomatch: 2.3.1
|
||||
@@ -1118,6 +1213,12 @@ snapshots:
|
||||
evtd: 0.2.4
|
||||
vue: 3.4.37(typescript@5.5.4)
|
||||
|
||||
vite-plugin-singlefile@2.0.2(rollup@4.20.0)(vite@5.4.0(@types/node@22.1.0)(sass@1.77.8)):
|
||||
dependencies:
|
||||
micromatch: 4.0.7
|
||||
rollup: 4.20.0
|
||||
vite: 5.4.0(@types/node@22.1.0)(sass@1.77.8)
|
||||
|
||||
vite@5.4.0(@types/node@22.1.0)(sass@1.77.8):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
|
||||
+62
-8
@@ -1,10 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive } from 'vue';
|
||||
import { NIcon, NScrollbar } from 'naive-ui';
|
||||
import { EyeOffOutline, EyeOutline, CloseOutline, CopyOutline, EllipsisVertical } from '@vicons/ionicons5'
|
||||
import { h, onMounted, reactive, ref, shallowRef } from 'vue';
|
||||
import { NIcon, NScrollbar, NDropdown, NQrCode } from 'naive-ui';
|
||||
import { EyeOffOutline, EyeOutline, CloseOutline, CopyOutline, EllipsisVertical, QrCodeOutline } from '@vicons/ionicons5'
|
||||
import miaoDirectory from './views/miaoDirectory.vue';
|
||||
import VirtualPage from './class/virtualPage';
|
||||
import VirtualDirectory from './class/virtualDirectory';
|
||||
import VirtualPage from './class/VirtualPage';
|
||||
import VirtualDirectory from './class/VirtualDirectory';
|
||||
import MiaoMask from './components/miaoMask.vue';
|
||||
import config from './config';
|
||||
|
||||
const {baseUrl} = config
|
||||
|
||||
const showModal = ref<boolean>(false)
|
||||
|
||||
const modalData = shallowRef<{
|
||||
component: any
|
||||
props: any
|
||||
}>()
|
||||
|
||||
const views = reactive<VirtualPage[]>([])
|
||||
|
||||
@@ -31,6 +42,37 @@ const deleteView = (index: number) => {
|
||||
}
|
||||
}
|
||||
|
||||
function renderIcon(icon: any) {
|
||||
return () => {
|
||||
return h(NIcon, null, {
|
||||
default: () => h(icon)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const openMenuOption = [
|
||||
{
|
||||
label: '分享',
|
||||
key: 'share',
|
||||
icon: renderIcon(QrCodeOutline)
|
||||
}
|
||||
]
|
||||
|
||||
const handleMenuSelect = (key: string) => {
|
||||
console.log(key)
|
||||
if(key === 'share') {
|
||||
showModal.value = true
|
||||
modalData.value = {
|
||||
component: NQrCode,
|
||||
props: {
|
||||
value: baseUrl,
|
||||
size: 500,
|
||||
errorCorrectionLevel: 'H'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
createView(rootDirectory)
|
||||
})
|
||||
@@ -39,6 +81,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="view">
|
||||
<div class="view-controler">
|
||||
<n-scrollbar x-scrollable>
|
||||
<div class="tags-container">
|
||||
@@ -62,21 +105,31 @@ onMounted(() => {
|
||||
</n-scrollbar>
|
||||
<div class="view-controler-menu">
|
||||
<div class="view-controler-menu-item">
|
||||
<n-icon class="icon" @click="">
|
||||
<n-dropdown trigger="click" :options="openMenuOption" @select="handleMenuSelect">
|
||||
<n-icon class="icon">
|
||||
<EllipsisVertical class="icon-inner" />
|
||||
</n-icon>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view-container">
|
||||
<div class="view" v-for="(view, index) of views" v-show="view.visible" :key="view.uid">
|
||||
<div class="view-container-item" v-for="(view, index) of views" v-show="view.visible" :key="view.uid">
|
||||
<miao-directory v-model:current-directory="view.currentDirectory" :color="view.color" :index="index" @exit="deleteView(index)"></miao-directory>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<MiaoMask v-model:show="showModal" @click="showModal = false" >
|
||||
<component :is="modalData?.component" v-bind="modalData?.props"></component>
|
||||
</MiaoMask>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$controler-height: 25px;
|
||||
.view{
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.view-controler {
|
||||
display: flex;
|
||||
@@ -180,7 +233,7 @@ $controler-height: 25px;
|
||||
height: calc(100% - $controler-height);
|
||||
overflow-y: overlay;
|
||||
overflow-x: overlay;
|
||||
.view {
|
||||
.view-container-item {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -203,4 +256,5 @@ $controler-height: 25px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,165 @@
|
||||
import generateId from "@/hooks/generateId";
|
||||
import useMiaoFetchApi from "@/hooks/useMiaoFetchApi";
|
||||
import VirtualDirectory from "./VirtualDirectory";
|
||||
|
||||
const miaoFetchApi = useMiaoFetchApi();
|
||||
|
||||
export class UploadQueueItem {
|
||||
constructor(
|
||||
file: File,
|
||||
targetDirectory: VirtualDirectory,
|
||||
config?: {
|
||||
onSuccess?: () => void;
|
||||
onFailed?: () => void;
|
||||
}
|
||||
) {
|
||||
this.file = file;
|
||||
this.targetDirectory = targetDirectory;
|
||||
this.uid = generateId();
|
||||
this.status = "waiting";
|
||||
this.process = 0;
|
||||
this.onSuccess = config && config.onSuccess;
|
||||
this.onFailed = config && config.onFailed;
|
||||
}
|
||||
uid: number;
|
||||
file: File;
|
||||
targetDirectory: VirtualDirectory;
|
||||
status: "waiting" | "uploading" | "success" | "failed";
|
||||
process: number;
|
||||
failedReason: unknown | undefined;
|
||||
|
||||
onSuccess?: () => void;
|
||||
onFailed?: () => void;
|
||||
|
||||
_abort: (() => void | undefined) | undefined;
|
||||
_status: Promise<any> | undefined;
|
||||
|
||||
/**
|
||||
* 开始上传文件
|
||||
*/
|
||||
startUpload() {
|
||||
if (this.status === "uploading") {
|
||||
return;
|
||||
}
|
||||
const { abort, status } = miaoFetchApi.upload(this.file, this.targetDirectory, {
|
||||
onProcess: percent => {
|
||||
this.process = percent;
|
||||
}
|
||||
});
|
||||
this._abort = abort;
|
||||
this._status = status;
|
||||
this.status = "uploading";
|
||||
status
|
||||
.then(() => {
|
||||
this.status = "success";
|
||||
this.onSuccess && this.onSuccess();
|
||||
this._abort = undefined;
|
||||
this._status = undefined;
|
||||
})
|
||||
.catch(e => {
|
||||
this.status = "failed";
|
||||
this.failedReason = e;
|
||||
this.onFailed && this.onFailed();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 终止上传文件
|
||||
*/
|
||||
abortUpload() {
|
||||
this._abort && this._abort();
|
||||
this.status = "failed";
|
||||
this.failedReason = "abort";
|
||||
}
|
||||
}
|
||||
|
||||
export default class UploadQueue {
|
||||
constructor() {
|
||||
this.uid = generateId();
|
||||
this.queue = [];
|
||||
this.mode = "serial";
|
||||
}
|
||||
uid: number;
|
||||
queue: UploadQueueItem[];
|
||||
current: UploadQueueItem | undefined;
|
||||
|
||||
// 未来再去实现,目前就是串行的
|
||||
// 好像也不用去实现
|
||||
mode: "serial" | "parallel";
|
||||
get status() {
|
||||
for (let item of this.queue) {
|
||||
if (item.status === "uploading") {
|
||||
return "busy";
|
||||
}
|
||||
}
|
||||
return "free";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一个需要被上传的item
|
||||
*/
|
||||
get nextUplpadItem() {
|
||||
for (let item of this.queue) {
|
||||
if (item.status === "waiting") {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始串行的上传循环
|
||||
*/
|
||||
loop() {
|
||||
if (this.status === "busy") {
|
||||
return;
|
||||
}
|
||||
if (this.nextUplpadItem) {
|
||||
this.nextUplpadItem.startUpload();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向上传文件队列输送一批新的文件
|
||||
* @param {any} files 需要上传的文件
|
||||
* @param {any} targetDirectory 目标文件夹
|
||||
* @param {any} option 每个文件上传完成以后都会触发一遍的回调函数
|
||||
* @returns {any}
|
||||
*/
|
||||
push(
|
||||
files: File[],
|
||||
targetDirectory: VirtualDirectory,
|
||||
option?: {
|
||||
/**
|
||||
* 每个文件上传完成以后都会触发一遍的回调函数
|
||||
*/
|
||||
onFinish?: () => void;
|
||||
/**
|
||||
* 是否立即开始上传,若否则按队列顺序一个一个上传
|
||||
*/
|
||||
immediately?: boolean;
|
||||
}
|
||||
) {
|
||||
const onFinish = option?.onFinish;
|
||||
const immediately = option?.immediately ?? false;
|
||||
const uploadQueue = files.map(file => {
|
||||
return new UploadQueueItem(file, targetDirectory, {
|
||||
onSuccess: () => {
|
||||
this.loop();
|
||||
onFinish && onFinish();
|
||||
},
|
||||
onFailed: () => {
|
||||
this.loop();
|
||||
}
|
||||
});
|
||||
});
|
||||
this.queue.push(...uploadQueue);
|
||||
if (!immediately) {
|
||||
this.loop();
|
||||
} else {
|
||||
uploadQueue.forEach(item => {
|
||||
item.startUpload();
|
||||
});
|
||||
}
|
||||
return uploadQueue;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import VirtualDirectory from "./virtualDirectory";
|
||||
import VirtualDirectory from "./VirtualDirectory";
|
||||
import generateId from "@/hooks/generateId";
|
||||
|
||||
const getRandomWebSafeColor = (() => {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import VirtualDirectory, { VirtualFile } from '@/class/virtualDirectory';
|
||||
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory';
|
||||
import { DocumentText, FileTray, Help, Image, LogoChrome, LogoCss3, LogoJavascript, LogoVue, PlayCircle, EllipsisVertical, Disc } from '@vicons/ionicons5';
|
||||
import { computed, ref } from 'vue';
|
||||
import dateFormatter from '@/hooks/dateFormatter';
|
||||
@@ -50,9 +50,13 @@ const time = computed(()=>{
|
||||
})
|
||||
|
||||
const dropDownOptions = computed(()=> {
|
||||
const options = []
|
||||
const options = [{
|
||||
label: '删除',
|
||||
key: 'delete'
|
||||
}]
|
||||
if(itemType.value === 'file'){
|
||||
options.push(...[{
|
||||
options.push(...[
|
||||
{
|
||||
label: '下载',
|
||||
key: 'download',
|
||||
}
|
||||
@@ -135,6 +139,7 @@ const handleDragStart = () => {
|
||||
.item-main-icon {
|
||||
margin-left: 10px;
|
||||
height: 80%;
|
||||
color: #00403e;
|
||||
}
|
||||
.item-main-info {
|
||||
margin-left: 10px;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<transition name="transition">
|
||||
<div class="mask-body" ref="maskBodyRef" v-show="showMask">
|
||||
<div @click="e=>e.stopPropagation()">
|
||||
<slot> {{}} </slot>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
+4
-2
@@ -4,6 +4,8 @@ export default {
|
||||
baseUrl,
|
||||
uploadSizeLimit: 1024 * 1024 * 100,
|
||||
api: {
|
||||
get: '/get'
|
||||
}
|
||||
get: '/get',
|
||||
upload: '/upload'
|
||||
},
|
||||
enableUpload: true,
|
||||
};
|
||||
@@ -6,7 +6,7 @@ export default function useDataBus() {
|
||||
dataStorage[key] = value;
|
||||
return value;
|
||||
},
|
||||
get(key: string | number) {
|
||||
pop(key: string | number) {
|
||||
const value = dataStorage[key];
|
||||
dataStorage[key] = undefined;
|
||||
return value;
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
type miaoFetchConfig = {
|
||||
retry: number;
|
||||
};
|
||||
|
||||
export default function useMiaoFetch(config: miaoFetchConfig) {
|
||||
const { retry } = config;
|
||||
|
||||
return async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
let retryTimes = 0;
|
||||
let err: any;
|
||||
while (retryTimes <= retry) {
|
||||
try {
|
||||
const response = await fetch(input, init);
|
||||
return response;
|
||||
} catch (e) {
|
||||
err = e;
|
||||
retryTimes += 1;
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import VirtualDirectory from "@/class/VirtualDirectory";
|
||||
import { getOption, getResponse, miaoFetchConfig, uploadOption } from "@/types/fetch";
|
||||
import Config from "@/config";
|
||||
import axios, { AxiosRequestConfig } 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>) => {
|
||||
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;
|
||||
|
||||
const { miaoFetch } = useMiaoFetch({
|
||||
retry
|
||||
});
|
||||
const response = await miaoFetch({
|
||||
url
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 上传单个文件到对应文件夹
|
||||
*/
|
||||
upload(file: 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 = file.size
|
||||
|
||||
const opType = option?.type ?? 'write'
|
||||
|
||||
const data = new FormData()
|
||||
|
||||
data.append('file', file)
|
||||
data.append('oprateType', opType)
|
||||
|
||||
return {
|
||||
abort: () => abortMiaoFetch(),
|
||||
status: new Promise(async (resolve)=>{
|
||||
const response = await miaoFetch({
|
||||
url,
|
||||
method: 'post',
|
||||
data: data,
|
||||
onUploadProgress(progressEvent) {
|
||||
option && option.onProcess && option.onProcess(progressEvent.loaded / sizeTotal)
|
||||
},
|
||||
})
|
||||
resolve(response.data)
|
||||
})
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default function useMiaoFetchApi() {
|
||||
return miaoFetchApi;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import UploadQueue from "@/class/UploadQueue";
|
||||
|
||||
const uploadQueue = new UploadQueue()
|
||||
|
||||
export default () => uploadQueue
|
||||
@@ -0,0 +1,24 @@
|
||||
import { directory, file } from "./type";
|
||||
|
||||
export type miaoFetchConfig = {
|
||||
retry?: number
|
||||
}
|
||||
|
||||
export type getOption = {
|
||||
} & miaoFetchConfig
|
||||
|
||||
export type getResponse = (file | directory)[]
|
||||
|
||||
export type uploadOption = {
|
||||
/**
|
||||
* 上传进度回调函数
|
||||
* @param {any} percent 进度百分比,float类型
|
||||
*/
|
||||
onProcess?: (percent: number) => void
|
||||
/**
|
||||
* 上传文件执行的操作
|
||||
* write即为覆盖写
|
||||
* append即为增量写
|
||||
*/
|
||||
type?: 'write' | 'append'
|
||||
} & miaoFetchConfig
|
||||
+27
-13
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="miao-directory-item-container" ref="rootDomRef" >
|
||||
<div class="container-top">
|
||||
<div class="container-top" :style="{ backgroundColor: props.index % 2 === 0 ? '#f8f8f8' : 'rgb(240 240 240)' }">
|
||||
<div class="container-top-colorbar" :style="{ backgroundColor: props.color }"></div>
|
||||
<div class="container-top-breadcrumb">
|
||||
<!-- <n-scrollbar x-scrollable> -->
|
||||
@@ -51,22 +51,21 @@
|
||||
<script setup lang="ts">
|
||||
import { NBreadcrumbItem, NBreadcrumb, NIcon, NScrollbar } from 'naive-ui'
|
||||
import type { file, directory } from '@/types/type.ts'
|
||||
import VirtualDirectory from '@/class/virtualDirectory';
|
||||
import VirtualDirectory from '@/class/VirtualDirectory';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import Config from '@/config'
|
||||
import dropHandler, { dropHandlerHooks } from '@/hooks/dropHandler';
|
||||
import miaoMask from '@/components/miaoMask.vue';
|
||||
import miaoDirectoryItem from '@/components/miaoDirectory/miaoDirectoryItem.vue';
|
||||
import useMiaoFetch from '@/hooks/useMiaoFetch';
|
||||
import useMiaoFetchApi from '@/hooks/useMiaoFetchApi';
|
||||
import useDataBus from '@/hooks/useDataBus';
|
||||
import { CloudOutline, ChevronBackOutline, ReloadOutline, CloseOutline } from '@vicons/ionicons5'
|
||||
import useUploadQueue from '@/hooks/useUploadQueue';
|
||||
|
||||
const { baseUrl, api } = Config
|
||||
const dataBus = useDataBus()
|
||||
|
||||
const miaoFetch = useMiaoFetch({
|
||||
retry: 5,
|
||||
})
|
||||
const miaoFetchApi = useMiaoFetchApi()
|
||||
|
||||
const props = defineProps<{
|
||||
color: string
|
||||
@@ -86,15 +85,17 @@ const showModel = ref(0)
|
||||
// 用于监听拖拽文件事件
|
||||
const rootDomRef = ref<HTMLDivElement>()
|
||||
|
||||
const uploadQueue = useUploadQueue()
|
||||
|
||||
// 设置显示的dir
|
||||
const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
|
||||
// 若没有缓存数据则同步刷新,有缓存数据则异步刷新
|
||||
if (virtualDirectory.files === undefined || virtualDirectory.directorys === undefined) {
|
||||
const data: (file | directory)[] = await (await miaoFetch(`${baseUrl}${api.get}${virtualDirectory.path}`)).json()
|
||||
const data: (file | directory)[] = await miaoFetchApi.get(virtualDirectory)
|
||||
virtualDirectory.updateContent(data)
|
||||
} else {
|
||||
; (async () => {
|
||||
const data: (file | directory)[] = await (await miaoFetch(`${baseUrl}${api.get}${virtualDirectory.path}`)).json()
|
||||
const data: (file | directory)[] = await miaoFetchApi.get(virtualDirectory)
|
||||
virtualDirectory.updateContent(data)
|
||||
currentDirectory.value = undefined
|
||||
currentDirectory.value = virtualDirectory
|
||||
@@ -106,17 +107,21 @@ const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
|
||||
// emit("onCurrentDirectoryChange", currentDirectory.value)
|
||||
}
|
||||
|
||||
const reload = () => {
|
||||
currentDirectory.value && setCurrentDirectory(currentDirectory.value)
|
||||
}
|
||||
|
||||
const openUrl = (href: string, config?: {
|
||||
download?: string
|
||||
target?: string
|
||||
}) => {
|
||||
let {target, download} = config ?? {}
|
||||
|
||||
console.log({target, download})
|
||||
console.log({target, download, href})
|
||||
const a = document.createElement('a');
|
||||
a.setAttribute('href', href);
|
||||
a.setAttribute('target', target ?? '_blank')
|
||||
a.setAttribute('download', download ?? '');
|
||||
download && a.setAttribute('download', download);
|
||||
a.click();
|
||||
// var a = document.createElement("a");
|
||||
// a.setAttribute('href', href)
|
||||
@@ -133,7 +138,7 @@ const handleBack = () => {
|
||||
}
|
||||
|
||||
const handleReload = () => {
|
||||
currentDirectory.value && setCurrentDirectory(currentDirectory.value)
|
||||
reload()
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -141,8 +146,17 @@ onMounted(async () => {
|
||||
// 拖动事件处理
|
||||
const dropFileOption:dropHandlerHooks = {
|
||||
onDropFiles(files: File[]) {
|
||||
const dragData = dataBus.get('dragData')
|
||||
const dragData = dataBus.pop('dragData')
|
||||
console.log({dragData, files})
|
||||
if(files && files.length > 0){
|
||||
currentDirectory.value && uploadQueue.push(files, currentDirectory.value, {
|
||||
onFinish() {
|
||||
reload()
|
||||
},
|
||||
})
|
||||
const _f = files[0]
|
||||
currentDirectory.value && miaoFetchApi.upload(_f, currentDirectory.value)
|
||||
}
|
||||
},
|
||||
onEnter() {
|
||||
showModel.value += 1
|
||||
@@ -238,7 +252,7 @@ $bottom-bar-height: 60px;
|
||||
content: '';
|
||||
height: 60%;
|
||||
position: absolute;
|
||||
right: -1px;
|
||||
right: -2px;
|
||||
width: 2px;
|
||||
background-color: #828282;
|
||||
}
|
||||
|
||||
+8
-1
@@ -1,10 +1,11 @@
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { resolve } from "path";
|
||||
import { viteSingleFile } from "vite-plugin-singlefile"
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
plugins: [vue(), viteSingleFile()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": resolve(__dirname, "src")
|
||||
@@ -16,6 +17,12 @@ export default defineConfig({
|
||||
target: "http://127.0.0.1:17705",
|
||||
changeOrigin: true,
|
||||
rewrite: path => path.replace(/^\/get/, "/get")
|
||||
},
|
||||
|
||||
"/upload": {
|
||||
target: "http://127.0.0.1:17705",
|
||||
changeOrigin: true,
|
||||
rewrite: path => path.replace(/^\/upload/, "/upload")
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user