@hzab/form-render 1.7.16 → 1.7.18
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.
- package/CHANGELOG.md +9 -1
- package/README.md +62 -3
- package/docs/README.md +21 -0
- package/docs/components/ArrayCards.md +68 -0
- package/docs/components/ArrayTable.md +111 -0
- package/docs/components/CheckboxWithTip.md +43 -0
- package/docs/components/DatePicker.md +54 -0
- package/docs/components/LocationListPicker.md +41 -0
- package/docs/components/LocationPicker.md +67 -0
- package/docs/components/PersonnelSelect.md +77 -0
- package/docs/components/RadioGroupWithTip.md +43 -0
- package/docs/components/RichEditor.md +94 -0
- package/docs/components/Text.md +26 -0
- package/docs/components/TreeCheckbox.md +52 -0
- package/{src/components/Upload/README.md → docs/components/Upload.md} +14 -1
- package/docs/components/UserSelect.md +59 -0
- package/package.json +11 -2
- package/src/components/LocationListPicker/index.tsx +1 -1
- package/src/components/LocationPicker/Map/AMap/common/loader.ts +2 -3
- package/src/components/Upload/common/handleIOFileList.ts +4 -40
- package/src/components/Upload/common/utils.js +3 -2
- package/src/components/Upload/uploader-input.jsx +1 -2
- package/src/components/Upload/uploader.jsx +71 -6
- package/src/components/LocationPicker/README.md +0 -44
- package/src/components/RichEditor/README.md +0 -82
- package/src/components/TreeCheckbox/README.md +0 -11
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# RichEditor
|
|
2
|
+
|
|
3
|
+
基于 wangEditor 的富文本编辑器,支持 OSS / 私有化上传。Schema 中可使用 `RichEditor` 或别名 `Editor`。
|
|
4
|
+
|
|
5
|
+
## PC 使用前安装依赖
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @wangeditor/editor-for-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Schema 示例
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"x-component": "RichEditor",
|
|
16
|
+
"x-component-props": {
|
|
17
|
+
"height": "400px",
|
|
18
|
+
"uploadMode": "oss",
|
|
19
|
+
"toolbarConfig": {},
|
|
20
|
+
"editorConfig": {
|
|
21
|
+
"placeholder": "请输入内容..."
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
独立使用:
|
|
28
|
+
|
|
29
|
+
```jsx
|
|
30
|
+
import { RichEditor } from "@hzab/form-render/src/components";
|
|
31
|
+
import { useRef } from "react";
|
|
32
|
+
|
|
33
|
+
export default function Demo() {
|
|
34
|
+
const editorRef = useRef();
|
|
35
|
+
return <RichEditor ref={editorRef} height="400px" />;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
向富文本 set 内容:`editorRef.current.setEditorContent(HtmlString)`
|
|
40
|
+
|
|
41
|
+
获取富文本当前内容:`editorRef.current.getEditorContent()`
|
|
42
|
+
|
|
43
|
+
### RichEditor Attributes
|
|
44
|
+
|
|
45
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
46
|
+
| ----------------- | ----------------------- | ---- | ------ | ---- |
|
|
47
|
+
| value | string | 否 | - | 编辑器 HTML 内容 |
|
|
48
|
+
| onChange | Function | 否 | - | 内容变化回调 |
|
|
49
|
+
| height | string | 否 | - | 编辑器高度 |
|
|
50
|
+
| toolbarConfig | Partial\<IToolbarConfig\> | 否 | {} | 工具栏配置 |
|
|
51
|
+
| editorConfig | Partial\<IEditorConfig\> | 否 | `{ placeholder: '请输入内容...' }` | 编辑器配置 |
|
|
52
|
+
| uploadMode | string | 否 | oss | 上传模式:`oss` / `offline` 等 |
|
|
53
|
+
| ossOpt | Object | 否 | - | OSS 上传配置 |
|
|
54
|
+
| uploadParams | Object | 否 | {} | 上传入参 |
|
|
55
|
+
| ossServerUrl | string | 否 | 全局配置或 `/api/v1/user/oss/getWebOssConfig` | 获取 OSS 配置接口 |
|
|
56
|
+
| ossUrl | string | 否 | 同 ossServerUrl | OSS 配置接口(兼容字段) |
|
|
57
|
+
| offlineServerUrl | string | 否 | - | 私有化上传接口 |
|
|
58
|
+
| offlinePreviewUrl | string | 否 | - | 私有化预览前缀 |
|
|
59
|
+
| customRequest | Function | 否 | - | 自定义上传请求 |
|
|
60
|
+
| zIndex | number | 否 | 9999 | 编辑器层级 |
|
|
61
|
+
|
|
62
|
+
图片上传可在 `editorConfig.MENU_CONF.uploadImage` 中配置,参考 [wangEditor 文档](https://www.wangeditor.com/v5/menu-config.html#upload-image)。
|
|
63
|
+
|
|
64
|
+
```jsx
|
|
65
|
+
editorConfig = {
|
|
66
|
+
MENU_CONF: {
|
|
67
|
+
uploadImage: {
|
|
68
|
+
server: "/api/upload",
|
|
69
|
+
fieldName: "your-custom-name",
|
|
70
|
+
maxFileSize: 1 * 1024 * 1024,
|
|
71
|
+
maxNumberOfFiles: 10,
|
|
72
|
+
allowedFileTypes: ["image/*"],
|
|
73
|
+
meta: { token: "xxx" },
|
|
74
|
+
headers: { Accept: "text/x-json" },
|
|
75
|
+
withCredentials: true,
|
|
76
|
+
timeout: 5 * 1000,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 移动端使用前安装依赖
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm install lib-flexible
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```jsx
|
|
89
|
+
import HandleMobile from "./components/handleMobileVw";
|
|
90
|
+
|
|
91
|
+
export default function Demo() {
|
|
92
|
+
return <HandleMobile content={HtmlString} />;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Text
|
|
2
|
+
|
|
3
|
+
只读文本展示组件,常用于 schema 合并、LocationListPicker 弹层等内部场景;也可在 schema 中直接使用。
|
|
4
|
+
|
|
5
|
+
## Schema 示例
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"x-component": "Text",
|
|
10
|
+
"x-component-props": {
|
|
11
|
+
"content": "静态文案",
|
|
12
|
+
"mode": "div"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
表单字段有值时优先展示 `value`,否则展示 `content`。
|
|
18
|
+
|
|
19
|
+
### Text Attributes
|
|
20
|
+
|
|
21
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
22
|
+
| --------- | ------ | ---- | ------ | ---- |
|
|
23
|
+
| value | any | 否 | - | 字段值,优先展示 |
|
|
24
|
+
| content | any | 否 | - | 无 value 时的静态内容 |
|
|
25
|
+
| mode | string | 否 | div | 渲染标签名;`normal` 或不传时为 `div`,也可设为 `span` / `p` 等 |
|
|
26
|
+
| className | string | 否 | - | 附加 class,根节点带 `formily-text` |
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# TreeCheckbox
|
|
2
|
+
|
|
3
|
+
树形多选复选框,支持按层级合并叶子节点,以及最外层 Tab 展示。
|
|
4
|
+
|
|
5
|
+
## Schema 示例
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"x-component": "TreeCheckbox",
|
|
10
|
+
"x-component-props": {
|
|
11
|
+
"mergeLeaf": true,
|
|
12
|
+
"mergeFullLeaf": true,
|
|
13
|
+
"tabBox": false,
|
|
14
|
+
"fieldNames": {
|
|
15
|
+
"label": "label",
|
|
16
|
+
"value": "value",
|
|
17
|
+
"children": "children"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"enum": [
|
|
21
|
+
{
|
|
22
|
+
"label": "一级",
|
|
23
|
+
"value": "1",
|
|
24
|
+
"children": [
|
|
25
|
+
{ "label": "二级-1", "value": "1-1" },
|
|
26
|
+
{ "label": "二级-2", "value": "1-2" }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
数据也可通过 `x-component-props.dataSource` 或 `field.dataSource` 传入。
|
|
34
|
+
|
|
35
|
+
### TreeCheckbox Attributes
|
|
36
|
+
|
|
37
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
38
|
+
| ------------- | ------- | ---- | -------------------------------------------------- | ---- |
|
|
39
|
+
| dataSource | Array | 否 | field.dataSource | 树数据 |
|
|
40
|
+
| mergeFullLeaf | boolean | 否 | true | 合并不存在 children 的层级 |
|
|
41
|
+
| mergeLeaf | boolean | 否 | true | 合并每一层级的叶子节点 |
|
|
42
|
+
| fieldNames | Object | 否 | `{ label, value, children }` | 自定义 options 中字段名 |
|
|
43
|
+
| disabled | boolean | 否 | false | 禁用状态 |
|
|
44
|
+
| readOnly | boolean | 否 | false | 只读状态 |
|
|
45
|
+
| tabBox | boolean | 否 | false | 最外层使用 tab |
|
|
46
|
+
| tabConfList | Array | 否 | - | tab 配置列表;存在时优先用于计算 tab 层级数 |
|
|
47
|
+
| tabLevel | number | 否 | - | tab 层级数(`tabBox === true` 时为 1) |
|
|
48
|
+
| labelKey | string | 否 | label | 兼容旧字段,后续废弃 |
|
|
49
|
+
| valueKey | string | 否 | value | 兼容旧字段,后续废弃 |
|
|
50
|
+
| childrenKey | string | 否 | children | 兼容旧字段,后续废弃 |
|
|
51
|
+
|
|
52
|
+
表单值为选中节点 `value` 组成的数组。
|
|
@@ -27,13 +27,26 @@
|
|
|
27
27
|
| ossServerUrl | string | 否 | - | 获取 oss 参数的接口,默认 /api/v1/user/oss/getWebOssConfig |
|
|
28
28
|
| ossOpt | Object | 否 | - | oss 上传的配置参数 |
|
|
29
29
|
| fileListConf | Object | 否 | {} | 结果数据配置 |
|
|
30
|
-
| previewConfig | Object | 否 | {} |
|
|
30
|
+
| previewConfig | Object | 否 | {} | 预览场景配置(见下表)。仅影响列表/弹窗预览,不进入 onChange / 表单提交 |
|
|
31
|
+
| previewBaseUrl | string | 否 | - | 仅预览使用的域名/路径前缀(糖衣)。与 `previewConfig.url` 并存时,以 `previewConfig.url` 为准;不进入表单提交 |
|
|
31
32
|
| onCountExceed | Function | 否 | - | 数量超出 maxCount 时的回调 |
|
|
32
33
|
| beforeUploadCheck | Function | 否 | - | 追加的 beforeUpload 检查,返回 Promise.reject() 进行拦截 |
|
|
33
34
|
| templateUrl | string | 否 | - | 模板下载的地址 |
|
|
34
35
|
| templateDownloadText | string | 否 | 模板下载 | 模板下载按钮的文案 |
|
|
35
36
|
| uploadParams | Object | 否 | {} | 文件上传接口入参 |
|
|
36
37
|
|
|
38
|
+
### previewConfig 预览配置
|
|
39
|
+
|
|
40
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
41
|
+
| ---- | ---- | ---- | ------ | ---- |
|
|
42
|
+
| url | string | 否 | - | 预览域名或路径前缀,如 `https://cdn.example.com`。相对路径会拼到此前缀后用于列表缩略图与弹窗预览 |
|
|
43
|
+
| query | object | 否 | - | 追加到预览地址的 query 对象,推荐写法,如 `{ loookType: 1 }` |
|
|
44
|
+
| search | string | 否 | - | `?` 后的原始字符串(可不含 `?`),会先解析再与 `query` 合并;同名键以 `query` 为准 |
|
|
45
|
+
|
|
46
|
+
兼容:把 `query` 写成字符串(如 `"loookType=1"`)时,组件会解析为 `search`,无需立刻改业务 schema。
|
|
47
|
+
|
|
48
|
+
> **边界**:`previewConfig.url` / `previewBaseUrl` 只用于上传列表视图与弹窗预览;`onChange` 与表单提交仍使用后端返回的相对/原始路径,不会提交拼接后的完整地址。
|
|
49
|
+
|
|
37
50
|
### fileListConf 结果数据配置
|
|
38
51
|
|
|
39
52
|
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# UserSelect
|
|
2
|
+
|
|
3
|
+
人员下拉选择器,基于 antd Select,支持头像、手机号、身份证号等扩展展示。
|
|
4
|
+
|
|
5
|
+
## Schema 示例
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"x-component": "UserSelect",
|
|
10
|
+
"x-component-props": {
|
|
11
|
+
"isAvatar": true,
|
|
12
|
+
"avatarSize": "default",
|
|
13
|
+
"configKey": {
|
|
14
|
+
"phoneKey": "phone",
|
|
15
|
+
"idCardKey": "idCard"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"enum": [
|
|
19
|
+
{
|
|
20
|
+
"label": "张三",
|
|
21
|
+
"value": "1",
|
|
22
|
+
"phone": "13800000000",
|
|
23
|
+
"idCard": "3301**********1234",
|
|
24
|
+
"avatar": "https://example.com/avatar.png"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
数据源也可通过 Formily `field.dataSource` 或 `x-component-props.options` 传入。
|
|
31
|
+
|
|
32
|
+
### UserSelect Attributes
|
|
33
|
+
|
|
34
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
35
|
+
| ---------- | -------- | ---- | ------- | ---- |
|
|
36
|
+
| options | Array | 否 | - | 下拉数据;也可使用 schema `enum` / `field.dataSource` |
|
|
37
|
+
| isAvatar | boolean | 否 | false | 是否显示头像 |
|
|
38
|
+
| avatarSize | AvatarSize | 否 | default | antd Avatar 尺寸 |
|
|
39
|
+
| configKey | Object | 否 | - | 自定义字段映射,见下表 |
|
|
40
|
+
| InfoRender | Function | 否 | - | 自定义 option 信息区渲染,入参为 option 对象 |
|
|
41
|
+
|
|
42
|
+
其余 props 透传 antd Select。
|
|
43
|
+
|
|
44
|
+
### configKey
|
|
45
|
+
|
|
46
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
47
|
+
| --------- | ------ | ---- | ------ | ---- |
|
|
48
|
+
| phoneKey | string | 否 | phone | 手机号字段名 |
|
|
49
|
+
| idCardKey | string | 否 | idCard | 身份证号字段名 |
|
|
50
|
+
|
|
51
|
+
### options 子项
|
|
52
|
+
|
|
53
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
54
|
+
| ------ | -------------- | ---- | ------ | ---- |
|
|
55
|
+
| label | string | 是 | - | 展示名称 |
|
|
56
|
+
| value | string\|number | 是 | - | 选项值 |
|
|
57
|
+
| avatar | string | 否 | - | 头像 URL |
|
|
58
|
+
| phone | string | 否 | - | 手机号(可被 configKey 覆盖) |
|
|
59
|
+
| idCard | string | 否 | - | 身份证号(可被 configKey 覆盖) |
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzab/form-render",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.18",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "webpack serve -c ./config/webpack.config.js --env local",
|
|
8
8
|
"build": "webpack -c ./config/webpack.config.js --env production",
|
|
9
|
+
"test": "vitest run",
|
|
10
|
+
"test:watch": "vitest",
|
|
11
|
+
"test:coverage": "vitest run --coverage",
|
|
9
12
|
"version:alpha": "npm version prerelease --preid=alpha",
|
|
10
13
|
"publish:alpha": "npm publish --tag alpha",
|
|
11
14
|
"version:beta": "npm version prerelease --preid=beta",
|
|
@@ -17,6 +20,7 @@
|
|
|
17
20
|
},
|
|
18
21
|
"files": [
|
|
19
22
|
"src",
|
|
23
|
+
"docs",
|
|
20
24
|
"CHANGELOG.md"
|
|
21
25
|
],
|
|
22
26
|
"keywords": [],
|
|
@@ -27,16 +31,21 @@
|
|
|
27
31
|
"@hzab/permissions": "^0.1.1",
|
|
28
32
|
"@hzab/utils": "^1.0.16",
|
|
29
33
|
"@hzab/webpack-config": "0.0.12",
|
|
34
|
+
"@testing-library/jest-dom": "^5.17.0",
|
|
35
|
+
"@testing-library/react": "^12.1.5",
|
|
36
|
+
"@testing-library/user-event": "^13.5.0",
|
|
30
37
|
"@types/react": "^17.0.62",
|
|
31
38
|
"@types/react-dom": "^17.0.20",
|
|
32
39
|
"antd": "^4.24.12",
|
|
33
40
|
"dayjs": "1.11.10",
|
|
34
41
|
"eslint": "^8.30.0",
|
|
42
|
+
"jsdom": "^30.0.1",
|
|
35
43
|
"less": "^4.1.3",
|
|
36
44
|
"react": "^17.0.2",
|
|
37
45
|
"react-dom": "^17.0.2",
|
|
38
46
|
"react-router-dom": "^6.8.1",
|
|
39
|
-
"typescript": "^4.9.4"
|
|
47
|
+
"typescript": "^4.9.4",
|
|
48
|
+
"vitest": "^4.1.10"
|
|
40
49
|
},
|
|
41
50
|
"peerDependencies": {
|
|
42
51
|
"@hzab/utils": ">=1.0.6",
|
|
@@ -55,7 +55,7 @@ export const LocationListPicker = observer((props) => {
|
|
|
55
55
|
// 取消监听
|
|
56
56
|
mapUtilsRef.current?.off("click", onMapClick);
|
|
57
57
|
mapUtilsRef.current?.off("dblclick", onMapDbClick);
|
|
58
|
-
mapDomRef.current
|
|
58
|
+
mapDomRef.current?.current?.removeEventListener?.("mousemove", onMouseMove);
|
|
59
59
|
};
|
|
60
60
|
}, []);
|
|
61
61
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import AMapLoader from "@amap/amap-jsapi-loader"
|
|
2
|
+
|
|
1
3
|
const defaultVersion = "2.0";
|
|
2
4
|
const defaultPlugins = ["AMap.Geocoder", "AMap.AutoComplete", "AMap.PolygonEditor", "AMap.PolylineEditor"];
|
|
3
5
|
|
|
@@ -33,9 +35,6 @@ function Loader(opt) {
|
|
|
33
35
|
|
|
34
36
|
window._AMapLoaderTemp.plugins = plugins ? [...defaultPlugins, ...(plugins || [])] : defaultPlugins;
|
|
35
37
|
|
|
36
|
-
// 不用地图组件时可以不安装 "@amap/amap-jsapi-loader"
|
|
37
|
-
const AMapLoader = require("@amap/amap-jsapi-loader");
|
|
38
|
-
|
|
39
38
|
window._AMapLoaderTemp.loading = true;
|
|
40
39
|
window._AMapLoaderTemp.promise = AMapLoader.load({
|
|
41
40
|
key: key || window._AMapLoaderTemp.key, // 申请好的Web端开发者Key,首次调用 load 时必填
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { getFileURL } from "@hzab/utils/src/file/file";
|
|
2
2
|
import { getFileType } from "@hzab/utils/src/file/fileType";
|
|
3
|
-
import { isBase64Str } from "@hzab/utils/src/base64Str";
|
|
4
3
|
import { getUFileName, getFileName, getFullFileName, getFileExt } from "@hzab/utils/src/file/fileName";
|
|
5
|
-
import { getFileNameObj } from "@hzab/utils/src/upload/uploadUtils";
|
|
4
|
+
import { getFileNameObj, mergePreviewConfig } from "@hzab/utils/src/upload/uploadUtils";
|
|
6
5
|
import { nanoidNumALetters } from "@hzab/utils/src/nanoid";
|
|
7
6
|
import { getFormRenderPCGlobalServeConfig } from "../../../globalConfig";
|
|
8
|
-
import { addQuery } from "@hzab/utils/src/url"
|
|
7
|
+
import { addQuery } from "@hzab/utils/src/url";
|
|
8
|
+
|
|
9
|
+
export { mergePreviewConfig };
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -139,43 +140,6 @@ export const objStrToObj = function (objStr) {
|
|
|
139
140
|
return _objStr;
|
|
140
141
|
};
|
|
141
142
|
|
|
142
|
-
/**
|
|
143
|
-
* 预览 url 添加前缀
|
|
144
|
-
* @param {*} uri
|
|
145
|
-
* @param {*} previewConfig
|
|
146
|
-
* @returns
|
|
147
|
-
*/
|
|
148
|
-
export function mergePreviewConfig(uri, previewConfig) {
|
|
149
|
-
let _uri = uri;
|
|
150
|
-
let basePath = "";
|
|
151
|
-
if (typeof _uri === "object") {
|
|
152
|
-
basePath = _uri.basePath;
|
|
153
|
-
_uri = _uri.previewUrl || _uri.url;
|
|
154
|
-
}
|
|
155
|
-
if (typeof _uri !== "string") {
|
|
156
|
-
return _uri;
|
|
157
|
-
}
|
|
158
|
-
_uri = _uri?.trim();
|
|
159
|
-
// base64 直接返回
|
|
160
|
-
if (isBase64Str(_uri)) {
|
|
161
|
-
return _uri;
|
|
162
|
-
}
|
|
163
|
-
const isUriPattern = /http[s]?:\/\/[^\s]+/.test(_uri);
|
|
164
|
-
const query = previewConfig?.query?.trim() ? "?" + previewConfig?.query?.trim() : "";
|
|
165
|
-
|
|
166
|
-
if (isUriPattern) {
|
|
167
|
-
// 源地址为 http 地址,直接拼接 query 参数
|
|
168
|
-
return `${_uri}${query}`;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (previewConfig) {
|
|
172
|
-
// 拼接前缀
|
|
173
|
-
return `${previewConfig?.url?.trim()}/${_uri}${query}`?.trim();
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return _uri;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
143
|
/**
|
|
180
144
|
* 子项数据归一化
|
|
181
145
|
* 字符串:url、base64
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { formatDirStr, mergeDirStr, handleMaxCount, mergePreviewConfig } from "@hzab/utils/upload/uploadUtils";
|
|
2
|
-
import { getFileURL } from "@hzab/utils/file/file";
|
|
1
|
+
import { formatDirStr, mergeDirStr, handleMaxCount, mergePreviewConfig } from "@hzab/utils/src/upload/uploadUtils";
|
|
2
|
+
import { getFileURL } from "@hzab/utils/src/file/file";
|
|
3
3
|
import { isBase64Str } from "@hzab/utils/src/base64Str";
|
|
4
4
|
import {
|
|
5
5
|
checkImageUrl,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
checkAudioUrl,
|
|
8
8
|
isValidMediaType,
|
|
9
9
|
checkUrlSuffix,
|
|
10
|
+
getFileType,
|
|
10
11
|
} from "@hzab/utils/src/file/fileType";
|
|
11
12
|
import { getArr } from "@hzab/utils/src/array";
|
|
12
13
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useMemo } from "react";
|
|
2
2
|
import { Button, Modal, message } from "antd";
|
|
3
|
+
import _ from "lodash";
|
|
3
4
|
|
|
4
5
|
import ItemList from "./components/ItemList";
|
|
5
6
|
|
|
@@ -9,8 +10,6 @@ import { handleOssUpload } from "./common/ossUpload";
|
|
|
9
10
|
|
|
10
11
|
import "./uploader.less";
|
|
11
12
|
|
|
12
|
-
const _ = require("lodash");
|
|
13
|
-
|
|
14
13
|
function Uploader(props) {
|
|
15
14
|
const {
|
|
16
15
|
name,
|
|
@@ -10,6 +10,7 @@ import { Button, Upload as AUpload, message } from "antd";
|
|
|
10
10
|
import React, { useEffect, useState, useMemo } from "react";
|
|
11
11
|
|
|
12
12
|
import { handleInputFileList, handleOutputFileList } from "./common/handleIOFileList";
|
|
13
|
+
import { mergePreviewConfig } from "@hzab/utils/src/upload/uploadUtils";
|
|
13
14
|
|
|
14
15
|
import PreviewModal, { hasPreviewRender, hasPreviewMedium } from "./components/PreviewModal";
|
|
15
16
|
import { getOssUploadRequest, getOfflineUploadRequest } from "./common/customRequest";
|
|
@@ -57,6 +58,8 @@ export function Uploader({ onChange, ...props }) {
|
|
|
57
58
|
isResRemoveArr = true,
|
|
58
59
|
/** 预览配置参数 */
|
|
59
60
|
previewConfig = {},
|
|
61
|
+
/** 仅预览使用的域名/路径前缀,不参与 onChange / 表单提交;优先级低于 previewConfig.url */
|
|
62
|
+
previewBaseUrl = getFormRenderPCGlobalServeConfig()?.previewBaseUrl || "",
|
|
60
63
|
onCountExceed,
|
|
61
64
|
templateUrl,
|
|
62
65
|
beforeUploadCheck,
|
|
@@ -65,10 +68,31 @@ export function Uploader({ onChange, ...props }) {
|
|
|
65
68
|
isFileJson = false,
|
|
66
69
|
thumbnailParams = { image_process: "resize,w_200" },
|
|
67
70
|
readPretty,
|
|
71
|
+
afterUpload
|
|
68
72
|
} = props;
|
|
69
73
|
const isPrivateStore =
|
|
70
74
|
props.uploadParams?.fileAcl === "private" || props.ossOpt?.signatureParams?.fileAcl === "private";
|
|
71
75
|
|
|
76
|
+
/** 预览前缀配置:previewConfig.url 优先,其次 previewBaseUrl;*/
|
|
77
|
+
const resolvedPreviewConfig = useMemo(() => {
|
|
78
|
+
const url = previewConfig?.url || previewBaseUrl;
|
|
79
|
+
const { query, search, ...rest } = previewConfig || {};
|
|
80
|
+
const isQueryObject = query && typeof query === "object";
|
|
81
|
+
const legacyQueryStr = typeof query === "string" ? query.trim() : "";
|
|
82
|
+
const resolvedSearch = (search || legacyQueryStr || "").replace(/^\?/, "") || undefined;
|
|
83
|
+
const resolvedQuery = isQueryObject ? query : undefined;
|
|
84
|
+
|
|
85
|
+
if (!url && !resolvedQuery && !resolvedSearch) {
|
|
86
|
+
return previewConfig || {};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
...rest,
|
|
90
|
+
url,
|
|
91
|
+
...(resolvedQuery ? { query: resolvedQuery } : {}),
|
|
92
|
+
...(resolvedSearch ? { search: resolvedSearch } : {}),
|
|
93
|
+
};
|
|
94
|
+
}, [previewConfig.url, previewConfig.query, previewConfig.search, previewBaseUrl]);
|
|
95
|
+
|
|
72
96
|
/**
|
|
73
97
|
* 数据格式配置
|
|
74
98
|
*/
|
|
@@ -96,6 +120,7 @@ export function Uploader({ onChange, ...props }) {
|
|
|
96
120
|
* @returns
|
|
97
121
|
*/
|
|
98
122
|
const handleChange = async ({ fileList, file, event }) => {
|
|
123
|
+
|
|
99
124
|
setFileList(fileList);
|
|
100
125
|
// 上传中不进行处理,结局 ossPromise 不存在的问题
|
|
101
126
|
if (file.status !== "done") {
|
|
@@ -103,6 +128,7 @@ export function Uploader({ onChange, ...props }) {
|
|
|
103
128
|
}
|
|
104
129
|
|
|
105
130
|
let _files = [...fileList];
|
|
131
|
+
|
|
106
132
|
// 取出异步 url
|
|
107
133
|
for (let i = 0; i < _files.length; i++) {
|
|
108
134
|
let _file = _files[i]?.originFileObj || _files[i];
|
|
@@ -132,10 +158,23 @@ export function Uploader({ onChange, ...props }) {
|
|
|
132
158
|
});
|
|
133
159
|
|
|
134
160
|
onChange && onChange?.(_files);
|
|
161
|
+
afterUpload && await afterUpload({
|
|
162
|
+
files: fileList,
|
|
163
|
+
urls: _files
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
setChecking(false);
|
|
167
|
+
|
|
135
168
|
};
|
|
136
169
|
|
|
170
|
+
|
|
137
171
|
useEffect(() => {
|
|
138
|
-
const list = handleInputFileList(value, {
|
|
172
|
+
const list = handleInputFileList(value, {
|
|
173
|
+
...fileListConf,
|
|
174
|
+
maxCount,
|
|
175
|
+
previewConfig: resolvedPreviewConfig,
|
|
176
|
+
thumbnailParams,
|
|
177
|
+
});
|
|
139
178
|
|
|
140
179
|
async function handlePreview() {
|
|
141
180
|
await handlePreviewUrls(list, {
|
|
@@ -150,7 +189,27 @@ export function Uploader({ onChange, ...props }) {
|
|
|
150
189
|
} else {
|
|
151
190
|
setFileList(list);
|
|
152
191
|
}
|
|
153
|
-
}, [value]);
|
|
192
|
+
}, [value, resolvedPreviewConfig]);
|
|
193
|
+
|
|
194
|
+
/** 仅用于列表展示:补齐 thumbUrl/previewUrl,不改动 url(提交仍用相对路径) */
|
|
195
|
+
const displayFileList = useMemo(() => {
|
|
196
|
+
if (!resolvedPreviewConfig?.url || !fileList?.length) {
|
|
197
|
+
return fileList;
|
|
198
|
+
}
|
|
199
|
+
return fileList.map((file) => {
|
|
200
|
+
if (!file || typeof file !== "object") {
|
|
201
|
+
return file;
|
|
202
|
+
}
|
|
203
|
+
// 用存储路径 url 拼前缀,避免已是完整 previewUrl 时语义混乱;无 url 时回退对象自身
|
|
204
|
+
const previewUrl = mergePreviewConfig(file.url || file, resolvedPreviewConfig);
|
|
205
|
+
const thumbUrl = file.thumbUrl ? mergePreviewConfig(file.thumbUrl, resolvedPreviewConfig) : previewUrl;
|
|
206
|
+
return {
|
|
207
|
+
...file,
|
|
208
|
+
previewUrl,
|
|
209
|
+
thumbUrl,
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
}, [fileList, resolvedPreviewConfig]);
|
|
154
213
|
|
|
155
214
|
const onRemove = (file) => {
|
|
156
215
|
const files = (fileList || []).filter((v) => v.url !== file.url);
|
|
@@ -206,7 +265,7 @@ export function Uploader({ onChange, ...props }) {
|
|
|
206
265
|
multiple: multiple,
|
|
207
266
|
listType: listType,
|
|
208
267
|
maxCount: maxCount,
|
|
209
|
-
fileList:
|
|
268
|
+
fileList: displayFileList,
|
|
210
269
|
onChange: handleChange,
|
|
211
270
|
disabled,
|
|
212
271
|
readOnly,
|
|
@@ -246,13 +305,16 @@ export function Uploader({ onChange, ...props }) {
|
|
|
246
305
|
return AUpload.LIST_IGNORE;
|
|
247
306
|
}
|
|
248
307
|
}
|
|
249
|
-
setChecking(false);
|
|
250
308
|
},
|
|
251
309
|
customRequest,
|
|
310
|
+
...(props || {}),
|
|
311
|
+
// 保证展示列表与预览逻辑不被 props 覆盖丢失
|
|
312
|
+
fileList: displayFileList,
|
|
252
313
|
onPreview(file) {
|
|
253
314
|
// TODO: 逻辑合并到数据处理中
|
|
254
315
|
const isShowPreview = hasPreviewRender(file) || hasPreviewMedium(props.accept);
|
|
255
|
-
|
|
316
|
+
// 预览出口统一走 mergePreviewConfig;提交仍使用 file.url 相对路径
|
|
317
|
+
const fileUrl = mergePreviewConfig(file.url || file, resolvedPreviewConfig);
|
|
256
318
|
if (isShowPreview) {
|
|
257
319
|
setPreviewFile({
|
|
258
320
|
...file,
|
|
@@ -283,6 +345,7 @@ export function Uploader({ onChange, ...props }) {
|
|
|
283
345
|
// },
|
|
284
346
|
...(props || {}),
|
|
285
347
|
};
|
|
348
|
+
|
|
286
349
|
const isShowUploadBtn = useMemo(() => {
|
|
287
350
|
if (disabled || readOnly || readPretty) {
|
|
288
351
|
return null;
|
|
@@ -301,6 +364,8 @@ export function Uploader({ onChange, ...props }) {
|
|
|
301
364
|
)
|
|
302
365
|
) : null;
|
|
303
366
|
}, [maxCount, fileList, disabled, readOnly, readPretty, checking, btnText, listType]);
|
|
367
|
+
|
|
368
|
+
|
|
304
369
|
return (
|
|
305
370
|
<>
|
|
306
371
|
<AUpload className="oss-uploader" {..._uploadProps}>
|
|
@@ -316,7 +381,7 @@ export function Uploader({ onChange, ...props }) {
|
|
|
316
381
|
accept={props?.accept}
|
|
317
382
|
setPreviewFile={setPreviewFile}
|
|
318
383
|
modalConf={props.modalConf}
|
|
319
|
-
previewConfig={
|
|
384
|
+
previewConfig={resolvedPreviewConfig}
|
|
320
385
|
/>
|
|
321
386
|
</>
|
|
322
387
|
);
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
## 使用前安装依赖
|
|
2
|
-
|
|
3
|
-
npm install @amap/amap-jsapi-loader
|
|
4
|
-
|
|
5
|
-
## 注意事项
|
|
6
|
-
|
|
7
|
-
- isObjectRes 在 @hzab/form-render0.5.0 版本中去除,结果全部存放在对象中
|
|
8
|
-
- changeMode 在 @hzab/form-render0.5.1 版本中去除,仅允许点击地图选点
|
|
9
|
-
|
|
10
|
-
## 引入
|
|
11
|
-
|
|
12
|
-
```jsx
|
|
13
|
-
import MapLocationPoint from "./mapLocationPoint";
|
|
14
|
-
|
|
15
|
-
export default function AMap(props) {
|
|
16
|
-
return <MapLocationPoint hasSearch={true}></MapLocationPoint>;
|
|
17
|
-
}
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
### InfoPanel Attributes
|
|
21
|
-
|
|
22
|
-
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
23
|
-
| ------------------ | ------- | ---- | --------- | ------------------------------------------------ |
|
|
24
|
-
| mode | string | 否 | dialog | 地图显示的类型, dialog 弹窗显示、 show 直接显示 |
|
|
25
|
-
| element | string | 否 | Polypoint | 地图绘制的元素名Polypoint&Polyline&Polygon |
|
|
26
|
-
| layout | string | 否 | ver | 选择器和地图的布局 hor 水平、 ver 垂直 |
|
|
27
|
-
| hasSearch | boolean | 否 | true | 是否允许搜索 |
|
|
28
|
-
| isAutoFixAddr | boolean | 否 | false | 打开地图时是否根据经纬度自动修正已填的地址 |
|
|
29
|
-
| lonKey | string | 否 | longitude | 经度字段 key |
|
|
30
|
-
| latKey | string | 否 | latitude | 维度字段 key |
|
|
31
|
-
| addrKey | string | 否 | address | 地址字段 key |
|
|
32
|
-
| isAutoSearch | boolean | 否 | false | 搜索框是否自动搜索 |
|
|
33
|
-
| markerIconConf | Object | 否 | - | markerIcon 配置对象 |
|
|
34
|
-
| icons | Object | 否 | - | icon 图片配置 |
|
|
35
|
-
| getCurPositionConf | Object | 否 | - | getCurrentPosition Config |
|
|
36
|
-
|
|
37
|
-
#### icons
|
|
38
|
-
|
|
39
|
-
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
40
|
-
| ------------ | ------ | ---- | ------ | ------------------------ |
|
|
41
|
-
| markerIcon | string | 否 | dialog | marker icon 图片地址 |
|
|
42
|
-
| pickerIcon | string | 否 | dialog | 选点 icon 图片地址或元素 |
|
|
43
|
-
| positionIcon | string | 否 | dialog | 定位 icon 图片地址或元素 |
|
|
44
|
-
| resetIcon | string | 否 | dialog | 重置 icon 图片地址或元素 |
|