@fe-free/core 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +2 -2
- package/src/crud/crud.stories.tsx +34 -0
- package/src/crud/crud.tsx +26 -82
- package/src/crud/crud_delete.tsx +16 -21
- package/src/crud/index.tsx +2 -2
- package/src/crud/types.tsx +98 -0
- package/src/crud/use_row_selection.tsx +84 -0
- package/src/table/index.tsx +3 -3
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fe-free/core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"author": "",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"react-syntax-highlighter": "^15.5.0",
|
|
30
30
|
"vanilla-jsoneditor": "^0.23.1",
|
|
31
31
|
"zustand": "^4.5.4",
|
|
32
|
-
"@fe-free/tool": "1.3.
|
|
32
|
+
"@fe-free/tool": "1.3.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@ant-design/pro-components": "^2.8.7",
|
|
@@ -348,3 +348,37 @@ export const CustomText: Story = {
|
|
|
348
348
|
);
|
|
349
349
|
},
|
|
350
350
|
};
|
|
351
|
+
|
|
352
|
+
export const RowSelection: Story = {
|
|
353
|
+
render: () => {
|
|
354
|
+
return (
|
|
355
|
+
<CRUD
|
|
356
|
+
actions={[]}
|
|
357
|
+
tableProps={{
|
|
358
|
+
columns: [
|
|
359
|
+
{
|
|
360
|
+
title: 'id',
|
|
361
|
+
dataIndex: 'id',
|
|
362
|
+
search: true,
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
title: '名字',
|
|
366
|
+
dataIndex: 'name',
|
|
367
|
+
search: true,
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
request: fakeRequest,
|
|
371
|
+
}}
|
|
372
|
+
batchActions={[
|
|
373
|
+
{
|
|
374
|
+
btnText: '批量删除',
|
|
375
|
+
danger: true,
|
|
376
|
+
onClick: async (_, { selectedRowKeys }) => {
|
|
377
|
+
console.log(selectedRowKeys);
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
]}
|
|
381
|
+
/>
|
|
382
|
+
);
|
|
383
|
+
},
|
|
384
|
+
};
|
package/src/crud/crud.tsx
CHANGED
|
@@ -1,91 +1,18 @@
|
|
|
1
|
-
import type { ActionType
|
|
1
|
+
import type { ActionType } from '@ant-design/pro-components';
|
|
2
2
|
import { Button, Space } from 'antd';
|
|
3
|
-
import type { ReactNode } from 'react';
|
|
4
3
|
import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef } from 'react';
|
|
5
4
|
import type { TableProps } from '../table';
|
|
6
5
|
import { Table } from '../table';
|
|
7
6
|
import { OperateDelete } from './crud_delete';
|
|
8
7
|
import { CRUDDetail } from './crud_detail';
|
|
9
8
|
import './style.scss';
|
|
9
|
+
import type { CRUDMethods, CRUDProps } from './types';
|
|
10
|
+
import { useRowSelection } from './use_row_selection';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* update 编辑
|
|
16
|
-
* delete 删除
|
|
17
|
-
*/
|
|
18
|
-
type CrudAction = 'create' | 'read' | 'read_detail' | 'update' | 'delete';
|
|
19
|
-
|
|
20
|
-
interface CRUDProps {
|
|
21
|
-
actions: CrudAction[];
|
|
22
|
-
|
|
23
|
-
/** 新建按钮,默认新建 */
|
|
24
|
-
createButton?: ReactNode;
|
|
25
|
-
|
|
26
|
-
/** 表格相关 */
|
|
27
|
-
tableProps: TableProps;
|
|
28
|
-
operateColumnProps?: {
|
|
29
|
-
width?: number;
|
|
30
|
-
/** 扩展操作区域,再其他操作之前 */
|
|
31
|
-
moreOperator?: (record) => ReactNode;
|
|
32
|
-
/** 扩展操作区域,在其他操作之后 */
|
|
33
|
-
moreOperatorAfter?: (record) => ReactNode;
|
|
34
|
-
};
|
|
35
|
-
readProps?: {
|
|
36
|
-
/** 文本 */
|
|
37
|
-
operateText?: string;
|
|
38
|
-
/** 打开方式, action 为 read_detail 有效 */
|
|
39
|
-
target?: '_blank';
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/** 删除接口 */
|
|
43
|
-
requestDeleteByRecord?: (record) => Promise<any>;
|
|
44
|
-
/** 删除相关 */
|
|
45
|
-
deleteProps?: {
|
|
46
|
-
/** 显示名称索引 */
|
|
47
|
-
nameIndex: string;
|
|
48
|
-
/** 删除确认描述 */
|
|
49
|
-
desc?: string;
|
|
50
|
-
/** 文本 */
|
|
51
|
-
operateText?: string;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/** 弹窗表单 */
|
|
55
|
-
detailForm?: (formProps: { readonly: boolean }, info: { action: CrudAction }) => ReactNode;
|
|
56
|
-
/** detailForm 的 formRef */
|
|
57
|
-
detailFormInstance?: ProFormInstance;
|
|
58
|
-
|
|
59
|
-
/** 新增接口 */
|
|
60
|
-
requestCreateByValues?: (values) => Promise<any>;
|
|
61
|
-
createProps?: {
|
|
62
|
-
/** 成功文案 */
|
|
63
|
-
successText?: string | (() => string);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/** 更新接口 */
|
|
67
|
-
requestUpdateByValues?: (values) => Promise<any>;
|
|
68
|
-
/** @deprecated 请使用 requestUpdateByValues 替代 */
|
|
69
|
-
requestUpdateById?: (values) => Promise<any>;
|
|
70
|
-
updateProps?: {
|
|
71
|
-
/** 文本 */
|
|
72
|
-
operateText?: string;
|
|
73
|
-
/** 成功文案 */
|
|
74
|
-
successText?: string | (() => string);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/** 获取详情接口 */
|
|
78
|
-
requestGetByRecord?: (record) => Promise<any>;
|
|
79
|
-
|
|
80
|
-
/** 跳转到详情的索引 ,默认 id */
|
|
81
|
-
detailIdIndex?: string;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
interface CRUDMethods {
|
|
85
|
-
getActionRef: () => React.MutableRefObject<ActionType | undefined>;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const CRUD = forwardRef<CRUDMethods, CRUDProps>(function CRUD(props, ref) {
|
|
12
|
+
function CRUDComponent<
|
|
13
|
+
DataSource extends Record<string, any> = any,
|
|
14
|
+
Key extends string | number = string,
|
|
15
|
+
>(props: CRUDProps<DataSource, Key>, ref: React.ForwardedRef<CRUDMethods>) {
|
|
89
16
|
const {
|
|
90
17
|
actions,
|
|
91
18
|
tableProps,
|
|
@@ -103,6 +30,7 @@ const CRUD = forwardRef<CRUDMethods, CRUDProps>(function CRUD(props, ref) {
|
|
|
103
30
|
requestUpdateById: originalRequestUpdateById,
|
|
104
31
|
requestUpdateByValues: originalRequestUpdateByValues,
|
|
105
32
|
detailFormInstance,
|
|
33
|
+
batchActions,
|
|
106
34
|
} = props;
|
|
107
35
|
|
|
108
36
|
const requestUpdateById = originalRequestUpdateByValues || originalRequestUpdateById;
|
|
@@ -248,6 +176,13 @@ const CRUD = forwardRef<CRUDMethods, CRUDProps>(function CRUD(props, ref) {
|
|
|
248
176
|
[actions, createButton, detailProps, handleReload, tableProps],
|
|
249
177
|
);
|
|
250
178
|
|
|
179
|
+
const { rowSelection, tableAlertRender, tableAlertOptionRender } = useRowSelection<
|
|
180
|
+
DataSource,
|
|
181
|
+
Key
|
|
182
|
+
>({
|
|
183
|
+
batchActions,
|
|
184
|
+
});
|
|
185
|
+
|
|
251
186
|
return (
|
|
252
187
|
<div className="crud-table">
|
|
253
188
|
<Table
|
|
@@ -256,10 +191,19 @@ const CRUD = forwardRef<CRUDMethods, CRUDProps>(function CRUD(props, ref) {
|
|
|
256
191
|
actionRef={actionRef}
|
|
257
192
|
toolBarRender={toolBarRender}
|
|
258
193
|
columns={newColumns}
|
|
194
|
+
rowSelection={rowSelection}
|
|
195
|
+
tableAlertRender={tableAlertRender}
|
|
196
|
+
tableAlertOptionRender={tableAlertOptionRender}
|
|
259
197
|
/>
|
|
260
198
|
</div>
|
|
261
199
|
);
|
|
262
|
-
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const CRUD = forwardRef(CRUDComponent) as <
|
|
203
|
+
DataSource extends Record<string, any> = any,
|
|
204
|
+
Key extends string | number = string,
|
|
205
|
+
>(
|
|
206
|
+
props: CRUDProps<DataSource, Key> & { ref?: React.ForwardedRef<CRUDMethods> },
|
|
207
|
+
) => JSX.Element;
|
|
263
208
|
|
|
264
209
|
export { CRUD };
|
|
265
|
-
export type { CRUDMethods, CRUDProps };
|
package/src/crud/crud_delete.tsx
CHANGED
|
@@ -11,15 +11,20 @@ interface Params {
|
|
|
11
11
|
function useDelete(params: Params) {
|
|
12
12
|
const { name, desc, onDelete } = params;
|
|
13
13
|
|
|
14
|
-
const doDelete = useCallback(() => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
const doDelete = useCallback(async () => {
|
|
15
|
+
await new Promise((resolve) => {
|
|
16
|
+
Modal.confirm({
|
|
17
|
+
title: `确认删除 “${name}” 吗?`,
|
|
18
|
+
content: desc || '删除后不可恢复,请谨慎操作',
|
|
19
|
+
okText: '确定',
|
|
20
|
+
cancelText: '取消',
|
|
21
|
+
onOk: () => {
|
|
22
|
+
resolve(onDelete());
|
|
23
|
+
},
|
|
24
|
+
onCancel: () => {
|
|
25
|
+
resolve(undefined);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
23
28
|
});
|
|
24
29
|
}, [name, desc, onDelete]);
|
|
25
30
|
|
|
@@ -30,20 +35,10 @@ function useDelete(params: Params) {
|
|
|
30
35
|
|
|
31
36
|
function OperateDelete(props: Params) {
|
|
32
37
|
const { name, desc, onDelete, operateText } = props;
|
|
33
|
-
const
|
|
34
|
-
Modal.confirm({
|
|
35
|
-
title: `确认删除 “${name}” 吗?`,
|
|
36
|
-
content: desc || '删除后不可恢复,请谨慎操作',
|
|
37
|
-
okText: '确定',
|
|
38
|
-
cancelText: '取消',
|
|
39
|
-
onOk: () => {
|
|
40
|
-
onDelete();
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
}, [name, desc, onDelete]);
|
|
38
|
+
const { doDelete } = useDelete({ name, desc, onDelete, operateText });
|
|
44
39
|
|
|
45
40
|
return (
|
|
46
|
-
<a style={{ color: 'red' }} onClick={
|
|
41
|
+
<a style={{ color: 'red' }} onClick={doDelete}>
|
|
47
42
|
{operateText || '删除'}
|
|
48
43
|
</a>
|
|
49
44
|
);
|
package/src/crud/index.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { CRUD } from './crud';
|
|
2
|
-
export
|
|
2
|
+
export { OperateDelete, useDelete } from './crud_delete';
|
|
3
3
|
export { CRUDDetail } from './crud_detail';
|
|
4
4
|
export type { CRUDDetailProps } from './crud_detail';
|
|
5
|
-
export {
|
|
5
|
+
export type { CRUDMethods, CRUDProps } from './types';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { ActionType, ProFormInstance } from '@ant-design/pro-components';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { TableProps } from '../table';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* create 创建
|
|
7
|
+
* read 查看
|
|
8
|
+
* read_detail 详情页查看
|
|
9
|
+
* update 编辑
|
|
10
|
+
* delete 删除
|
|
11
|
+
*/
|
|
12
|
+
type CrudAction = 'create' | 'read' | 'read_detail' | 'update' | 'delete';
|
|
13
|
+
|
|
14
|
+
interface CRUDProps<
|
|
15
|
+
DataSource extends Record<string, any> = any,
|
|
16
|
+
Key extends string | number = string,
|
|
17
|
+
> {
|
|
18
|
+
actions: CrudAction[];
|
|
19
|
+
|
|
20
|
+
/** 新建按钮,默认新建 */
|
|
21
|
+
createButton?: ReactNode;
|
|
22
|
+
|
|
23
|
+
/** 表格相关 */
|
|
24
|
+
tableProps: TableProps<DataSource>;
|
|
25
|
+
operateColumnProps?: {
|
|
26
|
+
width?: number;
|
|
27
|
+
/** 扩展操作区域,再其他操作之前 */
|
|
28
|
+
moreOperator?: (record: DataSource) => ReactNode;
|
|
29
|
+
/** 扩展操作区域,在其他操作之后 */
|
|
30
|
+
moreOperatorAfter?: (record: DataSource) => ReactNode;
|
|
31
|
+
};
|
|
32
|
+
readProps?: {
|
|
33
|
+
/** 文本 */
|
|
34
|
+
operateText?: string;
|
|
35
|
+
/** 打开方式, action 为 read_detail 有效 */
|
|
36
|
+
target?: '_blank';
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** 删除接口 */
|
|
40
|
+
requestDeleteByRecord?: (record: DataSource) => Promise<any>;
|
|
41
|
+
/** 删除相关 */
|
|
42
|
+
deleteProps?: {
|
|
43
|
+
/** 显示名称索引 */
|
|
44
|
+
nameIndex: keyof DataSource;
|
|
45
|
+
/** 删除确认描述 */
|
|
46
|
+
desc?: string;
|
|
47
|
+
/** 文本 */
|
|
48
|
+
operateText?: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** 弹窗表单 */
|
|
52
|
+
detailForm?: (formProps: { readonly: boolean }, info: { action: CrudAction }) => ReactNode;
|
|
53
|
+
/** detailForm 的 formRef */
|
|
54
|
+
detailFormInstance?: ProFormInstance;
|
|
55
|
+
|
|
56
|
+
/** 新增接口 */
|
|
57
|
+
requestCreateByValues?: (values: Partial<DataSource>) => Promise<any>;
|
|
58
|
+
createProps?: {
|
|
59
|
+
/** 成功文案 */
|
|
60
|
+
successText?: string | (() => string);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** 更新接口 */
|
|
64
|
+
requestUpdateByValues?: (values: Partial<DataSource>) => Promise<any>;
|
|
65
|
+
/** @deprecated 请使用 requestUpdateByValues 替代 */
|
|
66
|
+
requestUpdateById?: (values: Partial<DataSource>) => Promise<any>;
|
|
67
|
+
updateProps?: {
|
|
68
|
+
/** 文本 */
|
|
69
|
+
operateText?: string;
|
|
70
|
+
/** 成功文案 */
|
|
71
|
+
successText?: string | (() => string);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** 获取详情接口 */
|
|
75
|
+
requestGetByRecord?: (record: DataSource) => Promise<any>;
|
|
76
|
+
|
|
77
|
+
/** 跳转到详情的索引 ,默认 id */
|
|
78
|
+
detailIdIndex?: string;
|
|
79
|
+
|
|
80
|
+
/** 批量操作 */
|
|
81
|
+
batchActions?: {
|
|
82
|
+
/** 按钮文本 */
|
|
83
|
+
btnText: string;
|
|
84
|
+
/** 红色,且有确认框 */
|
|
85
|
+
danger?: boolean;
|
|
86
|
+
/** 批量操作接口 */
|
|
87
|
+
onClick: (
|
|
88
|
+
event: React.MouseEvent<HTMLElement>,
|
|
89
|
+
options: { selectedRowKeys: Key[]; selectedRows: DataSource[] },
|
|
90
|
+
) => Promise<any>;
|
|
91
|
+
}[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface CRUDMethods {
|
|
95
|
+
getActionRef: () => React.MutableRefObject<ActionType | undefined>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export type { CRUDMethods, CRUDProps };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Modal } from 'antd';
|
|
2
|
+
import { useCallback, useMemo } from 'react';
|
|
3
|
+
import { LoadingButton } from '../button';
|
|
4
|
+
import type { CRUDProps } from './types';
|
|
5
|
+
|
|
6
|
+
function useRowSelection<
|
|
7
|
+
DataSource extends Record<string, any> = any,
|
|
8
|
+
Key extends string | number = string,
|
|
9
|
+
>({ batchActions }: { batchActions?: CRUDProps<DataSource, Key>['batchActions'] }) {
|
|
10
|
+
const rowSelection = useMemo(() => ({}), []);
|
|
11
|
+
|
|
12
|
+
const tableAlertRender = useCallback(({ selectedRowKeys, onCleanSelected }) => {
|
|
13
|
+
return (
|
|
14
|
+
<div>
|
|
15
|
+
<span>
|
|
16
|
+
已选 {selectedRowKeys.length} 项
|
|
17
|
+
<a style={{ marginInlineStart: 8 }} onClick={onCleanSelected}>
|
|
18
|
+
取消选择
|
|
19
|
+
</a>
|
|
20
|
+
</span>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
const tableAlertOptionRender = useCallback(
|
|
26
|
+
({ selectedRowKeys, selectedRows }) => {
|
|
27
|
+
return (
|
|
28
|
+
<div className="flex gap-2 items-center">
|
|
29
|
+
{batchActions?.map((action) => (
|
|
30
|
+
<LoadingButton
|
|
31
|
+
key={action.btnText}
|
|
32
|
+
type="link"
|
|
33
|
+
danger={action.danger}
|
|
34
|
+
onClick={async (event) => {
|
|
35
|
+
if (action.danger) {
|
|
36
|
+
await new Promise((resolve) => {
|
|
37
|
+
Modal.confirm({
|
|
38
|
+
title: `确定要执行 ${action.btnText} 吗?`,
|
|
39
|
+
onOk: () => {
|
|
40
|
+
resolve(
|
|
41
|
+
action.onClick(event, {
|
|
42
|
+
selectedRowKeys,
|
|
43
|
+
selectedRows,
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
onCancel: () => {
|
|
48
|
+
resolve(undefined);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
} else {
|
|
53
|
+
await action.onClick(event, {
|
|
54
|
+
selectedRowKeys,
|
|
55
|
+
selectedRows,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
{action.btnText}
|
|
61
|
+
</LoadingButton>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
[batchActions],
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (!batchActions || batchActions.length === 0) {
|
|
70
|
+
return {
|
|
71
|
+
rowSelection: undefined,
|
|
72
|
+
tableAlertRender: undefined,
|
|
73
|
+
tableAlertOptionRender: undefined,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
rowSelection,
|
|
79
|
+
tableAlertRender,
|
|
80
|
+
tableAlertOptionRender,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { useRowSelection };
|
package/src/table/index.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { ParamsType, ProTableProps } from '@ant-design/pro-components';
|
|
1
2
|
import { ProTable } from '@ant-design/pro-components';
|
|
2
|
-
import type { ProTableProps, ParamsType } from '@ant-design/pro-components';
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
4
|
|
|
5
5
|
interface TableProps<DataSource = any, Params = any, ValueType = 'text'>
|
|
@@ -10,7 +10,7 @@ interface TableProps<DataSource = any, Params = any, ValueType = 'text'>
|
|
|
10
10
|
|
|
11
11
|
function Table<
|
|
12
12
|
DataSource extends Record<string, any> = any,
|
|
13
|
-
Params extends ParamsType = ParamsType
|
|
13
|
+
Params extends ParamsType = ParamsType,
|
|
14
14
|
>(props: TableProps<DataSource, Params>) {
|
|
15
15
|
const { columns, rowKey = 'id', search, ...rest } = props;
|
|
16
16
|
|
|
@@ -48,7 +48,7 @@ function Table<
|
|
|
48
48
|
scroll={getTableScroll(newColumns)}
|
|
49
49
|
search={
|
|
50
50
|
hasSearch && {
|
|
51
|
-
|
|
51
|
+
labelWidth: 'auto',
|
|
52
52
|
defaultCollapsed: false,
|
|
53
53
|
...search,
|
|
54
54
|
}
|