@cloudbase/weda-ui 0.2.11 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/CHANGELOG.md +240 -0
  2. package/package.json +61 -40
  3. package/src/.DS_Store +0 -0
  4. package/src/configs/.DS_Store +0 -0
  5. package/src/configs/components/button.json +7 -3
  6. package/src/configs/components/form/richText.json +1 -1
  7. package/src/configs/components/form/uploader.json +29 -1
  8. package/src/configs/components/form/uploaderFile.json +158 -0
  9. package/src/configs/components/image.json +12 -3
  10. package/src/configs/components/link.json +3 -3
  11. package/src/configs/components/richtextview.json +2 -2
  12. package/src/configs/components/scrollVeiw.json +5 -5
  13. package/src/configs/components/swiper.json +6 -6
  14. package/src/configs/components/tabs.json +3 -3
  15. package/src/configs/components/text.json +39 -4
  16. package/src/configs/index.js +5 -3
  17. package/src/mp/.gitignore +10 -0
  18. package/src/mp/components/button/index.js +1 -0
  19. package/src/mp/components/button/index.wxss +8 -0
  20. package/src/mp/components/form/select/index.js +18 -0
  21. package/src/mp/components/form/uploader/index.js +26 -29
  22. package/src/mp/components/form/uploaderFile/index.js +247 -0
  23. package/src/mp/components/form/uploaderFile/index.json +9 -0
  24. package/src/mp/components/form/uploaderFile/index.wxml +46 -0
  25. package/src/mp/components/form/uploaderFile/index.wxss +104 -0
  26. package/src/mp/components/text/index.js +33 -0
  27. package/src/mp/components/text/index.wxml +1 -1
  28. package/src/mp/components/text/index.wxss +18 -0
  29. package/src/mp/index.json +1 -0
  30. package/src/mp/utils/platform.js +20 -0
  31. package/src/mp/utils/tcb.js +11 -0
  32. package/src/web/.DS_Store +0 -0
  33. package/src/web/actions/showModal/{index.jsx → index.tsx} +53 -3
  34. package/src/web/components/auth/index.js +2 -2
  35. package/src/web/components/button/index.css +9 -0
  36. package/src/web/components/button/{index.jsx → index.tsx} +27 -41
  37. package/src/web/components/container/{index.jsx → index.tsx} +6 -10
  38. package/src/web/components/drawer/index.tsx +57 -0
  39. package/src/web/components/form/checkbox/{index.jsx → index.tsx} +24 -48
  40. package/src/web/components/form/enumSelect/{NormalSelect.jsx → NormalSelect.tsx} +2 -9
  41. package/src/web/components/form/form/index.tsx +48 -0
  42. package/src/web/components/form/formcell/{index.jsx → index.tsx} +6 -13
  43. package/src/web/components/form/input/index.css +4 -0
  44. package/src/web/components/form/input/{index.jsx → index.tsx} +33 -67
  45. package/src/web/components/form/radio/{index.jsx → index.tsx} +19 -42
  46. package/src/web/components/form/{renderDecorator.jsx → renderDecorator.tsx} +1 -3
  47. package/src/web/components/form/select/{h5.jsx → h5.tsx} +18 -62
  48. package/src/web/components/form/select/{index.jsx → index.tsx} +51 -94
  49. package/src/web/components/form/select/region/{cities.js → cities.ts} +1 -1
  50. package/src/web/components/form/select/region/{index.js → index.ts} +3 -3
  51. package/src/web/components/form/select/region/{provinces.js → provinces.ts} +1 -1
  52. package/src/web/components/form/select/region/{regions.js → regions.ts} +1 -1
  53. package/src/web/components/form/select/time.jsx +2 -2
  54. package/src/web/components/form/switch/{index.jsx → index.tsx} +30 -47
  55. package/src/web/components/form/textarea/{index.jsx → index.tsx} +22 -55
  56. package/src/web/components/form/tips/{index.jsx → index.tsx} +8 -22
  57. package/src/web/components/form/types.d.ts +12 -0
  58. package/src/web/components/form/uploader/{index.jsx → index.tsx} +16 -14
  59. package/src/web/components/form/uploader/{uploader.h5.jsx → uploader.h5.tsx} +67 -57
  60. package/src/web/components/form/uploader/{uploader.pc.jsx → uploader.pc.tsx} +26 -43
  61. package/src/web/components/form/uploaderFile/fail.svg +12 -0
  62. package/src/web/components/form/uploaderFile/index.css +423 -0
  63. package/src/web/components/form/uploaderFile/index.jsx +30 -0
  64. package/src/web/components/form/uploaderFile/pending.svg +18 -0
  65. package/src/web/components/form/uploaderFile/success.svg +12 -0
  66. package/src/web/components/form/uploaderFile/uploadFile.h5.jsx +562 -0
  67. package/src/web/components/form/uploaderFile/uploadFile.pc.jsx +487 -0
  68. package/src/web/components/image/{image.jsx → image.tsx} +8 -21
  69. package/src/web/components/image/{index.jsx → index.tsx} +22 -37
  70. package/src/web/components/index.js +35 -1
  71. package/src/web/components/link/{index.jsx → index.tsx} +19 -36
  72. package/src/web/components/modal/{index.jsx → index.tsx} +22 -9
  73. package/src/web/components/picker/{datePicker.jsx → datePicker.tsx} +11 -12
  74. package/src/web/components/picker/{picker.jsx → picker.tsx} +7 -10
  75. package/src/web/components/picker/{timePicker.jsx → timePicker.tsx} +8 -16
  76. package/src/web/components/richText/{const.js → const.ts} +0 -0
  77. package/src/web/components/richText/index.jsx +5 -2
  78. package/src/web/components/richTextView/index.tsx +67 -0
  79. package/src/web/components/scrollView/{index.jsx → index.tsx} +18 -33
  80. package/src/web/components/slot/{index.jsx → index.tsx} +8 -9
  81. package/src/web/components/swiper/index.css +1 -1
  82. package/src/web/components/swiper/{index.jsx → index.tsx} +66 -73
  83. package/src/web/components/tabs/index.tsx +33 -0
  84. package/src/web/components/tabs/{tabs.h5.jsx → tabs.h5.tsx} +4 -33
  85. package/src/web/components/tabs/{tabs.pc.jsx → tabs.pc.tsx} +5 -39
  86. package/src/web/components/text/index.css +18 -0
  87. package/src/web/components/text/index.tsx +69 -0
  88. package/src/web/components/uploaderFileView/index.css +11 -0
  89. package/src/web/components/uploaderFileView/index.jsx +75 -0
  90. package/src/web/components/uploaderView/{index.jsx → index.tsx} +12 -15
  91. package/src/web/types.d.ts +20 -0
  92. package/src/web/utils/constant.js +2 -0
  93. package/src/web/utils/loading-fallback.tsx +2 -0
  94. package/src/web/utils/platform.js +77 -6
  95. package/src/web/utils/useSetState.ts +14 -0
  96. package/src/web/utils/useSyncValue.ts +17 -0
  97. package/src/web/wedatheme/.git +1 -0
  98. package/src/web/wedatheme/.gitignore +5 -0
  99. package/src/web/wedatheme/.npmrc +1 -0
  100. package/src/web/wedatheme/package-lock.json +14335 -0
  101. package/src/configs/components/button.svg +0 -18
  102. package/src/web/components/drawer/index.jsx +0 -64
  103. package/src/web/components/form/form/index.jsx +0 -76
  104. package/src/web/components/link/test/__snapshots__/storybook.test.js.snap +0 -754
  105. package/src/web/components/richTextView/index.jsx +0 -89
  106. package/src/web/components/tabs/index.jsx +0 -10
  107. package/src/web/components/text/index.jsx +0 -71
  108. package/src/web/utils/useSyncValue.js +0 -14
