@cloudbase/weda-ui 3.16.0 → 3.17.1

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 (64) hide show
  1. package/dist/configs/components/container.js +0 -3
  2. package/dist/configs/components/wd-ad.d.ts +10 -1
  3. package/dist/configs/components/wd-ad.js +31 -1
  4. package/dist/configs/components/wd-cascader.d.ts +4 -0
  5. package/dist/configs/components/wd-checkbox.d.ts +4 -0
  6. package/dist/configs/components/wd-code-editor.d.ts +4 -0
  7. package/dist/configs/components/wd-date-range.d.ts +4 -0
  8. package/dist/configs/components/wd-date.d.ts +4 -0
  9. package/dist/configs/components/wd-department.d.ts +6 -0
  10. package/dist/configs/components/wd-department.js +1 -1
  11. package/dist/configs/components/wd-form-arr.d.ts +4 -0
  12. package/dist/configs/components/wd-form-detail.d.ts +4 -0
  13. package/dist/configs/components/wd-form-obj.d.ts +4 -0
  14. package/dist/configs/components/wd-input-email.d.ts +4 -0
  15. package/dist/configs/components/wd-input-number.d.ts +4 -0
  16. package/dist/configs/components/wd-input-phone.d.ts +4 -0
  17. package/dist/configs/components/wd-input-url.d.ts +4 -0
  18. package/dist/configs/components/wd-input.d.ts +4 -0
  19. package/dist/configs/components/wd-location.d.ts +4 -0
  20. package/dist/configs/components/wd-member.d.ts +4 -0
  21. package/dist/configs/components/wd-radio.d.ts +4 -0
  22. package/dist/configs/components/wd-rating.d.ts +4 -0
  23. package/dist/configs/components/wd-region.d.ts +4 -0
  24. package/dist/configs/components/wd-rich-text.d.ts +4 -0
  25. package/dist/configs/components/wd-select-multiple.d.ts +4 -0
  26. package/dist/configs/components/wd-select.d.ts +4 -0
  27. package/dist/configs/components/wd-switch.d.ts +4 -0
  28. package/dist/configs/components/wd-table.d.ts +1 -1
  29. package/dist/configs/components/wd-table.js +1 -1
  30. package/dist/configs/components/wd-tag-select.d.ts +4 -0
  31. package/dist/configs/components/wd-tag.d.ts +4 -0
  32. package/dist/configs/components/wd-textarea.d.ts +4 -0
  33. package/dist/configs/components/wd-time.d.ts +4 -0
  34. package/dist/configs/components/wd-upload-file.d.ts +4 -0
  35. package/dist/configs/components/wd-upload-image.d.ts +207 -15
  36. package/dist/configs/components/wd-upload-image.js +143 -6
  37. package/dist/configs/components/web-view.js +1 -1
  38. package/dist/configs/index.d.ts +522 -8
  39. package/dist/configs/type-utils/type-form.d.ts +4 -0
  40. package/dist/configs/type-utils/type-form.js +4 -0
  41. package/dist/configs/type-utils/x-runtime-default.d.ts +2 -0
  42. package/dist/configs/type-utils/x-runtime-default.js +2 -0
  43. package/dist/configs/utils/field.d.ts +1 -0
  44. package/dist/configs/utils/field.js +95 -0
  45. package/dist/style/weda-ui.min.css +1 -1
  46. package/dist/web/components/form/uploader/index.d.ts +1 -0
  47. package/dist/web/components/form/uploader/index.js +7 -4
  48. package/dist/web/components/form/uploader/upload/index.d.ts +26 -0
  49. package/dist/web/components/form/uploader/upload/index.js +200 -0
  50. package/dist/web/components/form/uploader/uploader.h5.d.ts +6 -1
  51. package/dist/web/components/form/uploader/uploader.h5.js +26 -94
  52. package/dist/web/components/form/uploader/uploader.pc.d.ts +1 -1
  53. package/dist/web/components/form/uploader/uploader.pc.js +30 -100
  54. package/dist/web/components/form/uploader/util.d.ts +16 -0
  55. package/dist/web/components/form/uploader/util.js +106 -5
  56. package/dist/web/components/richText/index.js +3 -1
  57. package/dist/web/components/uploaderView/index.js +1 -1
  58. package/dist/web/components/wd-ad/wd-ad.js +2 -4
  59. package/dist/web/components/wd-form/hooks/use-remote-value.js +18 -18
  60. package/dist/web/components/wd-modal/wd-modal.js +10 -13
  61. package/dist/web/components/wd-upload-image/wd-upload-image.js +14 -4
  62. package/package.json +5 -5
  63. package/dist/web/components/form/uploader/useUploadFile.d.ts +0 -16
  64. package/dist/web/components/form/uploader/useUploadFile.js +0 -99
@@ -5,7 +5,7 @@ export declare const IMAGE_TYPES: string[];
5
5
  interface TempFileProps {
6
6
  progress?: number;
7
7
  loading?: boolean;
8
- realUrl?: string;
8
+ cloudId?: string;
9
9
  tempUrl?: string;
10
10
  key?: string;
11
11
  }
@@ -1,14 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import * as React from 'react';
3
- import { Upload, Icon, ErrorTip, ConfigProvider } from 'tea-component';
3
+ import { Icon, ErrorTip, ConfigProvider } from 'tea-component';
4
4
  import { useTempUrl } from '../../../utils/hooks/use-cloud-id-temp-url';
5
- import { toBase64Uri } from '../../../utils/file2base64';
6
- import { isNil } from '../../../utils/lodash';
7
5
  import { errorHandler } from '../../../utils/error';
8
- import { alertErrorMessage } from '../../../utils/platform';
9
6
  import { WdIcon } from '../../wd-icon';
10
- import { useUploader } from './useUploadFile';
11
7
  import { ImagePreview } from '../../wd-image/ImagePreview';
8
+ import { Upload } from './upload';
12
9
  // 默认组件类前缀
13
10
  export const CLASS_PREFIX = 'weda-uploader-pc';
