@hzab/list-render 1.8.1 → 1.8.3-beta1
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 +11 -0
- package/README.md +30 -28
- package/package.json +3 -3
- package/src/DetailModal/index.jsx +112 -0
- package/src/DetailModal/index.less +2 -0
- package/src/FormModal/index.less +8 -0
- package/src/{form-dialog/index.jsx → FormModal/index.tsx} +56 -33
- package/src/common/handleQuerySchema.ts +75 -13
- package/src/common/utils.js +59 -5
- package/src/components/PrefixNode/index.less +9 -0
- package/src/components/PrefixNode/index.tsx +61 -0
- package/src/components/Tags/index.less +3 -0
- package/src/components/Tags/index.tsx +37 -0
- package/src/list-render.jsx +55 -40
- package/src/query-render/index.jsx +3 -2
- package/src/table-render/index.jsx +36 -4
- package/src/form-dialog/index.less +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
# @hzab/list-render@1.9.0
|
|
2
|
+
|
|
3
|
+
feat: 列表渲染支持 tag 模式、前缀 Node (前缀圆点)
|
|
4
|
+
feat: Switch 渲染模式优化,使用 前缀 Node (前缀圆点)
|
|
5
|
+
feat: 新增、编辑、详情弹窗支持抽屉模式
|
|
6
|
+
|
|
7
|
+
# @hzab/list-render@1.8.2
|
|
8
|
+
|
|
9
|
+
fix: query schema props scope 模式问题修复
|
|
10
|
+
fix: query allowClear 允许外部配置
|
|
11
|
+
|
|
1
12
|
# @hzab/list-render@1.6.2
|
|
2
13
|
|
|
3
14
|
fix: 监听 model query 更改
|
package/README.md
CHANGED
|
@@ -74,9 +74,11 @@ const listDM = useMemo(
|
|
|
74
74
|
| tableProps | Object | | {} | 直接传给 Table 的 props,相关 API 可直接参考 antd table 组件 |
|
|
75
75
|
| fetchOnEdit | Boolean | | true | 展示编辑弹框时,是否会调用一次详情接口进行回填;若为 false,则会使用表格列表接口返回的 row 数据进行回填 |
|
|
76
76
|
| fetchById | Boolean | | true | 编辑中的详情请求,是否使用 id 作为入参的 key |
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
77
|
+
| modalMode | string | | dialog | 新增/编辑表单、详情 展示模式: dialog drawer |
|
|
78
|
+
| modalConf | Object | | {} | modal/Drawer 配置对象 |
|
|
79
|
+
| modalDetailProps | Object | | {} | modal descriptions 配置对象 |
|
|
80
|
+
| modalFormProps | Object | | {} | modal/drawer fromRender 配置对象 |
|
|
81
|
+
| modalProps | Object | | {} | modal/drawer 配置对象 |
|
|
80
82
|
| schemaScope | Object | | {} | formRender schemaScope props |
|
|
81
83
|
| components | Object | | {} | formRender components props 自定义组件 |
|
|
82
84
|
| detailComponents | Object | | {} | descriptions components props 自定义组件 |
|
|
@@ -89,28 +91,29 @@ const listDM = useMemo(
|
|
|
89
91
|
| onCreateSuc | Function | | - | 新增成功返回的回调 |
|
|
90
92
|
| onEditSuc | Function | | - | 编辑成功返回的回调 |
|
|
91
93
|
| onDelSuc | Function | | - | 删除成功返回的回调 |
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
+
| onFormModalClose | Function | | - | 表单弹窗关闭回调 |
|
|
95
|
+
| modalFormMount | Function | | - | 新增、编辑弹窗 Form 渲染完成回调 |
|
|
94
96
|
| msgConf | Object | | {} | 新增、编辑、删除、列表查询,详情查询的报错 msg 提示设置 |
|
|
95
97
|
| i18n | Object | | {} | 文案配置 |
|
|
96
98
|
| queryFormInitialValues | Object | | {} | 列表上方查询 Form 默认值 |
|
|
97
99
|
| queryFormIsExtendModelQuery | Boolean | | false | 列表上方查询 Form 默认值是否继承 data-model.query 置 |
|
|
100
|
+
| useFormData | boolean | 否 | | 是否使用 form data 提交数据 |
|
|
98
101
|
|
|
99
102
|
- fetchOnEdit 展示编辑弹框时,是否会调用一次详情接口进行回填(某些场景下,列表接口只返回部分部分字段,只有详情接口会返回全部字段);若为 false,则会使用表格列表接口返回的 row 数据进行回填
|
|
100
103
|
|
|
101
104
|
#### tableConf
|
|
102
105
|
|
|
103
|
-
| 属性名称
|
|
104
|
-
|
|
|
105
|
-
| colConf
|
|
106
|
-
| rowSelection
|
|
107
|
-
| scroll
|
|
108
|
-
| expandable
|
|
109
|
-
| onRow
|
|
110
|
-
| orderColType
|
|
111
|
-
| orderColWidth
|
|
112
|
-
| tableEmptyValue
|
|
113
|
-
| isTableSortXIdex | Boolean
|
|
106
|
+
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
|
|
107
|
+
| ---------------- | ------------- | ---- | --------- | -------------------------------------------------------------------------------------------- |
|
|
108
|
+
| colConf | Object | | {} | 指定各列的配置(比如列宽),key 为字段的 name。可以指定名为 “\_$actions”的字段来设置“操作”列 |
|
|
109
|
+
| rowSelection | Object | | {} | 选择功能的配置。参考 antd table rowSelection 参数 |
|
|
110
|
+
| scroll | Object | | {} | 表格是否可滚动,也可以指定滚动区域的宽、高。参考 antd table scroll 参数 |
|
|
111
|
+
| expandable | Object | | {} | 配置展开属性。参考 antd table expandable 参数 |
|
|
112
|
+
| onRow | Object | | {} | 设置行属性。参考 antd table onRow 参数 |
|
|
113
|
+
| orderColType | string | | - | 序号列数据类型:page(按当前页的序号)、all(按所有页的序号) |
|
|
114
|
+
| orderColWidth | string/number | | - | 序号列 width 的参数 |
|
|
115
|
+
| tableEmptyValue | string/number | | undefined | table 列表空值展示数 |
|
|
116
|
+
| isTableSortXIdex | Boolean | | undefined | table 列表列排序是否按照 x-index 排序 |
|
|
114
117
|
|
|
115
118
|
##### tableConf.colConf[xxx]
|
|
116
119
|
|
|
@@ -159,7 +162,7 @@ const listDM = useMemo(
|
|
|
159
162
|
| ------------------ | -------- | ---- | ------ | ------------------------------------ |
|
|
160
163
|
| headerActionPrefix | Function | 否 | | 新增按钮左侧插槽 |
|
|
161
164
|
| headerActionSuffix | Function | 否 | | 新增按钮右侧插槽 |
|
|
162
|
-
| HeaderOthersSuffix | Function | 否 | | 表格和搜索项之间的插槽
|
|
165
|
+
| HeaderOthersSuffix | Function | 否 | | 表格和搜索项之间的插槽 |
|
|
163
166
|
| tableActionsSlot | Function | 否 | | 操作列插槽,会覆盖操作列 |
|
|
164
167
|
| actionPrefixSlot | Function | 否 | | 操作列 编辑按钮左侧插槽 |
|
|
165
168
|
| actionCenterSlot | Function | 否 | | 操作列 编辑、删除按钮中间插槽 |
|
|
@@ -203,7 +206,6 @@ const Slots = {
|
|
|
203
206
|
| cancelText | string | 否 | | 弹窗底部取消按钮文案 |
|
|
204
207
|
| footer | Array | 否 | | 自定义弹窗底部按钮 |
|
|
205
208
|
| beforeSubmit | Function | 否 | | 提交前的回调, return false; 表示拦截,不进行请求。 |
|
|
206
|
-
| useFormData | boolean | 否 | | 是否使用 form data 提交数据 |
|
|
207
209
|
|
|
208
210
|
#### paginationConf
|
|
209
211
|
|
|
@@ -223,16 +225,16 @@ const Slots = {
|
|
|
223
225
|
|
|
224
226
|
- 可使用 ref 获取并触发执行
|
|
225
227
|
|
|
226
|
-
| 函数名
|
|
227
|
-
|
|
|
228
|
-
| onSearch
|
|
229
|
-
| getList
|
|
230
|
-
| forceUpdate
|
|
231
|
-
|
|
|
232
|
-
| queryRef
|
|
233
|
-
| onCreate
|
|
234
|
-
| onEdit
|
|
235
|
-
| onDel
|
|
228
|
+
| 函数名 | 参数 | 说明 |
|
|
229
|
+
| ------------ | ----- | -------------------------------------------- |
|
|
230
|
+
| onSearch | query | 重置页码至 1,并刷新列表 |
|
|
231
|
+
| getList | query | 获取当前页列表数据 |
|
|
232
|
+
| forceUpdate | - | 强制重渲染列表,解决枚举数据渲染不正常的问题 |
|
|
233
|
+
| formModalRef | - | 新增、编辑 弹窗 form-modal 的 ref |
|
|
234
|
+
| queryRef | - | 筛选条件 query-render 的 ref |
|
|
235
|
+
| onCreate | - | 手动触发新增按钮相关操作 |
|
|
236
|
+
| onEdit | row | 手动触发编辑按钮相关操作 |
|
|
237
|
+
| onDel | row | 手动触发删除按钮相关操作 |
|
|
236
238
|
|
|
237
239
|
# Schema
|
|
238
240
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzab/list-render",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3-beta1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src",
|
|
6
6
|
"scripts": {
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"license": "ISC",
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@ant-design/icons": "^4.8.1",
|
|
23
|
-
"@hzab/data-model": "^1.
|
|
23
|
+
"@hzab/data-model": "^1.6.0",
|
|
24
24
|
"@hzab/form-render": "^1.1.5",
|
|
25
25
|
"@hzab/schema-descriptions": "^1.0.0",
|
|
26
|
-
"@hzab/webpack-config": "0.
|
|
26
|
+
"@hzab/webpack-config": "^0.7.2",
|
|
27
27
|
"@types/react": "^17.0.62",
|
|
28
28
|
"@types/react-dom": "^17.0.20",
|
|
29
29
|
"antd": "^4.24.12",
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { Modal, Drawer, Button } from "antd";
|
|
4
|
+
import Descriptions from "@hzab/schema-descriptions";
|
|
5
|
+
|
|
6
|
+
import "./index.less";
|
|
7
|
+
|
|
8
|
+
let _formData = null;
|
|
9
|
+
|
|
10
|
+
function DetailModal(props, parentRef) {
|
|
11
|
+
const { modalMode, Slots = {}, modalConf = {}, modalProps = {} } = props;
|
|
12
|
+
const [open, setOpen] = useState(false);
|
|
13
|
+
const [data, setData] = useState({});
|
|
14
|
+
const formRef = useRef();
|
|
15
|
+
function show(formData = props.formInitialValues) {
|
|
16
|
+
setOpen(true);
|
|
17
|
+
// 处理 formRef.current 为 undefined 的问题
|
|
18
|
+
setData(formData);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function close() {
|
|
22
|
+
props.onClose && props.onClose();
|
|
23
|
+
setOpen(false);
|
|
24
|
+
formRef.current?.formRender?.reset();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
useImperativeHandle(parentRef, () => ({
|
|
28
|
+
show,
|
|
29
|
+
close,
|
|
30
|
+
cancel: close,
|
|
31
|
+
formRef,
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
let footer = undefined;
|
|
35
|
+
const options = {
|
|
36
|
+
close,
|
|
37
|
+
form: formRef.current?.formRender,
|
|
38
|
+
scenario: "detail",
|
|
39
|
+
};
|
|
40
|
+
if (modalConf?.footer) {
|
|
41
|
+
footer = typeof modalConf?.footer === "function" ? modalConf.footer({ ...options, options }) : modalConf?.footer;
|
|
42
|
+
} else {
|
|
43
|
+
footer = [];
|
|
44
|
+
|
|
45
|
+
if (Slots.modalFooterPre) {
|
|
46
|
+
footer.push(<Slots.modalFooterPre key="pre" options={options} />);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
footer.push(
|
|
50
|
+
<Button key="confirm" onClick={close}>
|
|
51
|
+
{modalConf.okText || "关 闭"}
|
|
52
|
+
</Button>,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (Slots.modalFooterSuffix) {
|
|
56
|
+
footer.push(<Slots.modalFooterSuffix key="suffix" options={options} />);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 解决 show 函数中 formRef.current 为 undefined 的问题
|
|
62
|
+
*/
|
|
63
|
+
function didMount() {
|
|
64
|
+
props.modalFormMount && props.modalFormMount();
|
|
65
|
+
if (_formData) {
|
|
66
|
+
setData(_formData);
|
|
67
|
+
_formData = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const CModal = modalMode === "drawer" ? Drawer : Modal;
|
|
72
|
+
const _modalProps = {
|
|
73
|
+
className: "detail-modal",
|
|
74
|
+
wrapClassName: "detail-modal",
|
|
75
|
+
title: "详情",
|
|
76
|
+
visible: open,
|
|
77
|
+
open: open,
|
|
78
|
+
onClose: close,
|
|
79
|
+
onCancel: close,
|
|
80
|
+
footer: footer,
|
|
81
|
+
maskClosable: modalProps.maskClosable || false,
|
|
82
|
+
width: modalConf?.width ?? 720,
|
|
83
|
+
// 解决弹窗不销毁,表单远程数据没有更新的问题
|
|
84
|
+
destroyOnClose: true,
|
|
85
|
+
...modalProps,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<CModal {..._modalProps}>
|
|
90
|
+
<Descriptions
|
|
91
|
+
{...props.detailProps}
|
|
92
|
+
components={props.components}
|
|
93
|
+
schema={props.schema}
|
|
94
|
+
schemaScope={{
|
|
95
|
+
scenario: "detail",
|
|
96
|
+
...(props.schemaScope || {}),
|
|
97
|
+
}}
|
|
98
|
+
data={data}
|
|
99
|
+
/>
|
|
100
|
+
<DidMount didMount={didMount} />
|
|
101
|
+
</CModal>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function DidMount(props) {
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
props.didMount();
|
|
108
|
+
}, []);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export default forwardRef(DetailModal);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { forwardRef, useEffect, useImperativeHandle, useRef, useState, useMemo } from "react";
|
|
2
|
+
import _ from "lodash";
|
|
2
3
|
|
|
3
|
-
import { Modal, Button, message } from "antd";
|
|
4
|
+
import { Modal, Drawer, Button, message } from "antd";
|
|
4
5
|
|
|
5
6
|
import FormRender from "@hzab/form-render";
|
|
6
7
|
|
|
@@ -8,13 +9,29 @@ import "./index.less";
|
|
|
8
9
|
|
|
9
10
|
let _formData = null;
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
export interface IFormRender {
|
|
13
|
+
setValues: Function;
|
|
14
|
+
reset: Function;
|
|
15
|
+
validate: Function;
|
|
16
|
+
values: Object;
|
|
17
|
+
}
|
|
18
|
+
export interface IFormRef {
|
|
19
|
+
formRender: IFormRender;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 表单弹层,包含弹窗、抽屉两种模式
|
|
24
|
+
* @param props
|
|
25
|
+
* @param parentRef
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
export function FormModal(props, parentRef) {
|
|
29
|
+
const { modalMode, Slots = {}, modalConf = {}, modalProps = {} } = props;
|
|
13
30
|
const [loading, setLoading] = useState(false);
|
|
14
31
|
const [title, setTitle] = useState("新增");
|
|
15
32
|
const [scenario, setScenario] = useState("create");
|
|
16
33
|
const [open, setOpen] = useState(false);
|
|
17
|
-
const formRef = useRef();
|
|
34
|
+
const formRef = useRef<IFormRef>();
|
|
18
35
|
|
|
19
36
|
const FormSlot = useMemo(() => props.Slots?.FormSlot, [props.Slots?.FormSlot]);
|
|
20
37
|
|
|
@@ -48,8 +65,8 @@ function FormDialog(props, parentRef) {
|
|
|
48
65
|
function onOk() {
|
|
49
66
|
validate().then(async () => {
|
|
50
67
|
const submitForm = _.cloneDeep(await formRef.current?.formRender?.values);
|
|
51
|
-
if (
|
|
52
|
-
const isContinue = await
|
|
68
|
+
if (modalConf.beforeSubmit) {
|
|
69
|
+
const isContinue = await modalConf.beforeSubmit(submitForm, {
|
|
53
70
|
cancel: close,
|
|
54
71
|
formRef,
|
|
55
72
|
scenario,
|
|
@@ -74,7 +91,7 @@ function FormDialog(props, parentRef) {
|
|
|
74
91
|
* 校验表单
|
|
75
92
|
* @returns
|
|
76
93
|
*/
|
|
77
|
-
function validate(hideMessage) {
|
|
94
|
+
function validate(hideMessage = false) {
|
|
78
95
|
return new Promise((resolve, reject) => {
|
|
79
96
|
formRef.current?.formRender
|
|
80
97
|
?.validate()
|
|
@@ -98,33 +115,33 @@ function FormDialog(props, parentRef) {
|
|
|
98
115
|
validate,
|
|
99
116
|
scenario,
|
|
100
117
|
};
|
|
101
|
-
if (
|
|
102
|
-
footer = typeof
|
|
118
|
+
if (modalConf?.footer) {
|
|
119
|
+
footer = typeof modalConf?.footer === "function" ? modalConf.footer({ ...options, options }) : modalConf?.footer;
|
|
103
120
|
} else {
|
|
104
121
|
footer = [];
|
|
105
122
|
|
|
106
|
-
if (Slots.
|
|
107
|
-
footer.push(<Slots.
|
|
123
|
+
if (Slots.modalFooterPre) {
|
|
124
|
+
footer.push(<Slots.modalFooterPre key="pre" options={options} />);
|
|
108
125
|
}
|
|
109
126
|
|
|
110
127
|
footer.push(
|
|
111
128
|
<Button key="cancel" onClick={close}>
|
|
112
|
-
{
|
|
129
|
+
{modalConf.cancelText || "取 消"}
|
|
113
130
|
</Button>,
|
|
114
131
|
);
|
|
115
132
|
|
|
116
|
-
if (Slots.
|
|
117
|
-
footer.push(<Slots.
|
|
133
|
+
if (Slots.modalFooterCenter) {
|
|
134
|
+
footer.push(<Slots.modalFooterCenter key="center" options={options} />);
|
|
118
135
|
}
|
|
119
136
|
|
|
120
137
|
footer.push(
|
|
121
138
|
<Button key="confirm" type="primary" onClick={onOk} loading={loading}>
|
|
122
|
-
{
|
|
139
|
+
{modalConf.okText || "确 定"}
|
|
123
140
|
</Button>,
|
|
124
141
|
);
|
|
125
142
|
|
|
126
|
-
if (Slots.
|
|
127
|
-
footer.push(<Slots.
|
|
143
|
+
if (Slots.modalFooterSuffix) {
|
|
144
|
+
footer.push(<Slots.modalFooterSuffix key="suffix" options={options} />);
|
|
128
145
|
}
|
|
129
146
|
}
|
|
130
147
|
|
|
@@ -132,27 +149,33 @@ function FormDialog(props, parentRef) {
|
|
|
132
149
|
* 解决 show 函数中 formRef.current 为 undefined 的问题
|
|
133
150
|
*/
|
|
134
151
|
function didMount() {
|
|
135
|
-
props.
|
|
152
|
+
props.modalFormMount && props.modalFormMount();
|
|
136
153
|
if (_formData) {
|
|
137
154
|
formRef.current?.formRender?.setValues(_formData);
|
|
138
155
|
_formData = null;
|
|
139
156
|
}
|
|
140
157
|
}
|
|
141
158
|
|
|
159
|
+
const CModal = modalMode === "drawer" ? Drawer : Modal;
|
|
160
|
+
const _modalProps = {
|
|
161
|
+
className: "form-modal",
|
|
162
|
+
wrapClassName: "form-modal",
|
|
163
|
+
title: title,
|
|
164
|
+
visible: open,
|
|
165
|
+
open: open,
|
|
166
|
+
onClose: close,
|
|
167
|
+
onCancel: close,
|
|
168
|
+
onOk: onOk,
|
|
169
|
+
footer: footer,
|
|
170
|
+
maskClosable: modalProps.maskClosable || false,
|
|
171
|
+
width: modalConf?.width ?? 720,
|
|
172
|
+
// 解决弹窗不销毁,表单远程数据没有更新的问题
|
|
173
|
+
destroyOnClose: true,
|
|
174
|
+
...modalProps,
|
|
175
|
+
};
|
|
176
|
+
|
|
142
177
|
return (
|
|
143
|
-
<
|
|
144
|
-
wrapClassName="form-dialog"
|
|
145
|
-
title={title}
|
|
146
|
-
visible={open}
|
|
147
|
-
onCancel={close}
|
|
148
|
-
onOk={onOk}
|
|
149
|
-
footer={footer}
|
|
150
|
-
{...modalProps}
|
|
151
|
-
maskClosable={modalProps.maskClosable || false}
|
|
152
|
-
width={dialogConf?.width}
|
|
153
|
-
// 解决弹窗不销毁,表单远程数据没有更新的问题
|
|
154
|
-
destroyOnClose
|
|
155
|
-
>
|
|
178
|
+
<CModal {..._modalProps}>
|
|
156
179
|
{FormSlot ? (
|
|
157
180
|
<FormSlot {...props} ref={formRef} scenario={scenario} schema={props.schema?.schema} />
|
|
158
181
|
) : (
|
|
@@ -168,7 +191,7 @@ function FormDialog(props, parentRef) {
|
|
|
168
191
|
></FormRender>
|
|
169
192
|
)}
|
|
170
193
|
<DidMount didMount={didMount} />
|
|
171
|
-
</
|
|
194
|
+
</CModal>
|
|
172
195
|
);
|
|
173
196
|
}
|
|
174
197
|
|
|
@@ -179,4 +202,4 @@ function DidMount(props) {
|
|
|
179
202
|
return null;
|
|
180
203
|
}
|
|
181
204
|
|
|
182
|
-
export default forwardRef(
|
|
205
|
+
export default forwardRef(FormModal);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import _ from "lodash";
|
|
1
2
|
import { getFieldMap } from "./utils";
|
|
2
3
|
|
|
3
4
|
export const handleQuerySchema = (opt) => {
|
|
4
|
-
const { schema, search, filters, onSearch, replaceComList } = opt || {};
|
|
5
|
+
const { schema, search, filters, onSearch, replaceComList, schemaScope } = opt || {};
|
|
5
6
|
const queryProperties = {};
|
|
6
7
|
let index = 0;
|
|
7
8
|
if (search) {
|
|
@@ -10,13 +11,13 @@ export const handleQuerySchema = (opt) => {
|
|
|
10
11
|
index += 1;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
const fieldMap = getFieldMap(schema);
|
|
14
|
+
const fieldMap = getFieldMap(_.cloneDeep(schema));
|
|
14
15
|
filters?.forEach((key) => {
|
|
15
16
|
const item = fieldMap[key];
|
|
16
17
|
if (item) {
|
|
17
18
|
const xComponent = item["x-component"];
|
|
18
19
|
const replaceItem = replaceComList?.find((it) => it.name === key || (!it.name && it.component === xComponent));
|
|
19
|
-
|
|
20
|
+
|
|
20
21
|
const itemConf = {
|
|
21
22
|
...item,
|
|
22
23
|
...replaceItem,
|
|
@@ -25,11 +26,17 @@ export const handleQuerySchema = (opt) => {
|
|
|
25
26
|
"x-display": "visible",
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
// 处理 props 不存在、从 scope 中获取的情况
|
|
30
|
+
const comProps = itemConf["x-component-props"];
|
|
31
|
+
if (!comProps) {
|
|
29
32
|
itemConf["x-component-props"] = {};
|
|
33
|
+
} else if (isScopeKey(comProps)) {
|
|
34
|
+
itemConf["x-component-props"] = getValByScope(comProps, schemaScope) || {};
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
itemConf["x-component-props"].allowClear
|
|
37
|
+
if (typeof itemConf["x-component-props"].allowClear !== "boolean") {
|
|
38
|
+
itemConf["x-component-props"].allowClear = true;
|
|
39
|
+
}
|
|
33
40
|
|
|
34
41
|
handleInput(itemConf, opt);
|
|
35
42
|
handleSelect(itemConf, opt);
|
|
@@ -173,7 +180,7 @@ export const handleShortcutSubmit = (conf, opt) => {
|
|
|
173
180
|
|
|
174
181
|
// 输入框
|
|
175
182
|
if (isEnterSubmit && xComponent === "Input") {
|
|
176
|
-
const onPressEnter = xComponentProps?.onPressEnter;
|
|
183
|
+
const onPressEnter = getSchemaVal(xComponentProps?.onPressEnter, opt);
|
|
177
184
|
conf["x-component-props"].onPressEnter = function (e, ...args) {
|
|
178
185
|
e?.preventDefault && e?.preventDefault();
|
|
179
186
|
// 阻止默认事件,解决单个 input 提交问题
|
|
@@ -184,12 +191,12 @@ export const handleShortcutSubmit = (conf, opt) => {
|
|
|
184
191
|
// 清除事件
|
|
185
192
|
handleInputClear(conf, opt);
|
|
186
193
|
} else if (isChangeSubmit && onChangeList.includes(xComponent)) {
|
|
187
|
-
conf["x-component-props"].onChange = handleHoc(xComponentProps?.onChange, onSearch);
|
|
194
|
+
conf["x-component-props"].onChange = handleHoc(xComponentProps?.onChange, onSearch, opt);
|
|
188
195
|
}
|
|
189
196
|
// 处理自定义组件快捷提交逻辑
|
|
190
197
|
const item = customSubmitList?.find((it) => it.component === xComponent);
|
|
191
198
|
if (item) {
|
|
192
|
-
conf["x-component-props"][item.event] = handleHoc(xComponentProps[item.event], onSearch);
|
|
199
|
+
conf["x-component-props"][item.event] = handleHoc(xComponentProps[item.event], onSearch, opt);
|
|
193
200
|
}
|
|
194
201
|
};
|
|
195
202
|
|
|
@@ -199,11 +206,14 @@ export const handleShortcutSubmit = (conf, opt) => {
|
|
|
199
206
|
* @param cb
|
|
200
207
|
* @returns
|
|
201
208
|
*/
|
|
202
|
-
export const handleHoc = (source, cb) => {
|
|
209
|
+
export const handleHoc = (source, cb, opt) => {
|
|
203
210
|
return async function (...args) {
|
|
211
|
+
const { schemaScope } = opt;
|
|
212
|
+
let _source = getSchemaVal(source, schemaScope);
|
|
213
|
+
|
|
204
214
|
let res = null;
|
|
205
|
-
if (
|
|
206
|
-
res = await
|
|
215
|
+
if (_source) {
|
|
216
|
+
res = await _source(...args);
|
|
207
217
|
}
|
|
208
218
|
cb && cb(...args);
|
|
209
219
|
return res;
|
|
@@ -217,8 +227,8 @@ export const handleHoc = (source, cb) => {
|
|
|
217
227
|
* @returns
|
|
218
228
|
*/
|
|
219
229
|
export const handleInputClear = (conf, opt) => {
|
|
220
|
-
const { onSearch } = opt || {};
|
|
221
|
-
const onChange = conf["x-component-props"]?.onChange;
|
|
230
|
+
const { onSearch, schemaScope } = opt || {};
|
|
231
|
+
const onChange = getSchemaVal(conf["x-component-props"]?.onChange, schemaScope);
|
|
222
232
|
conf["x-component-props"].onChange = function (e, ...args) {
|
|
223
233
|
const res = onChange && onChange(e, ...args);
|
|
224
234
|
if (e.type === "click" && e.target?.value === "") {
|
|
@@ -229,4 +239,56 @@ export const handleInputClear = (conf, opt) => {
|
|
|
229
239
|
return conf;
|
|
230
240
|
};
|
|
231
241
|
|
|
242
|
+
/**
|
|
243
|
+
* 是否是 scope key
|
|
244
|
+
* @param strKey
|
|
245
|
+
* @returns
|
|
246
|
+
*/
|
|
247
|
+
export const isScopeKey = (strKey) => {
|
|
248
|
+
if (typeof strKey !== "string") {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
const key = strKey.trim();
|
|
252
|
+
return key.startsWith("{{") && key.endsWith("}}");
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 获取 scope key
|
|
257
|
+
* @param strKey
|
|
258
|
+
* @returns
|
|
259
|
+
*/
|
|
260
|
+
export const getScopeKey = (strKey) => {
|
|
261
|
+
if (!isScopeKey(strKey)) {
|
|
262
|
+
return "";
|
|
263
|
+
}
|
|
264
|
+
const key = strKey.trim();
|
|
265
|
+
return key.replace(/^\{\{/, "").replace(/\}\}$/, "");
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 通过字符串获取 schemaScope 中的数据
|
|
270
|
+
* @param strKey
|
|
271
|
+
* @param schemaScope
|
|
272
|
+
* @returns
|
|
273
|
+
*/
|
|
274
|
+
export const getSchemaVal = (strKey, schemaScope = {}) => {
|
|
275
|
+
const val = getValByScope(strKey, schemaScope);
|
|
276
|
+
if (!_.isNil(val) && val !== "") {
|
|
277
|
+
return val;
|
|
278
|
+
}
|
|
279
|
+
return strKey;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* 通过字符串获取 schemaScope 中的数据
|
|
284
|
+
* @param strKey
|
|
285
|
+
* @param schemaScope
|
|
286
|
+
* @returns
|
|
287
|
+
*/
|
|
288
|
+
export const getValByScope = (strKey, schemaScope = {}) => {
|
|
289
|
+
if (isScopeKey(strKey)) {
|
|
290
|
+
return schemaScope && schemaScope[getScopeKey(strKey)];
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
232
294
|
export default handleQuerySchema;
|
package/src/common/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Schema } from "@formily/json-schema";
|
|
1
2
|
import _ from "lodash";
|
|
2
3
|
import dayjs from "dayjs";
|
|
3
4
|
import advancedFormat from "dayjs/plugin/advancedFormat";
|
|
@@ -23,8 +24,9 @@ const dateFormatEnum = {
|
|
|
23
24
|
* @returns
|
|
24
25
|
*/
|
|
25
26
|
export function getVal(field = {}, data = {}, opt = {}) {
|
|
27
|
+
const {} = opt;
|
|
26
28
|
let val = _.get(data, field.name);
|
|
27
|
-
const {
|
|
29
|
+
const {} = field || {};
|
|
28
30
|
const xComponent = field["x-component"];
|
|
29
31
|
const xComponentProps = field["x-component-props"] || {};
|
|
30
32
|
|
|
@@ -89,9 +91,11 @@ export function getDateVal(val, format) {
|
|
|
89
91
|
return dayjs(val).format(format);
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
export function getFieldList(_schema, fieldList = [], opt = {},isTableSortXIdex = false) {
|
|
94
|
+
export function getFieldList(_schema, fieldList = [], opt = {}, isTableSortXIdex = false) {
|
|
93
95
|
const schema = _schema?.schema || _schema;
|
|
94
96
|
|
|
97
|
+
// 解决 schema 字符串可执行代码、变量等
|
|
98
|
+
const properties = Schema.getOrderProperties(schema);
|
|
95
99
|
const { boxList = [] } = opt || {};
|
|
96
100
|
let _boxList = ["FormGrid", "FormGrid.GridColumn", "Card"];
|
|
97
101
|
if (Array.isArray(boxList)) {
|
|
@@ -101,10 +105,10 @@ export function getFieldList(_schema, fieldList = [], opt = {},isTableSortXIdex
|
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
schema?.properties &&
|
|
104
|
-
|
|
105
|
-
const field = schema
|
|
108
|
+
properties.forEach((item) => {
|
|
109
|
+
const field = item.schema;
|
|
106
110
|
if (!field.name) {
|
|
107
|
-
field.name = key;
|
|
111
|
+
field.name = item.key;
|
|
108
112
|
}
|
|
109
113
|
const componentName = field["x-component"];
|
|
110
114
|
if (_boxList.includes(componentName)) {
|
|
@@ -142,3 +146,53 @@ export function objToFormData(data) {
|
|
|
142
146
|
});
|
|
143
147
|
return formData;
|
|
144
148
|
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 根据 val 获取对应的 options 项数据
|
|
152
|
+
* @param {string|number|boolean} val
|
|
153
|
+
* @param {Object} field
|
|
154
|
+
*/
|
|
155
|
+
export const getFieldOptItByVal = function (val, field, opt) {
|
|
156
|
+
if (!field) {
|
|
157
|
+
return {};
|
|
158
|
+
}
|
|
159
|
+
const options = Array.isArray(field.enum)
|
|
160
|
+
? field.enum
|
|
161
|
+
: Array.isArray(field.options)
|
|
162
|
+
? field.options
|
|
163
|
+
: field.dataSource || [];
|
|
164
|
+
return getOptItByVal(val, options, { fieldNames: field.fieldNames, ...opt });
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 根据 val 获取对应的 options 项数据,并进行数据归一化处理
|
|
169
|
+
* value, label, children
|
|
170
|
+
* @param {string|number|boolean} val
|
|
171
|
+
* @param {Object} field
|
|
172
|
+
*/
|
|
173
|
+
export const getOptItByVal = function (val, options, opt) {
|
|
174
|
+
const { fieldNames } = opt || {};
|
|
175
|
+
const { value = "value", label = "label", children = "children" } = fieldNames || {};
|
|
176
|
+
for (let i = 0; i < options.length; i++) {
|
|
177
|
+
const it = options[i];
|
|
178
|
+
if (it?.[value] === val) {
|
|
179
|
+
return {
|
|
180
|
+
...it,
|
|
181
|
+
value: it?.[value],
|
|
182
|
+
label: it?.[label],
|
|
183
|
+
children: it?.[children],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// 递归处理
|
|
187
|
+
const _children = it?.[children];
|
|
188
|
+
if (Array.isArray(_children) && _children.length > 0) {
|
|
189
|
+
const child = getOptItByVal(val, _children, opt);
|
|
190
|
+
return {
|
|
191
|
+
...child,
|
|
192
|
+
value: child?.[value],
|
|
193
|
+
label: child?.[label],
|
|
194
|
+
children: child?.[children],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import _ from "lodash";
|
|
3
|
+
|
|
4
|
+
import { getFieldOptItByVal } from "../../common/utils";
|
|
5
|
+
|
|
6
|
+
import "./index.less";
|
|
7
|
+
|
|
8
|
+
export interface IPrefixNodeProps {
|
|
9
|
+
showPrefixNode?: boolean | Object;
|
|
10
|
+
value: any;
|
|
11
|
+
field?: Object;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ITagOption {
|
|
15
|
+
value: string | number | boolean;
|
|
16
|
+
label: string | number;
|
|
17
|
+
children?: [ITagOption];
|
|
18
|
+
color: string;
|
|
19
|
+
icon: ReactNode | string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const defaultSwitchEnum = [
|
|
23
|
+
{
|
|
24
|
+
value: true,
|
|
25
|
+
label: "是",
|
|
26
|
+
color: "#00b42a",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
value: false,
|
|
30
|
+
label: "否",
|
|
31
|
+
color: "#c9cdd4",
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export const PrefixNode = (props) => {
|
|
36
|
+
const { value, field } = props;
|
|
37
|
+
let showVal = Array.isArray(value) ? value : [value];
|
|
38
|
+
|
|
39
|
+
const _field = { enum: defaultSwitchEnum, ...field };
|
|
40
|
+
|
|
41
|
+
return showVal?.map((it, i) => {
|
|
42
|
+
const option = getFieldOptItByVal(it, _field) || {};
|
|
43
|
+
const PreNode = option.PrefixNode;
|
|
44
|
+
console.log(it, option);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div key={it + "" + i} className="table-cell-prefix-box">
|
|
48
|
+
{PreNode ? (
|
|
49
|
+
<PreNode />
|
|
50
|
+
) : option.icon ? (
|
|
51
|
+
option.icon
|
|
52
|
+
) : (
|
|
53
|
+
<div className="prefix-node" style={{ backgroundColor: option.color }}></div>
|
|
54
|
+
)}
|
|
55
|
+
{option.label || it}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default PrefixNode;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { Tag } from "antd";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
|
|
5
|
+
import { getFieldOptItByVal } from "../../common/utils";
|
|
6
|
+
|
|
7
|
+
import "./index.less";
|
|
8
|
+
|
|
9
|
+
export interface ITagsProps {
|
|
10
|
+
showTags?: boolean | Object;
|
|
11
|
+
value: any;
|
|
12
|
+
field?: Object;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ITagOption {
|
|
16
|
+
value: string | number | boolean;
|
|
17
|
+
label: string | number;
|
|
18
|
+
children?: [ITagOption];
|
|
19
|
+
color: string;
|
|
20
|
+
icon: ReactNode | string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Tags = (props) => {
|
|
24
|
+
const { value, field } = props;
|
|
25
|
+
let showVal = Array.isArray(value) ? value : [value];
|
|
26
|
+
|
|
27
|
+
return showVal?.map((it, i) => {
|
|
28
|
+
const option = getFieldOptItByVal(it, field) || {};
|
|
29
|
+
return (
|
|
30
|
+
<Tag key={it + "" + i} className="table-cell-tag" icon={option.icon} color={option.color}>
|
|
31
|
+
{option.label || it}
|
|
32
|
+
</Tag>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default Tags;
|
package/src/list-render.jsx
CHANGED
|
@@ -9,8 +9,8 @@ import _ from "lodash";
|
|
|
9
9
|
import QueryRender from "./query-render";
|
|
10
10
|
import Pagination from "./pagination-render";
|
|
11
11
|
import TableRender from "./table-render";
|
|
12
|
-
import
|
|
13
|
-
import
|
|
12
|
+
import FormModal from "./FormModal";
|
|
13
|
+
import DetailModal from "./DetailModal";
|
|
14
14
|
|
|
15
15
|
import { objToFormData } from "./common/utils";
|
|
16
16
|
|
|
@@ -23,8 +23,17 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
23
23
|
queryFormIsExtendModelQuery = false,
|
|
24
24
|
queryFormInitialValues = {},
|
|
25
25
|
dialogConf = {},
|
|
26
|
+
modalConf = {},
|
|
26
27
|
/** 编辑接口使用 patch 发起请求 */
|
|
27
28
|
isPatchUpdate = false,
|
|
29
|
+
/**
|
|
30
|
+
* 表单、详情 展示模式: dialog drawer
|
|
31
|
+
*/
|
|
32
|
+
modalMode = "dialog",
|
|
33
|
+
/**
|
|
34
|
+
* 表单提交是否使用 FormData 格式
|
|
35
|
+
*/
|
|
36
|
+
useFormData: _useFormData,
|
|
28
37
|
} = props;
|
|
29
38
|
const { createText = props.createText } = i18n || {};
|
|
30
39
|
const [total, setTotal] = useState(0);
|
|
@@ -32,18 +41,20 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
32
41
|
const [formState, setFormState] = useState("");
|
|
33
42
|
const [rowId, setRowId] = useState(0);
|
|
34
43
|
const [listLoading, setListLoading] = useState(false);
|
|
35
|
-
const
|
|
36
|
-
const
|
|
44
|
+
const formModalRef = useRef();
|
|
45
|
+
const detailModalRef = useRef();
|
|
37
46
|
const queryRef = useRef();
|
|
38
47
|
const modelQueryRef = useRef({});
|
|
39
48
|
const formQueryRef = useRef({});
|
|
40
49
|
const paginationQueryRef = useRef({ pageNum: 1, pageSize: 10 });
|
|
50
|
+
const useFormData = _useFormData ?? dialogConf.useFormData ?? modalConf?.useFormData;
|
|
41
51
|
|
|
42
52
|
useImperativeHandle(parentRef, () => ({
|
|
43
53
|
getList,
|
|
44
54
|
onSearch,
|
|
45
55
|
forceUpdate,
|
|
46
|
-
|
|
56
|
+
formModalRef,
|
|
57
|
+
formDialogRef: formModalRef,
|
|
47
58
|
queryRef,
|
|
48
59
|
onCreate,
|
|
49
60
|
onEdit,
|
|
@@ -69,7 +80,6 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
69
80
|
model.query = {};
|
|
70
81
|
}
|
|
71
82
|
modelQueryRef.current = model?.query;
|
|
72
|
-
|
|
73
83
|
}, [model?.query]);
|
|
74
84
|
|
|
75
85
|
useEffect(() => {
|
|
@@ -110,7 +120,7 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
110
120
|
..._q,
|
|
111
121
|
..._q1,
|
|
112
122
|
..._q2,
|
|
113
|
-
..._q3
|
|
123
|
+
..._q3,
|
|
114
124
|
};
|
|
115
125
|
|
|
116
126
|
if (mergedQueries.$timerange !== undefined) {
|
|
@@ -119,7 +129,6 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
119
129
|
|
|
120
130
|
model.query = mergedQueries;
|
|
121
131
|
|
|
122
|
-
|
|
123
132
|
model
|
|
124
133
|
?.getList(mergedQueries)
|
|
125
134
|
.then((res) => {
|
|
@@ -145,8 +154,8 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
145
154
|
getList();
|
|
146
155
|
}
|
|
147
156
|
|
|
148
|
-
function onSearch(quer,source) {
|
|
149
|
-
const query = source === "queryRender" ? {...quer} :{...formQueryRef.current, ...quer};
|
|
157
|
+
function onSearch(quer, source) {
|
|
158
|
+
const query = source === "queryRender" ? { ...quer } : { ...formQueryRef.current, ...quer };
|
|
150
159
|
if (model && !model.query) {
|
|
151
160
|
model.query = {};
|
|
152
161
|
}
|
|
@@ -167,12 +176,12 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
167
176
|
|
|
168
177
|
function onCreate() {
|
|
169
178
|
setFormState("create");
|
|
170
|
-
|
|
179
|
+
formModalRef.current.show();
|
|
171
180
|
}
|
|
172
181
|
|
|
173
182
|
async function onCreateSubmit(data) {
|
|
174
183
|
let _data = typeof model?.createMap === "function" ? model.createMap(data) : data;
|
|
175
|
-
if (
|
|
184
|
+
if (useFormData) {
|
|
176
185
|
_data = objToFormData(_data);
|
|
177
186
|
}
|
|
178
187
|
return model
|
|
@@ -213,7 +222,7 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
213
222
|
|
|
214
223
|
function handleDetail(data, id) {
|
|
215
224
|
setRowId(id);
|
|
216
|
-
|
|
225
|
+
detailModalRef.current.show(data);
|
|
217
226
|
}
|
|
218
227
|
|
|
219
228
|
function onEdit(row, idx) {
|
|
@@ -241,13 +250,11 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
241
250
|
function handleEdit(data, id) {
|
|
242
251
|
setRowId(id);
|
|
243
252
|
setFormState("edit");
|
|
244
|
-
|
|
253
|
+
formModalRef.current.show(data, "编辑", "edit");
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
async function onEditSubmit(data) {
|
|
248
257
|
let _data = data;
|
|
249
|
-
console.log("isPatchUpdate", isPatchUpdate);
|
|
250
|
-
|
|
251
258
|
if (isPatchUpdate) {
|
|
252
259
|
if (model?.patchMap === "function") {
|
|
253
260
|
_data = model.patchMap(data);
|
|
@@ -256,7 +263,7 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
256
263
|
_data = model.updateMap(data);
|
|
257
264
|
}
|
|
258
265
|
|
|
259
|
-
if (
|
|
266
|
+
if (useFormData) {
|
|
260
267
|
_data = objToFormData(_data);
|
|
261
268
|
}
|
|
262
269
|
const request = isPatchUpdate ? model?.patch : model?.update;
|
|
@@ -289,6 +296,12 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
289
296
|
|
|
290
297
|
const { Slots = {} } = props;
|
|
291
298
|
|
|
299
|
+
const _modalConf = { ...props.dialogConf, ...modalConf };
|
|
300
|
+
const formProps = { ...props.dialogFormProps, ...props.modalFormProps };
|
|
301
|
+
const onFormModalClose = props.onFormDialogClose ?? props.onFormModalClose;
|
|
302
|
+
const modalProps = { ...props.dialogProps, ...props.modalProps };
|
|
303
|
+
const modalFormMount = props.dialogFormMount ?? props.modalFormMount;
|
|
304
|
+
|
|
292
305
|
return (
|
|
293
306
|
<div className={`list-render ${props.className}`}>
|
|
294
307
|
<div className={`list-header ${props.verticalHeader ? "vertical-header" : ""}`}>
|
|
@@ -302,9 +315,9 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
302
315
|
queryFormInitialValues={
|
|
303
316
|
queryFormIsExtendModelQuery
|
|
304
317
|
? {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
318
|
+
...queryFormInitialValues,
|
|
319
|
+
...model.query,
|
|
320
|
+
}
|
|
308
321
|
: queryFormInitialValues
|
|
309
322
|
}
|
|
310
323
|
onSearch={onSearch}
|
|
@@ -329,9 +342,7 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
329
342
|
)}
|
|
330
343
|
</div>
|
|
331
344
|
</div>
|
|
332
|
-
{Slots.HeaderOthersSuffix &&
|
|
333
|
-
<Slots.HeaderOthersSuffix onSearch={onSearch} getList={getList} />
|
|
334
|
-
)}
|
|
345
|
+
{Slots.HeaderOthersSuffix && <Slots.HeaderOthersSuffix onSearch={onSearch} getList={getList} />}
|
|
335
346
|
<TableRender
|
|
336
347
|
idKey={idKey}
|
|
337
348
|
schema={schema?.schema}
|
|
@@ -361,33 +372,37 @@ const ListRender = forwardRef(function (props, parentRef) {
|
|
|
361
372
|
i18n={i18n}
|
|
362
373
|
/>
|
|
363
374
|
) : null}
|
|
364
|
-
|
|
365
|
-
|
|
375
|
+
|
|
376
|
+
<FormModal
|
|
377
|
+
ref={formModalRef}
|
|
366
378
|
schema={schema}
|
|
367
|
-
dialogConf={props.dialogConf}
|
|
368
379
|
formInitialValues={props.formInitialValues}
|
|
369
|
-
onClose={props.onFormDialogClose}
|
|
370
|
-
onSubmit={formState === "edit" ? onEditSubmit : onCreateSubmit}
|
|
371
|
-
Slots={props.Slots}
|
|
372
|
-
modalProps={props.dialogModalProps}
|
|
373
|
-
formProps={props.dialogFormProps}
|
|
374
380
|
components={props.components}
|
|
375
381
|
schemaScope={props.schemaScope}
|
|
376
|
-
|
|
382
|
+
formProps={formProps}
|
|
383
|
+
modalMode={modalMode}
|
|
384
|
+
modalConf={_modalConf}
|
|
385
|
+
onClose={onFormModalClose}
|
|
386
|
+
onSubmit={formState === "edit" ? onEditSubmit : onCreateSubmit}
|
|
387
|
+
Slots={props.Slots}
|
|
388
|
+
modalProps={modalProps}
|
|
389
|
+
modalFormMount={modalFormMount}
|
|
377
390
|
i18n={i18n}
|
|
378
391
|
/>
|
|
379
|
-
|
|
380
|
-
|
|
392
|
+
|
|
393
|
+
<DetailModal
|
|
394
|
+
ref={detailModalRef}
|
|
381
395
|
schema={schema}
|
|
382
|
-
dialogConf={props.dialogConf}
|
|
383
396
|
formInitialValues={props.formInitialValues}
|
|
384
|
-
onClose={props.onFormDialogClose}
|
|
385
|
-
Slots={props.Slots}
|
|
386
|
-
detailProps={props.dialogDetailProps}
|
|
387
|
-
modalProps={props.dialogModalProps}
|
|
388
397
|
components={props.detailComponents}
|
|
389
398
|
schemaScope={props.schemaScope}
|
|
390
|
-
|
|
399
|
+
detailProps={props.dialogDetailProps || props.modalDetailProps}
|
|
400
|
+
modalMode={modalMode}
|
|
401
|
+
modalConf={_modalConf}
|
|
402
|
+
onClose={onFormModalClose}
|
|
403
|
+
Slots={props.Slots}
|
|
404
|
+
modalProps={modalProps}
|
|
405
|
+
modalFormMount={modalFormMount}
|
|
391
406
|
/>
|
|
392
407
|
</div>
|
|
393
408
|
);
|
|
@@ -18,6 +18,7 @@ function QueryRender(props, parentRef) {
|
|
|
18
18
|
setSchema(
|
|
19
19
|
handleQuerySchema({
|
|
20
20
|
...props?.config,
|
|
21
|
+
schemaScope: props.schemaScope,
|
|
21
22
|
schema: _.cloneDeep(props.schema),
|
|
22
23
|
search: props.search,
|
|
23
24
|
filters: _.cloneDeep(props.filters),
|
|
@@ -48,12 +49,12 @@ function QueryRender(props, parentRef) {
|
|
|
48
49
|
|
|
49
50
|
if (!beforeQuerySearchResult) return;
|
|
50
51
|
}
|
|
51
|
-
return props.onSearch && props.onSearch(query,
|
|
52
|
+
return props.onSearch && props.onSearch(query, "queryRender");
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
function onReset() {
|
|
55
56
|
formRef.current?.formRender?.reset();
|
|
56
|
-
props.onSearch && props.onSearch(_.cloneDeep(formRef?.current?.formRender?.values),
|
|
57
|
+
props.onSearch && props.onSearch(_.cloneDeep(formRef?.current?.formRender?.values), "queryRender");
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
return (
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { useEffect, useState, useMemo, useCallback, useRef } from "react";
|
|
2
2
|
import { Table, Button, Popconfirm, Tooltip } from "antd";
|
|
3
|
+
import { Schema } from "@formily/json-schema";
|
|
3
4
|
import { QuestionCircleOutlined } from "@ant-design/icons";
|
|
5
|
+
import _ from "lodash";
|
|
4
6
|
|
|
5
7
|
import { FormilyField } from "../components/Formily/FormilyField";
|
|
8
|
+
import Tags from "../components/Tags";
|
|
9
|
+
import PrefixNode from "../components/PrefixNode";
|
|
6
10
|
// getColRender 使用 observer 包裹一层 column 的 render 函数,解决数据无法响应的问题
|
|
7
11
|
import { getColRender } from "../common/formily-utils";
|
|
8
12
|
import { getVal, getFieldList } from "../common/utils";
|
|
@@ -15,7 +19,7 @@ const scenario = "table-render";
|
|
|
15
19
|
function TableRender(props) {
|
|
16
20
|
const { config = {}, query = {}, i18n } = props;
|
|
17
21
|
const { tableDel = "删除", tableEdit = "编辑", tableDelTip = "确认删除该项?", tableDetail = "详情" } = i18n || {};
|
|
18
|
-
const { orderColType, orderColWidth, tableEmptyValue, isTableSortXIdex = false} = config || {};
|
|
22
|
+
const { orderColType, orderColWidth, tableEmptyValue, isTableSortXIdex = false } = config || {};
|
|
19
23
|
const [columns, setColumns] = useState([]);
|
|
20
24
|
|
|
21
25
|
const formilyRef = useRef({
|
|
@@ -58,6 +62,7 @@ function TableRender(props) {
|
|
|
58
62
|
const fieldSchemas = formilyRef.current?.fields;
|
|
59
63
|
if (field.inTable !== false) {
|
|
60
64
|
const { name, title } = field;
|
|
65
|
+
const comName = field["x-component"];
|
|
61
66
|
|
|
62
67
|
const decoratorProps = field["x-decorator-props"] || {};
|
|
63
68
|
let _title = title;
|
|
@@ -93,11 +98,13 @@ function TableRender(props) {
|
|
|
93
98
|
};
|
|
94
99
|
} else {
|
|
95
100
|
colRender = function (text, record, index, ...args) {
|
|
96
|
-
const { width, ellipsis, emptyValue } = _colConf || {};
|
|
101
|
+
const { width, ellipsis, emptyValue, showTags, showPrefixNode } = _colConf || {};
|
|
97
102
|
const schemaDefaultValue = fieldSchemas[name]?.componentProps?.emptyValue;
|
|
98
103
|
const defaultValue = emptyValue ?? schemaDefaultValue ?? tableEmptyValue ?? "";
|
|
99
104
|
|
|
100
|
-
let val = getVal({ ...field, ...fieldSchemas[name] }, record, {
|
|
105
|
+
let val = getVal({ ...field, ...fieldSchemas[name] }, record, {
|
|
106
|
+
fieldSchema: fieldSchemas?.[name],
|
|
107
|
+
});
|
|
101
108
|
|
|
102
109
|
if (val === "" || val === undefined || val === null) {
|
|
103
110
|
val = defaultValue;
|
|
@@ -115,13 +122,37 @@ function TableRender(props) {
|
|
|
115
122
|
</Tooltip>
|
|
116
123
|
);
|
|
117
124
|
}
|
|
125
|
+
// 使用 tag 渲染内容
|
|
126
|
+
if (showTags) {
|
|
127
|
+
// field 通过 fieldSchemas 获取最新的 field 数据
|
|
128
|
+
return (
|
|
129
|
+
<Tags
|
|
130
|
+
value={_.get(record, name)}
|
|
131
|
+
config={typeof showTags === "object" ? showTags : undefined}
|
|
132
|
+
field={{ ...field, ...fieldSchemas?.[name] }}
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
// 使用 前缀节点 渲染内容
|
|
137
|
+
if (showPrefixNode || (showPrefixNode !== false && comName === "Switch")) {
|
|
138
|
+
// field 通过 fieldSchemas 获取最新的 field 数据
|
|
139
|
+
return (
|
|
140
|
+
<PrefixNode
|
|
141
|
+
value={_.get(record, name)}
|
|
142
|
+
config={typeof showPrefixNode === "object" ? showPrefixNode : undefined}
|
|
143
|
+
field={{ ...field, ...fieldSchemas?.[name] }}
|
|
144
|
+
/>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
118
148
|
return content;
|
|
119
149
|
};
|
|
120
150
|
}
|
|
121
151
|
|
|
122
152
|
columns.push({
|
|
123
153
|
..._colConf,
|
|
124
|
-
onCell: (record, rowIndex) =>
|
|
154
|
+
onCell: (record, rowIndex) =>
|
|
155
|
+
_colConf?.onCell?.({ ...record, _field: { ...field, ...(fieldSchemas?.[name] || {}) } }, rowIndex) || {},
|
|
125
156
|
title: _title,
|
|
126
157
|
key: name,
|
|
127
158
|
dataIndex: name,
|
|
@@ -153,6 +184,7 @@ function TableRender(props) {
|
|
|
153
184
|
//详情按钮权限
|
|
154
185
|
const _hasDetail =
|
|
155
186
|
hasDetail && typeof hasDetail === "function" ? hasDetail(record, index) : hasDetail !== false;
|
|
187
|
+
console.log("_hasDetail", hasDetail, _hasDetail);
|
|
156
188
|
|
|
157
189
|
//删除按钮权限
|
|
158
190
|
const _hasDel = hasDel && typeof hasDel === "function" ? hasDel(record, index) : hasDel !== false;
|