@fe-free/core 1.0.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.
@@ -0,0 +1,148 @@
1
+ import { range } from 'lodash-es';
2
+
3
+ const citys = {
4
+ 广州: ['白云', '黄埔', '增城'],
5
+ 深圳: ['福田', '南山', '宝安'],
6
+ };
7
+
8
+ const levels = {
9
+ HIGH: { text: '高' },
10
+ MEDIUM: { text: '中' },
11
+ LOW: { text: '低' },
12
+ };
13
+
14
+ const schools = [
15
+ { value: '0', label: '第一小学' },
16
+ { value: '1', label: '第二小学' },
17
+ { value: '2', label: '第三小学' },
18
+ ];
19
+
20
+ function random(length) {
21
+ return Math.floor(Math.random() * length);
22
+ }
23
+
24
+ function randomCity() {
25
+ return Object.keys(citys)[random(Object.keys(citys).length + 1)];
26
+ }
27
+ function randomArea(params: { city?: string }) {
28
+ if (!params.city) {
29
+ return undefined;
30
+ }
31
+
32
+ return params.city && citys[params.city][random(citys[params.city].length + 1)];
33
+ }
34
+
35
+ function randomLevel() {
36
+ return Object.keys(levels)[random(Object.keys(levels).length + 1)];
37
+ }
38
+
39
+ function makeData(count) {
40
+ return range(count).map((id) => {
41
+ const city = randomCity();
42
+ const area = randomArea({ city });
43
+
44
+ return {
45
+ id: `${id}`,
46
+ name: `这是名字这是名字这是名字 ${id}`,
47
+ city,
48
+ area,
49
+ level: randomLevel(),
50
+ status: random(2) === 1,
51
+ school: '' + random(schools.length),
52
+ };
53
+ });
54
+ }
55
+
56
+ let fakeData = makeData(21);
57
+
58
+ async function fakeRequest(params) {
59
+ console.log('fakeRequest', params);
60
+
61
+ return new Promise((resolve) => {
62
+ setTimeout(() => {
63
+ resolve({
64
+ data: fakeData,
65
+ success: true,
66
+ total: fakeData.length,
67
+ });
68
+ }, 1000);
69
+ }) as Promise<any>;
70
+ }
71
+
72
+ async function fakeDeleteByRecord(record) {
73
+ console.log('fakeDeleteByRecord', record);
74
+
75
+ fakeData = fakeData.filter((item) => item.id !== record.id);
76
+
77
+ return Promise.resolve({});
78
+ }
79
+
80
+ async function fakeGetByRecord(record) {
81
+ console.log('fakeGetByRecord', record);
82
+
83
+ return new Promise((resolve) => {
84
+ setTimeout(() => {
85
+ resolve({
86
+ data: {
87
+ data: fakeData.find((item) => item.id === record.id),
88
+ },
89
+ });
90
+ }, 1000);
91
+ });
92
+ }
93
+
94
+ async function fakeCreate(params) {
95
+ console.log('fakeCreate', params);
96
+
97
+ fakeData.push({
98
+ id: fakeData.length + 1,
99
+ ...params,
100
+ });
101
+
102
+ return Promise.resolve({});
103
+ }
104
+
105
+ async function fakeUpdateById(params) {
106
+ console.log('fakeUpdateById', params);
107
+
108
+ fakeData = fakeData.map((item) => {
109
+ if (item.id === params.id) {
110
+ return {
111
+ ...item,
112
+ ...params,
113
+ };
114
+ }
115
+ return item;
116
+ });
117
+
118
+ return Promise.resolve({});
119
+ }
120
+
121
+ function fakeRequestCity(): Promise<string[]> {
122
+ return Promise.resolve(Object.keys(citys));
123
+ }
124
+
125
+ function fakeRequestArea(params?: { city?: string }): Promise<string[]> {
126
+ if (!params?.city) {
127
+ return Promise.resolve(Object.values(citys).reduce((prev, cur) => prev.concat(cur), []));
128
+ }
129
+
130
+ return Promise.resolve(citys[params.city]);
131
+ }
132
+
133
+ function fakeRequestSchool() {
134
+ return Promise.resolve(schools);
135
+ }
136
+
137
+ export {
138
+ fakeData,
139
+ levels,
140
+ fakeRequest,
141
+ fakeDeleteByRecord,
142
+ fakeGetByRecord,
143
+ fakeCreate,
144
+ fakeUpdateById,
145
+ fakeRequestCity,
146
+ fakeRequestArea,
147
+ fakeRequestSchool,
148
+ };
@@ -0,0 +1,342 @@
1
+ import React, { useRef } from 'react';
2
+ import type { CRUDProps } from '@fe-free/core';
3
+ import { CRUD, proFormSelectSearchProps } from '@fe-free/core';
4
+ import { Button } from 'antd';
5
+ import { ProForm, ProFormSwitch, ProFormText } from '@ant-design/pro-components';
6
+ import {
7
+ fakeRequest,
8
+ fakeDeleteByRecord,
9
+ fakeCreate,
10
+ fakeGetByRecord,
11
+ fakeUpdateById,
12
+ fakeRequestCity,
13
+ fakeRequestArea,
14
+ levels,
15
+ fakeRequestSchool,
16
+ } from './data';
17
+
18
+ const Normal = () => {
19
+ const columns = [
20
+ {
21
+ title: 'id',
22
+ dataIndex: 'id',
23
+ search: true,
24
+ },
25
+ {
26
+ title: '名字(省略)',
27
+ dataIndex: 'name',
28
+ search: true,
29
+ ellipsis: true,
30
+ },
31
+ {
32
+ title: 'city',
33
+ dataIndex: 'city',
34
+ },
35
+ {
36
+ title: 'area',
37
+ dataIndex: 'area',
38
+ },
39
+ ];
40
+
41
+ return (
42
+ <CRUD
43
+ actions={['create', 'read', 'delete', 'update']}
44
+ tableProps={{
45
+ columns,
46
+ request: fakeRequest,
47
+ }}
48
+ deleteByRecord={fakeDeleteByRecord}
49
+ deleteProps={{
50
+ nameIndex: 'name',
51
+ }}
52
+ detailForm={(formProps) => (
53
+ <>
54
+ <ProFormText
55
+ {...formProps}
56
+ name="name"
57
+ label="名字"
58
+ required
59
+ rules={[{ required: true }]}
60
+ extra="extra extra extra extra"
61
+ />
62
+ </>
63
+ )}
64
+ requestGetByRecord={fakeGetByRecord}
65
+ requestCreate={fakeCreate}
66
+ requestUpdateById={fakeUpdateById}
67
+ />
68
+ );
69
+ };
70
+
71
+ function ReadDetail() {
72
+ const columns = [
73
+ {
74
+ title: 'id',
75
+ dataIndex: 'id',
76
+ search: true,
77
+ },
78
+ {
79
+ title: '名字',
80
+ dataIndex: 'name',
81
+ search: true,
82
+ },
83
+ ];
84
+
85
+ return (
86
+ <CRUD
87
+ actions={['read_detail']}
88
+ tableProps={{
89
+ columns,
90
+ request: fakeRequest,
91
+ }}
92
+ />
93
+ );
94
+ }
95
+
96
+ function Ref() {
97
+ const formRef = useRef<any>();
98
+ const [detailFormInstance] = ProForm.useForm();
99
+
100
+ // @ts-ignore
101
+ window._detailFormInstance = detailFormInstance;
102
+
103
+ const name = ProForm.useWatch('name', formRef.current);
104
+ const detailName = ProForm.useWatch('name', detailFormInstance);
105
+
106
+ // 不知道为啥这里 name 不生效,但是项目里是生效的。先忽略
107
+ console.log('useWatch', name, detailName);
108
+
109
+ const columns = [
110
+ {
111
+ title: 'id',
112
+ dataIndex: 'id',
113
+ search: true,
114
+ },
115
+ {
116
+ title: '名字',
117
+ dataIndex: 'name',
118
+ search: true,
119
+ },
120
+ ];
121
+
122
+ return (
123
+ <CRUD
124
+ actions={['create', 'read', 'update']}
125
+ tableProps={{
126
+ formRef,
127
+ columns,
128
+ request: fakeRequest,
129
+ }}
130
+ detailFormInstance={detailFormInstance}
131
+ detailForm={(formProps) => (
132
+ <>
133
+ <ProFormText
134
+ {...formProps}
135
+ name="name"
136
+ label="名字"
137
+ required
138
+ rules={[{ required: true }]}
139
+ initialValue={'default'}
140
+ />
141
+ <ProFormSwitch {...formProps} name="status" label="开启" initialValue={false} />
142
+ </>
143
+ )}
144
+ requestGetByRecord={fakeGetByRecord}
145
+ requestCreate={fakeCreate}
146
+ requestUpdateById={fakeUpdateById}
147
+ />
148
+ );
149
+ }
150
+
151
+ function ActionRef() {
152
+ const ref = useRef<any>();
153
+
154
+ const columns = [
155
+ {
156
+ title: 'id',
157
+ dataIndex: 'id',
158
+ search: true,
159
+ },
160
+ {
161
+ title: '名字',
162
+ dataIndex: 'name',
163
+ search: true,
164
+ },
165
+ ];
166
+
167
+ return (
168
+ <>
169
+ <Button onClick={() => ref.current.getActionRef().current?.reload()}>reload</Button>
170
+ <CRUD
171
+ ref={ref}
172
+ actions={[]}
173
+ tableProps={{
174
+ columns,
175
+ request: fakeRequest,
176
+ }}
177
+ />
178
+ </>
179
+ );
180
+ }
181
+
182
+ function RemoteData() {
183
+ const columns: CRUDProps['tableProps']['columns'] = [
184
+ {
185
+ title: 'id',
186
+ dataIndex: 'id',
187
+ search: true,
188
+ },
189
+ {
190
+ title: '名字',
191
+ dataIndex: 'name',
192
+ search: true,
193
+ },
194
+ {
195
+ title: '等级(本地数据)',
196
+ dataIndex: 'level',
197
+ search: true,
198
+ valueEnum: levels,
199
+ ...proFormSelectSearchProps,
200
+ },
201
+ {
202
+ title: 'city(远端数据)',
203
+ dataIndex: 'city',
204
+ search: true,
205
+ request: async () => {
206
+ console.log('request');
207
+ const res = await fakeRequestCity();
208
+
209
+ return (
210
+ res.map((item) => ({
211
+ label: item,
212
+ value: item,
213
+ })) || []
214
+ );
215
+ },
216
+ ...proFormSelectSearchProps,
217
+ },
218
+ {
219
+ title: 'area(联动 city)',
220
+ dataIndex: 'area',
221
+ search: true,
222
+ request: async (params) => {
223
+ console.log('params', params);
224
+ const res = await fakeRequestArea(params);
225
+
226
+ return (
227
+ res.map((item) => ({
228
+ label: item,
229
+ value: item,
230
+ })) || []
231
+ );
232
+ },
233
+ dependencies: ['city'],
234
+ ...proFormSelectSearchProps,
235
+ },
236
+ {
237
+ title: '学校(远端数据 label value)',
238
+ dataIndex: 'school',
239
+ search: true,
240
+ valueType: 'select',
241
+ request: () => fakeRequestSchool(),
242
+ ...proFormSelectSearchProps,
243
+ },
244
+ ];
245
+
246
+ return (
247
+ <CRUD
248
+ actions={[]}
249
+ tableProps={{
250
+ columns,
251
+ request: fakeRequest,
252
+ }}
253
+ />
254
+ );
255
+ }
256
+
257
+ function NoSearch() {
258
+ const ref = useRef<any>();
259
+
260
+ const columns = [
261
+ {
262
+ title: 'id',
263
+ dataIndex: 'id',
264
+ },
265
+ {
266
+ title: '名字',
267
+ dataIndex: 'name',
268
+ },
269
+ ];
270
+
271
+ return (
272
+ <CRUD
273
+ ref={ref}
274
+ actions={[]}
275
+ tableProps={{
276
+ columns,
277
+ request: fakeRequest,
278
+ }}
279
+ />
280
+ );
281
+ }
282
+
283
+ const CustomText = () => {
284
+ const columns = [
285
+ {
286
+ title: 'id',
287
+ dataIndex: 'id',
288
+ search: true,
289
+ },
290
+ {
291
+ title: '名字',
292
+ dataIndex: 'name',
293
+ search: true,
294
+ ellipsis: true,
295
+ },
296
+ ];
297
+
298
+ return (
299
+ <CRUD
300
+ actions={['create', 'read', 'delete', 'update']}
301
+ tableProps={{
302
+ columns,
303
+ request: fakeRequest,
304
+ }}
305
+ operateColumnProps={{
306
+ width: 230,
307
+ moreOperator: () => <div>custom</div>,
308
+ }}
309
+ readProps={{
310
+ operateText: '查看啦',
311
+ }}
312
+ deleteByRecord={fakeDeleteByRecord}
313
+ deleteProps={{
314
+ nameIndex: 'name',
315
+ operateText: '删除啦',
316
+ }}
317
+ detailForm={(formProps) => (
318
+ <>
319
+ <ProFormText
320
+ {...formProps}
321
+ name="name"
322
+ label="名字"
323
+ required
324
+ rules={[{ required: true }]}
325
+ />
326
+ </>
327
+ )}
328
+ requestGetByRecord={fakeGetByRecord}
329
+ requestCreate={fakeCreate}
330
+ createProps={{
331
+ successText: '新建成功啦',
332
+ }}
333
+ updateProps={{
334
+ operateText: '更新啦',
335
+ successText: '更新成功啦',
336
+ }}
337
+ requestUpdateById={fakeUpdateById}
338
+ />
339
+ );
340
+ };
341
+
342
+ export { Normal, ReadDetail, Ref, ActionRef, RemoteData, NoSearch, CustomText };
@@ -0,0 +1,163 @@
1
+ ---
2
+ nav:
3
+ title: '组件'
4
+ order: 10
5
+ group: 'core'
6
+ toc: content
7
+ ---
8
+
9
+ # CRUD
10
+
11
+ > 需要了解 ant pro-components ProForm ProTable
12
+
13
+ 基于 ant pro-components 通用的 CRUD 组件,同时保留扩展性。
14
+
15
+ ## 代码演示
16
+
17
+ ### 常规
18
+
19
+ ```tsx
20
+ import { Normal } from './demo';
21
+
22
+ export default Normal;
23
+ ```
24
+
25
+ ### 详情页查看
26
+
27
+ 调整 actions 为 `['read_detail']`,点击<查看>跳转到 `xxx/detail/[id]`,
28
+
29
+ ```tsx
30
+ import { ReadDetail } from './demo';
31
+
32
+ export default ReadDetail;
33
+ ```
34
+
35
+ ### 数据 本地&远程&依赖
36
+
37
+ ```tsx
38
+ import { RemoteData } from './demo';
39
+
40
+ export default RemoteData;
41
+ ```
42
+
43
+ ### 表格表单和详情表单 ref
44
+
45
+ 获取 ProTable 的 actionRef
46
+
47
+ ```tsx
48
+ import { Ref } from './demo';
49
+
50
+ export default Ref;
51
+ ```
52
+
53
+ ### ref.current.getActionRef
54
+
55
+ 通过 ref 你可以做更多操作
56
+
57
+ ```tsx
58
+ import { ActionRef } from './demo';
59
+
60
+ export default ActionRef;
61
+ ```
62
+
63
+ ### 没有搜索
64
+
65
+ ```tsx
66
+ import { NoSearch } from './demo';
67
+
68
+ export default NoSearch;
69
+ ```
70
+
71
+ ### 自定义文案
72
+
73
+ ```tsx
74
+ import { CustomText } from './demo';
75
+
76
+ export default CustomText;
77
+ ```
78
+
79
+ ## API
80
+
81
+ ```tsx | pure
82
+ import type { ReactNode } from 'react';
83
+ import type { TableProps } from '../table';
84
+ import type { ProFormInstance, ActionType } from '@ant-design/pro-components';
85
+
86
+ /**
87
+ * create 创建
88
+ * read 查看
89
+ * read_detail 详情页查看
90
+ * update 编辑
91
+ * delete 删除
92
+ */
93
+ type CrudAction = 'create' | 'read' | 'read_detail' | 'update' | 'delete';
94
+
95
+ interface CRUDProps {
96
+ actions: CrudAction[];
97
+
98
+ /** 表格相关 */
99
+ tableProps: TableProps;
100
+
101
+ /** 新建按钮,默认新建 */
102
+ createButton?: ReactNode;
103
+
104
+ operateColumnProps?: {
105
+ width?: number;
106
+ /** 扩展操作区域 */
107
+ moreOperator?: (record) => ReactNode;
108
+ };
109
+
110
+ readProps?: {
111
+ /** 文本 */
112
+ operateText?: string;
113
+ };
114
+
115
+ /** 删除接口 */
116
+ deleteById?: ({ id, ids }) => Promise<any>;
117
+ deleteByRecord?: (record) => Promise<any>;
118
+ /** 删除相关 */
119
+ deleteProps?: {
120
+ /** 显示名称索引 */
121
+ nameIndex: string;
122
+ /** 删除确认描述 */
123
+ desc?: string;
124
+ /** 文本 */
125
+ operateText?: string;
126
+ };
127
+
128
+ /** 弹窗表单 */
129
+ detailForm?: (formProps: { readonly: boolean }, info: { action: CrudAction }) => ReactNode;
130
+ /** detailForm 的 formRef */
131
+ detailFormInstance?: ProFormInstance;
132
+
133
+ /** 新增接口 */
134
+ requestAdd?: (values) => Promise<any>;
135
+
136
+ addProps?: {
137
+ /** 成功文案 */
138
+ successText?: string | (() => string);
139
+ };
140
+
141
+ /** 更新接口 */
142
+ requestUpdateById?: (values) => Promise<any>;
143
+ updateProps?: {
144
+ /** 文本 */
145
+ operateText?: string;
146
+ /** 成功文案 */
147
+ successText?: string | (() => string);
148
+ };
149
+
150
+ /** 获取详情接口 */
151
+ requestGetById?: ({ id }) => Promise<any>;
152
+
153
+ /** 获取详情接口,非 id 的时候 */
154
+ requestGetByRecord?: (record) => Promise<any>;
155
+
156
+ /** 跳转到详情的 id 所以,默认 id */
157
+ detailIdIndex?: string;
158
+ }
159
+
160
+ interface CRUDMethods {
161
+ getActionRef: () => React.MutableRefObject<ActionType | undefined>;
162
+ }
163
+ ```
@@ -0,0 +1,2 @@
1
+ export { CRUD } from './crud';
2
+ export type { CRUDProps, CRUDMethods } from './crud';
@@ -0,0 +1,10 @@
1
+ .crud-detail {
2
+ // 查看情况下隐藏 FormItem 的 extra
3
+ &.crud-detail-hide-extra {
4
+ .ant-form-item {
5
+ .ant-form-item-extra {
6
+ display: none;
7
+ }
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,64 @@
1
+ ---
2
+ group: 'core'
3
+ toc: content
4
+ ---
5
+
6
+ # EditorJavascript
7
+
8
+ ## 代码演示
9
+
10
+ ### 常规
11
+
12
+ ```tsx
13
+ import { useState } from 'react';
14
+ import { EditorJavascript } from '@fe-free/core';
15
+
16
+ function Demo() {
17
+ const [value, setValue] = useState(
18
+ `const name = 'world';
19
+ console.log('hello', name);
20
+ `
21
+ );
22
+
23
+ return (
24
+ <div style={{ width: '500px', height: '500px' }}>
25
+ <EditorJavascript value={value} onChange={setValue} />
26
+ </div>
27
+ );
28
+ }
29
+
30
+ export default Demo;
31
+ ```
32
+
33
+ ### readonly
34
+
35
+ ```tsx
36
+ import { useState } from 'react';
37
+ import { EditorJavascript } from '@fe-free/core';
38
+
39
+ function Demo() {
40
+ const [value, setValue] = useState(
41
+ `const name = 'world';
42
+ console.log('hello', name);
43
+ `
44
+ );
45
+
46
+ return (
47
+ <div style={{ width: '500px', height: '500px' }}>
48
+ <EditorJavascript value={value} onChange={setValue} readonly />
49
+ </div>
50
+ );
51
+ }
52
+
53
+ export default Demo;
54
+ ```
55
+
56
+ ## API
57
+
58
+ ```tsx | pure
59
+ interface EditorJavascriptProps {
60
+ value: string;
61
+ onChange: (value: string, event?: any) => void;
62
+ readonly?: boolean;
63
+ }
64
+ ```