@quansitech/antd-admin 1.0.0

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.
Files changed (38) hide show
  1. package/components/Column/Cascader.tsx +79 -0
  2. package/components/Column/File.tsx +168 -0
  3. package/components/Column/Image.tsx +77 -0
  4. package/components/Column/Readonly/Cascader.tsx +51 -0
  5. package/components/Column/Readonly/File.tsx +54 -0
  6. package/components/Column/Readonly/Image.tsx +78 -0
  7. package/components/Column/Readonly/Option.tsx +58 -0
  8. package/components/Column/Readonly/types.d.ts +9 -0
  9. package/components/Column/Ueditor.tsx +314 -0
  10. package/components/Column/types.d.ts +29 -0
  11. package/components/Form/Action/Button.tsx +125 -0
  12. package/components/Form/Action/types.d.ts +5 -0
  13. package/components/Form/Actions.tsx +35 -0
  14. package/components/Form.tsx +171 -0
  15. package/components/FormContext.ts +8 -0
  16. package/components/Layout.tsx +237 -0
  17. package/components/LayoutContext.ts +26 -0
  18. package/components/ModalContext.ts +16 -0
  19. package/components/Table/Action/Button.tsx +89 -0
  20. package/components/Table/Action/StartEditable.tsx +59 -0
  21. package/components/Table/Action/types.d.ts +7 -0
  22. package/components/Table/Option/Link.tsx +68 -0
  23. package/components/Table/Option/types.d.ts +5 -0
  24. package/components/Table/ToolbarActions.tsx +39 -0
  25. package/components/Table.scss +7 -0
  26. package/components/Table.tsx +279 -0
  27. package/components/TableContext.ts +14 -0
  28. package/components/Tabs.tsx +72 -0
  29. package/components/types.d.ts +0 -0
  30. package/lib/container.ts +82 -0
  31. package/lib/customRule.ts +10 -0
  32. package/lib/global.ts +11 -0
  33. package/lib/helpers.tsx +150 -0
  34. package/lib/http.ts +74 -0
  35. package/lib/schemaHandler.ts +122 -0
  36. package/lib/upload.ts +177 -0
  37. package/package.json +35 -0
  38. package/readme.md +128 -0