14
11
  // 默认图片类型
@@ -22,117 +19,50 @@ export const IMAGE_TYPES = [
22
19
  'image/gif',
23
20
  ];
24
21
  export function UploaderPCInner(props) {
25
- const { tips = '', btnTitle = '上传图片', maxUploadCount = 9, maxSize = 10, acceptTypes = IMAGE_TYPES, events, single = false, disabled = false, onChange, imgTypeCls, readOnly, sourceType, callbacks, popupContainer: portalContainer, } = props;
26
- const { tempFile, uploading, upload, getTempFile } = useUploader(props);
27
- const handleChange = (allFile = [], isDelete = false) => {
28
- var _a;
29
- const value = getTempFile(allFile);
30
- onChange === null || onChange === void 0 ? void 0 : onChange(value);
31
- (_a = events === null || events === void 0 ? void 0 : events.change) === null || _a === void 0 ? void 0 : _a.call(events, { value, isDelete });
32
- };
33
- // 方法:上传前,判断图片大小、数量是否满足,取消默认组件的上传事件,用自定义的 tcb 上传方法
34
- const beforeHandle = async (file, fileList, isAccepted, error) => {
35
- const finalMaxImgCount = single ? 1 : maxUploadCount;
36
- if (!isAccepted) {
37
- try {
38
- const errorList = [];
39
- if (error.find((item) => (item === null || item === void 0 ? void 0 : item.code) === 'file-invalid-type')) {
40
- errorList.push('上传图片类型错误');
41
- }
42
- if (error.find((item) => (item === null || item === void 0 ? void 0 : item.code) === 'file-too-large')) {
43
- errorList.push(`上传图片大小不能超过${maxSize}M`);
44
- }
45
- alertErrorMessage({
46
- message: errorList.join(', '),
47
- icon: 'error',
48
- });
49
- }
50
- catch (e) {
51
- errorHandler({
52
- code: 'BEFORE_UPLOAD_ERROR',
53
- error: e,
54
- });
55
- }
56
- return Promise.reject(false);
57
- }
58
- const ids = fileList.filter((f) => !!f.id);
59
- if (ids.length < fileList.length)
60
- return Promise.reject(false);
61
- if (fileList.length > finalMaxImgCount) {
62
- // 防止一下子选择过多文件
63
- alertErrorMessage({
64
- message: `最多只能上传${finalMaxImgCount}张图片,请重新选择`,
65
- icon: 'error',
66
- });
67
- return Promise.reject(false);
68
- }
69
- if (tempFile.length + fileList.length > finalMaxImgCount) {
70
- alertErrorMessage({
71
- message: `最多只能上传${finalMaxImgCount}张图片`,
72
- icon: 'error',
73
- });
74
- return Promise.reject(false);
75
- }
76
- let shouldUploadToCos = true;
77
- if (typeof (callbacks === null || callbacks === void 0 ? void 0 : callbacks.beforeUpload) === 'function') {
78
- try {
79
- const base64Uri = await Promise.all(fileList.map((file) => toBase64Uri(file)));
80
- const ret = await callbacks.beforeUpload({
81
- files: fileList,
82
- base64Uri,
83
- });
84
- if (typeof ret === 'boolean') {
85
- shouldUploadToCos = ret;
86
- }
87
- else if (Array.isArray(ret) && ret.every((item) => item instanceof File)) {
88
- fileList = ret;
89
- }
90
- else if (!isNil(ret)) {
91
- throw new TypeError('web端返回值接受布尔值 / File对象数组');
92
- }
93
- }
94
- catch (err) {
95
- errorHandler({
96
- code: 'BEFORE_UPLOAD_ERROR',
97
- error: err,
98
- });
99
- shouldUploadToCos = false;
100
- }
101
- }
102
- if (shouldUploadToCos === false) {
103
- return Promise.reject(false);
22
+ const { tips = '', btnTitle = '上传图片', maxUploadCount = 9, maxSize = 10, acceptTypes = IMAGE_TYPES, single = false, disabled = false, imgTypeCls, readOnly, sourceType, popupContainer: portalContainer, defaultValue, setUploadHandle: outSetUploadHandle, } = props;
23
+ const uploadRef = React.useRef(null);
24
+ const [uploadHandle, setUploadHandle] = React.useState({});
25
+ const tempFile = React.useMemo(() => (uploadHandle === null || uploadHandle === void 0 ? void 0 : uploadHandle.previewFile) || [], [uploadHandle === null || uploadHandle === void 0 ? void 0 : uploadHandle.previewFile]);
26
+ const uploading = tempFile === null || tempFile === void 0 ? void 0 : tempFile.some((i) => i.loading);
27
+ const setUploadRef = React.useCallback((uploadHandle) => {
28
+ setUploadHandle(uploadHandle);
29
+ // 设置最外层组件方法
30
+ // 兼容云后台数据库中使用uploader组件,未传outSetUploadHandle
31
+ if (outSetUploadHandle) {
32
+ outSetUploadHandle(uploadHandle);
104
33
  }
105
- const allFile = await upload(fileList);
106
- handleChange(allFile);
107
- };
34
+ }, [outSetUploadHandle]);
108
35
  // 删除图片
109
- const deleteHandle = (fileItem) => {
110
- const fileList = tempFile.filter((d) => d.key !== fileItem.key);
111
- handleChange(fileList, true);
36
+ const deleteHandle = (file) => {
37
+ var _a;
38
+ (_a = uploadRef === null || uploadRef === void 0 ? void 0 : uploadRef.current) === null || _a === void 0 ? void 0 : _a.delete({ cloudId: file.cloudId });
112
39
  };
113
40
  // 转换后的属性
114
- const extraProps = {};
41
+ const extraProps = { ...props };
115
42
  //是否支持多选
116
43
  extraProps['multiple'] = !single;
117
44
  extraProps['accept'] = acceptTypes.length === 0 ? IMAGE_TYPES : Array.from(new Set(acceptTypes));
118
45
  tips && (extraProps['title'] = tips);
119
46
  maxSize && (extraProps['maxSize'] = maxSize * 1024 * 1024);
120
47
  const hasActions = !uploading && !readOnly && !(disabled || sourceType === 'camera');
121
- return (_jsx(ConfigProvider, { classPrefix: "wedatea2td", children: _jsxs("div", { className: "_weda-fn-upload-result", children: [tempFile === null || tempFile === void 0 ? void 0 : tempFile.map((d, index) => (_jsx("div", { className: `_weda-fn-upload-result__item ${imgTypeCls}`, children: _jsx(TcbImage, { index: index, allFile: tempFile, tempFile: d, imgTypeCls: imgTypeCls, isZoom: true, previewIcon: "td:browse", portalContainer: portalContainer, actions: hasActions && (_jsx(WdIcon, { className: `${CLASS_PREFIX}__image-actions-delete`, name: "td:delete", onClick: () => deleteHandle(d), size: "sm" })) }) }, d.key))), _jsxs("div", { className: `${CLASS_PREFIX}__input-box`, children: [readOnly && tempFile.length < 1 && _jsx("div", { children: "-" }), sourceType === 'camera' || (disabled && !readOnly) ? (_jsx("div", { className: `_weda-fn-upload-result__item wedatea2td-disabled weda-uploader-btn__box ${imgTypeCls}`, children: _jsxs("div", { className: "_weda-fn-upload-result__status", children: [_jsx("i", { className: "wedatea2td-icon wedatea2td-icon-plus", role: "img", "aria-label": "plus" }), _jsx("span", { className: "wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset", children: btnTitle })] }) })) : (((!single && tempFile.length < maxUploadCount) || (single && tempFile.length < 1 && !uploading)) &&
122
- !readOnly && (
123
- // single 模式时,当数组为空且不在上传文件过程中时显示
124
- _jsx(Upload, { ...extraProps, beforeUpload: beforeHandle, children: _jsxs("div", {
48
+ return (_jsx(ConfigProvider, { classPrefix: "wedatea2td", children: _jsx(Upload, { ...extraProps, ref: uploadRef, value: defaultValue, setUploadHandle: setUploadRef, children: _jsxs("div", { className: "_weda-fn-upload-result", children: [tempFile === null || tempFile === void 0 ? void 0 : tempFile.map((d, index) => (_jsx("div", { className: `_weda-fn-upload-result__item ${imgTypeCls}`, children: _jsx(TcbImage, { index: index, allFile: tempFile, tempFile: d, imgTypeCls: imgTypeCls, isZoom: true, previewIcon: "td:browse", portalContainer: portalContainer, actions: hasActions && (_jsx(WdIcon, { className: `${CLASS_PREFIX}__image-actions-delete`, name: "td:delete", onClick: () => deleteHandle(d), size: "sm" })) }) }, d.cloudId))), _jsxs("div", { className: `${CLASS_PREFIX}__input-box`, children: [readOnly && tempFile.length < 1 && _jsx("div", { children: "-" }), sourceType === 'camera' || (disabled && !readOnly) ? (_jsx("div", { className: `_weda-fn-upload-result__item wedatea2td-disabled weda-uploader-btn__box ${imgTypeCls}`, children: _jsxs("div", { className: "_weda-fn-upload-result__status", children: [_jsx("i", { className: "wedatea2td-icon wedatea2td-icon-plus", role: "img", "aria-label": "plus" }), _jsx("span", { className: "wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset", children: btnTitle })] }) })) : (((!single && tempFile.length < maxUploadCount) || (single && tempFile.length < 1 && !uploading)) &&
49
+ !readOnly && (
50
+ // single 模式时,当数组为空且不在上传文件过程中时显示
51
+ _jsxs("div", {
125
52
  // className={"_weda-fn-upload-result__item _weda-fn-upload-result__item--upload" imgTypeCls}
126
53
  // className={classNames(
127
54
  // `_weda-fn-upload-result__item _weda-fn-upload-result__item--upload`,
128
55
  // imgTypeCls
129
56
  // )}
130
- className: `_weda-fn-upload-result__item weda-uploader-btn__box _weda-fn-upload-result__item--upload ${imgTypeCls}`, children: [imgTypeCls, _jsxs("div", { className: "_weda-fn-upload-result__status", children: [_jsx("i", { className: "wedatea2td-icon wedatea2td-icon-plus", role: "img", "aria-label": "plus" }), _jsx("span", { className: "wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset", children: btnTitle })] })] }) })))] })] }) }));
57
+ className: `_weda-fn-upload-result__item weda-uploader-btn__box _weda-fn-upload-result__item--upload ${imgTypeCls}`, onClick: () => {
58
+ var _a;
59
+ (_a = uploadRef === null || uploadRef === void 0 ? void 0 : uploadRef.current) === null || _a === void 0 ? void 0 : _a.upload();
60
+ }, children: [imgTypeCls, _jsxs("div", { className: "_weda-fn-upload-result__status", children: [_jsx("i", { className: "wedatea2td-icon wedatea2td-icon-plus", role: "img", "aria-label": "plus" }), _jsx("span", { className: "wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset", children: btnTitle })] })] })))] })] }) }) }));
131
61
  }
132
62
  export const TcbImage = (props) => {
133
- const { fileID, tempFile = { progress: 100, loading: false, realUrl: null, tempUrl: null }, isZoom, imgTypeCls, previewIcon, actions, allFile = [], index, portalContainer, ...rest } = props;
134
- const { progress, loading, realUrl, tempUrl } = tempFile;
135
- const fileCloudID = (realUrl !== null && realUrl !== void 0 ? realUrl : tempUrl) || fileID;
63
+ const { fileID, tempFile = { progress: 100, loading: false, cloudId: null, tempUrl: null }, isZoom, imgTypeCls, previewIcon, actions, allFile = [], index, portalContainer, ...rest } = props;
64
+ const { progress, loading, cloudId, tempUrl } = tempFile;
65
+ const fileCloudID = (cloudId !== null && cloudId !== void 0 ? cloudId : tempUrl) || fileID;
136
66
  const [isError, setIsError] = React.useState(false);
137
67
  const { data: src, error: requestError } = useTempUrl(fileCloudID);
138
68
  const encodeSrc = encodeConvert(src);
@@ -152,7 +82,7 @@ export const TcbImage = (props) => {
152
82
  };
153
83
  if (!isZoom)
154
84
  return renderImg();
155
- const previewImageList = allFile.map((i) => i.realUrl || i.tempUrl);
85
+ const previewImageList = allFile.map((i) => i.cloudId || i.tempUrl);
156
86
  const previewProps = {
157
87
  index,
158
88
  'data-testid': 'uploaderpc_imgStyle',
@@ -1,4 +1,20 @@
1
+ import { TempFileProps } from './upload/index';
2
+ export declare const DEFAULT_UPLOAD_PATH = "weda-uploader";
1
3
  export declare const getBase64: (files: any) => Promise<any[]>;
2
4
  export declare const uploadTcbMulti: (files: any, props: any) => Promise<any[]>;
3
5
  export declare const filenameRegex: RegExp;
4
6
  export declare const checkAcceptedFiles: (file: any, acceptedFiles: any) => any;
7
+ export declare const checkBeforeUpload: ({ tempFile, files, accepts, maxSize, maxUploadCount }: {
8
+ tempFile: any;
9
+ files: any;
10
+ accepts: any;
11
+ maxSize: any;
12
+ maxUploadCount: any;
13
+ }) => boolean;
14
+ export declare const getPreviewFileMap: (previewFile: any) => any;
15
+ export declare const getInitTempFile: ({ value }: {
16
+ value?: any;
17
+ }) => TempFileProps[];
18
+ export declare const CLASS_PREFIX = "weda-uploader-pc";
19
+ export declare const IMAGE_TYPES: string[];
20
+ export declare const upload: (fileList: any, uploadInstance: any, allTempFile: any) => Promise<void>;
@@ -1,8 +1,9 @@
1
1
  import { compressImage } from './compress';
2
2
  import { getCloudInstance, getDefaultUploadPath } from '../../../utils/tcb';
3
3
  import { toBase64Uri } from '../../../utils/file2base64';
4
- import { randomStr } from '../../../utils/platform';
4
+ import { randomStr, alertErrorMessage } from '../../../utils/platform';
5
5
  import { errorHandler } from '../../../utils/error';
6
+ export const DEFAULT_UPLOAD_PATH = 'weda-uploader';
6
7
  export const getBase64 = (files) => {
7
8
  return Promise.all(files.map(async (item) => {
8
9
  let tempUrl = '';
@@ -35,13 +36,29 @@ export const uploadTcbMulti = async (files, props) => {
35
36
  return result;
36
37
  };
37
38
  export const filenameRegex = /[^a-zA-Z0-9\u4e00-\u9fff-*!_.]/g;
39
+ const sanitizeFilename = (filename, replacement = '') => {
40
+ return (filename
41
+ // 移除非法字符
42
+ // eslint-disable-next-line no-control-regex
43
+ .replace(/[<>.:"\\|?*\x00-\x1F]/g, replacement)
44
+ // 处理Windows保留文件名(CON, PRN等)
45
+ .replace(/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\..*)?$/i, replacement)
46
+ // 移除开头和结尾的点,空格,反斜杠(Windows不允许)
47
+ .replace(/^[. /]+/, '')
48
+ .replace(/[. /]+$/, '')
49
+ // 可选:限制长度
50
+ .slice(0, 255));
51
+ };
38
52
  const uploadToTcb = async (item, props) => {
39
53
  var _a;
40
- const { onUploadProgress, onUploadFinish, onUploadError } = props;
41
- const { file, uploadPath } = item;
54
+ const { onUploadProgress, onUploadFinish, onUploadError, uploadPath, customUploadPath } = props;
55
+ const { file } = item;
42
56
  try {
43
57
  const tcb = await getCloudInstance();
44
- const _uploadPath = getDefaultUploadPath(uploadPath);
58
+ let _uploadPath = getDefaultUploadPath(uploadPath);
59
+ if (customUploadPath) {
60
+ _uploadPath = `${_uploadPath}/${sanitizeFilename(customUploadPath, '')}}`;
61
+ }
45
62
  const cloudPath = `${_uploadPath}/${randomStr()}-${(_a = file === null || file === void 0 ? void 0 : file.name) === null || _a === void 0 ? void 0 : _a.replace(filenameRegex, '-')}`;
46
63
  const { fileID } = await tcb.uploadFile({
47
64
  cloudPath,
@@ -67,7 +84,7 @@ const uploadToTcb = async (item, props) => {
67
84
  ...item,
68
85
  progress: 100,
69
86
  loading: false,
70
- realUrl: fileID,
87
+ cloudId: fileID,
71
88
  };
72
89
  if (onUploadFinish) {
73
90
  onUploadFinish(fileItem);
@@ -109,3 +126,87 @@ export const checkAcceptedFiles = (file, acceptedFiles) => {
109
126
  }
110
127
  return true;
111
128
  };
129
+ export const checkBeforeUpload = ({ tempFile, files, accepts, maxSize, maxUploadCount }) => {
130
+ const isAccepted = files.every((i) => checkAcceptedFiles(i, accepts));
131
+ if (!isAccepted) {
132
+ alertErrorMessage({
133
+ message: `上传图片类型错误`,
134
+ icon: 'error',
135
+ });
136
+ return false;
137
+ }
138
+ if (files.some((f) => f.size > maxSize * 1024 * 1024)) {
139
+ alertErrorMessage({
140
+ message: `请上传不超过 ${maxSize}M 的图片`,
141
+ icon: 'error',
142
+ });
143
+ return false;
144
+ }
145
+ if (files.length > maxUploadCount) {
146
+ // 防止一下子选择过多文件
147
+ alertErrorMessage({
148
+ message: `最多只能上传${maxUploadCount}张图片,请重新选择`,
149
+ icon: 'error',
150
+ });
151
+ return false;
152
+ }
153
+ if ((tempFile === null || tempFile === void 0 ? void 0 : tempFile.length) + (files === null || files === void 0 ? void 0 : files.length) > maxUploadCount) {
154
+ alertErrorMessage({
155
+ message: `最多只能上传${maxUploadCount}张图片`,
156
+ icon: 'error',
157
+ });
158
+ return false;
159
+ }
160
+ return true;
161
+ };
162
+ export const getPreviewFileMap = (previewFile) => {
163
+ return previewFile.reduce((acc, obj) => {
164
+ acc[obj === null || obj === void 0 ? void 0 : obj.cloudId] = obj; // 使用 cloudId 作为新对象的 key
165
+ return acc;
166
+ }, {});
167
+ };
168
+ export const getInitTempFile = ({ value }) => {
169
+ const tempFile = value.map((i) => ({
170
+ key: randomStr(),
171
+ cloudId: i,
172
+ tempUrl: '',
173
+ progress: 100,
174
+ loading: false,
175
+ }));
176
+ return tempFile;
177
+ };
178
+ // 默认组件类前缀
179
+ export const CLASS_PREFIX = 'weda-uploader-pc';
180
+ // 默认图片类型
181
+ export const IMAGE_TYPES = [
182
+ 'image/jpg',
183
+ 'image/png',
184
+ 'image/tif',
185
+ 'image/bmp',
186
+ 'image/jpeg',
187
+ 'image/tiff',
188
+ 'image/gif',
189
+ ];
190
+ export const upload = async (fileList, uploadInstance, allTempFile) => {
191
+ const { config = {}, onComplete, onSuccess, onFail, onUploadProgress } = uploadInstance;
192
+ const { isCompressBeforeUpload, compressQuality, compressedHeight, compressedWidth } = config;
193
+ const result = await uploadTcbMulti(fileList, {
194
+ isCompressBeforeUpload,
195
+ compressedHeight,
196
+ compressedWidth,
197
+ compressQuality,
198
+ customUploadPath: config.customUploadPath,
199
+ uploadPath: DEFAULT_UPLOAD_PATH,
200
+ onUploadProgress: (item) => {
201
+ onUploadProgress(item);
202
+ },
203
+ onUploadFinish: (item) => {
204
+ onSuccess(item);
205
+ },
206
+ onUploadError: (err) => {
207
+ onFail(err);
208
+ },
209
+ });
210
+ const allFile = allTempFile.map((i) => result.find((j) => (j === null || j === void 0 ? void 0 : j.key) === (i === null || i === void 0 ? void 0 : i.key)) || i);
211
+ onComplete(allFile);
212
+ };
@@ -68,6 +68,7 @@ initialContent, placeholder, iconPack, maxSize, cloudPath, visible, }) {
68
68
  'is-disabled': disabled,
69
69
  'is-readonly': readOnly,
70
70
  });
71
+ const [ready, setReady] = React.useState(false);
71
72
  const [, setRandomId] = React.useState('');
72
73
  const [editorHeight, setEditorHeight] = React.useState(0);
73
74
  const [syncedValue] = useSyncValue(xss(value, getWhitelist()));
@@ -266,6 +267,7 @@ initialContent, placeholder, iconPack, maxSize, cloudPath, visible, }) {
266
267
  setEditorHeight(((_a = toolbarDomRef === null || toolbarDomRef === void 0 ? void 0 : toolbarDomRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0);
267
268
  });
268
269
  ref.current.editor = editor;
270
+ setReady(true);
269
271
  return () => {
270
272
  editor.destroy();
271
273
  };
@@ -316,7 +318,7 @@ initialContent, placeholder, iconPack, maxSize, cloudPath, visible, }) {
316
318
  }
317
319
  }, 0);
318
320
  }
319
- }, [syncedValue, ref.current.editor]);
321
+ }, [syncedValue, ref.current.editor, ready]);
320
322
  React.useEffect(() => {
321
323
  var _a;
322
324
  setEditorHeight(((_a = toolbarDomRef === null || toolbarDomRef === void 0 ? void 0 : toolbarDomRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) || 0);
@@ -38,7 +38,7 @@ alt = '[加载失败]', gutter = 8, height = 100, width = 100, events = emptyObj
38
38
  onLoad: () => setSuccessList((list) => [...list, d]),
39
39
  onError: () => setErrorList((list) => [...list, d]),
40
40
  portalContainer,
41
- allFile: values === null || values === void 0 ? void 0 : values.map((d) => ({ realUrl: d })),
41
+ allFile: values === null || values === void 0 ? void 0 : values.map((d) => ({ cloudId: d })),
42
42
  index: i,
43
43
  };
44
44
  return (_jsx("div", { className: `${CLASS_PREFIX}__image-box`, style: boxStyle, title: d, children: _jsx(TcbImage, { ...imgProps }) }, `${d}-${i}`));
@@ -9,13 +9,11 @@ import { X_RUNTIME_DEFAULT } from '../../../configs/type-utils/x-runtime-default
9
9
  */
10
10
  export function WdAd(props) {
11
11
  const { className, id, style, adType: _adType = X_RUNTIME_DEFAULT.adType, gridCount: _gridCount = X_RUNTIME_DEFAULT.gridCount, } = props;
12
- const adType = ['banner', 'video', 'grid'].includes(_adType)
13
- ? _adType
14
- : 'banner';
12
+ const adType = ['banner', 'video', 'grid', 'rewardedVideoAd'].includes(_adType) ? _adType : 'banner';
15
13
  const gridCount = _gridCount == 8 ? 8 : 5;
16
14
  const { classPrefix } = useConfig();
17
15
  const canPreview = useCanPreview();
18
16
  if (!canPreview)
19
17
  return null;
20
- return (_jsx(ConfigProvider, { classPrefix: "wedatea2td", children: _jsx(Bubble, { placement: "auto", openDelay: 300, content: _jsxs(_Fragment, { children: ["\u8BE5\u7EC4\u4EF6\u5FC5\u987B\u5728\u5C0F\u7A0B\u5E8F\u771F\u5B9E\u73AF\u5883\u4F7F\u7528\u624D\u80FD\u591F\u770B\u5230\u5B9E\u9645\u6548\u679C\u3002", _jsx("br", {}), "\u8BF7\u9075\u5FAA\u5FAE\u4FE1\u5E7F\u544A\u7EC4\u4EF6\u5E94\u7528\u89C4\u8303\uFF0C\u5426\u5219\u53EF\u80FD\u5BFC\u81F4\u5C0F\u7A0B\u5E8F\u5BA1\u6838\u5931\u8D25\u3002"] }), children: _jsxs("div", { className: `${classPrefix}-ad ${classPrefix}-ad--${adType} ${className}`, id: id, style: style, children: [adType === 'banner' && _jsx(BannerAd, {}), adType === 'video' && _jsx(VideoAd, {}), adType === 'grid' && _jsx(GridAd, { gridCount: gridCount })] }) }) }));
18
+ return (_jsx(ConfigProvider, { classPrefix: "wedatea2td", children: _jsx(Bubble, { placement: "auto", openDelay: 300, content: _jsxs(_Fragment, { children: ["\u8BE5\u7EC4\u4EF6\u5FC5\u987B\u5728\u5C0F\u7A0B\u5E8F\u771F\u5B9E\u73AF\u5883\u4F7F\u7528\u624D\u80FD\u591F\u770B\u5230\u5B9E\u9645\u6548\u679C\u3002", _jsx("br", {}), "\u8BF7\u9075\u5FAA\u5FAE\u4FE1\u5E7F\u544A\u7EC4\u4EF6\u5E94\u7528\u89C4\u8303\uFF0C\u5426\u5219\u53EF\u80FD\u5BFC\u81F4\u5C0F\u7A0B\u5E8F\u5BA1\u6838\u5931\u8D25\u3002"] }), children: _jsxs("div", { className: `${classPrefix}-ad ${classPrefix}-ad--${adType} ${className}`, id: id, style: style, children: [adType === 'banner' && _jsx(BannerAd, {}), ['rewardedVideoAd', 'video'].includes(adType) && _jsx(VideoAd, {}), adType === 'grid' && _jsx(GridAd, { gridCount: gridCount })] }) }) }));
21
19
  }
@@ -49,7 +49,7 @@ methodGetItem, paramGetItem, appCloud, isDataModel, allSelectFields = emptyObjec
49
49
  }
50
50
  return true;
51
51
  }, [_id, dataSourceName, formType, isDataModel, methodGetItem, paramGetItem]);
