Skip to content

Commit 401e352

Browse files
committed
✨ feat: support actions render
1 parent bdaa7c5 commit 401e352

File tree

3 files changed

+80
-43
lines changed

3 files changed

+80
-43
lines changed

src/ProSender/demos/actionsRender.tsx

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import { CheckCircleOutlined } from '@ant-design/icons';
12
import { ProChat, ProSender } from '@ant-design/pro-chat';
2-
import { Card, Empty, Space } from 'antd';
3+
import { Space, Tag } from 'antd';
34
import { useTheme } from 'antd-style';
45

56
export default () => {
@@ -11,16 +12,26 @@ export default () => {
1112
return (
1213
<ProSender
1314
actions={{
14-
actionsInfoRender: (defaultdom, fileList) => {
15+
actionsInfoRender: (defaultdom, fileList, onRemove) => {
1516
if (!fileList || fileList.length === 0) {
16-
return <Empty />;
17+
return;
1718
}
1819
return (
1920
<Space>
2021
{fileList.map((item) => {
21-
console.log('item', item);
22-
23-
return <Card key={item.uid} style={{ width: 300 }} title={item.fileName} />;
22+
return (
23+
<Tag
24+
icon={<CheckCircleOutlined />}
25+
color="success"
26+
key={item.uid}
27+
closable
28+
onClose={() => {
29+
onRemove(item.uid);
30+
}}
31+
>
32+
{item.name}
33+
</Tag>
34+
);
2435
})}
2536
</Space>
2637
);

src/ProSender/index.tsx

+18-7
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ import {
1313
} from 'antd';
1414
import { useContext, useEffect, useState } from 'react';
1515
import EnterTypeButton from './components/EnterTypeButton.tsx';
16-
import LocalStorageManager from './storageManager';
16+
import LocalStorageManager from './storageManager.js';
1717
import { useStyles } from './style';
1818

1919
type ActionsType = {
20+
onFileUpload?: (file: File) => void;
21+
onRemoveFile?: (file: UploadFile) => void;
2022
actionsRender?: ([fileUpBtn, imgUpBtn]: Array<React.ReactNode>) => React.ReactNode;
21-
actionsInfoRender?: (defaultdom: React.ReactNode, []: Array<UploadFile>) => React.ReactNode;
23+
actionsInfoRender?: (
24+
defaultdom?: React.ReactNode,
25+
[]?: Array<UploadFile>,
26+
onRemoveFile?: (uid: string) => Promise<{ key: string; success: boolean; error?: string }>,
27+
) => React.ReactNode;
2228
};
2329

2430
const ProSender = (
@@ -51,9 +57,10 @@ const ProSender = (
5157
beforeUpload: (file) => {
5258
localStorageManager
5359
.storeFile(file)
54-
.then((key) => {
55-
const storedFiles = localStorageManager.getFiles([key]);
60+
.then(async (key) => {
61+
const storedFiles = await localStorageManager.getFiles([key]);
5662
setFileList((prevList) => [...prevList, ...storedFiles]);
63+
actions?.onFileUpload?.(file);
5764
})
5865
.catch((error) => {
5966
message.error(error);
@@ -104,10 +111,11 @@ const ProSender = (
104111
{...upload}
105112
fileList={fileList}
106113
listType="picture"
107-
onRemove={(file) => {
108-
const result = localStorageManager.removeFiles([file.uid]);
114+
onRemove={async (file) => {
115+
const result = await localStorageManager.removeFiles([file.uid]);
109116
if (result[0].success) {
110117
setFileList((prevList) => prevList.filter((item) => item.uid !== file.uid));
118+
actions?.onRemoveFile?.(file);
111119
} else {
112120
message.error(result[0].error);
113121
}
@@ -121,7 +129,10 @@ const ProSender = (
121129
};
122130

123131
if (actions?.actionsInfoRender) {
124-
return actions.actionsInfoRender(fileInputRender(), fileList);
132+
return actions.actionsInfoRender(fileInputRender(), fileList, async (uid) => {
133+
setFileList((prevList) => prevList.filter((item) => item.uid !== uid));
134+
return await localStorageManager.removeFiles([uid]);
135+
});
125136
}
126137
return fileInputRender();
127138
};

src/ProSender/storageManager.js

+45-30
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,41 @@
1+
import { openDB } from 'idb';
12
import { v4 as uuidv4 } from 'uuid';
23

3-
class LocalStorageManager {
4+
class IndexedDBManager {
45
constructor(defaultExpiryTime = 60 * 60 * 1000) {
56
this.defaultExpiryTime = defaultExpiryTime; // 默认过期时间为 1 小时
7+
this.dbPromise = openDB('file-store', 1, {
8+
upgrade(db) {
9+
db.createObjectStore('files', { keyPath: 'uid' });
10+
},
11+
});
612
}
713

814
// 存储数据方法,返回生成的唯一 key
9-
storeFile(file) {
15+
async storeFile(file) {
1016
const key = uuidv4();
1117
const expiry = new Date(new Date().getTime() + this.defaultExpiryTime);
1218
const reader = new FileReader();
1319

1420
return new Promise((resolve, reject) => {
1521
reader.readAsDataURL(file);
16-
reader.onload = () => {
22+
reader.onload = async () => {
1723
const base64 = reader.result;
1824
const fileInfo = {
25+
uid: key,
1926
name: file.name,
2027
type: file.type,
2128
size: file.size,
2229
base64,
2330
expiry,
2431
};
25-
localStorage.setItem(key, JSON.stringify(fileInfo));
26-
resolve(key);
32+
try {
33+
const db = await this.dbPromise;
34+
await db.put('files', fileInfo);
35+
resolve(key);
36+
} catch (e) {
37+
reject('IndexedDB 存储失败');
38+
}
2739
};
2840
reader.onerror = (error) => {
2941
reject('文件读取失败');
@@ -32,22 +44,21 @@ class LocalStorageManager {
3244
}
3345

3446
// 按照 keys 数组,返回批量取出存储的 files
35-
getFiles(keys) {
36-
return keys
37-
.map((key) => {
38-
const item = localStorage.getItem(key);
39-
if (item) {
40-
const fileInfo = JSON.parse(item);
41-
if (new Date(fileInfo.expiry) > new Date()) {
42-
return { ...fileInfo, uid: key };
43-
} else {
44-
localStorage.removeItem(key);
45-
return null;
46-
}
47+
async getFiles(keys) {
48+
const db = await this.dbPromise;
49+
const files = await Promise.all(
50+
keys.map(async (key) => {
51+
const file = await db.get('files', key);
52+
if (file && new Date(file.expiry) > new Date()) {
53+
return file;
54+
} else if (file) {
55+
await db.delete('files', key);
56+
return null;
4757
}
4858
return null;
49-
})
50-
.filter((file) => file !== null);
59+
}),
60+
);
61+
return files.filter((file) => file !== null);
5162
}
5263

5364
// 设置过期时间
@@ -56,17 +67,21 @@ class LocalStorageManager {
5667
}
5768

5869
// 按照指定的 keys 从存储里面删除数据
59-
removeFiles(keys) {
60-
return keys.map((key) => {
61-
const item = localStorage.getItem(key);
62-
if (item) {
63-
localStorage.removeItem(key);
64-
return { key, success: true };
65-
} else {
66-
return { key, success: false, error: '文件不存在' };
67-
}
68-
});
70+
async removeFiles(keys) {
71+
const db = await this.dbPromise;
72+
const results = await Promise.all(
73+
keys.map(async (key) => {
74+
const file = await db.get('files', key);
75+
if (file) {
76+
await db.delete('files', key);
77+
return { key, success: true };
78+
} else {
79+
return { key, success: false, error: '文件不存在' };
80+
}
81+
}),
82+
);
83+
return results;
6984
}
7085
}
7186

72-
export default LocalStorageManager;
87+
export default IndexedDBManager;

0 commit comments

Comments
 (0)