@@ -0,0 +1,314 @@
1
+ import {ColumnProps} from "./types";
2
+ import {Component} from "react";
3
+ import {createScript, filterObjectKeys} from "../../lib/helpers";
4
+ import {Spin} from "antd";
5
+ import {ModalContext, ModalContextProps} from "../ModalContext";
6
+ import uniqueId from "lodash/uniqueId";
7
+ import {FormContext, FormContextProps} from "../FormContext";
8
+
9
+ declare global {
10
+ interface Window {
11
+ UE: any,
12
+ UE_LOADING_PROMISE: Promise<any>,
13
+ }
14
+ }
15
+
16
+ export default class Ueditor extends Component<ColumnProps & {
17
+ fieldProps: {
18
+ ueditorPath: string,
19
+ }
20
+ }, any> {
21
+ modalContext = {} as ModalContextProps
22
+ formContext = {} as FormContextProps
23
+
24
+ editor: any = null
25
+ catching = false
26
+ containerRef: HTMLElement | null = null
27
+ state = {
28
+ loading: true,
29
+ containerId: uniqueId('ueditor_'),
30
+ width: '',
31
+ }
32
+
33
+
34
+ componentDidMount() {
35
+ this.setState({
36
+ width: this.containerRef?.offsetWidth ? `${this.containerRef?.offsetWidth}px` : '100%'
37
+ })
38
+
39
+ this.props.rules?.push({
40
+ validator: async (rule: any, value: any) => {
41
+ if (this.catching) {
42
+ throw new Error('正在抓取图片')
43
+ }
44
+ return true
45
+ },
46
+ })
47
+
48
+ if (!window.UE && !window.UE_LOADING_PROMISE) {
49
+ window.UE_LOADING_PROMISE =
50
+ createScript(this.props.fieldProps.configJsPath || this.props.fieldProps.ueditorPath + '/ueditor.config.js')
51
+ .then(() => {
52
+ return createScript(this.props.fieldProps.ueditorPath + '/ueditor.all.js')
53
+ })
54
+ .then(() => {
55
+ return createScript(this.props.fieldProps.ueditorPath + '/lang/zh-cn/zh-cn.js')
56
+ })
57
+ }
58
+
59
+ window.UE_LOADING_PROMISE.then(() => {
60
+ let that = this
61
+ window.UE.plugins['forceCatchRemoteImg'] = function () {
62
+ if (this.options.forcecatchremote) {
63
+ this.addListener("afterpaste", function (t: any, a: any) {
64
+ const load_src = that.props.fieldProps.ueditorPath + '/img/load.gif';
65
+ const domUtils = window.UE.dom.domUtils;
66
+
67
+ const parser = new DOMParser();
68
+ const pasteDom = parser.parseFromString(a.html, "text/html");
69
+
70
+ // @ts-ignore
71
+ const allImgs = domUtils.getElementsByTagName(this.document, "img");
72
+ const imgs = domUtils.getElementsByTagName(pasteDom, "img");
73
+
74
+ let notCatch = (src: string) => {
75
+ if (src.indexOf(location.host) !== -1) {
76
+ return true;
77
+ }
78
+ if (/(^\.)|(^\/)/.test(src)) {
79
+ return true;
80
+ }
81
+ return src.indexOf('img_catch_success') !== -1;
82
+
83
+ }
84
+
85
+ let catchGo = false;
86
+ for (let i = 0; i < imgs.length; i++) {
87
+ if (notCatch(imgs[i].src)) {
88
+ continue
89
+ }
90
+ for (let l = 0; l < allImgs.length; l++) {
91
+ if (allImgs[l].src == imgs[i].src) {
92
+ catchGo = true;
93
+ domUtils.setAttributes(allImgs[l], {
94
+ "src": load_src,
95
+ "_src": allImgs[l].src
96
+ });
97
+ }
98
+ }
99
+ }
100
+
101
+ if (catchGo) {
102
+ // $('.submit').trigger('startHandlePostData', '正在抓取图片');
103
+ that.catching = true
104
+ that.props.dataIndex && that.props.form?.validateFields([that.props.dataIndex])
105
+ }
106
+ });
107
+
108
+ this.addListener("catchremotesuccess", function () {
109
+ that.catching = false
110
+ that.props.dataIndex && that.props.form?.validateFields([that.props.dataIndex])
111
+ // $('.submit').trigger('endHandlePostData');
112
+ });
113
+ }
114
+
115
+ }
116
+
117
+ // plugins/insert_richtext.js
118
+ /**
119
+ * 抓取微信富文本
120
+ */
121
+ window.UE.plugin.register('insert_richtext', function () {
122
+ // @ts-ignore
123
+ const me = this;
124
+
125
+ function filter(div: HTMLElement) {
126
+ const domUtils = window.UE.dom.domUtils;
127
+ const browser = window.UE.browser;
128
+ const utils = window.UE.utils;
129
+
130
+ let html;
131
+ let ci;
132
+ if (div.firstChild) {
133
+ //去掉cut中添加的边界值
134
+ const nodes = domUtils.getElementsByTagName(div, 'span');
135
+ for (let i = 0, ni; ni = nodes[i++];) {
136
+ if (ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end') {
137
+ domUtils.remove(ni);
138
+ }
139
+ }
140
+
141
+ if (browser.webkit) {
142
+
143
+ let brs = div.querySelectorAll('div br');
144
+ for (let i = 0, bi; bi = brs[i++];) {
145
+ const pN = bi.parentNode as HTMLElement;
146
+ if (pN) {
147
+ if (pN.tagName == 'DIV' && pN.childNodes.length == 1) {
148
+ pN.innerHTML = '<p><br/></p>';
149
+ domUtils.remove(pN);
150
+ }
151
+ }
152
+ }
153
+ const divs = div.querySelectorAll('#baidu_pastebin');
154
+ for (let i = 0, di; di = divs[i++];) {
155
+ const tmpP = me.document.createElement('p');
156
+ di.parentNode?.insertBefore(tmpP, di);
157
+ while (di.firstChild) {
158
+ tmpP.appendChild(di.firstChild);
159
+ }
160
+ domUtils.remove(di);
161
+ }
162
+
163
+ const metas = div.querySelectorAll('meta');
164
+ for (let i = 0, ci; ci = metas[i++];) {
165
+ domUtils.remove(ci);
166
+ }
167
+
168
+ brs = div.querySelectorAll('br');
169
+ for (let i = 0; ci = brs[i++];) {
170
+ if (/^apple-/i.test(ci.className)) {
171
+ domUtils.remove(ci);
172
+ }
173
+ }
174
+ }
175
+ if (browser.gecko) {
176
+ const dirtyNodes = div.querySelectorAll('[_moz_dirty]');
177
+ for (let i = 0; ci = dirtyNodes[i++];) {
178
+ ci.removeAttribute('_moz_dirty');
179
+ }
180
+ }
181
+ if (!browser.ie) {
182
+ const spans = div.querySelectorAll('span.Apple-style-span');
183
+ for (let i = 0, ci; ci = spans[i++];) {
184
+ domUtils.remove(ci, true);
185
+ }
186
+ }
187
+
188
+ //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
189
+ html = div.innerHTML;//.replace(/>(?:(\s|&nbsp;)*?)</g,'><');
190
+
191
+ //过滤word粘贴过来的冗余属性
192
+ html = window.UE.filterWord(html);
193
+ //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
194
+ var root = window.UE.htmlparser(html);
195
+
196
+ //如果给了过滤规则就先进行过滤
197
+ if (me.options.filterRules) {
198
+ window.UE.filterNode(root, me.options.filterRules);
199
+ }
200
+ //执行默认的处理
201
+ me.filterInputRule(root);
202
+ //针对chrome的处理
203
+ if (browser.webkit) {
204
+ var br = root.lastChild();
205
+ if (br && br.type == 'element' && br.tagName == 'br') {
206
+ root.removeChild(br)
207
+ }
208
+ utils.each(me.body.querySelectorAll('div'), function (node: HTMLElement) {
209
+ if (domUtils.isEmptyBlock(node)) {
210
+ domUtils.remove(node, true)
211
+ }
212
+ })
213
+ }
214
+ html = {'html': root.toHtml()};
215
+ me.fireEvent('beforepaste', html, root);
216
+ //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
217
+ if (!html.html) {
218
+ return;
219
+ }
220
+ root = window.UE.htmlparser(html.html, true);
221
+ //如果开启了纯文本模式
222
+ if (me.queryCommandState('pasteplain') === 1) {
223
+ me.execCommand('insertHtml', window.UE.filterNode(root, me.options.filterTxtRules).toHtml(), true);
224
+ } else {
225
+ //文本模式
226
+ window.UE.filterNode(root, me.options.filterTxtRules);
227
+ const txtContent = root.toHtml();
228
+ //完全模式
229
+ const htmlContent = html.html;
230
+
231
+ const address = me.selection.getRange().createAddress(true);
232
+ // @ts-ignore
233
+ me.execCommand('insertHtml', me.getOpt('retainOnlyLabelPasted') === true ? getPureHtml(htmlContent) : htmlContent, true);
234
+ }
235
+
236
+ me.fireEvent("afterpaste", html);
237
+ }
238
+ }
239
+
240
+
241
+ return {
242
+ bindEvents: {
243
+ 'afterInsertRichText': function (e: Event, html: HTMLElement) {
244
+ me.execCommand('cleardoc');
245
+ filter.call(me, html);
246
+ me.document.body.innerHTML = `<section>${html}</section>`;
247
+
248
+ me.fireEvent('catchremoteimage');
249
+
250
+ that.catching = true
251
+ that.props.dataIndex && that.props.form?.validateFields([that.props.dataIndex])
252
+ // $('.submit').trigger('startHandlePostData', '正在抓取图片');
253
+ },
254
+ },
255
+ commands: {}
256
+ }
257
+ });
258
+
259
+
260
+ const config = {
261
+ ...this.props.fieldProps?.config,
262
+ forcecatchremote: typeof this.props.fieldProps?.config?.forcecatchremote === 'undefined' ? true : this.props.fieldProps.config.forcecatchremote,
263
+ }
264
+ if (this.modalContext?.inModal) {
265
+ config.zIndex = 2000
266
+ config.topOffset = 0
267
+ }
268
+
269
+ this.editor = window.UE.getEditor(this.state.containerId, config)
270
+ this.editor?.ready(() => {
271
+ this.editor?.addListener('contentChange', () => {
272
+ this.formContext.formRef?.current?.setFieldValue(this.props.dataIndex, this.editor?.getContent())
273
+ })
274
+ this.setState({loading: false})
275
+ })
276
+ })
277
+
278
+ }
279
+
280
+ componentWillUnmount() {
281
+ this.editor?.destroy()
282
+ }
283
+
284
+ render() {
285
+ return <ModalContext.Consumer>
286
+ {
287
+ modalContext =>
288
+ <FormContext.Consumer>
289
+ {
290
+ formContext => {
291
+ this.modalContext = modalContext
292
+ this.formContext = formContext
293
+ return <div {...filterObjectKeys(this.props, [
294
+ 'id',
295
+ 'fieldProps',
296
+ 'onChange',
297
+ 'value',
298
+ 'form',
299
+ 'config',
300
+ 'rules',
301
+ 'ueditorPath',
302
+ 'dataIndex',
303
+ ])} ref={el => this.containerRef = el}>
304
+ <Spin spinning={this.state.loading}>
305
+ <div id={this.state.containerId} style={{width: this.state.width}}/>
306
+ </Spin>
307
+ </div>
308
+ }
309
+ }
310
+ </FormContext.Consumer>
311
+ }
312
+ </ModalContext.Consumer>
313
+ }
314
+ }
@@ -0,0 +1,29 @@
1
+ import type {FormInstance} from "antd/lib/form";
2
+ import {ProSchema} from "@ant-design/pro-components";
3
+ import {Rule} from "rc-field-form/lib/interface";
4
+ import {Key} from "react";
5
+
6
+ export type ColumnProps = {
7
+ className: any,
8
+ onChange?: <T = any>(value: T) => void;
9
+ onBlur?: <T = any>(event: T) => void;
10
+ schema?: ProSchema<Entity, ExtraProps, ComponentsType, ValueType>,
11
+ config: {
12
+ onSelect?: (value: any) => void;
13
+ onChange?: <T = any>(value: T) => void;
14
+ value?: any;
15
+ type: ComponentsType;
16
+ recordKey?: React.Key | React.Key[];
17
+ record?: Entity;
18
+ isEditable?: boolean;
19
+ defaultRender: (newItem: ProSchema<Entity, ExtraProps, ComponentsType, ValueType>) => JSX.Element | null;
20
+ options?: any[];
21
+ }
22
+ form: FormInstance,
23
+ fieldProps: any,
24
+ rules?: Rule[],
25
+ dataIndex?: Key,
26
+ value?: any,
27
+
28
+ record?: any,
29
+ }
@@ -0,0 +1,125 @@
1
+ import {FormActionType} from "./types";
2
+ import {Button, Popconfirm} from "antd";
3
+ import {useContext, useEffect, useState} from "react";
4
+ import http from "../../../lib/http";
5
+ import {FormContext} from "../../FormContext";
6
+ import {modal, replaceParams, replaceUrl, routerNavigateTo} from "../../../lib/helpers";
7
+ import {ModalContext} from "../../ModalContext";
8
+ import {TableContext} from "../../TableContext";
9
+
10
+ export default function (props: FormActionType & {
11
+ props: any,
12
+
13
+ // 操作
14
+ submit?: boolean | {
15
+ confirm?: string
16
+ },
17
+ request?: RequestOptions,
18
+ link?: {
19
+ url: string,
20
+ }
21
+ back?: boolean,
22
+ reset?: boolean,
23
+ modal?: ModalOptions,
24
+ }) {
25
+
26
+ const [loading, setLoading] = useState(false)
27
+ const formContext = useContext(FormContext)
28
+ const tableContext = useContext(TableContext)
29
+ const modalContext = useContext(ModalContext)
30
+
31
+ const onClick = async () => {
32
+ try {
33
+ setLoading(true)
34
+ const handleAfterAction = async (req?: RequestOptions) => {
35
+ if (req?.afterAction?.includes('tableReload')) {
36
+ if (modalContext.contexts) {
37
+ modalContext.setAfterClose(() => {
38
+ modalContext.contexts?.tableContext?.actionRef.reload()
39
+ })
40
+ }
41
+ if (tableContext.actionRef) {
42
+ await tableContext.actionRef.reload()
43
+ }
44
+ }
45
+ if (req?.afterAction?.includes('closeModal') && modalContext.inModal) {
46
+ modalContext.closeModal()
47
+ }
48
+ }
49
+
50
+ if (props.submit) {
51
+ formContext.formRef?.current?.submit()
52
+ return
53
+ }
54
+ if (props.request) {
55
+ await http({
56
+ method: props.request.method,
57
+ url: props.request.url,
58
+ headers: props.request.headers || {},
59
+ data: replaceParams(props.request.data || {}, {
60
+ ...(await formContext.formRef?.current?.getFieldsValue()),
61
+ })
62
+ })
63
+
64
+ await handleAfterAction(props.request)
65
+ return
66
+ }
67
+ if (props.modal) {
68
+ await modal({
69
+ ...props.modal,
70
+ content: {
71
+ ...props.modal.content,
72
+ url: replaceUrl(props.modal.content.url as string, formContext.formRef?.current?.getFieldsValue())
73
+ }
74
+ })
75
+ return
76
+ }
77
+
78
+ if (props.link) {
79
+ routerNavigateTo(replaceUrl(props.link.url, await formContext.formRef?.current?.getFieldsValue()))
80
+ return
81
+ }
82
+ if (props.reset) {
83
+ formContext.formRef?.current?.resetFields()
84
+ return
85
+ }
86
+ if (props.back) {
87
+ history.back()
88
+ return
89
+ }
90
+ } finally {
91
+ setLoading(false)
92
+ }
93
+ }
94
+
95
+ useEffect(() => {
96
+ if (props.submit) {
97
+ setLoading(props.loading || false)
98
+ }
99
+ }, [props.loading]);
100
+
101
+ const MyButton = ({onClick}: {
102
+ onClick?: () => void,
103
+ }) => {
104
+
105
+ return <>
106
+ <Button {...props.props}
107
+ onClick={onClick}
108
+ loading={loading}
109
+ >{props.title}</Button>
110
+ </>
111
+ }
112
+
113
+ const confirm = (typeof props.submit === 'object' ? props.submit.confirm : null)
114
+ || props.request?.confirm
115
+
116
+ return <>
117
+ {
118
+ confirm ?
119
+ <Popconfirm title={confirm} onConfirm={onClick}>
120
+ <MyButton></MyButton>
121
+ </Popconfirm>
122
+ : <MyButton onClick={onClick}></MyButton>
123
+ }
124
+ </>
125
+ }
@@ -0,0 +1,5 @@
1
+ export type FormActionType = {
2
+ type: string,
3
+ title: string,
4
+ loading?: boolean,
5
+ }
@@ -0,0 +1,35 @@
1
+ import {FormActionType} from "./Action/types";
2
+ import {lazy, useEffect, useState} from "react";
3
+ import {ReactComponentLike} from "prop-types";
4
+ import {Space} from "antd";
5
+ import container from "../../lib/container";
6
+ import upperFirst from "lodash/upperFirst";
7
+
8
+ export default function (props: {
9
+ actions?: FormActionType[]
10
+ loading?: boolean
11
+ }) {
12
+ const [components, setComponents] = useState<{
13
+ Component: ReactComponentLike,
14
+ props: FormActionType,
15
+ }[]>([])
16
+
17
+ useEffect(() => {
18
+ setComponents(props.actions?.map(a => {
19
+ return {
20
+ Component: lazy(container.get('Form.Action.' + upperFirst(a.type))),
21
+ props: {
22
+ ...a,
23
+ },
24
+ }
25
+ }) || [])
26
+ }, []);
27
+
28
+ return <>
29
+ <Space>
30
+ {components.map(item => (
31
+ <item.Component key={item.props.title} loading={props.loading} {...item.props}></item.Component>
32
+ ))}
33
+ </Space>
34
+ </>
35
+ }
@@ -0,0 +1,171 @@
1
+ import {BetaSchemaForm, ProFormColumnsType, ProFormInstance, ProSkeleton} from "@ant-design/pro-components";
2
+ import type {FormSchema} from "@ant-design/pro-form/es/components/SchemaForm/typing";
3
+ import React, {lazy, Suspense, useContext, useEffect, useRef, useState} from "react";
4
+ import upperFirst from "lodash/upperFirst";
5
+ import container from "../lib/container";
6
+ import {FormActionType} from "./Form/Action/types";
7
+ import Actions from "./Form/Actions";
8
+ import {FormContext} from "./FormContext";
9
+ import {Col, Row, Spin} from "antd";
10
+ import http from "../lib/http";
11
+ import {RuleObject} from "rc-field-form/lib/interface";
12
+ import customRule from "../lib/customRule";
13
+ import cloneDeep from "lodash/cloneDeep";
14
+ import {ModalContext} from "./ModalContext";
15
+ import {TableContext} from "./TableContext";
16
+ import {commonHandler} from "../lib/schemaHandler";
17
+
18
+ type SubmitRequestType = {
19
+ url: string,
20
+ method?: string,
21
+ data?: any,
22
+ afterSubmit?: () => void,
23
+ headers?: Record<string, string>
24
+ afterAction?: string[],
25
+ }
26
+
27
+
28
+ export default function (props: FormSchema & {
29
+ actions?: FormActionType[]
30
+ metaTitle?: string,
31
+ columns?: ProFormColumnsType[],
32
+ submitRequest?: SubmitRequestType
33
+ }) {
34
+
35
+ const [columns, setColumns] = useState<ProFormColumnsType[]>([])
36
+ const formRef = useRef<ProFormInstance>()
37
+ const [initialized, setInitialized] = useState(false)
38
+ const [loading, setLoading] = useState(false)
39
+
40
+ useEffect(() => {
41
+ setColumns((cloneDeep(props.columns)?.map((c: ProFormColumnsType & {
42
+ formItemProps?: {
43
+ rules?: (RuleObject & {
44
+ customType?: string
45
+ })[]
46
+ }
47
+ }) => {
48
+ // rules
49
+ if (!c.formItemProps) {
50
+ c.formItemProps = {}
51
+ }
52
+ if (!c.formItemProps?.rules) {
53
+ c.formItemProps.rules = []
54
+ }
55
+ c.formItemProps.rules = c.formItemProps.rules.map(rule => {
56
+ if (rule.customType) {
57
+ if (customRule[rule.customType]) {
58
+ rule.validator = customRule[rule.customType]
59
+ }
60
+ }
61
+ return rule
62
+ })
63
+
64
+ // item render
65
+ const formItemComponent = 'Column.' + upperFirst(c.valueType as string)
66
+ if (container.check(formItemComponent)) {
67
+ const Component = lazy(container.get(formItemComponent))
68
+ c.renderFormItem = (schema, config, form) =>
69
+ <Suspense fallback={<Spin/>}>
70
+ <Component config={config}
71
+ form={form}
72
+ fieldProps={c.fieldProps}
73
+ key={c.title as string}
74
+ rules={c.formItemProps?.rules}
75
+ dataIndex={c.dataIndex}
76
+ ></Component>
77
+ </Suspense>
78
+ }
79
+ // readonly render
80
+ const readonlyComponent = 'Column.Readonly.' + upperFirst(c.valueType as string)
81
+ if (container.check(readonlyComponent)) {
82
+ const Component = lazy(container.get(readonlyComponent))
83
+ c.render = (dom, entity, index, action, schema) =>
84
+ <Suspense fallback={<Spin/>}>
85
+ <Component key={c.title as string}
86
+ entity={entity}
87
+ index={index}
88
+ action={action}
89
+ schema={schema}
90
+ dom={dom}
91
+ ></Component>
92
+ </Suspense>
93
+ }
94
+
95
+ commonHandler(c)
96
+ if (container.schemaHandler[c.valueType as string]) {
97
+ return container.schemaHandler[c.valueType as string](c)
98
+ }
99
+
100
+ return c
101
+ }) || []) as ProFormColumnsType[])
102
+
103
+ setInitialized(true)
104
+ }, []);
105
+
106
+ const modalContext = useContext(ModalContext)
107
+ const tableContext = useContext(TableContext)
108
+
109
+ const handleAfterAction = async (req?: SubmitRequestType) => {
110
+ if (req?.afterAction?.includes('tableReload')) {
111
+ if (modalContext.contexts) {
112
+ modalContext.setAfterClose(() => {
113
+ modalContext.contexts?.tableContext?.actionRef.reload()
114
+ })
115
+ }
116
+ if (tableContext.actionRef) {
117
+ await tableContext.actionRef.reload()
118
+ }
119
+ }
120
+ if (req?.afterAction?.includes('closeModal') && modalContext.inModal) {
121
+ modalContext.closeModal()
122
+ }
123
+ }
124
+
125
+ const onFinish = async (values: any) => {
126
+ if (props.submitRequest) {
127
+ setLoading(true)
128
+ try {
129
+ await http({
130
+ method: props.submitRequest.method,
131
+ url: props.submitRequest.url,
132
+ data: Object.assign({}, props.submitRequest.data, values),
133
+ headers: props.submitRequest.headers,
134
+ })
135
+
136
+ handleAfterAction(props.submitRequest)
137
+ } finally {
138
+ setLoading(false)
139
+ }
140
+ }
141
+ }
142
+
143
+ return <>
144
+ <Row justify={'center'}>
145
+ <Col sm={24} md={22} lg={20}>
146
+ <FormContext.Provider value={{
147
+ formRef: formRef,
148
+ }}>
149
+ {!initialized
150
+ ? <ProSkeleton type={"list"} list={2}></ProSkeleton>
151
+ : <BetaSchemaForm columns={columns}
152
+ colProps={props.colProps}
153
+ readonly={props.readonly}
154
+ grid={true}
155
+ loading={loading}
156
+ formRef={formRef}
157
+ initialValues={props.initialValues}
158
+ onFinish={onFinish}
159
+ submitter={{
160
+ render: () => [
161
+ <Actions key={'actions'} loading={loading}
162
+ actions={props.actions}></Actions>
163
+ ]
164
+ }}
165
+ ></BetaSchemaForm>
166
+ }
167
+ </FormContext.Provider>
168
+ </Col>
169
+ </Row>
170
+ </>
171
+ }
@@ -0,0 +1,8 @@
1
+ import {ProFormInstance} from "@ant-design/pro-components";
2
+ import {createContext, MutableRefObject} from "react";
3
+
4
+ export type FormContextProps = {
5
+ formRef?: MutableRefObject<ProFormInstance | undefined>,
6
+ }
7
+
8
+ export const FormContext = createContext<FormContextProps>({})