@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,487 @@
1
+ import * as React from 'react';
2
+ import * as PropTypes from 'prop-types';
3
+ import {
4
+ Upload,
5
+ ConfigProvider,
6
+ Button,
7
+ message,
8
+ Icon,
9
+ Text,
10
+ List,
11
+ } from 'tea-component';
12
+ import { v4 } from 'uuid';
13
+ import {
14
+ filterStrList,
15
+ isCloudFileID,
16
+ isHttpFileID,
17
+ transSize,
18
+ downloadFile,
19
+ cutFileTitle
20
+ } from '../../../utils/platform';
21
+ import { getCloudInstance, getTempFileURL } from '../../../utils/tcb';
22
+ import classNames from '../../../utils/classnames';
23
+ import { renderDecorator } from '../renderDecorator';
24
+
25
+ // 默认组件类前缀
26
+ const CLASS_PREFIX = 'weda-upload-file-pc';
27
+
28
+ // 上传状态字典
29
+ const statusMap = {
30
+ 0: { title: '待上传', icon: 'pending-gray' },
31
+ 1: { title: '上传 ...', icon: 'loading' },
32
+ 2: { title: '上传成功', icon: 'success' },
33
+ 3: { title: '上传失败', icon: 'error' },
34
+ };
35
+
36
+ // 上传文件Context
37
+ const FileContext = React.createContext(null);
38
+
39
+ /**
40
+ * 上传文件 PC 版本
41
+ */
42
+ export function UploadFilePc({
43
+ // 系统属性
44
+ layout = {},
45
+ id = '',
46
+ style = {},
47
+ labelVisible = true,
48
+ title = '上传文件',
49
+ requiredFlag = false,
50
+ disabled = false,
51
+ className = '',
52
+ // 组件属性
53
+ decorator,
54
+ tips = '',
55
+ btnTitle = '点击上传',
56
+ maxUploadCount = 9,
57
+ maxSize = 1024,
58
+ single = true,
59
+ defaultValue = [], // 默认值,和 value 同时存在
60
+ acceptTypes = [],
61
+ events = { success: null, error: null, change: null },
62
+ downloadVisible = true,
63
+ deleteVisible = true,
64
+ uploadPath = 'weda-uploader',
65
+ value = [], // 需要兼容 cloud:和https: 协议,需要兼容字符串和字符串数组
66
+ onChange = null,
67
+ isEdit = true,
68
+ }) {
69
+ const [fileIDList, setfileIDList] = React.useState(
70
+ filterStrList([].concat(defaultValue, value))
71
+ ); // 上传成功文件ID列表,fileID[]
72
+ const [fileList, setFileList] = React.useState([]); // 上传中的文件列表,file[],file为原始文件 + uuid属性
73
+ const [fileSizeObj, setFileSizeObj] = React.useState({}); // 管理上传文件大小 {uuid:size}
74
+
75
+ React.useEffect(() => {
76
+ // 外部 onChange 事件
77
+ const pureFileIDList = fileIDList.filter(
78
+ (d) => isCloudFileID(d) || isHttpFileID(d)
79
+ );
80
+ if (single) {
81
+ const file = pureFileIDList[0] || '';
82
+ onChange?.(file);
83
+ events?.change?.({ value: file });
84
+ events?.success?.({ value: file });
85
+ } else {
86
+ onChange?.(pureFileIDList);
87
+ events?.change?.({ value: pureFileIDList });
88
+ events?.success?.({ value: pureFileIDList });
89
+ }
90
+ }, [fileIDList]);
91
+
92
+ // 外层组件类
93
+ const cls = classNames({
94
+ 'weda-ui': true,
95
+ [className]: className,
96
+ });
97
+
98
+ // 批量上传文件前置事件
99
+ const handleBefore = (file, fileList, isAccepted, error) => {
100
+ if (fileList.length + fileIDList.length > maxUploadCount) {
101
+ message.warning({ content: `上传文件总数不能超过${maxUploadCount}个` });
102
+ return false;
103
+ }
104
+ if (!isAccepted) {
105
+ try {
106
+ const errorList = [];
107
+ if (error.find((item) => item?.code === 'file-invalid-type')) {
108
+ errorList.push('上传文件类型错误');
109
+ }
110
+ if (error.find((item) => item?.code === 'file-too-large')) {
111
+ errorList.push(`上传文件大小不能超过${maxSize}M`);
112
+ }
113
+ message.error({ content: errorList.join(', ') });
114
+ } catch (e) {}
115
+ return false;
116
+ }
117
+ file['_uuid'] = v4();
118
+ setFileList((list) => [...list, file]);
119
+ return false;
120
+ };
121
+
122
+ // 上传后文件列表 fileIDList 改变事件,'add'|'delete'
123
+ const handleChange = ({ fileID, uuid, type, size }) => {
124
+ // 上传时新增事件
125
+ if (type === 'add') {
126
+ fileID && setFileSizeObj((obj) => ({ ...obj, [fileID]: size }));
127
+ fileID && setfileIDList((list) => [...list, fileID]);
128
+ } else {
129
+ fileID && setfileIDList((list) => list.filter((d) => d !== fileID));
130
+ }
131
+ uuid && setFileList((list) => list.filter((item) => uuid !== item?._uuid));
132
+ };
133
+
134
+ // 上传组件属性
135
+ const uploadProps = { multiple: !single };
136
+ if (
137
+ !(
138
+ !acceptTypes?.length ||
139
+ acceptTypes?.includes('*') ||
140
+ acceptTypes?.includes('')
141
+ )
142
+ ) {
143
+ uploadProps['accept'] = Array.from(new Set(acceptTypes));
144
+ }
145
+ tips && (uploadProps['title'] = tips);
146
+ maxSize && (uploadProps['maxSize'] = maxSize * 1024 * 1024);
147
+ const btnDisabled =
148
+ fileIDList.length >= maxUploadCount || (single && fileIDList.length > 0);
149
+
150
+ return renderDecorator(
151
+ <ConfigProvider classPrefix="wedatea2td">
152
+ <FileContext.Provider
153
+ value={{
154
+ uploadPath,
155
+ downloadVisible,
156
+ deleteVisible,
157
+ onChange: handleChange,
158
+ isEdit,
159
+ events,
160
+ fileSizeObj,
161
+ }}
162
+ >
163
+ <div className={`${CLASS_PREFIX}`}>
164
+ {isEdit && (
165
+ <div className={`${CLASS_PREFIX}__input-box`}>
166
+ {disabled || btnDisabled ? (
167
+ <Button type="weak" disabled={true}>
168
+ {btnTitle}
169
+ </Button>
170
+ ) : (
171
+ <Upload {...uploadProps} beforeUpload={handleBefore}>
172
+ <Button type="weak" className={`${CLASS_PREFIX}__btn--weak`}>
173
+ {btnTitle}
174
+ </Button>
175
+ {!single && (
176
+ <Text
177
+ theme="weak"
178
+ className={`${CLASS_PREFIX}__btn-descripe`}
179
+ >
180
+ 支持批量上传
181
+ </Text>
182
+ )}
183
+ </Upload>
184
+ )}
185
+ </div>
186
+ )}
187
+ <List split="divide">
188
+ <List.Item>
189
+ <div
190
+ className={`${CLASS_PREFIX}--item ${CLASS_PREFIX}--item-header`}
191
+ >
192
+ <div
193
+ className={`${CLASS_PREFIX}--item-title ${CLASS_PREFIX}--item-label`}
194
+ >
195
+ 文件名
196
+ </div>
197
+ <div
198
+ className={`${CLASS_PREFIX}--item-size ${CLASS_PREFIX}--item-label`}
199
+ >
200
+ 大小
201
+ </div>
202
+ <div
203
+ className={`${CLASS_PREFIX}--item-status ${CLASS_PREFIX}--item-label`}
204
+ >
205
+ 状态
206
+ </div>
207
+ <div className={`${CLASS_PREFIX}--item-action`}>操作</div>
208
+ </div>
209
+ </List.Item>
210
+
211
+ {fileIDList.map((d) => (
212
+ <List.Item key={d}>{<TcbFileEcho fileID={d} />}</List.Item>
213
+ ))}
214
+
215
+ {fileList.map((item) => (
216
+ <List.Item key={item?._uuid}>
217
+ {<TcbFileUpload file={item} />}
218
+ </List.Item>
219
+ ))}
220
+
221
+ {isEdit && fileIDList.length === 0 && fileList.length === 0 && (
222
+ <List.Item className={`${CLASS_PREFIX}--item-empty`}>
223
+ <div className={`${CLASS_PREFIX}--item`}>
224
+ 点击上方“{btnTitle}”按钮
225
+ </div>
226
+ </List.Item>
227
+ )}
228
+ </List>
229
+ </div>
230
+ </FileContext.Provider>
231
+ </ConfigProvider>,
232
+ decorator
233
+ )({
234
+ id,
235
+ className: cls,
236
+ style,
237
+ label: labelVisible ? title : null,
238
+ layout,
239
+ multiCell: false,
240
+ requiredFlag,
241
+ });
242
+ }
243
+
244
+ UploadFilePc.propTypes = {
245
+ className: PropTypes.string, // 传入类
246
+ title: PropTypes.string, // 官方属性:标题
247
+ labelVisible: PropTypes.bool, // 官方属性:显示标题
248
+ btnTitle: PropTypes.string, // 官方属性:上传按钮标题,[web]
249
+ maxUploadCount: PropTypes.number, // 官方属性:上传文件最大数量,作用于 数组,用 single 控制数组还是单个对象
250
+ downloadVisible: PropTypes.bool, // 官方属性:显示下载按钮
251
+ deleteVisible: PropTypes.bool, // 官方属性:显示删除按钮
252
+ defaultValue: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), // 官方属性:初始值值
253
+ maxSize: PropTypes.number, // 官方属性:单个图片大小限制,单位是M
254
+ requiredFlag: PropTypes.bool, // 官方属性:是否必填
255
+ disabled: PropTypes.bool, // 官方属性:是否禁用
256
+ events: PropTypes.any, // 官方属性:上传成功/失败事件
257
+ single: PropTypes.bool, // 官方属性:单张上传还是多张上传,对应 onChange 参数为字符串还是字符串数组,value 在处理过程统一转为字符串数组
258
+ acceptTypes: PropTypes.array, // 官方属性:支持的上传类型
259
+ tips: PropTypes.string, // 提示
260
+ value: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), // 值
261
+ onChange: PropTypes.objectOf(PropTypes.func), // 配合 fomily 受控使用
262
+ uploadPath: PropTypes.string, // 上传路径
263
+ decorator: PropTypes.any,
264
+ isEdit: PropTypes.bool, // 是否展示上传按钮,用户详情页面展示
265
+ };
266
+
267
+ /**
268
+ * 基于 FileID 回显文件表格行组件
269
+ */
270
+ const TcbFileEcho = ({ fileID }) => {
271
+ const [src, setSrc] = React.useState('');
272
+ const { fileSizeObj } = React.useContext(FileContext) || {};
273
+ React.useEffect(() => {
274
+ const fetchFileId = async (id) => {
275
+ if (isCloudFileID(id)) {
276
+ try {
277
+ const fileSrc = await getTempFileURL(id);
278
+ setSrc(fileSrc);
279
+ } catch (e) {}
280
+ } else {
281
+ setSrc(id);
282
+ }
283
+ };
284
+ fetchFileId(fileID);
285
+ }, [fileID]);
286
+
287
+ const title = React.useMemo(() => {
288
+ if (isCloudFileID(fileID)) {
289
+ const uuidReg = /file-[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}-/;
290
+ const lastIndex = `${fileID}`.lastIndexOf('/');
291
+ const name = `${fileID}`.slice(lastIndex + 1);
292
+ const title = name.replace(uuidReg, '');
293
+ return title;
294
+ } else {
295
+ return fileID;
296
+ }
297
+ }, [fileID]);
298
+
299
+ return (
300
+ <div className={`${CLASS_PREFIX}--item ${CLASS_PREFIX}--item-body`}>
301
+ <div className={`${CLASS_PREFIX}--item-title`} title={title}>{cutFileTitle(title)}</div>
302
+ <div className={`${CLASS_PREFIX}--item-size`}>
303
+ {fileSizeObj[fileID] || '--'}
304
+ </div>
305
+ <div className={`${CLASS_PREFIX}--item-status`}>
306
+ <UploadFileStatus />
307
+ </div>
308
+ <div className={`${CLASS_PREFIX}--item-action`}>
309
+ <UploadFileAction status="2" fileID={fileID} src={src} />
310
+ </div>
311
+ </div>
312
+ );
313
+ };
314
+
315
+ /**
316
+ * 基于 File 上传文件过程表格行组件
317
+ */
318
+ const TcbFileUpload = ({ file }) => {
319
+ const { uploadPath, onChange, events } = React.useContext(FileContext) || {};
320
+ const [percent, setPercent] = React.useState(0); // 上传进度
321
+ const [status, setStatus] = React.useState('0'); // 上传状态
322
+ const cancleRef = React.useRef(''); // 取消的uuid
323
+
324
+ // 上传文件相关属性
325
+ const { size, title, uuid } = React.useMemo(() => {
326
+ const size = transSize(file?.size);
327
+ const title = file?.name || '';
328
+ const uuid = file?._uuid;
329
+ return { size, title, uuid };
330
+ }, [file?._uuid]);
331
+
332
+ React.useEffect(() => {
333
+ handleUpload(file);
334
+ }, [file?._uuid]);
335
+
336
+ // 上传过程
337
+ const handleUpload = async (file) => {
338
+ const tcb = await getCloudInstance();
339
+ try {
340
+ setStatus('0');
341
+ const { fileID } = await tcb.uploadFile({
342
+ cloudPath: `${uploadPath}/${`file-${uuid}-${title}`}`,
343
+ filePath: file,
344
+ onUploadProgress: (progressEvent) => {
345
+ let percent = 0;
346
+ percent = Math.round(
347
+ (progressEvent.loaded * 100) / progressEvent.total
348
+ );
349
+ setStatus('1');
350
+ setPercent(percent < 100 ? percent : 100);
351
+ },
352
+ });
353
+ !cancleRef.current && onChange?.({ fileID, type: 'add', uuid, size });
354
+ setStatus('2');
355
+ } catch (e) {
356
+ setStatus('3');
357
+ events.error && events.error(e);
358
+ }
359
+ };
360
+
361
+ return (
362
+ <div className={`${CLASS_PREFIX}--item ${CLASS_PREFIX}--item-body`}>
363
+ <div className={`${CLASS_PREFIX}--item-title`} title={title}>{cutFileTitle(title)}</div>
364
+ <div className={`${CLASS_PREFIX}--item-size`}>{size}</div>
365
+ <div className={`${CLASS_PREFIX}--item-status`}>
366
+ <UploadFileStatus status={status} percent={percent} />
367
+ </div>
368
+ <div className={`${CLASS_PREFIX}--item-action`}>
369
+ <UploadFileAction
370
+ file={file}
371
+ uuid={file?._uuid}
372
+ status={status}
373
+ onCancel={(uuid) => {
374
+ cancleRef.current = uuid;
375
+ onChange?.({ type: 'delete', uuid });
376
+ }}
377
+ onReLoad={handleUpload}
378
+ />
379
+ </div>
380
+ </div>
381
+ );
382
+ };
383
+
384
+ /**
385
+ * 上传文件状态组件
386
+ */
387
+ const UploadFileStatus = ({ status = '2', percent = 0 }) => {
388
+ if (status == '1' && percent) {
389
+ return (
390
+ <>
391
+ <Icon type="loading" />
392
+ 上传{percent}% ...
393
+ </>
394
+ );
395
+ }
396
+ return (
397
+ <>
398
+ <Icon type={statusMap[status]?.icon || statusMap['0'].icon} />
399
+ {statusMap[status]?.title || statusMap['0'].title}
400
+ </>
401
+ );
402
+ };
403
+
404
+ /**
405
+ * 操作列组件, onChange 从最外层 UploadFilePc 传进来
406
+ * props: { status, fileID, uuid, src, onChange }
407
+ */
408
+ const UploadFileAction = ({
409
+ status = '0',
410
+ fileID = '',
411
+ uuid = '',
412
+ src = '',
413
+ file = null,
414
+ onReLoad = null,
415
+ onCancel = null,
416
+ }) => {
417
+ const { onChange, downloadVisible, deleteVisible, isEdit } =
418
+ React.useContext(FileContext) || {};
419
+
420
+ // 操作列按钮-删除
421
+ const renderDelete = () =>
422
+ isEdit &&
423
+ deleteVisible && (
424
+ <Button
425
+ type="link"
426
+ onClick={() => onChange?.({ fileID, uuid, type: 'delete' })}
427
+ >
428
+ 删除
429
+ </Button>
430
+ );
431
+
432
+ // 操作列按钮-取消
433
+ const renderCancel = () =>
434
+ isEdit && (
435
+ <Button onClick={() => onCancel?.(uuid)} type="link">
436
+ 取消
437
+ </Button>
438
+ );
439
+
440
+ // 操作列按钮-重新上传
441
+ const renderReLoad = () =>
442
+ isEdit && (
443
+ <Button
444
+ type="link"
445
+ onClick={() => {
446
+ onReLoad?.(file);
447
+ }}
448
+ >
449
+ 重新上传
450
+ </Button>
451
+ );
452
+
453
+ // 操作列按钮-下载
454
+ const renderDownLoad = () =>
455
+ downloadVisible && (
456
+ <Button
457
+ type="link"
458
+ title="点击下载文件"
459
+ onClick={() => downloadFile(src)}
460
+ >
461
+ 下载
462
+ </Button>
463
+ );
464
+
465
+ switch (status) {
466
+ case '0':
467
+ return renderCancel();
468
+ case '1':
469
+ return renderCancel();
470
+ case '2':
471
+ return (
472
+ <>
473
+ {renderDelete()}
474
+ {renderDownLoad()}
475
+ </>
476
+ );
477
+ case '3':
478
+ return (
479
+ <>
480
+ {renderDelete()}
481
+ {renderReLoad()}
482
+ </>
483
+ );
484
+ default:
485
+ return null;
486
+ }
487
+ };
@@ -3,23 +3,12 @@ import * as PropTypes from 'prop-types';
3
3
  import { ConfigProvider, ImagePreview } from 'tea-component';
