diff --git a/src/ProSender/demos/actionsRender.tsx b/src/ProSender/demos/actionsRender.tsx index b8a2784..61e4120 100644 --- a/src/ProSender/demos/actionsRender.tsx +++ b/src/ProSender/demos/actionsRender.tsx @@ -1,5 +1,6 @@ +import { CheckCircleOutlined } from '@ant-design/icons'; import { ProChat, ProSender } from '@ant-design/pro-chat'; -import { Card, Empty, Space } from 'antd'; +import { Space, Tag } from 'antd'; import { useTheme } from 'antd-style'; export default () => { @@ -11,16 +12,26 @@ export default () => { return ( { + actionsInfoRender: (defaultdom, fileList, onRemove) => { if (!fileList || fileList.length === 0) { - return ; + return; } return ( {fileList.map((item) => { - console.log('item', item); - - return ; + return ( + } + color="success" + key={item.uid} + closable + onClose={() => { + onRemove(item.uid); + }} + > + {item.name} + + ); })} ); diff --git a/src/ProSender/index.tsx b/src/ProSender/index.tsx index a652d4d..083e02b 100644 --- a/src/ProSender/index.tsx +++ b/src/ProSender/index.tsx @@ -13,12 +13,18 @@ import { } from 'antd'; import { useContext, useEffect, useState } from 'react'; import EnterTypeButton from './components/EnterTypeButton.tsx'; -import LocalStorageManager from './storageManager'; +import LocalStorageManager from './storageManager.js'; import { useStyles } from './style'; type ActionsType = { + onFileUpload?: (file: File) => void; + onRemoveFile?: (file: UploadFile) => void; actionsRender?: ([fileUpBtn, imgUpBtn]: Array) => React.ReactNode; - actionsInfoRender?: (defaultdom: React.ReactNode, []: Array) => React.ReactNode; + actionsInfoRender?: ( + defaultdom?: React.ReactNode, + []?: Array, + onRemoveFile?: (uid: string) => Promise<{ key: string; success: boolean; error?: string }>, + ) => React.ReactNode; }; const ProSender = ( @@ -51,9 +57,10 @@ const ProSender = ( beforeUpload: (file) => { localStorageManager .storeFile(file) - .then((key) => { - const storedFiles = localStorageManager.getFiles([key]); + .then(async (key) => { + const storedFiles = await localStorageManager.getFiles([key]); setFileList((prevList) => [...prevList, ...storedFiles]); + actions?.onFileUpload?.(file); }) .catch((error) => { message.error(error); @@ -104,10 +111,11 @@ const ProSender = ( {...upload} fileList={fileList} listType="picture" - onRemove={(file) => { - const result = localStorageManager.removeFiles([file.uid]); + onRemove={async (file) => { + const result = await localStorageManager.removeFiles([file.uid]); if (result[0].success) { setFileList((prevList) => prevList.filter((item) => item.uid !== file.uid)); + actions?.onRemoveFile?.(file); } else { message.error(result[0].error); } @@ -121,7 +129,10 @@ const ProSender = ( }; if (actions?.actionsInfoRender) { - return actions.actionsInfoRender(fileInputRender(), fileList); + return actions.actionsInfoRender(fileInputRender(), fileList, async (uid) => { + setFileList((prevList) => prevList.filter((item) => item.uid !== uid)); + return await localStorageManager.removeFiles([uid]); + }); } return fileInputRender(); }; diff --git a/src/ProSender/storageManager.js b/src/ProSender/storageManager.js index 1dd1850..753a4dc 100644 --- a/src/ProSender/storageManager.js +++ b/src/ProSender/storageManager.js @@ -1,29 +1,41 @@ +import { openDB } from 'idb'; import { v4 as uuidv4 } from 'uuid'; -class LocalStorageManager { +class IndexedDBManager { constructor(defaultExpiryTime = 60 * 60 * 1000) { this.defaultExpiryTime = defaultExpiryTime; // 默认过期时间为 1 小时 + this.dbPromise = openDB('file-store', 1, { + upgrade(db) { + db.createObjectStore('files', { keyPath: 'uid' }); + }, + }); } // 存储数据方法,返回生成的唯一 key - storeFile(file) { + async storeFile(file) { const key = uuidv4(); const expiry = new Date(new Date().getTime() + this.defaultExpiryTime); const reader = new FileReader(); return new Promise((resolve, reject) => { reader.readAsDataURL(file); - reader.onload = () => { + reader.onload = async () => { const base64 = reader.result; const fileInfo = { + uid: key, name: file.name, type: file.type, size: file.size, base64, expiry, }; - localStorage.setItem(key, JSON.stringify(fileInfo)); - resolve(key); + try { + const db = await this.dbPromise; + await db.put('files', fileInfo); + resolve(key); + } catch (e) { + reject('IndexedDB 存储失败'); + } }; reader.onerror = (error) => { reject('文件读取失败'); @@ -32,22 +44,21 @@ class LocalStorageManager { } // 按照 keys 数组,返回批量取出存储的 files - getFiles(keys) { - return keys - .map((key) => { - const item = localStorage.getItem(key); - if (item) { - const fileInfo = JSON.parse(item); - if (new Date(fileInfo.expiry) > new Date()) { - return { ...fileInfo, uid: key }; - } else { - localStorage.removeItem(key); - return null; - } + async getFiles(keys) { + const db = await this.dbPromise; + const files = await Promise.all( + keys.map(async (key) => { + const file = await db.get('files', key); + if (file && new Date(file.expiry) > new Date()) { + return file; + } else if (file) { + await db.delete('files', key); + return null; } return null; - }) - .filter((file) => file !== null); + }), + ); + return files.filter((file) => file !== null); } // 设置过期时间 @@ -56,17 +67,21 @@ class LocalStorageManager { } // 按照指定的 keys 从存储里面删除数据 - removeFiles(keys) { - return keys.map((key) => { - const item = localStorage.getItem(key); - if (item) { - localStorage.removeItem(key); - return { key, success: true }; - } else { - return { key, success: false, error: '文件不存在' }; - } - }); + async removeFiles(keys) { + const db = await this.dbPromise; + const results = await Promise.all( + keys.map(async (key) => { + const file = await db.get('files', key); + if (file) { + await db.delete('files', key); + return { key, success: true }; + } else { + return { key, success: false, error: '文件不存在' }; + } + }), + ); + return results; } } -export default LocalStorageManager; +export default IndexedDBManager;