parent
d5fa2d1522
commit
fccb823801
@ -17,6 +17,7 @@
|
|||||||
"filesize": "^9.0.11",
|
"filesize": "^9.0.11",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"naive-ui": "^2.32.1",
|
"naive-ui": "^2.32.1",
|
||||||
|
"semaphore": "^1.1.0",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"util": "^0.12.4",
|
"util": "^0.12.4",
|
||||||
"vue": "^3.2.37",
|
"vue": "^3.2.37",
|
||||||
@ -25,6 +26,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rushstack/eslint-patch": "^1.1.4",
|
"@rushstack/eslint-patch": "^1.1.4",
|
||||||
"@types/node": "^18.7.14",
|
"@types/node": "^18.7.14",
|
||||||
|
"@types/semaphore": "^1.1.1",
|
||||||
"@vitejs/plugin-vue": "^3.0.1",
|
"@vitejs/plugin-vue": "^3.0.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^2.0.0",
|
"@vitejs/plugin-vue-jsx": "^2.0.0",
|
||||||
"@vue/eslint-config-prettier": "^7.0.0",
|
"@vue/eslint-config-prettier": "^7.0.0",
|
||||||
|
@ -40,8 +40,14 @@ export const post_token_form = (
|
|||||||
},
|
},
|
||||||
onUploadProgress: onProgress
|
onUploadProgress: onProgress
|
||||||
})
|
})
|
||||||
.then((res) => res.data)
|
.then((res) => {
|
||||||
.catch((err) => err.response.data);
|
console.log(res);
|
||||||
|
return res.data;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return err.response.data;
|
||||||
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
export const get = (url: string) =>
|
export const get = (url: string) =>
|
||||||
|
@ -4,6 +4,16 @@ import jwtDecode from 'jwt-decode';
|
|||||||
import { isErrorResponse } from './base';
|
import { isErrorResponse } from './base';
|
||||||
import { refresh_token } from './auth';
|
import { refresh_token } from './auth';
|
||||||
|
|
||||||
|
export async function update_token(
|
||||||
|
token: TokenInjectType
|
||||||
|
): Promise<string | void> {
|
||||||
|
if (!token.jwt.value) return token.logout();
|
||||||
|
const new_token = await refresh_token(token.jwt.value);
|
||||||
|
if (isErrorResponse(new_token)) return token.logout();
|
||||||
|
token.setToken(new_token.jwt);
|
||||||
|
return new_token.jwt;
|
||||||
|
}
|
||||||
|
|
||||||
export async function check_token(
|
export async function check_token(
|
||||||
token: TokenInjectType
|
token: TokenInjectType
|
||||||
): Promise<string | void> {
|
): Promise<string | void> {
|
||||||
@ -13,10 +23,7 @@ export async function check_token(
|
|||||||
// Expires in more than 60 Minute
|
// Expires in more than 60 Minute
|
||||||
if (payload.exp && payload.exp > Math.floor(Date.now() / 1000 + 60 * 60))
|
if (payload.exp && payload.exp > Math.floor(Date.now() / 1000 + 60 * 60))
|
||||||
return token.jwt.value;
|
return token.jwt.value;
|
||||||
const new_token = await refresh_token(token.jwt.value);
|
return update_token(token);
|
||||||
if (isErrorResponse(new_token)) return token.logout();
|
|
||||||
token.setToken(new_token.jwt);
|
|
||||||
return new_token.jwt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TokenInjectType = {
|
export type TokenInjectType = {
|
||||||
|
@ -33,6 +33,7 @@ import {
|
|||||||
Delete,
|
Delete,
|
||||||
Download
|
Download
|
||||||
} from '@vicons/carbon';
|
} from '@vicons/carbon';
|
||||||
|
import semaphore from 'semaphore';
|
||||||
import NLink from '@/components/NLink.vue';
|
import NLink from '@/components/NLink.vue';
|
||||||
import PreviewImage from '@/components/DirViewer/PreviewImage.vue';
|
import PreviewImage from '@/components/DirViewer/PreviewImage.vue';
|
||||||
import createZipDialog from '@/components/DirViewer/CreateZipDialog';
|
import createZipDialog from '@/components/DirViewer/CreateZipDialog';
|
||||||
@ -59,6 +60,7 @@ const props = defineProps<{
|
|||||||
showPreview: boolean;
|
showPreview: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const previewDownloadSem = semaphore(40);
|
||||||
const checkedRows = ref<number[]>([]);
|
const checkedRows = ref<number[]>([]);
|
||||||
const deleteNodes = ref<number[]>([]);
|
const deleteNodes = ref<number[]>([]);
|
||||||
const deleteDialog = ref();
|
const deleteDialog = ref();
|
||||||
@ -222,7 +224,12 @@ const previewColumns: DataTableColumn<Responses.GetNodeEntry>[] = [
|
|||||||
return node.isFile ? (
|
return node.isFile ? (
|
||||||
<Suspense>
|
<Suspense>
|
||||||
{{
|
{{
|
||||||
default: () => <PreviewImage node={node} />,
|
default: () => (
|
||||||
|
<PreviewImage
|
||||||
|
node={node}
|
||||||
|
sem={previewDownloadSem}
|
||||||
|
/>
|
||||||
|
),
|
||||||
fallback: () => <NSpin size="small" />
|
fallback: () => <NSpin size="small" />
|
||||||
}}
|
}}
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script setup async lang="ts">
|
<script setup async lang="ts">
|
||||||
import type { TokenInjectType, Responses } from '@/api';
|
import type { TokenInjectType, Responses } from '@/api';
|
||||||
|
import type { Semaphore } from 'semaphore';
|
||||||
import { inject, ref } from 'vue';
|
import { inject, ref } from 'vue';
|
||||||
import { NImage, NIcon } from 'naive-ui';
|
import { NImage, NIcon } from 'naive-ui';
|
||||||
import { Image, Music, Video, Document } from '@vicons/carbon';
|
import { Image, Music, Video, Document } from '@vicons/carbon';
|
||||||
@ -7,6 +8,7 @@ import { check_token, FS, isErrorResponse } from '@/api';
|
|||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
node: Responses.GetNodeEntry;
|
node: Responses.GetNodeEntry;
|
||||||
|
sem: Semaphore;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
enum fileTypes {
|
enum fileTypes {
|
||||||
@ -23,8 +25,10 @@ const success = ref(false);
|
|||||||
const data = ref('');
|
const data = ref('');
|
||||||
const fileType = ref<fileTypes>(fileTypes.UNKNOWN);
|
const fileType = ref<fileTypes>(fileTypes.UNKNOWN);
|
||||||
|
|
||||||
const token = await check_token(jwt);
|
await new Promise<void>((resolve) => {
|
||||||
if (token) {
|
props.sem.take(async () => {
|
||||||
|
const token = await check_token(jwt);
|
||||||
|
if (token) {
|
||||||
if (props.node.preview) {
|
if (props.node.preview) {
|
||||||
const resp = await FS.download_preview(token, props.node.id);
|
const resp = await FS.download_preview(token, props.node.id);
|
||||||
if (!isErrorResponse(resp)) {
|
if (!isErrorResponse(resp)) {
|
||||||
@ -35,7 +39,8 @@ if (token) {
|
|||||||
fileType.value = fileTypes.UNKNOWN;
|
fileType.value = fileTypes.UNKNOWN;
|
||||||
const resp = await FS.get_type(token, props.node.id);
|
const resp = await FS.get_type(token, props.node.id);
|
||||||
if (!isErrorResponse(resp)) {
|
if (!isErrorResponse(resp)) {
|
||||||
if (resp.type.startsWith('image')) fileType.value = fileTypes.IMAGE;
|
if (resp.type.startsWith('image'))
|
||||||
|
fileType.value = fileTypes.IMAGE;
|
||||||
else if (resp.type.startsWith('application/pdf'))
|
else if (resp.type.startsWith('application/pdf'))
|
||||||
fileType.value = fileTypes.PDF;
|
fileType.value = fileTypes.PDF;
|
||||||
else if (resp.type.startsWith('audio'))
|
else if (resp.type.startsWith('audio'))
|
||||||
@ -44,7 +49,11 @@ if (token) {
|
|||||||
fileType.value = fileTypes.VIDEO;
|
fileType.value = fileTypes.VIDEO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
props.sem.leave();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TokenInjectType, UploadFile } from '@/api';
|
import type { TokenInjectType, UploadFile } from '@/api';
|
||||||
import { ref, inject } from 'vue';
|
import { ref, inject } from 'vue';
|
||||||
import { check_token } from '@/api';
|
import { update_token } from '@/api';
|
||||||
import UploadEntry from '@/components/UploadDialog/UploadEntry.vue';
|
import UploadEntry from '@/components/UploadDialog/UploadEntry.vue';
|
||||||
import { NCard } from 'naive-ui';
|
import { NCard } from 'naive-ui';
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
|
|||||||
const entries = ref<typeof UploadEntry[]>([]);
|
const entries = ref<typeof UploadEntry[]>([]);
|
||||||
|
|
||||||
async function startUpload() {
|
async function startUpload() {
|
||||||
const token = await check_token(jwt);
|
const token = await update_token(jwt);
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
const ents: typeof UploadEntry[] = entries.value;
|
const ents: typeof UploadEntry[] = entries.value;
|
||||||
const allProms: Promise<void>[] = [];
|
const allProms: Promise<void>[] = [];
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
import type { TokenInjectType, Responses } from '@/api';
|
import type { TokenInjectType, Responses } from '@/api';
|
||||||
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
|
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
|
||||||
import { inject, onBeforeMount, ref } from 'vue';
|
import { inject, onBeforeMount, ref } from 'vue';
|
||||||
import { NCard } from 'naive-ui';
|
import { NCard, useMessage } from 'naive-ui';
|
||||||
import { check_token, FS, isErrorResponse } from '@/api';
|
import { check_token, FS, isErrorResponse } from '@/api';
|
||||||
import UploadField from '@/components/UploadDialog/UploadField.vue';
|
import UploadField from '@/components/UploadDialog/UploadField.vue';
|
||||||
import DirViewer from '@/components/DirViewer/DirViewer.vue';
|
import DirViewer from '@/components/DirViewer/DirViewer.vue';
|
||||||
import FileViewer from '@/components/FileViewer/FileViewer.vue';
|
import FileViewer from '@/components/FileViewer/FileViewer.vue';
|
||||||
import NLink from '@/components/NLink.vue';
|
import NLink from '@/components/NLink.vue';
|
||||||
|
import { loadingMsgWrapper } from '@/utils';
|
||||||
|
|
||||||
|
const message = useMessage();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
|
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
|
||||||
@ -22,7 +24,7 @@ function nameCompare(a: Responses.GetNodeEntry, b: Responses.GetNodeEntry) {
|
|||||||
return aStr.localeCompare(bStr);
|
return aStr.localeCompare(bStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetch_node(node_id: number) {
|
const fetch_node = loadingMsgWrapper(message, async (node_id: number) => {
|
||||||
const token = await check_token(jwt);
|
const token = await check_token(jwt);
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
const [p, n] = [
|
const [p, n] = [
|
||||||
@ -41,7 +43,7 @@ async function fetch_node(node_id: number) {
|
|||||||
n.children = [...folders, ...files];
|
n.children = [...folders, ...files];
|
||||||
}
|
}
|
||||||
[path.value, node.value] = [p, n];
|
[path.value, node.value] = [p, n];
|
||||||
}
|
});
|
||||||
|
|
||||||
onBeforeRouteUpdate(async (to) => {
|
onBeforeRouteUpdate(async (to) => {
|
||||||
await fetch_node(Number(to.params.node_id));
|
await fetch_node(Number(to.params.node_id));
|
||||||
|
@ -13,6 +13,7 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
sourcemap: 'inline',
|
||||||
chunkSizeWarningLimit: 1024 * 1024
|
chunkSizeWarningLimit: 1024 * 1024
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -421,6 +421,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190"
|
||||||
integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==
|
integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==
|
||||||
|
|
||||||
|
"@types/semaphore@^1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/semaphore/-/semaphore-1.1.1.tgz#035baeec703fe8cf9f56a2b7af22bdda4f22d6ea"
|
||||||
|
integrity sha512-jmFpMslMtBGOXY2s7x6O8vBebcj6zhkwl0Pd/viZApo1uZaPk733P8doPvaiBbCG+R7201OLOl4QP7l1mFyuyw==
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^5.0.0":
|
"@typescript-eslint/eslint-plugin@^5.0.0":
|
||||||
version "5.36.1"
|
version "5.36.1"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.1.tgz#471f64dc53600025e470dad2ca4a9f2864139019"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.1.tgz#471f64dc53600025e470dad2ca4a9f2864139019"
|
||||||
@ -2317,6 +2322,11 @@ seemly@^0.3.6:
|
|||||||
resolved "https://registry.yarnpkg.com/seemly/-/seemly-0.3.6.tgz#7ef97e8083dea00804965e2662f572a5df9cb18e"
|
resolved "https://registry.yarnpkg.com/seemly/-/seemly-0.3.6.tgz#7ef97e8083dea00804965e2662f572a5df9cb18e"
|
||||||
integrity sha512-lEV5VB8BUKTo/AfktXJcy+JeXns26ylbMkIUco8CYREsQijuz4mrXres2Q+vMLdwkuLxJdIPQ8IlCIxLYm71Yw==
|
integrity sha512-lEV5VB8BUKTo/AfktXJcy+JeXns26ylbMkIUco8CYREsQijuz4mrXres2Q+vMLdwkuLxJdIPQ8IlCIxLYm71Yw==
|
||||||
|
|
||||||
|
semaphore@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa"
|
||||||
|
integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==
|
||||||
|
|
||||||
"semver@2 || 3 || 4 || 5", semver@^5.5.0:
|
"semver@2 || 3 || 4 || 5", semver@^5.5.0:
|
||||||
version "5.7.1"
|
version "5.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||||
|
Loading…
Reference in New Issue
Block a user