52
- const { querySuccess: triggerQuerySuccessEvent, queryEmpty, queryFail, } = eventsRef.current;
52
+ const { querySuccess: triggerQuerySuccessEvent, queryEmpty, queryFail } = eventsRef.current;
53
53
  // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 试了一下大概300 -400毫秒
54
54
  const querySuccess = useDebouncedCallback(triggerQuerySuccessEvent, 500);
55
55
  const { data: remoteValue, error, isLoading, mutate, } = useSWR(() => {
@@ -83,7 +83,7 @@ methodGetItem, paramGetItem, appCloud, isDataModel, allSelectFields = emptyObjec
83
83
  };
84
84
  }, async (params) => {
85
85
  var _a, _b, _c, _d;
86
- const { dataSourceName, _id, isDataModel, allSelectFields, value, datasourceType, } = params;
86
+ const { dataSourceName, _id, isDataModel, allSelectFields, value, datasourceType } = params;
87
87
  if (datasourceType === 'expression') {
88
88
  return value !== null && value !== void 0 ? value : {};
89
89
  }
@@ -185,15 +185,9 @@ const SINGLE_SELECT_FORMATS = [
185
185
  const MULTI_SELECT_FORMATS = ['many-many', 'one-many'];
186
186
  export function useInitValueFromRemote(dataSourceType, dataSourceProfile, fetchedInitialValues) {
187
187
  return useSWR(() => {
188
- if ((dataSourceType === 'expression' || dataSourceProfile) &&
189
- fetchedInitialValues) {
188
+ if ((dataSourceType === 'expression' || dataSourceProfile) && fetchedInitialValues) {
190
189
  logger.debug('datasourceProfile', dataSourceProfile, fetchedInitialValues, dataSourceType);
191
- return [
192
- 'useInitValueFromRemote',
193
- dataSourceType,
194
- dataSourceProfile,
195
- fetchedInitialValues,
196
- ];
190
+ return ['useInitValueFromRemote', dataSourceType, dataSourceProfile, fetchedInitialValues];
197
191
  }
198
192
  return null;
199
193
  }, () => {
@@ -205,8 +199,7 @@ export function useInitValueFromRemote(dataSourceType, dataSourceProfile, fetche
205
199
  var _a, _b, _c;
206
200
  const format = (_c = (_b = (_a = dataSourceProfile.schema) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b[field]) === null || _c === void 0 ? void 0 : _c.format;
207
201
  acc[field] = fetchedInitialValues[field];
208
- if ([...SINGLE_SELECT_FORMATS, 'father-son'].includes(format) &&
209
- fetchedInitialValues[field]['_id']) {
202
+ if ([...SINGLE_SELECT_FORMATS, 'father-son'].includes(format) && fetchedInitialValues[field]['_id']) {
210
203
  acc[field] = fetchedInitialValues[field]['_id'];
211
204
  }
212
205
  if (MULTI_SELECT_FORMATS.includes(format)) {
@@ -227,12 +220,7 @@ export function useRemoteParamsFromValue({ dataSourceProfile, formData, formType
227
220
  if (!dataSourceProfile || !formData) {
228
221
  return null;
229
222
  }
230
- return [
231
- 'useRemoteParamsFromValueParams',
232
- dataSourceProfile,
233
- formType,
234
- formData,
235
- ];
223
+ return ['useRemoteParamsFromValueParams', dataSourceProfile, formType, formData];
236
224
  }, () => {
237
225
  const data = Object.keys(formData).reduce((acc, cur) => {
238
226
  var _a, _b, _c, _d;
@@ -244,6 +232,18 @@ export function useRemoteParamsFromValue({ dataSourceProfile, formData, formType
244
232
  if (MULTI_SELECT_FORMATS.includes(format)) {
245
233
  acc[cur] = (_d = acc[cur]) === null || _d === void 0 ? void 0 : _d.map((_id) => ({ _id }));
246
234
  }
235
+ if ('x-json' === format && typeof formData[cur] === 'string') {
236
+ try {
237
+ acc[cur] = formData[cur] ? JSON.parse(formData[cur]) : null;
238
+ }
239
+ catch (error) {
240
+ const err = new WdCompError(`字段 ${cur} 的 JSON 格式错误,请检查`, {
241
+ code: 'WdForm.submit.jsonParse',
242
+ original: error,
243
+ });
244
+ console.warn(err.code, err);
245
+ }
246
+ }
247
247
  return acc;
248
248
  }, {});
249
249
  const result = {
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /* eslint-disable @typescript-eslint/no-magic-numbers */
3
- import { forwardRef, useImperativeHandle, useEffect, useState, useCallback, } from 'react';
3
+ import { forwardRef, useImperativeHandle, useEffect, useState, useCallback } from 'react';
4
4
  import classNames from '../../utils/classnames';
5
5
  import { useConfig } from '../../utils/config-context';
6
6
  import { usePlatform } from '../../utils/platform';
7
- let timer = null;
7
+ let timer = {};
8
8
  const MASK_SHOW_TIME = 200;
9
9
  const ESC_KEYBOARD_NUM = 27;
10
10
  export const WdModal = forwardRef(function WdModal(props, ref) {
@@ -40,14 +40,14 @@ export const WdModal = forwardRef(function WdModal(props, ref) {
40
40
  const dealShow = (isOpen) => {
41
41
  setIsBdShow(isOpen);
42
42
  setIsMaskShow(!isOpen);
43
- timer && clearTimeout(timer);
43
+ timer[id] && clearTimeout(timer[id]);
44
44
  if (isOpen) {
45
45
  setMaskPreToShow(true);
46
46
  }
47
47
  else {
48
48
  // 延迟控制遮罩层消失,为了动画效果
49
49
  // eslint-disable-next-line rulesdir/no-timer
50
- timer = setTimeout(() => {
50
+ timer[id] = setTimeout(() => {
51
51
  setMaskPreToShow(false);
52
52
  }, MASK_SHOW_TIME);
53
53
  }
@@ -88,8 +88,10 @@ export const WdModal = forwardRef(function WdModal(props, ref) {
88
88
  }
89
89
  return () => {
90
90
  window === null || window === void 0 ? void 0 : window.removeEventListener('keydown', escKeyDown);
91
+ timer[id] && clearTimeout(timer[id]);
92
+ timer = {};
91
93
  };
92
- }, [escKeyDown, platform, props.closeType]);
94
+ }, [escKeyDown, id, platform, props.closeType]);
93
95
  // Widget API,挂载组件只读属性和组件方法
94
96
  useImperativeHandle(ref, () => {
95
97
  return {
@@ -121,9 +123,7 @@ export const WdModal = forwardRef(function WdModal(props, ref) {
121
123
  center_pc: !(style === null || style === void 0 ? void 0 : style.width) ? '680px' : 'auto',
122
124
  }[`${positionInner || 'bottom'}_${platform}`],
123
125
  };
124
- if (props.template === 'activity' &&
125
- platform === 'pc' &&
126
- positionInner === 'center') {
126
+ if (props.template === 'activity' && platform === 'pc' && positionInner === 'center') {
127
127
  styleList.width = '312px';
128
128
  delete styleList.minWidth;
129
129
  }
@@ -138,12 +138,9 @@ export const WdModal = forwardRef(function WdModal(props, ref) {
138
138
  }
139
139
  }, children: _jsxs("div", { style: { ...styleList, ...style }, className: classNames(modalBdClasses), onClick: (e) => {
140
140
  e.stopPropagation();
141
- }, children: [_jsx("div", { className: `${classPrefix}-modal-bd__hd`, style: headerFooterStlye, children: props.headerSlot }), _jsx("div", { className: `${classPrefix}-modal-bd__main`, children: props.contentSlot }), _jsx("div", { className: `${classPrefix}-modal-bd__ft ${['confirm', 'notice'].includes(props.template) &&
142
- platform === 'h5'
141
+ }, children: [_jsx("div", { className: `${classPrefix}-modal-bd__hd`, style: headerFooterStlye, children: props.headerSlot }), _jsx("div", { className: `${classPrefix}-modal-bd__main`, children: props.contentSlot }), _jsx("div", { className: `${classPrefix}-modal-bd__ft ${['confirm', 'notice'].includes(props.template) && platform === 'h5'
143
142
  ? `${classPrefix}-modal-bd__ft-text-btn`
144
- : ''} ${props.template === 'notice' && platform === 'h5'
145
- ? `${classPrefix}-modal-bd__ft-text-btn--vertical`
146
- : ''}`, style: headerFooterStlye, children: props.footerSlot })] }) })] }));
143
+ : ''} ${props.template === 'notice' && platform === 'h5' ? `${classPrefix}-modal-bd__ft-text-btn--vertical` : ''}`, style: headerFooterStlye, children: props.footerSlot })] }) })] }));
147
144
  };
148
145
  return (_jsx("div", { id: id, className: classNames(classes, className), style: { display: (style === null || style === void 0 ? void 0 : style.display) || 'block' }, "data-testid": "wd-modal-test", children: maskPreToShow && renderNode() }));
149
146
  });
@@ -1,28 +1,33 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { forwardRef, useMemo, useRef } from 'react';
2
+ import { forwardRef, useMemo, useRef, useState } from 'react';
3
3
  import { useFormInputTrait } from '../../components/form-input-hooks';
4
4
  import { WdFormItem } from '../wd-form-item';
5
5
  import Uploader from '../form/uploader';
6
6
  import { emptyObject } from '../../utils/constant';
7
7
  import { convertSingleValue } from '../../utils/tool';
8
+ import { useSetWidgetApi } from '../../utils/widget-api/use-set-widget-api';
8
9
  import { X_RUNTIME_DEFAULT } from '../../../configs/type-utils/x-runtime-default';
9
10
  import './style';
11
+ import { Upload } from '../form/uploader/upload/index';
10
12
  /**
11
13
  * 图片上传-标准化
12
14
  */
13
15
  export const WdUploadImage = forwardRef(function WdUploadImage(props, ref) {
14
16
  const { classRoot = 'upload-image', showShape = X_RUNTIME_DEFAULT.showShape, acceptTypes = X_RUNTIME_DEFAULT.acceptTypes, maxSize = X_RUNTIME_DEFAULT.maxSize, single = X_RUNTIME_DEFAULT.single, maxUploadCount = X_RUNTIME_DEFAULT.maxUploadCount, events = emptyObject, isCompressBeforeUpload = false,
15
17
  // eslint-disable-next-line @typescript-eslint/no-magic-numbers
16
- compressQuality = 70, compressedHeight = 0, compressedWidth = 0, sourceType = 'both', tips, callbacks, } = props;
18
+ compressQuality = 70, compressedHeight = 0, compressedWidth = 0, sourceType = 'both', tips, callbacks, template = 'normal', children, } = props;
17
19
  // 强制转换初始值
18
20
  const initRef = useRef(false);
21
+ const uploadRef = useRef(null);
19
22
  const formValue = useMemo(() => {
20
23
  if (initRef.current)
21
24
  return props.value;
22
25
  initRef.current = true;
23
26
  return convertSingleValue(props.value, single);
24
27
  }, [props.value, single]);
25
- const traitProps = { ...props, value: formValue, inputRef: ref };
28
+ const [innerHandle, setInnerHandle] = useState({});
29
+ const [uploadHandle, setUploadHandle] = useState({});
30
+ const traitProps = { ...props, value: formValue, inputRef: ref, setInnerHandle };
26
31
  const trait = useFormInputTrait(traitProps);
27
32
  const { value, onChange, disabled, readOnly, visible } = trait;
28
33
  const formItemProps = {
@@ -32,7 +37,12 @@ export const WdUploadImage = forwardRef(function WdUploadImage(props, ref) {
32
37
  readOnly: false,
33
38
  size: 'md',
34
39
  };
40
+ useSetWidgetApi(() => ({
41
+ ...innerHandle,
42
+ ...uploadHandle,
43
+ }), [innerHandle, uploadHandle], ref);
44
+ const multiple = !single;
35
45
  if (!visible)
36
46
  return null;
37
- return (_jsx(WdFormItem, { ...formItemProps, children: _jsx(Uploader, { events: events, labelVisible: false, acceptTypes: acceptTypes, defaultValue: value, maxSize: maxSize, maxUploadCount: maxUploadCount, single: single, tips: tips, showShape: showShape, readOnly: readOnly, disabled: disabled, decorator: null, onChange: onChange, isCompressBeforeUpload: isCompressBeforeUpload, compressQuality: compressQuality, compressedHeight: compressedHeight, compressedWidth: compressedWidth, sourceType: sourceType, callbacks: callbacks }) }));
47
+ return (_jsx(WdFormItem, { ...formItemProps, children: template === 'custom' ? (_jsx(Upload, { events: events, acceptTypes: acceptTypes, maxSize: maxSize, maxUploadCount: maxUploadCount, readOnly: readOnly, disabled: disabled, isCompressBeforeUpload: isCompressBeforeUpload, compressQuality: compressQuality, compressedHeight: compressedHeight, compressedWidth: compressedWidth, callbacks: callbacks, value: value, multiple: multiple, capture: sourceType === 'camera' ? 'capture' : null, onChange: onChange, ref: uploadRef, setUploadHandle: setUploadHandle, children: children })) : (_jsx(Uploader, { events: events, labelVisible: false, acceptTypes: acceptTypes, defaultValue: value, maxSize: maxSize, maxUploadCount: maxUploadCount, single: single, tips: tips, showShape: showShape, readOnly: readOnly, disabled: disabled, decorator: null, onChange: onChange, isCompressBeforeUpload: isCompressBeforeUpload, compressQuality: compressQuality, compressedHeight: compressedHeight, compressedWidth: compressedWidth, sourceType: sourceType, callbacks: callbacks, setUploadHandle: setUploadHandle })) }));
38
48
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/weda-ui",
3
- "version": "3.16.0",
3
+ "version": "3.17.1",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index",
6
6
  "miniprogram": "mpdist",
@@ -85,7 +85,7 @@
85
85
  "description": "腾讯云微搭低代码组件库模板",
86
86
  "dependencies": {
87
87
  "@antv/g6": "^4.8.5",
88
- "@cloudbase/weda-client": "^1.1.26",
88
+ "@cloudbase/weda-client": "^1.1.27",
89
89
  "@codemirror/autocomplete": "^6.16.0",
90
90
  "@codemirror/lang-javascript": "^6.2.2",
91
91
  "@codemirror/lang-json": "^6.0.1",
@@ -147,9 +147,9 @@
147
147
  "@babel/preset-env": "^7.22.15",
148
148
  "@babel/preset-react": "^7.22.15",
149
149
  "@babel/preset-typescript": "^7.22.15",
150
- "@cloudbase/cals": "^1.2.13",
151
- "@cloudbase/lowcode-cli": "^0.22.1",
152
- "@cloudbase/weda-cloud-sdk": "^1.0.97",
150
+ "@cloudbase/cals": "^1.2.14",
151
+ "@cloudbase/lowcode-cli": "^0.22.2",
152
+ "@cloudbase/weda-cloud-sdk": "^1.0.99",
153
153
  "@commitlint/cli": "^16.0.2",
154
154
  "@commitlint/config-conventional": "^17.7.0",
155
155
  "@craco/craco": "^7.1.0",