Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f477c99d1 | ||
|
|
e840e4eb5a |
No files matched your search
@@ -5,20 +5,24 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
"dev:host": "vite --host 0.0.0.0",
|
||||||
"build": "vue-tsc -b && vite build",
|
"build": "vue-tsc -b && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vicons/ionicons5": "^0.12.0",
|
"@vicons/ionicons5": "^0.12.0",
|
||||||
|
"axios": "^1.7.3",
|
||||||
"naive-ui": "^2.39.0",
|
"naive-ui": "^2.39.0",
|
||||||
"sass": "^1.77.8",
|
"sass": "^1.77.8",
|
||||||
"vue": "^3.4.35"
|
"vue": "^3.4.35"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.17.7",
|
||||||
"@types/node": "^22.1.0",
|
"@types/node": "^22.1.0",
|
||||||
"@vitejs/plugin-vue": "^5.1.2",
|
"@vitejs/plugin-vue": "^5.1.2",
|
||||||
"typescript": "^5.5.3",
|
"typescript": "^5.5.3",
|
||||||
"vite": "^5.4.0",
|
"vite": "^5.4.0",
|
||||||
|
"vite-plugin-singlefile": "^2.0.2",
|
||||||
"vue-tsc": "^2.0.29"
|
"vue-tsc": "^2.0.29"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Generated
+101
@@ -11,6 +11,9 @@ importers:
|
|||||||
'@vicons/ionicons5':
|
'@vicons/ionicons5':
|
||||||
specifier: ^0.12.0
|
specifier: ^0.12.0
|
||||||
version: 0.12.0
|
version: 0.12.0
|
||||||
|
axios:
|
||||||
|
specifier: ^1.7.3
|
||||||
|
version: 1.7.3
|
||||||
naive-ui:
|
naive-ui:
|
||||||
specifier: ^2.39.0
|
specifier: ^2.39.0
|
||||||
version: 2.39.0(vue@3.4.37(typescript@5.5.4))
|
version: 2.39.0(vue@3.4.37(typescript@5.5.4))
|
||||||
@@ -21,6 +24,9 @@ importers:
|
|||||||
specifier: ^3.4.35
|
specifier: ^3.4.35
|
||||||
version: 3.4.37(typescript@5.5.4)
|
version: 3.4.37(typescript@5.5.4)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@types/lodash':
|
||||||
|
specifier: ^4.17.7
|
||||||
|
version: 4.17.7
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.1.0
|
specifier: ^22.1.0
|
||||||
version: 22.1.0
|
version: 22.1.0
|
||||||
@@ -33,6 +39,9 @@ importers:
|
|||||||
vite:
|
vite:
|
||||||
specifier: ^5.4.0
|
specifier: ^5.4.0
|
||||||
version: 5.4.0(@types/node@22.1.0)(sass@1.77.8)
|
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:
|
vue-tsc:
|
||||||
specifier: ^2.0.29
|
specifier: ^2.0.29
|
||||||
version: 2.0.29(typescript@5.5.4)
|
version: 2.0.29(typescript@5.5.4)
|
||||||
@@ -387,6 +396,12 @@ packages:
|
|||||||
async-validator@4.2.5:
|
async-validator@4.2.5:
|
||||||
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
|
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:
|
balanced-match@1.0.2:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
|
|
||||||
@@ -405,6 +420,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||||
engines: {node: '>= 8.10.0'}
|
engines: {node: '>= 8.10.0'}
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
computeds@0.0.1:
|
computeds@0.0.1:
|
||||||
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
|
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
|
||||||
|
|
||||||
@@ -429,6 +448,10 @@ packages:
|
|||||||
de-indent@1.0.2:
|
de-indent@1.0.2:
|
||||||
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
|
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:
|
entities@5.0.0:
|
||||||
resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==}
|
resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
@@ -448,6 +471,19 @@ packages:
|
|||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
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:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@@ -493,6 +529,18 @@ packages:
|
|||||||
magic-string@0.30.11:
|
magic-string@0.30.11:
|
||||||
resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
|
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:
|
minimatch@9.0.5:
|
||||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
@@ -528,6 +576,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
|
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
proxy-from-env@1.1.0:
|
||||||
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||||
|
|
||||||
readdirp@3.6.0:
|
readdirp@3.6.0:
|
||||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||||
engines: {node: '>=8.10.0'}
|
engines: {node: '>=8.10.0'}
|
||||||
@@ -581,6 +632,13 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.0.11
|
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:
|
vite@5.4.0:
|
||||||
resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==}
|
resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
@@ -902,6 +960,16 @@ snapshots:
|
|||||||
|
|
||||||
async-validator@4.2.5: {}
|
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: {}
|
balanced-match@1.0.2: {}
|
||||||
|
|
||||||
binary-extensions@2.3.0: {}
|
binary-extensions@2.3.0: {}
|
||||||
@@ -926,6 +994,10 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
dependencies:
|
||||||
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
computeds@0.0.1: {}
|
computeds@0.0.1: {}
|
||||||
|
|
||||||
css-render@0.15.14:
|
css-render@0.15.14:
|
||||||
@@ -947,6 +1019,8 @@ snapshots:
|
|||||||
|
|
||||||
de-indent@1.0.2: {}
|
de-indent@1.0.2: {}
|
||||||
|
|
||||||
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
entities@5.0.0: {}
|
entities@5.0.0: {}
|
||||||
|
|
||||||
esbuild@0.21.5:
|
esbuild@0.21.5:
|
||||||
@@ -983,6 +1057,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
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:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -1016,6 +1098,17 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@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:
|
minimatch@9.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion: 2.0.1
|
brace-expansion: 2.0.1
|
||||||
@@ -1061,6 +1154,8 @@ snapshots:
|
|||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
source-map-js: 1.2.0
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
|
proxy-from-env@1.1.0: {}
|
||||||
|
|
||||||
readdirp@3.6.0:
|
readdirp@3.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
@@ -1118,6 +1213,12 @@ snapshots:
|
|||||||
evtd: 0.2.4
|
evtd: 0.2.4
|
||||||
vue: 3.4.37(typescript@5.5.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):
|
vite@5.4.0(@types/node@22.1.0)(sass@1.77.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.21.5
|
esbuild: 0.21.5
|
||||||
|
|||||||
+189
-135
@@ -1,10 +1,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, reactive } from 'vue';
|
import { h, onMounted, reactive, ref, shallowRef } from 'vue';
|
||||||
import { NIcon, NScrollbar } from 'naive-ui';
|
import { NIcon, NScrollbar, NDropdown, NQrCode } from 'naive-ui';
|
||||||
import { EyeOffOutline, EyeOutline, CloseOutline, CopyOutline, EllipsisVertical } from '@vicons/ionicons5'
|
import { EyeOffOutline, EyeOutline, CloseOutline, CopyOutline, EllipsisVertical, QrCodeOutline } from '@vicons/ionicons5'
|
||||||
import miaoDirectory from './views/miaoDirectory.vue';
|
import miaoDirectory from './views/miaoDirectory.vue';
|
||||||
import VirtualPage from './class/virtualPage';
|
import VirtualPage from './class/VirtualPage';
|
||||||
import VirtualDirectory from './class/virtualDirectory';
|
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[]>([])
|
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(() => {
|
onMounted(() => {
|
||||||
createView(rootDirectory)
|
createView(rootDirectory)
|
||||||
})
|
})
|
||||||
@@ -39,168 +81,180 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="view-controler">
|
<div class="view">
|
||||||
<n-scrollbar x-scrollable>
|
<div class="view-controler">
|
||||||
<div class="tags-container">
|
<n-scrollbar x-scrollable>
|
||||||
<div class="tag" v-for="(view, index) of views" :key="view.uid">
|
<div class="tags-container">
|
||||||
<div class="tag-title">{{ view.title }}</div>
|
<div class="tag" v-for="(view, index) of views" :key="view.uid">
|
||||||
<div class="tag-point" :style="{ backgroundColor: view.color } "></div>
|
<div class="tag-title">{{ view.title }}</div>
|
||||||
<div class="tag-control">
|
<div class="tag-point" :style="{ backgroundColor: view.color } "></div>
|
||||||
<n-icon class="tag-control-icon icon" @click="view.switchShow()">
|
<div class="tag-control">
|
||||||
<EyeOutline v-show="view.visible" class="icon-inner" />
|
<n-icon class="tag-control-icon icon" @click="view.switchShow()">
|
||||||
<EyeOffOutline v-show="!view.visible" class="icon-inner" />
|
<EyeOutline v-show="view.visible" class="icon-inner" />
|
||||||
</n-icon>
|
<EyeOffOutline v-show="!view.visible" class="icon-inner" />
|
||||||
<n-icon class="tag-control-icon icon" @click="createView(view.currentDirectory, index + 1)">
|
</n-icon>
|
||||||
<CopyOutline />
|
<n-icon class="tag-control-icon icon" @click="createView(view.currentDirectory, index + 1)">
|
||||||
</n-icon>
|
<CopyOutline />
|
||||||
<n-icon class="tag-control-icon icon" @click="deleteView(index)">
|
</n-icon>
|
||||||
<CloseOutline class="icon-inner" />
|
<n-icon class="tag-control-icon icon" @click="deleteView(index)">
|
||||||
</n-icon>
|
<CloseOutline class="icon-inner" />
|
||||||
|
</n-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</n-scrollbar>
|
||||||
|
<div class="view-controler-menu">
|
||||||
|
<div class="view-controler-menu-item">
|
||||||
|
<n-dropdown trigger="click" :options="openMenuOption" @select="handleMenuSelect">
|
||||||
|
<n-icon class="icon">
|
||||||
|
<EllipsisVertical class="icon-inner" />
|
||||||
|
</n-icon>
|
||||||
|
</n-dropdown>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</n-scrollbar>
|
</div>
|
||||||
<div class="view-controler-menu">
|
<div class="view-container">
|
||||||
<div class="view-controler-menu-item">
|
<div class="view-container-item" v-for="(view, index) of views" v-show="view.visible" :key="view.uid">
|
||||||
<n-icon class="icon" @click="">
|
<miao-directory v-model:current-directory="view.currentDirectory" :color="view.color" :index="index" @exit="deleteView(index)"></miao-directory>
|
||||||
<EllipsisVertical class="icon-inner" />
|
|
||||||
</n-icon>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="view-container">
|
<MiaoMask v-model:show="showModal" @click="showModal = false" >
|
||||||
<div class="view" v-for="(view, index) of views" v-show="view.visible" :key="view.uid">
|
<component :is="modalData?.component" v-bind="modalData?.props"></component>
|
||||||
<miao-directory v-model:current-directory="view.currentDirectory" :color="view.color" :index="index" @exit="deleteView(index)"></miao-directory>
|
</MiaoMask>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$controler-height: 25px;
|
$controler-height: 25px;
|
||||||
|
.view{
|
||||||
.view-controler {
|
position: relative;
|
||||||
display: flex;
|
height: 100%;
|
||||||
height: $controler-height;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #dadada;
|
|
||||||
// overflow: hidden;
|
|
||||||
|
|
||||||
.tags-container {
|
.view-controler {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-left: 5px;
|
height: $controler-height;
|
||||||
flex: 1;
|
width: 100%;
|
||||||
// overflow-x: scroll;
|
background-color: #dadada;
|
||||||
.tag {
|
// overflow: hidden;
|
||||||
position: relative;
|
|
||||||
width: 170px;
|
.tags-container {
|
||||||
margin: 0 5px;
|
|
||||||
// flex: 1;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
border-radius: 5px 5px 0 0;
|
margin-left: 5px;
|
||||||
align-items: center;
|
flex: 1;
|
||||||
|
// overflow-x: scroll;
|
||||||
.tag-title {
|
.tag {
|
||||||
margin-left: 4px;
|
position: relative;
|
||||||
// width: 70%;
|
width: 170px;
|
||||||
user-select: none;
|
margin: 0 5px;
|
||||||
}
|
// flex: 1;
|
||||||
|
|
||||||
.tag-point {
|
|
||||||
height: 5px;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
border-radius: 66px;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-control {
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.tag-control-icon:not(:last-child) {
|
.tag-title {
|
||||||
margin-right: 5px;
|
margin-left: 4px;
|
||||||
|
// width: 70%;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-point {
|
||||||
|
height: 5px;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
border-radius: 66px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-control {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.tag-control-icon:not(:last-child) {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child)::after {
|
||||||
|
content: '';
|
||||||
|
height: calc($controler-height*0.6);
|
||||||
|
width: 1px;
|
||||||
|
border-right: 1px solid black;
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:not(:last-child)::after {
|
.view-controler-menu {
|
||||||
content: '';
|
position: relative;
|
||||||
height: calc($controler-height*0.6);
|
display: flex;
|
||||||
width: 1px;
|
align-items: center;
|
||||||
border-right: 1px solid black;
|
padding: 0 5px;
|
||||||
position: absolute;
|
.view-controler-menu-item {
|
||||||
right: 0px;
|
height: 100%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
height: calc($controler-height*0.6);
|
||||||
|
width: 1px;
|
||||||
|
border-right: 1px solid black;
|
||||||
|
position: absolute;
|
||||||
|
left: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.view-controler-menu {
|
.icon {
|
||||||
position: relative;
|
height: calc($controler-height * 0.7);
|
||||||
display: flex;
|
width: calc($controler-height * 0.7);
|
||||||
align-items: center;
|
border-radius: 5px;
|
||||||
padding: 0 5px;
|
|
||||||
.view-controler-menu-item {
|
|
||||||
height: 100%;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
cursor: pointer;
|
||||||
&::before {
|
background-color: rgba(128, 128, 128, 0);
|
||||||
content: '';
|
transition: background-color 0.3s;
|
||||||
height: calc($controler-height*0.6);
|
|
||||||
width: 1px;
|
&:hover {
|
||||||
border-right: 1px solid black;
|
background-color: rgba(128, 128, 128, 0.4);
|
||||||
position: absolute;
|
}
|
||||||
left: 2px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.view-container {
|
||||||
height: calc($controler-height * 0.7);
|
position: relative;
|
||||||
width: calc($controler-height * 0.7);
|
|
||||||
border-radius: 5px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
// flex-direction: column;
|
||||||
align-items: center;
|
height: calc(100% - $controler-height);
|
||||||
cursor: pointer;
|
overflow-y: overlay;
|
||||||
background-color: rgba(128, 128, 128, 0);
|
overflow-x: overlay;
|
||||||
transition: background-color 0.3s;
|
.view-container-item {
|
||||||
|
flex: 1;
|
||||||
&:hover {
|
height: 100%;
|
||||||
background-color: rgba(128, 128, 128, 0.4);
|
}
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
position: absolute;
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
// 滚动条轨道
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
// background: rgb(239, 239, 239);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
// 小滑块
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #e0e0e0;
|
||||||
|
// border-radius: 5px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #999999;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-container {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
// flex-direction: column;
|
|
||||||
height: calc(100% - $controler-height);
|
|
||||||
overflow-y: overlay;
|
|
||||||
overflow-x: overlay;
|
|
||||||
.view {
|
|
||||||
flex: 1;
|
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
&::-webkit-scrollbar {
|
|
||||||
position: absolute;
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
// 滚动条轨道
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
// background: rgb(239, 239, 239);
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
// 小滑块
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: #e0e0e0;
|
|
||||||
// border-radius: 5px;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #999999;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</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";
|
import generateId from "@/hooks/generateId";
|
||||||
|
|
||||||
const getRandomWebSafeColor = (() => {
|
const getRandomWebSafeColor = (() => {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<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 { DocumentText, FileTray, Help, Image, LogoChrome, LogoCss3, LogoJavascript, LogoVue, PlayCircle, EllipsisVertical, Disc } from '@vicons/ionicons5';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import dateFormatter from '@/hooks/dateFormatter';
|
import dateFormatter from '@/hooks/dateFormatter';
|
||||||
@@ -50,9 +50,13 @@ const time = computed(()=>{
|
|||||||
})
|
})
|
||||||
|
|
||||||
const dropDownOptions = computed(()=> {
|
const dropDownOptions = computed(()=> {
|
||||||
const options = []
|
const options = [{
|
||||||
|
label: '删除',
|
||||||
|
key: 'delete'
|
||||||
|
}]
|
||||||
if(itemType.value === 'file'){
|
if(itemType.value === 'file'){
|
||||||
options.push(...[{
|
options.push(...[
|
||||||
|
{
|
||||||
label: '下载',
|
label: '下载',
|
||||||
key: 'download',
|
key: 'download',
|
||||||
}
|
}
|
||||||
@@ -135,6 +139,7 @@ const handleDragStart = () => {
|
|||||||
.item-main-icon {
|
.item-main-icon {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
|
color: #00403e;
|
||||||
}
|
}
|
||||||
.item-main-info {
|
.item-main-info {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition name="transition">
|
<transition name="transition">
|
||||||
<div class="mask-body" ref="maskBodyRef" v-show="showMask">
|
<div class="mask-body" ref="maskBodyRef" v-show="showMask">
|
||||||
<slot> {{}} </slot>
|
<div @click="e=>e.stopPropagation()">
|
||||||
|
<slot> {{}} </slot>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
+4
-2
@@ -4,6 +4,8 @@ export default {
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
uploadSizeLimit: 1024 * 1024 * 100,
|
uploadSizeLimit: 1024 * 1024 * 100,
|
||||||
api: {
|
api: {
|
||||||
get: '/get'
|
get: '/get',
|
||||||
}
|
upload: '/upload'
|
||||||
|
},
|
||||||
|
enableUpload: true,
|
||||||
};
|
};
|
||||||
@@ -6,7 +6,7 @@ export default function useDataBus() {
|
|||||||
dataStorage[key] = value;
|
dataStorage[key] = value;
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
get(key: string | number) {
|
pop(key: string | number) {
|
||||||
const value = dataStorage[key];
|
const value = dataStorage[key];
|
||||||
dataStorage[key] = undefined;
|
dataStorage[key] = undefined;
|
||||||
return value;
|
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
|
||||||
+28
-14
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="miao-directory-item-container" ref="rootDomRef">
|
<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-colorbar" :style="{ backgroundColor: props.color }"></div>
|
||||||
<div class="container-top-breadcrumb">
|
<div class="container-top-breadcrumb">
|
||||||
<!-- <n-scrollbar x-scrollable> -->
|
<!-- <n-scrollbar x-scrollable> -->
|
||||||
@@ -51,22 +51,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NBreadcrumbItem, NBreadcrumb, NIcon, NScrollbar } from 'naive-ui'
|
import { NBreadcrumbItem, NBreadcrumb, NIcon, NScrollbar } from 'naive-ui'
|
||||||
import type { file, directory } from '@/types/type.ts'
|
import type { file, directory } from '@/types/type.ts'
|
||||||
import VirtualDirectory from '@/class/virtualDirectory';
|
import VirtualDirectory from '@/class/VirtualDirectory';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import Config from '@/config'
|
import Config from '@/config'
|
||||||
import dropHandler, { dropHandlerHooks } from '@/hooks/dropHandler';
|
import dropHandler, { dropHandlerHooks } from '@/hooks/dropHandler';
|
||||||
import miaoMask from '@/components/miaoMask.vue';
|
import miaoMask from '@/components/miaoMask.vue';
|
||||||
import miaoDirectoryItem from '@/components/miaoDirectory/miaoDirectoryItem.vue';
|
import miaoDirectoryItem from '@/components/miaoDirectory/miaoDirectoryItem.vue';
|
||||||
import useMiaoFetch from '@/hooks/useMiaoFetch';
|
import useMiaoFetchApi from '@/hooks/useMiaoFetchApi';
|
||||||
import useDataBus from '@/hooks/useDataBus';
|
import useDataBus from '@/hooks/useDataBus';
|
||||||
import { CloudOutline, ChevronBackOutline, ReloadOutline, CloseOutline } from '@vicons/ionicons5'
|
import { CloudOutline, ChevronBackOutline, ReloadOutline, CloseOutline } from '@vicons/ionicons5'
|
||||||
|
import useUploadQueue from '@/hooks/useUploadQueue';
|
||||||
|
|
||||||
const { baseUrl, api } = Config
|
const { baseUrl, api } = Config
|
||||||
const dataBus = useDataBus()
|
const dataBus = useDataBus()
|
||||||
|
|
||||||
const miaoFetch = useMiaoFetch({
|
const miaoFetchApi = useMiaoFetchApi()
|
||||||
retry: 5,
|
|
||||||
})
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
color: string
|
color: string
|
||||||
@@ -86,15 +85,17 @@ const showModel = ref(0)
|
|||||||
// 用于监听拖拽文件事件
|
// 用于监听拖拽文件事件
|
||||||
const rootDomRef = ref<HTMLDivElement>()
|
const rootDomRef = ref<HTMLDivElement>()
|
||||||
|
|
||||||
|
const uploadQueue = useUploadQueue()
|
||||||
|
|
||||||
// 设置显示的dir
|
// 设置显示的dir
|
||||||
const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
|
const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
|
||||||
// 若没有缓存数据则同步刷新,有缓存数据则异步刷新
|
// 若没有缓存数据则同步刷新,有缓存数据则异步刷新
|
||||||
if (virtualDirectory.files === undefined || virtualDirectory.directorys === undefined) {
|
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)
|
virtualDirectory.updateContent(data)
|
||||||
} else {
|
} else {
|
||||||
; (async () => {
|
; (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)
|
virtualDirectory.updateContent(data)
|
||||||
currentDirectory.value = undefined
|
currentDirectory.value = undefined
|
||||||
currentDirectory.value = virtualDirectory
|
currentDirectory.value = virtualDirectory
|
||||||
@@ -106,17 +107,21 @@ const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
|
|||||||
// emit("onCurrentDirectoryChange", currentDirectory.value)
|
// emit("onCurrentDirectoryChange", currentDirectory.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
currentDirectory.value && setCurrentDirectory(currentDirectory.value)
|
||||||
|
}
|
||||||
|
|
||||||
const openUrl = (href: string, config?: {
|
const openUrl = (href: string, config?: {
|
||||||
download?: string
|
download?: string
|
||||||
target?: string
|
target?: string
|
||||||
}) => {
|
}) => {
|
||||||
let {target, download} = config ?? {}
|
let {target, download} = config ?? {}
|
||||||
|
|
||||||
console.log({target, download})
|
console.log({target, download, href})
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.setAttribute('href', href);
|
a.setAttribute('href', href);
|
||||||
a.setAttribute('target', target ?? '_blank')
|
a.setAttribute('target', target ?? '_blank')
|
||||||
a.setAttribute('download', download ?? '');
|
download && a.setAttribute('download', download);
|
||||||
a.click();
|
a.click();
|
||||||
// var a = document.createElement("a");
|
// var a = document.createElement("a");
|
||||||
// a.setAttribute('href', href)
|
// a.setAttribute('href', href)
|
||||||
@@ -133,7 +138,7 @@ const handleBack = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleReload = () => {
|
const handleReload = () => {
|
||||||
currentDirectory.value && setCurrentDirectory(currentDirectory.value)
|
reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
@@ -141,8 +146,17 @@ onMounted(async () => {
|
|||||||
// 拖动事件处理
|
// 拖动事件处理
|
||||||
const dropFileOption:dropHandlerHooks = {
|
const dropFileOption:dropHandlerHooks = {
|
||||||
onDropFiles(files: File[]) {
|
onDropFiles(files: File[]) {
|
||||||
const dragData = dataBus.get('dragData')
|
const dragData = dataBus.pop('dragData')
|
||||||
console.log({dragData, files})
|
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() {
|
onEnter() {
|
||||||
showModel.value += 1
|
showModel.value += 1
|
||||||
@@ -238,7 +252,7 @@ $bottom-bar-height: 60px;
|
|||||||
content: '';
|
content: '';
|
||||||
height: 60%;
|
height: 60%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -1px;
|
right: -2px;
|
||||||
width: 2px;
|
width: 2px;
|
||||||
background-color: #828282;
|
background-color: #828282;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -1,10 +1,11 @@
|
|||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import vue from "@vitejs/plugin-vue";
|
import vue from "@vitejs/plugin-vue";
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
|
import { viteSingleFile } from "vite-plugin-singlefile"
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue()],
|
plugins: [vue(), viteSingleFile()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": resolve(__dirname, "src")
|
"@": resolve(__dirname, "src")
|
||||||
@@ -16,6 +17,12 @@ export default defineConfig({
|
|||||||
target: "http://127.0.0.1:17705",
|
target: "http://127.0.0.1:17705",
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: path => path.replace(/^\/get/, "/get")
|
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