4
4
  import { usePlatform } from '../../utils/platform';
5
5
  import { useGesture } from '@use-gesture/react';
6
-
7
- ImageInner.propTypes = {
8
- objectFit: PropTypes.string,
9
- className: PropTypes.string,
10
- events: PropTypes.object,
11
- style: PropTypes.object,
12
- src: PropTypes.string,
13
- alt: PropTypes.string,
14
- lazyLoad: PropTypes.bool,
15
- isError: PropTypes.bool,
16
- setIsError: PropTypes.func,
17
- maskClosable: PropTypes.bool,
18
- imgPreview: PropTypes.bool
19
- };
20
-
21
- const failImgBase64 = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIiBmaWxsPSJub25lIj4KICA8cGF0aCBkPSJNMjUuMzIgMTYuMzU5N0MyNi4wNzY0IDE2LjM1OTcgMjYuODI1NCAxNi41MDg3IDI3LjUyNDMgMTYuNzk4MUMyOC4yMjMxIDE3LjA4NzYgMjguODU4MSAxNy41MTE5IDI5LjM5MjkgMTguMDQ2OEMyOS45Mjc4IDE4LjU4MTYgMzAuMzUyMSAxOS4yMTY2IDMwLjY0MTYgMTkuOTE1NEMzMC45MzEgMjAuNjE0MyAzMS4wOCAyMS4zNjMzIDMxLjA4IDIyLjExOTdDMzEuMDggMjIuODc2MSAzMC45MzEgMjMuNjI1MSAzMC42NDE2IDI0LjMyMzlDMzAuMzUyMSAyNS4wMjI4IDI5LjkyNzggMjUuNjU3OCAyOS4zOTI5IDI2LjE5MjZDMjguODU4MSAyNi43Mjc1IDI4LjIyMzEgMjcuMTUxOCAyNy41MjQzIDI3LjQ0MTJDMjYuODI1NCAyNy43MzA3IDI2LjA3NjQgMjcuODc5NyAyNS4zMiAyNy44Nzk3QzIzLjc5MjQgMjcuODc5NyAyMi4zMjczIDI3LjI3MjggMjEuMjQ3MSAyNi4xOTI2QzIwLjE2NjkgMjUuMTEyNCAxOS41NiAyMy42NDczIDE5LjU2IDIyLjExOTdDMTkuNTYgMjAuNTkyIDIwLjE2NjkgMTkuMTI3IDIxLjI0NzEgMTguMDQ2OEMyMi4zMjczIDE2Ljk2NjUgMjMuNzkyNCAxNi4zNTk3IDI1LjMyIDE2LjM1OTdaTTI4IDMuNTU5NjlWMTQuODc2OEMyNy4xNzc3IDE0LjU4NjYgMjYuMTkyIDE0LjQzODggMjUuMzIgMTQuNDM5N0MyNC4wMzEgMTQuNDM5NyAyMi44MTU3IDE0Ljc1NzEgMjEuNzQ4OCAxNS4zMTg0TDIwLjc5NTIgMTMuMTU5N0wxNi4wMjU5IDIwLjAyNzVMOC40NDU3NiAxNi40NDFMMy41NiAyMy4zOTk3SDE3Ljc0NjJDMTcuOTg2NyAyNC44MjkgMTguNjI4MiAyNi4xNjA2IDE5LjU5NTggMjcuMjM5N0gxVjMuNTU5NjlIMjhaTTI1Ljk2IDI0LjAzOTdIMjQuNjhWMjUuMzE5N0gyNS45NlYyNC4wMzk3Wk0yNS45NiAxOC45MTk3SDI0LjY4VjIzLjM5OTdIMjUuOTZWMTguOTE5N1pNNi4xMiAxMC41OTk3QzYuMTIgMTEuOTk4MSA3LjE5OTA0IDEzLjEwODUgOC42MDc2OCAxMy4xNTg0QzEwLjAyMDggMTMuMjA3NyAxMS4yNCAxMi4wNDggMTEuMjQgMTAuNTk5N0MxMS4yNCA5LjI0NjA5IDEwLjA2NDMgOC4wODU3NyA4Ljc1MjMyIDguMDQwOTdDNy4yOTU2OCA3Ljk5MTY5IDYuMTIgOS4xNTEzNyA2LjEyIDEwLjU5OTdaIiBmaWxsPSIjQkNDNEQwIj48L3BhdGg+Cjwvc3ZnPgo=';
22
-
6
+ import { PropsType } from './index';
7
+ interface ImageInnerPropsType extends Omit<PropsType, 'fit'|'mode'> {
8
+ objectFit: React.CSSProperties['objectFit'],
9
+ isError: boolean,
10
+ setIsError: React.Dispatch<React.SetStateAction<boolean>>
11
+ }
23
12
  export function ImageInner({
24
13
  objectFit,
25
14
  style,
@@ -32,7 +21,7 @@ export function ImageInner({
32
21
  lazyLoad,
33
22
  maskClosable,
34
23
  imgPreview
35
- }) {
24
+ }: ImageInnerPropsType) {
36
25
  const platform = usePlatform();
37
26
  const [imgShow, setImgShow] = React.useState(false);
38
27
  const onMaskClick = () => {
@@ -100,8 +89,7 @@ export function ImageInner({
100
89
  alt={alt}
101
90
  src={src}
102
91
  onLoad={(e) => {
103
- /* @type {HTMLImageElement} */
104
- const img = e.target;
92
+ const img = e.target as HTMLImageElement;
105
93
  const {naturalHeight, naturalWidth} = img;
106
94
  realHeight.current = naturalHeight;
107
95
  realWidth.current = naturalWidth;
@@ -154,7 +142,6 @@ export function ImageInner({
154
142
  <ConfigProvider classPrefix="wedatea2td">
155
143
  <ImagePreview
156
144
  previewSrc={src}
157
- lazyLoad
158
145
  maskClosable={maskClosable}
159
146
  className={className}
160
147
  style={{...style,
@@ -1,25 +1,36 @@
1
1
  import * as React from 'react';
2
2
  import { useState, useEffect } from 'react';
3
- import * as PropTypes from 'prop-types';
4
3
 
5
4
  import classNames from '../../utils/classnames';
6
5
  import './index.css';
7
6
  import { ImageInner } from './image';
7
+ import { CommonPropsType } from '../../types';
8
+
9
+
10
+ const defaultSrc = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48Y2lyY2xlIGN4PSI0MCIgY3k9IjQwIiByPSI0MCIgZmlsbD0iI0VCRUZGNSIvPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0yMCA1NlYyNGg0MHYzMnoiLz48cGF0aCBmaWxsPSIjQzFDQ0REIiBkPSJNMjYgMzdoMjh2MkgyNnptMCA3aDIwdjJIMjZ6bS02LTIwaDQwdjdIMjB6Ii8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDggNDQpIj48Y2lyY2xlIGZpbGw9IiNGRkYiIGN4PSIxMCIgY3k9IjEwIiByPSI3Ii8+PHBhdGggZD0iTTEwIDJhOCA4IDAgMSAxIDAgMTYgOCA4IDAgMCAxIDAtMTZ6bTEgMTBIOXYyaDJ2LTJ6bTAtNkg5djVoMlY2eiIgZmlsbD0iIzAwNkVGRiIvPjwvZz48L2c+PC9zdmc+'
11
+ type TMode = 'scaleToFill' | 'aspectFit' | 'aspectFill' | 'widthFix' | 'heightFix' | 'top' | 'bottom' | 'center' | 'left' | 'right' | 'top left' | 'top right' | 'bottom left' | 'bottom right';
12
+ export interface PropsType extends CommonPropsType, Pick<HTMLImageElement, 'src'|'alt'> {
13
+ mode: TMode,
14
+ lazyLoad: boolean,
15
+ maskClosable: boolean,
16
+ imgPreview: boolean,
17
+ fit: React.CSSProperties['objectFit']
18
+ }
8
19
 
9
20
  export default function Image({
10
21
  // 系统属性
11
22
  className,
12
23
  events = {},
13
- style,
24
+ style = {},
14
25
  // 组件属性
15
- src,
16
- alt,
17
- mode,
18
- lazyLoad,
19
- imgPreview,
20
- maskClosable,
26
+ src = defaultSrc,
27
+ alt = '[图片]',
28
+ mode = 'scaleToFill',
29
+ lazyLoad = false,
30
+ imgPreview = false,
31
+ maskClosable = true,
21
32
  fit,
22
- }) {
33
+ }: PropsType) {
23
34
  const [isError, setIsError] = useState(false);
24
35
  const cls = classNames({
25
36
  'weda-ui': true,
@@ -64,22 +75,8 @@ export default function Image({
64
75
  ) : null;
65
76
  }
66
77
 
67
- Image.defaultPropTypes = {
68
- // 系统属性
69
- events: {},
70
- style: {},
71
- // 组件属性
72
- src:
73
- 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48Y2lyY2xlIGN4PSI0MCIgY3k9IjQwIiByPSI0MCIgZmlsbD0iI0VCRUZGNSIvPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0yMCA1NlYyNGg0MHYzMnoiLz48cGF0aCBmaWxsPSIjQzFDQ0REIiBkPSJNMjYgMzdoMjh2MkgyNnptMCA3aDIwdjJIMjZ6bS02LTIwaDQwdjdIMjB6Ii8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDggNDQpIj48Y2lyY2xlIGZpbGw9IiNGRkYiIGN4PSIxMCIgY3k9IjEwIiByPSI3Ii8+PHBhdGggZD0iTTEwIDJhOCA4IDAgMSAxIDAgMTYgOCA4IDAgMCAxIDAtMTZ6bTEgMTBIOXYyaDJ2LTJ6bTAtNkg5djVoMlY2eiIgZmlsbD0iIzAwNkVGRiIvPjwvZz48L2c+PC9zdmc+',
74
- alt: '[图片]',
75
- lazyLoad: false,
76
- fit: 'fill',
77
- mode: 'scaleToFill',
78
- imgPreview: false,
79
- maskClosable: true
80
- };
81
78
 
82
- function getObjectFitByWxImageMode(mode) {
79
+ function getObjectFitByWxImageMode(mode: TMode): React.CSSProperties['objectFit'] {
83
80
  const array = [
84
81
  {
85
82
  mode: 'scaleToFill',
@@ -101,20 +98,8 @@ function getObjectFitByWxImageMode(mode) {
101
98
  mode: 'heightFix',
102
99
  h5: 'contain',
103
100
  },
104
- ];
101
+ ] as const;
105
102
  const item = array.find((item) => item.mode === mode);
106
103
  return item?.h5;
107
104
  }
108
105
 
109
- Image.propTypes = {
110
- className: PropTypes.string,
111
- events: PropTypes.object,
112
- style: PropTypes.object,
113
- src: PropTypes.string,
114
- alt: PropTypes.string,
115
- mode: PropTypes.string,
116
- fit: PropTypes.string,
117
- lazyLoad: PropTypes.bool,
118
- maskClosable: PropTypes.bool,
119
- imgPreview: PropTypes.bool
120
- };
@@ -1,4 +1,36 @@
1
1
  import '../wedatheme/style-package/index.css';
2
+ import loadable from '@loadable/component';
3
+ import { fallback } from '../utils/loading-fallback';
4
+
5
+ // export const Button = loadable(() => import('./button'), {fallback});
6
+ // export const Text = loadable(() => import('./text'), {fallback});
7
+ // export const Container = loadable(() => import('./container'), {fallback});
8
+ // export const Image = loadable(() => import('./image'), {fallback});
9
+ // export const Slot = loadable(() => import('./slot'), {fallback});
10
+ // export const ScrollView = loadable(() => import('./scrollView'), {fallback});
11
+ // export const Swiper = loadable(() => import('./swiper'), {fallback});
12
+ // export const Modal = loadable(() => import('./modal'), {fallback});
13
+ // export const RichText = loadable(() => import('./richText'), {fallback});
14
+ // export const RichTextView = loadable(() => import('./richTextView'), {fallback});
15
+ // export const Link = loadable(() => import('./link'), {fallback});
16
+ // export const Drawer = loadable(() => import('./drawer'), {fallback});
17
+ // export const UploaderView = loadable(() => import('./uploaderView'), {fallback});
18
+ // // picker
19
+ // export const Picker = loadable(() => import('./picker/picker'), {fallback});
20
+ // export const DatePicker = loadable(() => import('./picker/datePicker'), {fallback});
21
+ // export const TimePicker = loadable(() => import('./picker/timePicker'), {fallback});
22
+ // // form
23
+ // export const Form = loadable(() => import('./form/form'), {fallback});
24
+ // export const Input = loadable(() => import('./form/input'), {fallback});
25
+ // export const Textarea = loadable(() => import('./form/textarea'), {fallback});
26
+ // export const Checkbox = loadable(() => import('./form/checkbox'), {fallback});
27
+ // export const Radio = loadable(() => import('./form/radio'), {fallback});
28
+ // export const Switch = loadable(() => import('./form/switch'), {fallback});
29
+ // export const Select = loadable(() => import('./form/select'), {fallback});
30
+ // export const Uploader = loadable(() => import('./form/uploader'), {fallback});
31
+ // export const Tips = loadable(() => import('./form/tips'), {fallback});
32
+ // export const EnumSelect = loadable(() => import('./form/enumSelect'), {fallback});
33
+ // export const Tabs = loadable(() => import('./tabs'), {fallback});
2
34
 
3
35
  export { default as Button } from './button';
4
36
  export { default as Text } from './text';
@@ -13,7 +45,7 @@ export { default as RichTextView } from './richTextView';
13
45
  export { default as Link } from './link';
14
46
  export { default as Drawer } from './drawer';
15
47
  export { default as UploaderView } from './uploaderView';
16
- // picker
48
+
17
49
  export { default as Picker } from './picker/picker';
18
50
  export { default as DatePicker } from './picker/datePicker';
19
51
  export { default as TimePicker } from './picker/timePicker';
@@ -26,9 +58,11 @@ export { default as Radio } from './form/radio';
26
58
  export { default as Switch } from './form/switch';
27
59
  export { default as Select } from './form/select';
28
60
  export { default as Uploader } from './form/uploader';
61
+ export { default as UploaderFile } from './form/uploaderFile';
29
62
  export { default as Tips } from './form/tips';
30
63
  export { default as Tabs } from './tabs';
31
64
  export { default as EnumSelect } from './form/enumSelect';
65
+
32
66
  // open
33
67
  // import Auth from './auth';
34
68