From 8f2df8520814e0656e7e045c45aa7c268e5304c1 Mon Sep 17 00:00:00 2001 From: tone <3341154833@qq.com> Date: Thu, 19 Jun 2025 22:03:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84OssStore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/components/UploadManager.tsx | 12 ++-- .../app/console/(with-menu)/storage/page.tsx | 38 ++++++----- tone-page-web/lib/oss/OssStore.ts | 67 +++++++------------ 3 files changed, 52 insertions(+), 65 deletions(-) diff --git a/tone-page-web/app/console/(with-menu)/storage/components/UploadManager.tsx b/tone-page-web/app/console/(with-menu)/storage/components/UploadManager.tsx index 454750b..0331419 100644 --- a/tone-page-web/app/console/(with-menu)/storage/components/UploadManager.tsx +++ b/tone-page-web/app/console/(with-menu)/storage/components/UploadManager.tsx @@ -10,13 +10,13 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog" -import OSS from "ali-oss"; -import { ArrowUpFromLine, Check, CloudUpload, ClubIcon, Coins, File, Files, X } from "lucide-react"; +import { Check, CloudUpload, File, Files, X } from "lucide-react"; import React, { useRef, useState } from "react"; import { Progress } from '@/components/ui/progress'; import { cn } from "@/lib/utils"; import { toast } from "sonner"; import { OssStore } from "@/lib/oss/OssStore"; +import { Checkpoint } from "ali-oss"; interface UploadManagerProps { children: React.ReactNode; @@ -37,7 +37,7 @@ export function UploadManager({ children, ossStore, handleRefreshFileList }: Upl const handleFileSelect = (fileList: FileList) => { setFileList(currentFileList => { const newFiles: UploadFileItem[] = []; - for (let file of fileList) { + for (const file of fileList) { const repeatFile = currentFileList.find(f => f.file.name === file.name && f.file.size === file.size && @@ -90,7 +90,7 @@ export function UploadManager({ children, ossStore, handleRefreshFileList }: Upl setIsUploading(true); for (const fileItem of needUploadFiles) { fileItem.status = 'uploading'; - await startUploadFile(fileItem).catch(e => { fileItem.status = 'failed'; failCount++; }); + await startUploadFile(fileItem).catch(() => { fileItem.status = 'failed'; failCount++; }); fileItem.status = 'finish'; } setIsUploading(false); @@ -109,10 +109,10 @@ export function UploadManager({ children, ossStore, handleRefreshFileList }: Upl const startUploadFile = async (fileItem: UploadFileItem) => { if (!ossStore) return; - let checkpoint: any; + let checkpoint: Checkpoint | undefined; await ossStore.storeMeta.store?.multipartUpload(`${ossStore.getWorkDir()}/${fileItem.file.name}`, fileItem.file, { checkpoint: checkpoint, - progress: (p, cpt, res) => { + progress: (p, cpt) => { setFileList(currentFileList => { return currentFileList.map(f => { if (f.id == fileItem.id) { diff --git a/tone-page-web/app/console/(with-menu)/storage/page.tsx b/tone-page-web/app/console/(with-menu)/storage/page.tsx index 392a7ab..8ce26f4 100644 --- a/tone-page-web/app/console/(with-menu)/storage/page.tsx +++ b/tone-page-web/app/console/(with-menu)/storage/page.tsx @@ -3,10 +3,8 @@ import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; -import { useOssStore } from '@/hooks/admin/web/blog/use-oss-store'; -import { ObjectMeta } from 'ali-oss'; -import { Delete, Download, Edit, RefreshCcw, Upload } from 'lucide-react'; -import { useEffect, useMemo, useState } from 'react'; +import { Delete, Download, RefreshCcw, Upload } from 'lucide-react'; +import { useMemo, useState } from 'react'; import { toast } from 'sonner'; import { DropdownMenu, @@ -15,12 +13,12 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { UploadManager } from './components/UploadManager'; -import { OssStore } from '@/lib/oss/OssStore'; +import { OssObjectItem, OssObjectList, OssStore } from '@/lib/oss/OssStore'; const formatSizeNumber = (n: number) => { const unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']; - for (const [i, u] of unit.entries()) { + for (const [i] of unit.entries()) { if (n < 1024 ** (i + 1)) { if (i <= 0) { return `${(n)}${unit[i]}`; @@ -34,11 +32,14 @@ const formatSizeNumber = (n: number) => { export default function Page() { + const [objectList, setObjectList] = useState(null) + const ossStore = new OssStore({ prefix: 'tone-page', prefixAddUserId: true, + objectList: () => objectList, + setObjectList, }); - const objectList = ossStore.useObjectList; const handleRefreshFileList = async () => ossStore.loadObjectList().catch(e => toast.error(e.message)); const handleCheckboxChange = ossStore.handleObjectCheckedStateChanged.bind(ossStore); @@ -47,14 +48,17 @@ export default function Page() { return (objectList || []).filter(i => i.isChecked).map(i => i.id); }, [objectList]) - const handleDeleteObject = async (id: string) => { - await ossStore.deleteObject(id) + const handleDeleteObject = async (objectItem: OssObjectItem) => { + await ossStore.deleteObject(objectItem) .then(() => ossStore.loadObjectList()) .catch(e => toast.error(`${e.message}`)) } const handleDeleteCheckedFiles = async () => { - const res = await ossStore.deleteCheckedObjects(); + if (!objectList) return; + const checkedObjects = objectList.filter(o => o.isChecked); + + const res = await ossStore.deleteCheckedObjects(checkedObjects); if (res.failed > 0) { toast.warning(`删除完成,共有${res.failed}个文件删除失败`) @@ -64,8 +68,8 @@ export default function Page() { handleRefreshFileList(); } - const handleDownloadObject = async (id: string) => { - ossStore.downloadObject(id).catch(e => toast.error(`${e.message}`)); + const handleDownloadObject = async (objectItem: OssObjectItem) => { + ossStore.downloadObject(objectItem).catch(e => toast.error(`${e.message}`)); } return ( @@ -90,9 +94,9 @@ export default function Page() { - {/* {(ossStore.isLoading || ( == null && !error)) &&
加载中...
} - {error &&
{`${error}`}
} - {fileList && fileList.length === 0 &&
暂无文件
} */} + {objectList === null &&
加载中...
} + {/* {error &&
{`${error}`}
} */} + {objectList && objectList.length === 0 &&
暂无文件
}
@@ -115,9 +119,9 @@ export default function Page() { {d.name} - handleDownloadObject(d.id)}>下载 + handleDownloadObject(d)}>下载 {/* 编辑 */} - handleDeleteObject(d.id)}>删除 + handleDeleteObject(d)}>删除 diff --git a/tone-page-web/lib/oss/OssStore.ts b/tone-page-web/lib/oss/OssStore.ts index ac65864..9759da0 100644 --- a/tone-page-web/lib/oss/OssStore.ts +++ b/tone-page-web/lib/oss/OssStore.ts @@ -1,7 +1,7 @@ import { useOssStore } from "@/hooks/admin/web/blog/use-oss-store"; -import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { Dispatch, SetStateAction, useState } from "react"; -interface OssObjectItem { +export interface OssObjectItem { id: string; name: string; size: number;// Byte @@ -9,22 +9,21 @@ interface OssObjectItem { isChecked: boolean; }; -type OssObjectList = null | OssObjectItem[]; +export type OssObjectList = OssObjectItem[] | null; export class OssStore { - private objectList: OssObjectList = null; - private setObjectList: Dispatch>; + private setObjectList?: Dispatch>; public storeMeta: ReturnType; constructor(private options: { prefix?: string; prefixAddUserId?: boolean; + objectList?: () => (OssObjectList | null); + setObjectList?: Dispatch>; } = {}) { - const [objectList, setObjectList] = useState(null); - this.objectList = objectList; - this.setObjectList = setObjectList; + this.setObjectList = options.setObjectList; this.storeMeta = useOssStore({ region: 'oss-cn-chengdu', @@ -36,11 +35,11 @@ export class OssStore { }); } - get useObjectList() { - return this.objectList; - } - public async loadObjectList() { + if (!this.setObjectList) { + throw new Error('setObjectList need provided'); + } + const store = await this.getStore(); this.setObjectList(null); @@ -58,6 +57,10 @@ export class OssStore { } public handleObjectCheckedStateChanged(id: string, value: boolean) { + if (!this.setObjectList) { + throw new Error('setObjectList need provided'); + } + this.setObjectList(current => current ? current.map(objectItem => { if (objectItem.id === id) { return { ...objectItem, isChecked: value } @@ -66,41 +69,37 @@ export class OssStore { }) : null) } - public async deleteObject(id: string) { + public async deleteObject(objectItem: OssObjectItem) { if (!this.storeMeta.store || !this.storeMeta.stsTokenData) { throw new Error('初始化失败,请刷新界面重试'); } - const fileItem = (this.objectList || []).find(i => i.id === id); - if (!fileItem) throw new Error('文件不存在'); - const objectName = this.getObjectName(fileItem.name); + const objectName = this.getObjectNameByLocalname(objectItem.name); const delRes = await this.storeMeta.store.delete(objectName).catch(() => null); if (!delRes) throw new Error('删除失败'); } - public async deleteCheckedObjects() { + public async deleteCheckedObjects(objectItems: OssObjectItem[]) { if (!this.storeMeta.store || !this.storeMeta.stsTokenData) { throw new Error('初始化失败,请刷新界面重试'); } - const objects = (this.objectList || []).filter(i => i.isChecked); - if (objects.length === 0) throw new Error('请选择需要删除的文件'); + if (objectItems.length === 0) throw new Error('请选择需要删除的文件'); let failedCount = 0; - for (const objectItem of objects) { - await this.deleteObject(objectItem.id).catch(e => failedCount++); + for (const objectItem of objectItems) { + await this.deleteObject(objectItem).catch(e => failedCount++); } - return { all: objects.length, failed: failedCount }; + return { all: objectItems.length, failed: failedCount }; } - public async downloadObject(id: string) { + public async downloadObject(objectItem: OssObjectItem) { if (!this.storeMeta.store || !this.storeMeta.stsTokenData) { throw new Error('初始化失败,请刷新界面重试'); } - const objectItem = this.getObjectItemById(id); - const url = this.storeMeta.store.signatureUrl(this.getObjectName(objectItem.name)); + const url = this.storeMeta.store.signatureUrl(this.getObjectNameByLocalname(objectItem.name)); const a = document.createElement('a'); a.href = url; a.download = objectItem.name; @@ -117,21 +116,10 @@ export class OssStore { return this.storeMeta.store; } - private getObjectName(localName: string) { + private getObjectNameByLocalname(localName: string) { return `${this.getWorkDir()}/${localName}`; } - private getObjectNameById(id: string) { - const objectItem = this.getObjectItemById(id); - return this.getObjectName(objectItem.name); - } - - private getObjectItemById(id: string) { - const objectItem = (this.objectList || []).find(i => i.id === id); - if (!objectItem) throw new Error('文件不存在'); - return objectItem; - } - public getWorkDir() { const { stsTokenData } = this.storeMeta; if (!stsTokenData) return; @@ -142,9 +130,4 @@ export class OssStore { return this.options.prefix; } } - - get isLoading() { - return this.storeMeta.isLoading; - } - } \ No newline at end of file