@@ -0,0 +1,562 @@
1
+ import * as React from 'react';
2
+ import * as PropTypes from 'prop-types';
3
+ import { useSyncValue } from '../../../utils/useSyncValue';
4
+ import isObjectEqual from '../../../utils/isObjectEqual';
5
+ import weui from '../../../utils/weui';
6
+ import {
7
+ Upload,
8
+ ConfigProvider,
9
+ Button,
10
+ message,
11
+ Icon,
12
+ Text,
13
+ List,
14
+ Progress,
15
+ Tooltip,
16
+ } from 'tea-component';
17
+ import { v4 } from 'uuid';
18
+ import {
19
+ filterStrList,
20
+ isCloudFileID,
21
+ isHttpFileID,
22
+ transSize,
23
+ downloadFile,
24
+ } from '../../../utils/platform';
25
+ import { getCloudInstance, getTempFileURL } from '../../../utils/tcb';
26
+ import classNames from '../../../utils/classnames';
27
+ import { renderDecorator } from '../renderDecorator';
28
+
29
+ // 默认组件类前缀
30
+ const CLASS_PREFIX = 'weda-upload-file-mobile';
31
+ // 默认图片类型
32
+ export const FILES_TYPES = [
33
+ '.doc',
34
+ '.docx',
35
+ '.xml',
36
+ 'application/msword',
37
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
38
+ ];
39
+ // 上传状态字典
40
+ const statusMap = {
41
+ UPLOAD_STATUS_PENDING: { title: '等待上传', icon: 'pending' },
42
+ UPLOAD_STATUS_LOADING: { title: '上传中', icon: 'loading' },
43
+ UPLOAD_STATUS_SUCCESS: { title: '上传成功', icon: 'success' },
44
+ UPLOAD_STATUS_ERROR: { title: '上传失败', icon: 'error' },
45
+ };
46
+ // 上传文件Context
47
+ const FileContext = React.createContext(null);
48
+ /**
49
+ * 上传文件 H5 版本
50
+ */
51
+ export function UploadFileH5({
52
+ // 系统属性
53
+ layout,
54
+ id = '',
55
+ style = { margin: '0,-5px' },
56
+ labelVisible = true,
57
+ label = '上传文件',
58
+ requiredFlag = false,
59
+ disabled = false,
60
+ className = '',
61
+ acceptTypes = [],
62
+ // 组件属性
63
+ tips = '',
64
+ btnTitle = '点击上传',
65
+ maxUploadCount = 9,
66
+ maxSize = 10,
67
+ deleteVisible = true,
68
+ downloadVisible = true,
69
+ value = [], // 需要兼容 cloud:和https: 协议,需要兼容字符串和字符串数组
70
+ events,
71
+ defaultValue,
72
+ uploadPath = 'weda-uploader',
73
+ single = true,
74
+ onChange = null,
75
+ }) {
76
+ //const [inputValue, setInputValue] = useSyncValue(defaultValue, isObjectEqual);
77
+ const [fileIDList, setfileIDList] = React.useState(
78
+ filterStrList([].concat(defaultValue, value))
79
+ ); // 上传成功文件ID列表,fileID[]
80
+ const [fileList, setFileList] = React.useState([]); // 上传中的文件列表,file[],file为原始文件 + uuid属性
81
+ const [fileSizeObj, setFileSizeObj] = React.useState({}); // 管理上传文件大小 {uuid:size}
82
+ React.useEffect(() => {
83
+ // 外部 onChange 事件
84
+ const pureFileIDList = fileIDList.filter(
85
+ (d) => isCloudFileID(d) || isHttpFileID(d)
86
+ );
87
+ if (single) {
88
+ const file = pureFileIDList[0] || '';
89
+ file && onChange && onChange(file);
90
+ events?.change?.({ value: file });
91
+ } else {
92
+ onChange && onChange(pureFileIDList);
93
+ events?.change?.({ value: pureFileIDList });
94
+ }
95
+ events?.success?.({ value: pureFileIDList });
96
+ }, [fileIDList]);
97
+
98
+ // 外层组件类
99
+ const cls = classNames({
100
+ 'weda-ui': true,
101
+ //'weui-cells': true,
102
+ //'weui-cells_form': true,
103
+ 'weui-cells_checkbox': true,
104
+ [className]: className,
105
+ });
106
+ const accepts = React.useMemo(() => {
107
+ return acceptTypes.includes('*') || acceptTypes.length === 0
108
+ ? ['*']
109
+ : Array.from(new Set(acceptTypes));
110
+ }, [acceptTypes]);
111
+
112
+ // 上传后文件列表 fileIDList 改变事件,'add'|'delete'
113
+ const handleChange = ({ fileID, uuid, type, size }) => {
114
+ // 上传时新增事件
115
+ if (type === 'add') {
116
+ fileID && setFileSizeObj((obj) => ({ ...obj, [fileID]: size }));
117
+ fileID && setfileIDList((list) => [...list, fileID]);
118
+ } else {
119
+ fileID && setfileIDList((list) => list.filter((f) => f !== fileID));
120
+ }
121
+ uuid && setFileList((list) => list.filter((item) => uuid !== item?._uuid));
122
+ };
123
+
124
+ // 上传组件属性
125
+ const uploadProps = {
126
+ multiple: !single,
127
+ };
128
+ tips && (uploadProps['label'] = tips);
129
+ maxSize && (uploadProps['maxSize'] = maxSize * 1024 * 1024);
130
+ const btnDisabled =
131
+ fileIDList.length >= maxUploadCount ||
132
+ (single && fileIDList.length > 0) ||
133
+ disabled;
134
+
135
+ return renderDecorator(
136
+ <ConfigProvider classPrefix="wedatea2td">
137
+ <FileContext.Provider
138
+ value={{
139
+ uploadPath,
140
+ downloadVisible,
141
+ deleteVisible,
142
+ onChange: handleChange,
143
+ events,
144
+ fileSizeObj,
145
+ }}
146
+ >
147
+ <div data-testid="uploadFileH5" className={cls} id={id} style={style}>
148
+ <div className={classNames(`${CLASS_PREFIX}`)}>
149
+ <div className={classNames(`${CLASS_PREFIX}__hd`, layout)}>
150
+ <div>
151
+ {btnDisabled ? (
152
+ <Button
153
+ type="weak"
154
+ className={classNames(`${CLASS_PREFIX}__btn--weak`)}
155
+ disabled={btnDisabled}
156
+ >
157
+ {btnTitle}
158
+ </Button>
159
+ ) : (
160
+ <div>
161
+ <input
162
+ id="uploaderInput"
163
+ type="file"
164
+ data-testid="button-up"
165
+ className="weui-uploader-mobile__input"
166
+ accept={accepts.join(',')}
167
+ multiple={!single}
168
+ onChange={(e) => {
169
+ const fileList = [...e.target.files];
170
+ if (single && fileList.length > 1) {
171
+ weui.alert(`上传文件总数不能超过1个`);
172
+ return false;
173
+ }
174
+ if (
175
+ fileList.length + fileIDList.length >
176
+ maxUploadCount
177
+ ) {
178
+ weui.alert(`上传文件总数不能超过${maxUploadCount}个`);
179
+ return false;
180
+ }
181
+ if (
182
+ maxSize &&
183
+ fileList.some((f) => f.size > maxSize * 1024 * 1024)
184
+ ) {
185
+ weui.alert(`请上传不超过${maxSize}M的文件`);
186
+ return false;
187
+ }
188
+ if (fileList.some((f) => f.size > 1024 * 1024 * 1024)) {
189
+ weui.alert(`请上传不超过1024M的文件`);
190
+ return false;
191
+ }
192
+ fileList.forEach((f) => (f['_uuid'] = v4()));
193
+ setFileList((list) => [...list, ...fileList]);
194
+ }}
195
+ />
196
+ <a
197
+ type="weak"
198
+ className="wedatea2td-btn wedatea2td-btn--weak"
199
+ >
200
+ 点击上传
201
+ </a>
202
+ {!single && (
203
+ <Text className={`${CLASS_PREFIX}__tips`}>
204
+ 支持批量上传
205
+ </Text>
206
+ )}
207
+ </div>
208
+ )}
209
+ </div>
210
+ </div>
211
+ <div className={`${CLASS_PREFIX}__bd`}>
212
+ <List>
213
+ {fileIDList.map((d) => (
214
+ <List.Item key={d}>
215
+ {
216
+ <TcbFileEcho
217
+ fileID={d}
218
+ fileList={fileList}
219
+ onChange={handleChange}
220
+ deleteVisible={deleteVisible}
221
+ downloadVisible={downloadVisible}
222
+ />
223
+ }
224
+ </List.Item>
225
+ ))}
226
+ {fileList.map((item) => (
227
+ <List.Item key={item?._uuid}>
228
+ {
229
+ <TcbFileUpload
230
+ file={item}
231
+ downloadVisible={downloadVisible}
232
+ deleteVisible={deleteVisible}
233
+ uploadPath={uploadPath}
234
+ events={events}
235
+ onChange={handleChange}
236
+ />
237
+ }
238
+ </List.Item>
239
+ ))}
240
+ </List>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </FileContext.Provider>
245
+ </ConfigProvider>
246
+ )({
247
+ id,
248
+ className: cls,
249
+ style,
250
+ label: labelVisible ? label : null,
251
+ layout,
252
+ multiCell: false,
253
+ requiredFlag,
254
+ });
255
+ }
256
+
257
+ UploadFileH5.propTypes = {
258
+ layout: PropTypes.oneOf(['horizontal', 'vertical']),
259
+ className: PropTypes.string, // 传入类
260
+ label: PropTypes.string, // 官方属性:标题
261
+ tips: PropTypes.string, // 官方属性:提示
262
+ btnTitle: PropTypes.string, // 官方属性:上传按钮标题
263
+ maxUploadCount: PropTypes.number, // 官方属性:上传文件最大数量,作用于 数组,用 single 控制数组还是单个对象
264
+ deleteVisible: PropTypes.bool,
265
+ downloadVisible: PropTypes.bool,
266
+ disabled: PropTypes.bool,
267
+ defaultValue: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
268
+ maxSize: PropTypes.number, // 官方属性:单个图片大小限制,单位是M
269
+ value: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), // 官方属性:值
270
+ events: PropTypes.objectOf(PropTypes.func), // 事件
271
+ uploadPath: PropTypes.string, // 上传路径
272
+ single: PropTypes.bool, // 单张上传还是多张上传,对应 onChange 参数为字符串还是字符串数组,value 在处理过程统一转为字符串数组
273
+ onChange: PropTypes.objectOf(PropTypes.func), // 配合 fomily 受控使用
274
+ };
275
+
276
+ /**
277
+ * 基于 FileID 文件回显组件
278
+ */
279
+ const TcbFileEcho = ({
280
+ fileID,
281
+ fileList,
282
+ onChange,
283
+ deleteVisible,
284
+ downloadVisible,
285
+ }) => {
286
+ const [src, setSrc] = React.useState('');
287
+ const { fileSizeObj } = React.useContext(FileContext) || {};
288
+ const size = '--';
289
+ React.useEffect(() => {
290
+ const fetchFileId = async (id) => {
291
+ if (isCloudFileID(id)) {
292
+ try {
293
+ const fileSrc = await getTempFileURL(id);
294
+ setSrc(fileSrc);
295
+ } catch (e) {}
296
+ } else {
297
+ setSrc(id);
298
+ }
299
+ };
300
+ fetchFileId(fileID);
301
+ }, [fileID]);
302
+ //上传文件名称
303
+ const label = React.useMemo(() => {
304
+ if (isCloudFileID(fileID)) {
305
+ const uuidReg = /file-[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}-/;
306
+ const lastIndex = `${fileID}`.lastIndexOf('/');
307
+ const name = `${fileID}`.slice(lastIndex + 1);
308
+ const label = name.replace(uuidReg, '');
309
+ return label;
310
+ } else {
311
+ return fileID;
312
+ }
313
+ }, [fileID]);
314
+ //上传文件列表展示
315
+ return (
316
+ <div className={`${CLASS_PREFIX}__item`}>
317
+ <div className={`${CLASS_PREFIX}__item-left`}>
318
+ <UploadFileStatus title={label} size={fileSizeObj[fileID] || '--'} />
319
+ </div>
320
+ <div className={`${CLASS_PREFIX}__btn-group`}>
321
+ <UploadFileAction
322
+ status="UPLOAD_STATUS_SUCCESS"
323
+ fileID={fileID}
324
+ src={src}
325
+ downloadVisible={downloadVisible}
326
+ deleteVisible={deleteVisible}
327
+ onChange={onChange}
328
+ />
329
+ </div>
330
+ </div>
331
+ );
332
+ };
333
+
334
+ /**
335
+ * 基于 File 上传文件过程组件
336
+ */
337
+ const TcbFileUpload = ({
338
+ file,
339
+ uploadPath,
340
+ onChange,
341
+ downloadVisible,
342
+ deleteVisible,
343
+ events,
344
+ }) => {
345
+ const [percent, setPercent] = React.useState(0); // 上传进度
346
+ const [status, setStatus] = React.useState('UPLOAD_STATUS_PENDING'); // 上传状态
347
+ const cancleRef = React.useRef(''); // 取消的uuid
348
+
349
+ // 上传文件相关属性
350
+ const { size, title, uuid } = React.useMemo(() => {
351
+ const size = transSize(file?.size);
352
+ const title = file?.name || '';
353
+ const uuid = file?._uuid;
354
+ return { size, title, uuid };
355
+ }, [file?._uuid]);
356
+
357
+ React.useEffect(() => {
358
+ const test = handleUpload(file);
359
+ }, [file?._uuid]);
360
+
361
+ // 上传过程
362
+ const handleUpload = async (file) => {
363
+ const tcb = await getCloudInstance();
364
+ try {
365
+ setStatus('UPLOAD_STATUS_PENDING');
366
+ const { fileID } = await tcb.uploadFile({
367
+ cloudPath: `${uploadPath}/${`file-${uuid}-${title}`}`,
368
+ filePath: file,
369
+ onUploadProgress: (progressEvent) => {
370
+ let percent = 0;
371
+ percent = Math.round(
372
+ (progressEvent.loaded * 100) / progressEvent.total
373
+ );
374
+ setStatus('UPLOAD_STATUS_LOADING');
375
+ setPercent(percent < 100 ? percent : 100);
376
+ },
377
+ });
378
+ !cancleRef.current && onChange?.({ fileID, type: 'add', uuid, size });
379
+ setStatus('UPLOAD_STATUS_SUCCESS');
380
+ } catch (err) {
381
+ setStatus('UPLOAD_STATUS_ERROR');
382
+ events?.error?.(err);
383
+ }
384
+ };
385
+
386
+ return (
387
+ <div className={`${CLASS_PREFIX}__item`} role="TcbFileUpload">
388
+ <div className={`${CLASS_PREFIX}__item-left`}>
389
+ <UploadFileStatus
390
+ status={status}
391
+ percent={percent}
392
+ size={size}
393
+ title={title}
394
+ percentSize={((file?.size / 1024) * percent) / 100}
395
+ />
396
+ </div>
397
+ <div className={`${CLASS_PREFIX}__btn-group`}>
398
+ <UploadFileAction
399
+ file={file}
400
+ uuid={file?._uuid}
401
+ status={status}
402
+ downloadVisible={downloadVisible}
403
+ deleteVisible={deleteVisible}
404
+ onChange={onChange}
405
+ onCancel={(uuid) => {
406
+ cancleRef.current = uuid;
407
+ onChange?.({ type: 'delete', uuid });
408
+ }}
409
+ onReLoad={handleUpload}
410
+ />
411
+ </div>
412
+ </div>
413
+ );
414
+ };
415
+
416
+ /**
417
+ * 上传文件状态组件
418
+ */
419
+ const UploadFileStatus = ({
420
+ status = 'UPLOAD_STATUS_SUCCESS',
421
+ percent = 0,
422
+ size,
423
+ title = null,
424
+ percentSize = 0,
425
+ }) => {
426
+ //上传中、待上传状态
427
+ if (
428
+ status == 'UPLOAD_STATUS_LOADING' ||
429
+ (status == 'UPLOAD_STATUS_PENDING' && percent)
430
+ ) {
431
+ return (
432
+ <>
433
+ <div className={`${CLASS_PREFIX}__file-detail`}>
434
+ <Text className={`${CLASS_PREFIX}__file-name`}>{title}</Text>
435
+ <div className={`${CLASS_PREFIX}__file-status`}>
436
+ <div className={`${CLASS_PREFIX}__file-status`}>
437
+ <Progress
438
+ percent={percent}
439
+ theme="default"
440
+ strokeColor={'#0052D9'}
441
+ className={`${CLASS_PREFIX}__file-progress`}
442
+ />
443
+ </div>
444
+ </div>
445
+ </div>
446
+ <div className={`${CLASS_PREFIX}__file-foot`}>
447
+ <div>
448
+ <Text>{`${Math.floor(percentSize)}K/`}</Text>
449
+
450
+ <Text>{size}</Text>
451
+ </div>
452
+ <Text>
453
+ {status === 'UPLOAD_STATUS_PENDING' ? '等待上传' : '上传中'}
454
+ </Text>
455
+ </div>
456
+ </>
457
+ );
458
+ }
459
+
460
+ return (
461
+ <>
462
+ <div className={`${CLASS_PREFIX}__file-detail`}>
463
+ <Tooltip title={title}>
464
+ <Text className={`${CLASS_PREFIX}__file-name`}>{title}</Text>
465
+ </Tooltip>
466
+ <div className={`${CLASS_PREFIX}__file-status`}>
467
+ <Icon
468
+ type={
469
+ statusMap[status]?.icon || statusMap['UPLOAD_STATUS_PENDING'].icon
470
+ }
471
+ ></Icon>
472
+ <Text className={`${CLASS_PREFIX}__file-status--msg`}>
473
+ {statusMap[status]?.title ||
474
+ statusMap['UPLOAD_STATUS_PENDING'].title}
475
+ </Text>
476
+ </div>
477
+ </div>
478
+ <div className={`${CLASS_PREFIX}__file-foot`}>
479
+ <div>
480
+ <Text>{size}</Text>
481
+ </div>
482
+ </div>
483
+ </>
484
+ );
485
+ };
486
+
487
+ /**
488
+ * 操作列组件, onChange 从最外层 UploadFilePc 传进来
489
+ * props: { status, fileID, uuid, src, onChange }
490
+ */
491
+ const UploadFileAction = ({
492
+ status = 'UPLOAD_STATUS_PENDING',
493
+ fileID = '',
494
+ uuid = '',
495
+ src = '',
496
+ downloadVisible = true,
497
+ deleteVisible = true,
498
+ file = null,
499
+ onChange = null,
500
+ onReLoad = null,
501
+ onCancel = null,
502
+ }) => {
503
+ // 操作列按钮-删除
504
+ const renderDelete = () => (
505
+ <Icon
506
+ type="delete"
507
+ style={{ cursor: 'pointer' }}
508
+ onClick={() => onChange?.({ fileID, uuid, type: 'delete' })}
509
+ />
510
+ );
511
+
512
+ // 操作列按钮-取消
513
+ const renderCancel = () => (
514
+ <Icon
515
+ type="dismiss"
516
+ style={{ cursor: 'pointer' }}
517
+ onClick={() => onCancel?.(uuid)}
518
+ />
519
+ );
520
+
521
+ // 操作列按钮-重新上传
522
+ const renderReLoad = () => (
523
+ <Icon
524
+ type="refresh"
525
+ style={{ cursor: 'pointer' }}
526
+ onClick={() => {
527
+ onReLoad?.(file);
528
+ }}
529
+ />
530
+ );
531
+
532
+ // 操作列按钮-下载
533
+ const renderDownLoad = () => (
534
+ <Icon
535
+ type="download"
536
+ style={{ cursor: 'pointer' }}
537
+ onClick={() => downloadFile(src)}
538
+ />
539
+ );
540
+
541
+ switch (status) {
542
+ case 'UPLOAD_STATUS_PENDING':
543
+ return renderCancel();
544
+ case 'UPLOAD_STATUS_LOADING':
545
+ return renderCancel();
546
+ case 'UPLOAD_STATUS_SUCCESS':
547
+ return (
548
+ <>
549
+ {deleteVisible && renderDelete()}{' '}
550
+ {downloadVisible && renderDownLoad()}
551
+ </>
552
+ );
553
+ case 'UPLOAD_STATUS_ERROR':
554
+ return (
555
+ <>
556
+ {deleteVisible && renderDelete()} {renderReLoad()}
557
+ </>
558
+ );
559
+ default:
560
+ return null;
561
+ }
562
+ };