@cqsjjb/jjb-react-admin-component 3.3.7 → 3.3.9
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/ListDataContainer/index.d.ts +8 -0
- package/ListDataContainer/index.js +105 -18
- package/PageLayout/index.less +2 -2
- package/PhoneBox/index.less +3 -2
- package/SearchForm/index.d.ts +1 -3
- package/SearchForm/index.js +81 -17
- package/Table/README.md +1 -1
- package/Table/index.d.ts +64 -17
- package/Table/index.js +78 -97
- package/Table/index.less +7 -5
- package/TableAction/index.js +1 -3
- package/package.json +1 -1
|
@@ -143,6 +143,14 @@ export interface ListDataContainerProps<T extends boolean = false> {
|
|
|
143
143
|
? OverTableProps // ProTable 专属属性(如 search、toolBar 等)
|
|
144
144
|
: TableProps<any>; // antd 原生 Table 属性(如 bordered、scroll 等)
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* 搜索表单的自定义属性
|
|
148
|
+
* 描述:传递给SearchForm组件的属性
|
|
149
|
+
* @type {Object}
|
|
150
|
+
* @optional
|
|
151
|
+
*/
|
|
152
|
+
searchFormProps?: Object;
|
|
153
|
+
|
|
146
154
|
/**
|
|
147
155
|
* 表格类型切换开关
|
|
148
156
|
* 描述:控制组件内部使用「项目自定义 ProTable」还是「antd 原生 Table」,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
-
import React, { useState, useEffect, useCallback, useImperativeHandle, forwardRef } from 'react';
|
|
2
|
+
import React, { useState, useEffect, useCallback, useImperativeHandle, forwardRef, useRef } from 'react';
|
|
3
3
|
import { Table, Row, Col, Form } from 'antd';
|
|
4
4
|
import { isEqual } from 'lodash';
|
|
5
5
|
import SearchForm from '@cqsjjb/jjb-react-admin-component/SearchForm';
|
|
@@ -22,6 +22,7 @@ import ProTable from '@cqsjjb/jjb-react-admin-component/Table';
|
|
|
22
22
|
* @props {string} rowKey - 表格行键值,默认为'id'
|
|
23
23
|
* @props {Object} initialPagination - 初始分页配置,包含current、pageSize等分页属性
|
|
24
24
|
* @props {Object} tableProps - 传递给Table组件的属性
|
|
25
|
+
* @props {Object} searchFormProps - 传递给SearchForm组件的属性
|
|
25
26
|
* @props {boolean} proTable - 是否使用ProTable组件,默认为false
|
|
26
27
|
* @example
|
|
27
28
|
* // 基础用法
|
|
@@ -59,14 +60,18 @@ const ListDataContainer = /*#__PURE__*/forwardRef(({
|
|
|
59
60
|
showQuickJumper: true
|
|
60
61
|
},
|
|
61
62
|
tableProps = {},
|
|
63
|
+
searchFormProps = {},
|
|
62
64
|
proTable = false,
|
|
63
65
|
onRest = () => {}
|
|
64
66
|
}, ref) => {
|
|
65
|
-
const [form] = Form.useForm();
|
|
66
67
|
const [tableData, setTableData] = useState([]);
|
|
67
68
|
const [loading, setLoading] = useState(false);
|
|
68
69
|
const [pagination, setPagination] = useState(initialPagination);
|
|
69
70
|
const [totalCount, setTotalCount] = useState(0);
|
|
71
|
+
const [tableScrollY, setTableScrollY] = useState(undefined);
|
|
72
|
+
const form = useRef(null);
|
|
73
|
+
const searchFormRef = useRef(null);
|
|
74
|
+
const containerRef = useRef(null);
|
|
70
75
|
const getComponentName = Component => {
|
|
71
76
|
return Component.displayName || Component.constructor.name;
|
|
72
77
|
};
|
|
@@ -80,8 +85,17 @@ const ListDataContainer = /*#__PURE__*/forwardRef(({
|
|
|
80
85
|
if (!fetchDataApi) return;
|
|
81
86
|
setLoading(true);
|
|
82
87
|
try {
|
|
88
|
+
if (overrideParams.pageIndex && overrideParams.pageSize) {
|
|
89
|
+
setPagination(prev => ({
|
|
90
|
+
...prev,
|
|
91
|
+
pageIndex: overrideParams.pageIndex,
|
|
92
|
+
pageSize: overrideParams.pageSize
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
|
|
83
96
|
// 1. 获取组件内部的表单参数
|
|
84
|
-
const formValues = await form.validateFields();
|
|
97
|
+
const formValues = await form.current.validateFields();
|
|
98
|
+
console.warn("formValues", formValues);
|
|
85
99
|
|
|
86
100
|
// 2. 构造基础参数:分页参数 + 表单参数
|
|
87
101
|
const baseParams = {
|
|
@@ -107,7 +121,7 @@ const ListDataContainer = /*#__PURE__*/forwardRef(({
|
|
|
107
121
|
} finally {
|
|
108
122
|
setLoading(false);
|
|
109
123
|
}
|
|
110
|
-
}, [fetchDataApi, pagination, form]);
|
|
124
|
+
}, [fetchDataApi, pagination, form, searchFormConfig]);
|
|
111
125
|
|
|
112
126
|
// 暴露刷新方法给父组件
|
|
113
127
|
useImperativeHandle(ref, () => ({
|
|
@@ -127,11 +141,11 @@ const ListDataContainer = /*#__PURE__*/forwardRef(({
|
|
|
127
141
|
};
|
|
128
142
|
const handleReset = () => {
|
|
129
143
|
// 清空表单
|
|
130
|
-
form.setFieldsValue(searchFormConfig.reduce((obj, item) => {
|
|
144
|
+
form.current.setFieldsValue(searchFormConfig.reduce((obj, item) => {
|
|
131
145
|
obj[item.name] = undefined;
|
|
132
146
|
return obj;
|
|
133
147
|
}, {}));
|
|
134
|
-
onRest && onRest(form);
|
|
148
|
+
onRest && onRest(form.current);
|
|
135
149
|
// 重置分页并使用内部默认参数查询
|
|
136
150
|
setPagination(initialPagination);
|
|
137
151
|
loadDataSource();
|
|
@@ -150,6 +164,59 @@ const ListDataContainer = /*#__PURE__*/forwardRef(({
|
|
|
150
164
|
useEffect(() => {
|
|
151
165
|
loadDataSource();
|
|
152
166
|
}, []);
|
|
167
|
+
|
|
168
|
+
// 动态计算表格滚动高度
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
const calculateScrollY = () => {
|
|
171
|
+
if (!containerRef.current || !searchFormRef.current) return;
|
|
172
|
+
const containerHeight = containerRef.current.clientHeight;
|
|
173
|
+
const searchFormHeight = searchFormRef.current.offsetHeight;
|
|
174
|
+
const gap = 16; // gap between searchForm and table
|
|
175
|
+
const paginationHeight = 64; // 分页器高度(包含margin)
|
|
176
|
+
|
|
177
|
+
// 计算表格可用高度 = 容器高度 - 搜索表单高度 - gap - 分页器高度 - 间隔
|
|
178
|
+
const availableHeight = containerHeight - searchFormHeight - gap - paginationHeight - 12;
|
|
179
|
+
|
|
180
|
+
// 确保最小高度为 100px
|
|
181
|
+
if (availableHeight > 100) {
|
|
182
|
+
setTableScrollY(availableHeight);
|
|
183
|
+
} else {
|
|
184
|
+
setTableScrollY(100);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// 延迟计算,确保 DOM 渲染完成
|
|
189
|
+
const timer = setTimeout(() => {
|
|
190
|
+
calculateScrollY();
|
|
191
|
+
}, 100);
|
|
192
|
+
|
|
193
|
+
// 使用 ResizeObserver 监听搜索表单高度变化
|
|
194
|
+
let resizeObserver = null;
|
|
195
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
196
|
+
resizeObserver = new ResizeObserver(() => {
|
|
197
|
+
// 使用 requestAnimationFrame 确保在下一帧计算
|
|
198
|
+
requestAnimationFrame(() => {
|
|
199
|
+
calculateScrollY();
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
if (searchFormRef.current) {
|
|
203
|
+
resizeObserver.observe(searchFormRef.current);
|
|
204
|
+
}
|
|
205
|
+
if (containerRef.current) {
|
|
206
|
+
resizeObserver.observe(containerRef.current);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 监听窗口大小变化
|
|
211
|
+
window.addEventListener('resize', calculateScrollY);
|
|
212
|
+
return () => {
|
|
213
|
+
clearTimeout(timer);
|
|
214
|
+
if (resizeObserver) {
|
|
215
|
+
resizeObserver.disconnect();
|
|
216
|
+
}
|
|
217
|
+
window.removeEventListener('resize', calculateScrollY);
|
|
218
|
+
};
|
|
219
|
+
}, [searchFormConfig]);
|
|
153
220
|
const generateFormItems = () => {
|
|
154
221
|
return searchFormConfig.map((item, index) => {
|
|
155
222
|
const {
|
|
@@ -172,26 +239,40 @@ const ListDataContainer = /*#__PURE__*/forwardRef(({
|
|
|
172
239
|
required: true,
|
|
173
240
|
message: `${SELECT_COMPONENTS.includes(getComponentName(FieldComponent)) ? '请选择' : '请输入'}${label}`
|
|
174
241
|
}]
|
|
175
|
-
} : {},
|
|
242
|
+
} : {}, {
|
|
243
|
+
style: {
|
|
244
|
+
marginBottom: 0
|
|
245
|
+
}
|
|
246
|
+
}, itemProps, restProps), /*#__PURE__*/React.createElement(FieldComponent, _extends({
|
|
176
247
|
allowClear: true,
|
|
177
248
|
placeholder: `${SELECT_COMPONENTS.includes(getComponentName(FieldComponent)) ? '请选择' : '请输入'}${label}`
|
|
178
249
|
}, fieldProps), content || null));
|
|
179
250
|
}).filter(Boolean);
|
|
180
251
|
};
|
|
181
252
|
const TableComponent = proTable ? ProTable : Table;
|
|
182
|
-
return /*#__PURE__*/React.createElement(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
253
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
254
|
+
ref: containerRef,
|
|
255
|
+
style: {
|
|
256
|
+
display: 'flex',
|
|
257
|
+
flexDirection: 'column',
|
|
258
|
+
gap: 16,
|
|
259
|
+
height: '100%',
|
|
260
|
+
overflow: 'hidden'
|
|
261
|
+
}
|
|
262
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
263
|
+
ref: searchFormRef
|
|
264
|
+
}, /*#__PURE__*/React.createElement(SearchForm, _extends({
|
|
265
|
+
defaultExpand: true,
|
|
188
266
|
form: form,
|
|
189
267
|
loading: loading,
|
|
190
268
|
formLine: generateFormItems(),
|
|
191
269
|
onReset: handleReset,
|
|
192
270
|
onFinish: handleFinish
|
|
193
|
-
})), /*#__PURE__*/React.createElement(
|
|
194
|
-
|
|
271
|
+
}, searchFormProps))), /*#__PURE__*/React.createElement("div", {
|
|
272
|
+
style: {
|
|
273
|
+
flex: 1,
|
|
274
|
+
overflow: 'hidden'
|
|
275
|
+
}
|
|
195
276
|
}, /*#__PURE__*/React.createElement(TableComponent, _extends({
|
|
196
277
|
columns: columns,
|
|
197
278
|
dataSource: tableData,
|
|
@@ -203,10 +284,16 @@ const ListDataContainer = /*#__PURE__*/forwardRef(({
|
|
|
203
284
|
total: totalCount
|
|
204
285
|
},
|
|
205
286
|
onChange: handlePaginationChange,
|
|
206
|
-
scroll: {
|
|
207
|
-
|
|
287
|
+
scroll: tableProps?.scroll ? tableProps.scroll : {
|
|
288
|
+
y: tableScrollY !== undefined ? tableScrollY : tableProps.scroll?.y || undefined
|
|
208
289
|
},
|
|
209
290
|
bordered: true
|
|
210
|
-
},
|
|
291
|
+
}, (() => {
|
|
292
|
+
const {
|
|
293
|
+
scroll,
|
|
294
|
+
...restTableProps
|
|
295
|
+
} = tableProps;
|
|
296
|
+
return restTableProps;
|
|
297
|
+
})()))));
|
|
211
298
|
});
|
|
212
299
|
export default ListDataContainer;
|
package/PageLayout/index.less
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
.@{com-prefix-cls}-layout-container-tools {
|
|
23
23
|
margin-top: 0;
|
|
24
24
|
margin-bottom: 0;
|
|
25
|
-
padding: 0 20px
|
|
25
|
+
padding: 0 20px 0 20px;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
.@{com-prefix-cls}-layout-container-content {
|
|
@@ -44,4 +44,4 @@
|
|
|
44
44
|
padding: 20px;
|
|
45
45
|
border-top: 1px #f0f0f0 solid;
|
|
46
46
|
}
|
|
47
|
-
}
|
|
47
|
+
}
|
package/PhoneBox/index.less
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.phone-box {
|
|
2
2
|
display: flex;
|
|
3
|
+
justify-content: center;
|
|
3
4
|
gap: 12px;
|
|
4
5
|
position: relative;
|
|
5
6
|
z-index: 1;
|
|
@@ -7,7 +8,7 @@
|
|
|
7
8
|
.phone-content {
|
|
8
9
|
position: absolute;
|
|
9
10
|
top: 17px;
|
|
10
|
-
left:
|
|
11
|
+
left: calc(50% - 158px);
|
|
11
12
|
z-index: 2;
|
|
12
13
|
border-radius: 40px;
|
|
13
14
|
overflow: hidden;
|
|
@@ -53,7 +54,7 @@
|
|
|
53
54
|
.phone-box-action {
|
|
54
55
|
position: absolute;
|
|
55
56
|
top: 0;
|
|
56
|
-
left:
|
|
57
|
+
left: calc(100% - 88px);
|
|
57
58
|
display: flex;
|
|
58
59
|
flex-direction: column;
|
|
59
60
|
gap: 16px;
|
package/SearchForm/index.d.ts
CHANGED
|
@@ -11,8 +11,6 @@ export interface SearchFormProps {
|
|
|
11
11
|
expand?: boolean;
|
|
12
12
|
// 内部默认展开状态,仅在 expand 未传入时生效 默认-false
|
|
13
13
|
defaultExpand?: boolean;
|
|
14
|
-
// 列数 默认-3
|
|
15
|
-
colSize?: number;
|
|
16
14
|
// 查询 loading 状态 默认-false
|
|
17
15
|
loading?: boolean;
|
|
18
16
|
// 表单行节点数组 默认-[]
|
|
@@ -31,4 +29,4 @@ export interface SearchFormProps {
|
|
|
31
29
|
|
|
32
30
|
declare const SearchForm: React.FC<SearchFormProps>;
|
|
33
31
|
|
|
34
|
-
export default SearchForm;
|
|
32
|
+
export default SearchForm;
|
package/SearchForm/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
1
2
|
import React, { useState, useRef, useEffect } from 'react';
|
|
2
3
|
import { Form, Button, Space, Row, Col } from 'antd';
|
|
3
4
|
import { SearchOutlined, DoubleRightOutlined, UndoOutlined } from '@ant-design/icons';
|
|
@@ -8,7 +9,6 @@ const SearchForm = ({
|
|
|
8
9
|
// 受控
|
|
9
10
|
defaultExpand = false,
|
|
10
11
|
// 内部默认展开
|
|
11
|
-
colSize = 3,
|
|
12
12
|
loading = false,
|
|
13
13
|
formLine = [],
|
|
14
14
|
initialValues = {},
|
|
@@ -17,14 +17,45 @@ const SearchForm = ({
|
|
|
17
17
|
onFinish = () => {},
|
|
18
18
|
onExpand
|
|
19
19
|
}) => {
|
|
20
|
-
|
|
21
|
-
const
|
|
20
|
+
// 如果外部没有传入 form,使用 Form.useForm() 创建实例
|
|
21
|
+
const [internalFormInstance] = Form.useForm();
|
|
22
|
+
const internalFormRef = useRef(internalFormInstance);
|
|
23
|
+
|
|
24
|
+
// 判断外部传入的是 ref 还是 form 实例
|
|
25
|
+
// ref 对象有 current 属性,form 实例没有
|
|
26
|
+
const isExternalRef = externalForm && 'current' in externalForm;
|
|
27
|
+
|
|
28
|
+
// 警告:ref 用法将在后续版本中移除
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (isExternalRef) {
|
|
31
|
+
console.warn('[SearchForm] 警告:通过 ref 传入 form 的方式已废弃,将在后续版本中移除。' + '请使用 Form.useForm() 创建 form 实例并直接传入,例如:\n' + ' const [form] = Form.useForm();\n' + ' <SearchForm form={form} />');
|
|
32
|
+
}
|
|
33
|
+
}, [isExternalRef]);
|
|
34
|
+
|
|
35
|
+
// 获取实际的 form 实例(兼容 ref 和直接传入实例两种情况)
|
|
36
|
+
const getFormInstance = () => {
|
|
37
|
+
if (externalForm) {
|
|
38
|
+
return isExternalRef ? externalForm.current : externalForm;
|
|
39
|
+
}
|
|
40
|
+
return internalFormInstance;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// 兼容性处理:用于 form.current 访问方式的 ref
|
|
44
|
+
const formRef = externalForm && isExternalRef ? externalForm : internalFormRef;
|
|
45
|
+
|
|
46
|
+
// 更新内部 ref,确保 formRef.current 始终指向正确的实例
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!isExternalRef && externalForm) {
|
|
49
|
+
// 如果外部传入的是实例,将其赋值给内部 ref 的 current
|
|
50
|
+
internalFormRef.current = externalForm;
|
|
51
|
+
}
|
|
52
|
+
}, [externalForm, isExternalRef]);
|
|
22
53
|
const [internalOpen, setInternalOpen] = useState(defaultExpand);
|
|
23
54
|
useEffect(() => {
|
|
24
55
|
if (onRef) {
|
|
25
|
-
onRef(
|
|
56
|
+
onRef(formRef);
|
|
26
57
|
}
|
|
27
|
-
}, [
|
|
58
|
+
}, [formRef, onRef]);
|
|
28
59
|
const isControlled = expand !== undefined;
|
|
29
60
|
const isOpen = isControlled ? expand : internalOpen;
|
|
30
61
|
const handleToggle = () => {
|
|
@@ -47,10 +78,11 @@ const SearchForm = ({
|
|
|
47
78
|
icon: /*#__PURE__*/React.createElement(UndoOutlined, null),
|
|
48
79
|
loading: loading,
|
|
49
80
|
onClick: () => {
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
const formInstance = getFormInstance();
|
|
82
|
+
formInstance.resetFields();
|
|
83
|
+
onReset(formInstance.getFieldsValue());
|
|
52
84
|
}
|
|
53
|
-
}, "\u91CD\u7F6E"), formLine.length
|
|
85
|
+
}, "\u91CD\u7F6E"), formLine.length > 2 && /*#__PURE__*/React.createElement(Button, {
|
|
54
86
|
icon: /*#__PURE__*/React.createElement(DoubleRightOutlined, {
|
|
55
87
|
style: {
|
|
56
88
|
transform: isOpen ? 'rotate(-90deg)' : 'rotate(90deg)'
|
|
@@ -58,38 +90,70 @@ const SearchForm = ({
|
|
|
58
90
|
}),
|
|
59
91
|
onClick: handleToggle
|
|
60
92
|
}, isOpen ? '收起' : '展开'));
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 处理 formLine,确保所有 Form.Item 都有 noStyle 属性
|
|
96
|
+
* @param {ReactNode[]} nodes - 表单节点数组
|
|
97
|
+
* @returns {ReactNode[]} - 处理后的节点数组
|
|
98
|
+
*/
|
|
99
|
+
const processFormLine = nodes => {
|
|
100
|
+
return nodes.map(node => {
|
|
101
|
+
// 检查是否是 Form.Item 组件
|
|
102
|
+
if (/*#__PURE__*/React.isValidElement(node) && node.type === Form.Item) {
|
|
103
|
+
// 如果没有 noStyle 属性,则克隆并添加
|
|
104
|
+
if (!node.props.noStyle) {
|
|
105
|
+
return /*#__PURE__*/React.cloneElement(node, {
|
|
106
|
+
noStyle: true
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return node;
|
|
111
|
+
});
|
|
112
|
+
};
|
|
61
113
|
const groupsList = () => {
|
|
62
|
-
|
|
114
|
+
// 先处理 formLine,确保所有 Form.Item 都有 noStyle
|
|
115
|
+
const processedFormLine = processFormLine(formLine);
|
|
116
|
+
const arr = processedFormLine.map(node => ({
|
|
63
117
|
show: true,
|
|
64
118
|
node
|
|
65
119
|
}));
|
|
66
|
-
if (isOpen || arr.length <=
|
|
120
|
+
if (isOpen || arr.length <= 2) {
|
|
67
121
|
return arr;
|
|
68
122
|
}
|
|
69
|
-
return arr.map((item, index) => index >
|
|
123
|
+
return arr.map((item, index) => index > 1 ? {
|
|
70
124
|
...item,
|
|
71
125
|
show: false
|
|
72
126
|
} : item);
|
|
73
127
|
};
|
|
74
128
|
const formItemList = groupsList();
|
|
75
129
|
if (formItemList.length === 0) return null;
|
|
76
|
-
return /*#__PURE__*/React.createElement(Form, {
|
|
77
|
-
ref:
|
|
130
|
+
return /*#__PURE__*/React.createElement(Form, _extends({}, externalForm && isExternalRef ? {
|
|
131
|
+
ref: externalForm
|
|
132
|
+
} : {
|
|
133
|
+
form: externalForm || internalFormInstance
|
|
134
|
+
}, {
|
|
78
135
|
style: style,
|
|
79
136
|
initialValues: initialValues,
|
|
80
137
|
onFinish: values => onFinish(values)
|
|
81
|
-
}, /*#__PURE__*/React.createElement(Row, {
|
|
138
|
+
}), /*#__PURE__*/React.createElement(Row, {
|
|
82
139
|
gutter: [16, 16]
|
|
83
140
|
}, formItemList.map((item, index) => /*#__PURE__*/React.createElement(Col, {
|
|
84
141
|
key: index,
|
|
85
|
-
span:
|
|
142
|
+
span: 8,
|
|
86
143
|
style: {
|
|
87
144
|
display: item.show ? 'block' : 'none'
|
|
88
145
|
}
|
|
89
146
|
}, item.node)), /*#__PURE__*/React.createElement(Col, {
|
|
90
|
-
span:
|
|
147
|
+
span: 8,
|
|
148
|
+
style: {
|
|
149
|
+
display: 'flex',
|
|
150
|
+
alignItems: 'flex-start'
|
|
151
|
+
}
|
|
91
152
|
}, /*#__PURE__*/React.createElement(Form.Item, {
|
|
92
|
-
noStyle: true
|
|
153
|
+
noStyle: true,
|
|
154
|
+
style: {
|
|
155
|
+
marginBottom: 0
|
|
156
|
+
}
|
|
93
157
|
}, getButtons()))));
|
|
94
158
|
};
|
|
95
159
|
export default SearchForm;
|
package/Table/README.md
CHANGED
|
@@ -33,4 +33,4 @@ function App() {
|
|
|
33
33
|
| disabledResizer | 是否禁用内容区滚动,设置true自动将适配内容区滚动高度 | `boolean` | false |
|
|
34
34
|
| storeIndex | 当一个路由下存在多个表格的情况下 需要给每一个表格设置一个唯一存储索引 若没有设置则使用默认索引,请注意缓存数据会被覆盖 | `number` | - |
|
|
35
35
|
|
|
36
|
-
其他属性参考 https://ant-design.antgroup.com/components/table-cn#api
|
|
36
|
+
其他属性参考 https://ant-design.antgroup.com/components/table-cn#api
|
package/Table/index.d.ts
CHANGED
|
@@ -1,17 +1,64 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
// @ts-ignore
|
|
4
|
-
import type { TableProps } from 'antd';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import type { TableProps } from 'antd';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 列设置配置项
|
|
8
|
+
*/
|
|
9
|
+
export interface SettingOptionType {
|
|
10
|
+
/** 是否可拖拽排序 */
|
|
11
|
+
draggable?: boolean;
|
|
12
|
+
/** 是否显示复选框 */
|
|
13
|
+
checkable?: boolean;
|
|
14
|
+
/** 是否显示列表项选项 */
|
|
15
|
+
showListItemOption?: boolean;
|
|
16
|
+
/** 重置时是否恢复选中状态 */
|
|
17
|
+
checkedReset?: boolean;
|
|
18
|
+
/** 列表高度 */
|
|
19
|
+
listsHeight?: number;
|
|
20
|
+
/** 额外内容 */
|
|
21
|
+
extra?: React.ReactNode;
|
|
22
|
+
/** 子元素 */
|
|
23
|
+
children?: React.ReactNode;
|
|
24
|
+
/** 自定义设置图标 */
|
|
25
|
+
settingIcon?: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* ProTable options 配置项
|
|
30
|
+
*/
|
|
31
|
+
export interface OptionConfig {
|
|
32
|
+
/** 是否显示密度切换 */
|
|
33
|
+
density?: boolean;
|
|
34
|
+
/** 是否显示全屏按钮,或自定义函数 */
|
|
35
|
+
fullScreen?: boolean | ((e: React.MouseEvent<HTMLSpanElement>, action?: any) => void);
|
|
36
|
+
/** 是否显示刷新按钮,或自定义函数 */
|
|
37
|
+
reload?: boolean | ((e: React.MouseEvent<HTMLSpanElement>, action?: any) => void);
|
|
38
|
+
/** 列设置配置 */
|
|
39
|
+
setting?: boolean | SettingOptionType;
|
|
40
|
+
/** 搜索配置 */
|
|
41
|
+
search?: boolean | {
|
|
42
|
+
name?: string;
|
|
43
|
+
[key: string]: any;
|
|
44
|
+
};
|
|
45
|
+
/** 自定义刷新图标 */
|
|
46
|
+
reloadIcon?: React.ReactNode;
|
|
47
|
+
/** 自定义密度图标 */
|
|
48
|
+
densityIcon?: React.ReactNode;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface OverTableProps extends TableProps {
|
|
52
|
+
// 当一个路由下存在多个表格的情况下 需要给每一个表格设置一个唯一存储索引 若没有设置则使用默认索引,请注意缓存数据会被覆盖
|
|
53
|
+
storeIndex?: string;
|
|
54
|
+
// 是否启用自动计算滚动高度,默认-true
|
|
55
|
+
enableAutoScrollY?: boolean;
|
|
56
|
+
// ProTable options 配置项
|
|
57
|
+
options?: OptionConfig | false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface TableFc extends React.FC<OverTableProps> {
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare const Table: TableFc;
|
|
64
|
+
export default Table;
|
package/Table/index.js
CHANGED
|
@@ -1,118 +1,99 @@
|
|
|
1
1
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { tools } from '@cqsjjb/jjb-common-lib';
|
|
2
|
+
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
|
4
3
|
import { ProTable } from '@ant-design/pro-components';
|
|
5
|
-
import { useAntdResizableHeader } from 'use-antd-resizable-header';
|
|
6
|
-
import { antPrefix, setTableSize, getTableSize, getPersistenceKey } from './utils';
|
|
7
4
|
import './index.less';
|
|
8
|
-
|
|
5
|
+
import { antPrefix } from './utils';
|
|
9
6
|
export default function TablePro(props) {
|
|
10
7
|
const prefix = antPrefix || 'ant';
|
|
11
8
|
const baseCls = `.${prefix}-table`;
|
|
12
|
-
const
|
|
9
|
+
const ref = useRef(null);
|
|
13
10
|
const tableBodyCls = `${baseCls}-body`;
|
|
11
|
+
const tablePaginationCls = `${baseCls}-pagination`;
|
|
12
|
+
const tableFooterCls = `${baseCls}-footer`;
|
|
14
13
|
const {
|
|
15
|
-
|
|
14
|
+
enableAutoScrollY = true,
|
|
15
|
+
options = {
|
|
16
|
+
reload: false,
|
|
17
|
+
density: true,
|
|
18
|
+
fullScreen: true,
|
|
19
|
+
setting: {
|
|
20
|
+
checkedReset: true,
|
|
21
|
+
draggable: false,
|
|
22
|
+
checkable: true
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
...restProps
|
|
16
26
|
} = props;
|
|
17
|
-
const [
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
childList: true
|
|
38
|
-
});
|
|
27
|
+
const [scrollY, setScrollY] = useState(undefined);
|
|
28
|
+
const timerRef = useRef(null);
|
|
29
|
+
const calcTableScrollY = () => {
|
|
30
|
+
const tableBody = ref.current?.querySelector?.(tableBodyCls);
|
|
31
|
+
const tableBodyRect = tableBody?.getBoundingClientRect();
|
|
32
|
+
const tableFooter = ref.current?.querySelector?.(tableFooterCls);
|
|
33
|
+
const tableFooterRect = tableFooter?.getBoundingClientRect();
|
|
34
|
+
const tablePagination = ref.current?.querySelector?.(tablePaginationCls);
|
|
35
|
+
const tablePaginationRect = tablePagination?.getBoundingClientRect();
|
|
36
|
+
const tableFooterHeight = tableFooterRect?.height || 0;
|
|
37
|
+
const tablePaginationMargin = 16;
|
|
38
|
+
const tablePaginationHeight = tablePaginationRect?.height || 0;
|
|
39
|
+
const border = 2;
|
|
40
|
+
const margin = 20;
|
|
41
|
+
const scrollY = window.innerHeight - tableBodyRect.top - tableFooterHeight - tablePaginationHeight - tablePaginationMargin - border - margin;
|
|
42
|
+
return scrollY;
|
|
43
|
+
};
|
|
44
|
+
const debouncedCalcScrollY = useCallback(() => {
|
|
45
|
+
if (timerRef.current) {
|
|
46
|
+
clearTimeout(timerRef.current);
|
|
39
47
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
timerRef.current = setTimeout(() => {
|
|
49
|
+
const height = calcTableScrollY();
|
|
50
|
+
if (height) {
|
|
51
|
+
setScrollY(height);
|
|
44
52
|
}
|
|
45
|
-
};
|
|
53
|
+
}, 150);
|
|
46
54
|
}, []);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!ref.current || !enableAutoScrollY) return;
|
|
57
|
+
|
|
58
|
+
// 创建 ResizeObserver 监听元素尺寸变化
|
|
59
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
60
|
+
// 等待 table-pagination 元素生成后再计算
|
|
61
|
+
debouncedCalcScrollY();
|
|
62
|
+
});
|
|
63
|
+
const mutationObserver = new MutationObserver(() => {
|
|
64
|
+
debouncedCalcScrollY();
|
|
65
|
+
});
|
|
66
|
+
mutationObserver.observe(ref.current, {
|
|
67
|
+
childList: true,
|
|
68
|
+
subtree: true,
|
|
69
|
+
attributes: true
|
|
70
|
+
});
|
|
50
71
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// table-body元素
|
|
57
|
-
const tableBodyEl = document.querySelector(tableBodyCls);
|
|
58
|
-
if (tableBodyEl && tableEl) {
|
|
59
|
-
// 获取table元素的矩形数据
|
|
60
|
-
const tableRect = tableEl.getBoundingClientRect();
|
|
61
|
-
// 获取table-body元素的矩形数据
|
|
62
|
-
const tableBodyRect = tableBodyEl.getBoundingClientRect();
|
|
63
|
-
// 获取底部的高度差
|
|
64
|
-
const bottomHeight = tableRect.bottom - tableBodyRect.bottom;
|
|
65
|
-
// 计算最终值
|
|
66
|
-
setTableHeight(innerHeight - tableBodyRect.top - bottomHeight - (window.__IN_BASE__ ? 38 : 22));
|
|
72
|
+
// 开始观察 ref.current 的尺寸变化
|
|
73
|
+
resizeObserver.observe(ref.current);
|
|
74
|
+
return () => {
|
|
75
|
+
if (timerRef.current) {
|
|
76
|
+
clearTimeout(timerRef.current);
|
|
67
77
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
resetColumns
|
|
77
|
-
// refresh
|
|
78
|
-
} = useAntdResizableHeader({
|
|
79
|
-
columns: props.columns,
|
|
80
|
-
columnsState: {
|
|
81
|
-
persistenceKey: persistenceKey.resizable,
|
|
82
|
-
persistenceType: 'localStorage'
|
|
78
|
+
resizeObserver.disconnect();
|
|
79
|
+
mutationObserver.disconnect();
|
|
80
|
+
};
|
|
81
|
+
}, [ref, enableAutoScrollY, debouncedCalcScrollY]);
|
|
82
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
83
|
+
ref: ref,
|
|
84
|
+
style: {
|
|
85
|
+
height: '100%'
|
|
83
86
|
}
|
|
84
|
-
}
|
|
85
|
-
const scroll = {
|
|
86
|
-
x: tableWidth
|
|
87
|
-
};
|
|
88
|
-
if (enabledResizer) {
|
|
89
|
-
scroll.y = tableHeight;
|
|
90
|
-
}
|
|
91
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ProTable, _extends({
|
|
87
|
+
}, /*#__PURE__*/React.createElement(ProTable, _extends({
|
|
92
88
|
ghost: true,
|
|
93
89
|
columnEmptyText: true,
|
|
94
|
-
size: size,
|
|
95
90
|
search: false,
|
|
96
|
-
scroll:
|
|
91
|
+
scroll: enableAutoScrollY ? {
|
|
92
|
+
y: scrollY || 0
|
|
93
|
+
} : undefined,
|
|
97
94
|
className: `${antPrefix}-gbs-pro-table`,
|
|
98
|
-
options:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
setting: {
|
|
102
|
-
checkedReset: true,
|
|
103
|
-
extra: /*#__PURE__*/React.createElement("a", {
|
|
104
|
-
className: `${antPrefix}-pro-table-column-setting-action-rest-button`,
|
|
105
|
-
onClick: resetColumns
|
|
106
|
-
}, "\u91CD\u7F6E\u5217\u5BBD")
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
components: components,
|
|
110
|
-
columnsState: {
|
|
111
|
-
persistenceKey: persistenceKey.columnState,
|
|
112
|
-
persistenceType: 'localStorage'
|
|
113
|
-
},
|
|
114
|
-
onSizeChange: setSize
|
|
115
|
-
}, props, {
|
|
116
|
-
columns: resizableColumns
|
|
95
|
+
options: options
|
|
96
|
+
}, restProps, {
|
|
97
|
+
columns: restProps.columns
|
|
117
98
|
})));
|
|
118
99
|
}
|
package/Table/index.less
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
@com-prefix-cls: if(isdefined(@ant-prefix), @ant-prefix, ant);
|
|
2
|
+
|
|
3
|
+
.@{com-prefix-cls} {
|
|
2
4
|
&-gbs-pro-table {
|
|
3
|
-
.@{
|
|
5
|
+
.@{com-prefix-cls}-pro-card {
|
|
4
6
|
&-body {
|
|
5
|
-
.@{
|
|
7
|
+
.@{com-prefix-cls}-pro-table-list-toolbar {
|
|
6
8
|
&-container {
|
|
7
|
-
padding-
|
|
9
|
+
padding-block: 0;
|
|
8
10
|
}
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
|
-
}
|
|
15
|
+
}
|
package/TableAction/index.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { tools } from '@cqsjjb/jjb-common-lib';
|
|
3
|
-
import { MoreOutlined } from '@ant-design/icons';
|
|
4
3
|
import { Dropdown, Space } from 'antd';
|
|
5
4
|
export default function TableAction({
|
|
6
5
|
maximum = 3,
|
|
7
6
|
children,
|
|
8
7
|
space,
|
|
9
|
-
icon: Icon = MoreOutlined,
|
|
10
8
|
placement = 'bottomRight',
|
|
11
9
|
// 下拉菜单位置,默认 bottomRight
|
|
12
10
|
trigger = ['hover'] // 下拉触发方式,默认 hover
|
|
@@ -26,5 +24,5 @@ export default function TableAction({
|
|
|
26
24
|
},
|
|
27
25
|
placement: placement,
|
|
28
26
|
trigger: trigger
|
|
29
|
-
}, /*#__PURE__*/React.createElement("a", null,
|
|
27
|
+
}, /*#__PURE__*/React.createElement("a", null, "\u66F4\u591A")));
|
|
30
28
|
}
|