@quansitech/antd-admin 1.0.0 → 1.1.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 (41) hide show
  1. package/components/Column/Cascader.tsx +78 -78
  2. package/components/Column/File.tsx +165 -167
  3. package/components/Column/Image.tsx +76 -76
  4. package/components/{Table/Option → Column/Readonly/Action}/Link.tsx +77 -67
  5. package/components/{Table/Option → Column/Readonly/Action}/types.d.ts +5 -4
  6. package/components/Column/Readonly/Action.tsx +80 -0
  7. package/components/Column/Readonly/Cascader.tsx +50 -50
  8. package/components/Column/Readonly/File.tsx +52 -53
  9. package/components/Column/Readonly/Image.tsx +38 -77
  10. package/components/Column/Readonly/Ueditor.tsx +18 -0
  11. package/components/Column/Readonly/types.d.ts +9 -8
  12. package/components/Column/Ueditor.tsx +313 -313
  13. package/components/Column/types.d.ts +29 -28
  14. package/components/Form/Action/Button.tsx +128 -124
  15. package/components/Form/Action/types.d.ts +5 -4
  16. package/components/Form/Actions.tsx +38 -34
  17. package/components/Form.tsx +176 -170
  18. package/components/FormContext.ts +8 -7
  19. package/components/Layout/New.tsx +252 -0
  20. package/components/Layout.tsx +52 -237
  21. package/components/LayoutContext.ts +25 -25
  22. package/components/ModalContext.ts +15 -15
  23. package/components/Table/Action/Button.tsx +88 -88
  24. package/components/Table/Action/StartEditable.tsx +58 -58
  25. package/components/Table/Action/types.d.ts +7 -6
  26. package/components/Table/ToolbarActions.tsx +43 -38
  27. package/components/Table.scss +4 -7
  28. package/components/Table.tsx +280 -279
  29. package/components/TableContext.ts +14 -13
  30. package/components/Tabs.tsx +71 -71
  31. package/lib/container.ts +83 -81
  32. package/lib/customRule.ts +9 -9
  33. package/lib/global.ts +10 -10
  34. package/lib/helpers.tsx +145 -149
  35. package/lib/http.ts +73 -73
  36. package/lib/schemaHandler.ts +121 -121
  37. package/lib/upload.ts +177 -177
  38. package/lib/writeExtra.js +31 -0
  39. package/package.json +2 -6
  40. package/readme.md +151 -128
  41. package/components/Column/Readonly/Option.tsx +0 -58
@@ -1,68 +1,78 @@
1
- import React, {useContext, useState} from "react";
2
- import {modal, replaceParams, replaceUrl, routerNavigateTo} from "../../../lib/helpers";
3
- import {Button, Popconfirm, Spin} from "antd";
4
- import {TableContext} from "../../TableContext";
5
- import http from "../../../lib/http";
6
- import {TableColumnOptionProps} from "./types";
7
-
8
- type Props = TableColumnOptionProps & {
9
- href?: string,
10
- request?: RequestOptions,
11
- modal?: ModalOptions,
12
- danger?: boolean
13
- }
14
-
15
- export default function (props: Props) {
16
-
17
- const [loading, setLoading] = useState(false)
18
- const tableContext = useContext(TableContext)
19
-
20
- const onClick = async (e: any) => {
21
- setLoading(true)
22
- try {
23
- if (props.href) {
24
- routerNavigateTo(replaceUrl(props.href, props.record))
25
- return
26
- }
27
- if (props.request) {
28
- await http({
29
- method: props.request.method,
30
- url: replaceUrl(props.request.url, props.record),
31
- headers: props.request.headers || {},
32
- data: props.request.data ? replaceParams(props.request.data, props.record) : null,
33
- })
34
-
35
- await tableContext.actionRef?.reload()
36
- }
37
- if (props.modal) {
38
- let url
39
- if (props.modal.content.url) {
40
- url = replaceUrl(props.modal.content.url, props.record)
41
- }
42
- await modal({
43
- ...props.modal,
44
- contexts: {
45
- tableContext,
46
- },
47
- content: {
48
- ...props.modal.content,
49
- url,
50
- },
51
- })
52
- }
53
- } finally {
54
- setLoading(false)
55
- }
56
- }
57
-
58
- return <>
59
- <Spin spinning={loading}>
60
- {props.request?.confirm
61
- ? <Popconfirm title={props.request?.confirm} onConfirm={onClick}>
62
- <Button type={"link"} danger={props.danger} onClick={() => {
63
- }}>{props.title}</Button>
64
- </Popconfirm> : <Button type={"link"} danger={props.danger} onClick={onClick}>{props.title}</Button>
65
- }
66
- </Spin>
67
- </>
1
+ import React, {useContext, useState} from "react";
2
+ import {modalShow, replaceParams, replaceUrl, routerNavigateTo} from "../../../../lib/helpers";
3
+ import {Button, Popconfirm, Spin} from "antd";
4
+ import {TableContext} from "../../../TableContext";
5
+ import http from "../../../../lib/http";
6
+ import {TableColumnOptionProps} from "./types";
7
+
8
+ type Props = TableColumnOptionProps & {
9
+ href?: string,
10
+ request?: RequestOptions,
11
+ modal?: ModalOptions,
12
+ modalByField?: string,
13
+ danger?: boolean
14
+ }
15
+
16
+ export default function (props: Props) {
17
+
18
+ const [loading, setLoading] = useState(false)
19
+ const tableContext = useContext(TableContext)
20
+
21
+ const onClick = async (e: any) => {
22
+ setLoading(true)
23
+ try {
24
+ if (props.href) {
25
+ routerNavigateTo(replaceUrl(props.href, props.record))
26
+ return
27
+ }
28
+ if (props.request) {
29
+ await http({
30
+ method: props.request.method,
31
+ url: replaceUrl(props.request.url, props.record),
32
+ headers: props.request.headers || {},
33
+ data: props.request.data ? replaceParams(props.request.data, props.record) : null,
34
+ })
35
+
36
+ await tableContext.actionRef?.reload()
37
+ }
38
+ if (props.modal) {
39
+ let url
40
+ if (props.modal.content.url) {
41
+ url = replaceUrl(props.modal.content.url, props.record)
42
+ }
43
+ await modalShow({
44
+ ...props.modal,
45
+ contexts: {
46
+ tableContext,
47
+ },
48
+ content: {
49
+ ...props.modal.content,
50
+ url,
51
+ },
52
+ })
53
+ }
54
+ if (props.modalByField) {
55
+ const m = props.record[props.modalByField]
56
+ await modalShow({
57
+ ...m,
58
+ contexts: {
59
+ tableContext,
60
+ },
61
+ })
62
+ }
63
+ } finally {
64
+ setLoading(false)
65
+ }
66
+ }
67
+
68
+ return <>
69
+ <Spin spinning={loading}>
70
+ {props.request?.confirm
71
+ ? <Popconfirm title={props.request?.confirm} onConfirm={onClick}>
72
+ <Button type={"link"} danger={props.danger} onClick={() => {
73
+ }}>{props.title}</Button>
74
+ </Popconfirm> : <Button type={"link"} danger={props.danger} onClick={onClick}>{props.title}</Button>
75
+ }
76
+ </Spin>
77
+ </>
68
78
  }
@@ -1,5 +1,6 @@
1
- export type TableColumnOptionProps = {
2
- type: string,
3
- title: string,
4
- record: Record<string, any>,
1
+ export type TableColumnActionProps = {
2
+ type: string,
3
+ title: string,
4
+ record: Record<string, any>,
5
+ badge?: string,
5
6
  }
@@ -0,0 +1,80 @@
1
+ import {Component, lazy, useEffect, useState} from "react";
2
+ import {ReactComponentLike} from "prop-types";
3
+ import container from "../../../lib/container";
4
+ import {Badge, Flex} from "antd";
5
+ import {ColumnReadonlyProps} from "./types";
6
+ import {asyncFilter, handleRules} from "../../../lib/helpers";
7
+ import {Rules} from "@rc-component/async-validator/lib/interface";
8
+ import {upperFirst} from "lodash";
9
+ import {TableColumnActionProps} from "./Action/types";
10
+
11
+ type ComponentType = {
12
+ component: ReactComponentLike,
13
+ props: any,
14
+ }
15
+
16
+ export default ({actions, record}: ColumnReadonlyProps & {
17
+ actions?: {
18
+ type: string,
19
+ title: string,
20
+ showRules?: Rules,
21
+ badge?: any,
22
+ }[],
23
+ }) => {
24
+
25
+ const [Components, setComponents] = useState<ComponentType[]>([]);
26
+
27
+ useEffect(() => {
28
+ if (actions) {
29
+ asyncFilter(actions, async (Component) => {
30
+ if (!Component.showRules) {
31
+ return true
32
+ }
33
+ return await handleRules(Component.showRules, record)
34
+ }).then((Components: TableColumnActionProps[]) => setComponents(Components.map(a => {
35
+ let badge = a.badge
36
+ const matches = (badge + '').match(/^__(\w+)__$/)
37
+ if (matches) {
38
+ badge = record[matches[1]]
39
+ }
40
+
41
+ const c = `Column.Readonly.Action.${upperFirst(a.type)}`
42
+ return {
43
+ props: {
44
+ ...a,
45
+ record,
46
+ badge,
47
+ },
48
+ component: lazy(container.get(c)),
49
+ }
50
+ })))
51
+ }
52
+ }, []);
53
+
54
+
55
+ return <>
56
+ {
57
+ <Flex wrap={true}>
58
+ {
59
+ Components.map(Component => (
60
+ Component.props.badge ?
61
+ <Badge key={Component.props.title}
62
+ count={Component.props.badge}
63
+ offset={[-12, 6]}
64
+ size={'small'}
65
+ styles={{
66
+ indicator: {
67
+ zIndex: 100,
68
+ padding: '0 4px',
69
+ }
70
+ }}>
71
+ <Component.component
72
+ key={Component.props.title} {...Component.props}></Component.component>
73
+ </Badge> :
74
+ <Component.component key={Component.props.title} {...Component.props}></Component.component>
75
+ ))
76
+ }
77
+ </Flex>
78
+ }
79
+ </>
80
+ }
@@ -1,51 +1,51 @@
1
- import {ColumnReadonlyProps} from "./types";
2
- import {ReactNode, useEffect, useState} from "react";
3
- import http from "../../../lib/http";
4
-
5
- export default function (props: ColumnReadonlyProps & {
6
- schema: {
7
- fieldProps: {
8
- loadDataUrl: string
9
- }
10
- }
11
- }) {
12
- const [text, setText] = useState<ReactNode>('-');
13
-
14
- useEffect(() => {
15
- setText(props.dom)
16
- const value = props.entity.value
17
-
18
- // 远程获取数据
19
- if (props.schema.fieldProps?.loadDataUrl) {
20
- http({
21
- url: props.schema.fieldProps.loadDataUrl,
22
- method: 'get',
23
- params: {
24
- value,
25
- }
26
- }).then(res => {
27
- if (!value) {
28
- return
29
- }
30
- const findValue = (options: any[], value: any): any => {
31
- for (let i = 0; i < options.length; i++) {
32
- const option = options[i];
33
- if (option.value === value) {
34
- return [option.label]
35
- } else if (option.children) {
36
- return [option.label, ...findValue(option.children, value)]
37
- }
38
- }
39
- }
40
-
41
- setText(findValue(res.data, value).join(' / '))
42
-
43
- })
44
- }
45
-
46
- }, []);
47
-
48
- return <div className={props.entity.className}>
49
- {text}
50
- </div>
1
+ import {ColumnReadonlyProps} from "./types";
2
+ import {ReactNode, useEffect, useState} from "react";
3
+ import http from "../../../lib/http";
4
+
5
+ export default function (props: ColumnReadonlyProps & {
6
+ schema: {
7
+ fieldProps: {
8
+ loadDataUrl: string
9
+ }
10
+ }
11
+ }) {
12
+ const [text, setText] = useState<ReactNode>('-');
13
+
14
+ useEffect(() => {
15
+ setText(props.dom)
16
+ const value = props.entity.value
17
+
18
+ // 远程获取数据
19
+ if (props.schema.fieldProps?.loadDataUrl) {
20
+ http({
21
+ url: props.schema.fieldProps.loadDataUrl,
22
+ method: 'get',
23
+ params: {
24
+ value,
25
+ }
26
+ }).then(res => {
27
+ if (!value) {
28
+ return
29
+ }
30
+ const findValue = (options: any[], value: any): any => {
31
+ for (let i = 0; i < options.length; i++) {
32
+ const option = options[i];
33
+ if (option.value === value) {
34
+ return [option.label]
35
+ } else if (option.children) {
36
+ return [option.label, ...findValue(option.children, value)]
37
+ }
38
+ }
39
+ }
40
+
41
+ setText(findValue(res.data, value).join(' / '))
42
+
43
+ })
44
+ }
45
+
46
+ }, []);
47
+
48
+ return <div className={props.entity.className}>
49
+ {text}
50
+ </div>
51
51
  }
@@ -1,54 +1,53 @@
1
- import {ColumnReadonlyProps} from "./types";
2
- import {Spin, Upload, UploadFile} from "antd";
3
- import React, {useEffect, useState} from "react";
4
- import http from "../../../lib/http";
5
-
6
- export default function (props: ColumnReadonlyProps & {
7
- schema: {
8
- fieldProps?: {
9
- loadUrl: string,
10
- }
11
- },
12
- }) {
13
-
14
- const [loading, setLoading] = useState(true);
15
- const [fileList, setFileList] = useState<UploadFile[]>([]);
16
-
17
- useEffect(() => {
18
- if (props.entity.value && props.schema.fieldProps?.loadUrl) {
19
- http({
20
- url: props.schema.fieldProps.loadUrl,
21
- params: {
22
- ids: props.entity.value
23
- },
24
- method: 'get',
25
- }).then(res => {
26
- setFileList(res.data.map((item: any) => {
27
- return {
28
- uid: item.id,
29
- status: 'done',
30
- url: item.url,
31
- name: item.name,
32
- response: {
33
- file_id: item.id,
34
- }
35
- }
36
- }))
37
- setLoading(false)
38
- })
39
- } else {
40
- setLoading(false)
41
- }
42
- }, []);
43
-
44
-
45
- return <>
46
- <Spin spinning={loading}>
47
- <Upload
48
- disabled={true}
49
- listType="text"
50
- fileList={fileList}
51
- ></Upload>
52
- </Spin>
53
- </>
1
+ import {ColumnReadonlyProps} from "./types";
2
+ import {Spin, Upload, UploadFile} from "antd";
3
+ import React, {useContext, useEffect, useState} from "react";
4
+ import {FormContext} from "../../FormContext";
5
+ import {UploadListType} from "antd/es/upload/interface";
6
+ import {TableContext} from "../../TableContext";
7
+
8
+ export default function (props: ColumnReadonlyProps & {
9
+ listType?: UploadListType,
10
+ onPreview?: (file: UploadFile) => void,
11
+ }) {
12
+
13
+ const [loading, setLoading] = useState(true);
14
+ const [fileList, setFileList] = useState<UploadFile[]>([]);
15
+ const formContext = useContext(FormContext);
16
+ const tableContext = useContext(TableContext);
17
+
18
+ useEffect(() => {
19
+ let extraRenderValue = [];
20
+ if (formContext && formContext.extraRenderValues) {
21
+ extraRenderValue = formContext.extraRenderValues[props.schema.dataIndex as string] ?? []
22
+ } else if (tableContext && tableContext.extraRenderValues) {
23
+ extraRenderValue = tableContext.extraRenderValues[props.index]?.[props.schema.dataIndex as string] ?? []
24
+ }
25
+ setFileList(extraRenderValue.map((item: any) => {
26
+ return {
27
+ uid: item.id,
28
+ status: 'done',
29
+ url: item.url,
30
+ name: item.name,
31
+ hash_id: item.hash_id,
32
+ response: {
33
+ file_id: item.id,
34
+ url: item.url,
35
+ }
36
+ }
37
+ }))
38
+
39
+ setLoading(false)
40
+ }, []);
41
+
42
+
43
+ return <>
44
+ <Spin spinning={loading}>
45
+ <Upload
46
+ disabled={true}
47
+ listType={props.listType || 'text'}
48
+ fileList={fileList}
49
+ onPreview={props.onPreview}
50
+ ></Upload>
51
+ </Spin>
52
+ </>
54
53
  }
@@ -1,78 +1,39 @@
1
- import {ColumnReadonlyProps} from "./types";
2
- import {Image, Spin, Upload, UploadFile} from "antd";
3
- import {FileType, getBase64} from "../../../lib/upload";
4
- import React, {useEffect, useState} from "react";
5
- import http from "../../../lib/http";
6
-
7
- export default function (props: ColumnReadonlyProps & {
8
- schema: {
9
- fieldProps?: {
10
- loadUrl: string,
11
- }
12
- },
13
- }) {
14
-
15
- const [loading, setLoading] = useState(true);
16
- const [fileList, setFileList] = useState<UploadFile[]>([]);
17
- const [previewImage, setPreviewImage] = useState('');
18
- const [previewOpen, setPreviewOpen] = useState(false);
19
-
20
- const handlePreview = async (file: UploadFile) => {
21
- if (!file.url && !file.preview) {
22
- file.preview = await getBase64(file.originFileObj as FileType);
23
- }
24
-
25
- setPreviewImage(file.url || (file.preview as string));
26
- setPreviewOpen(true);
27
- };
28
-
29
- useEffect(() => {
30
- if (props.entity.value && props.schema.fieldProps?.loadUrl) {
31
- http({
32
- url: props.schema.fieldProps.loadUrl,
33
- params: {
34
- ids: props.entity.value
35
- },
36
- method: 'get',
37
- }).then(res => {
38
- setFileList(res.data.map((item: any) => {
39
- return {
40
- uid: item.id,
41
- status: 'done',
42
- url: item.url,
43
- name: '',
44
- response: {
45
- file_id: item.id,
46
- }
47
- }
48
- }))
49
- setLoading(false)
50
- })
51
- } else {
52
- setLoading(false)
53
- }
54
- }, []);
55
-
56
-
57
- return <>
58
- <Spin spinning={loading}>
59
- <Upload
60
- disabled={true}
61
- listType="picture-card"
62
- fileList={fileList}
63
- onPreview={handlePreview}
64
- ></Upload>
65
- {previewImage && (
66
- <Image
67
- wrapperStyle={{display: 'none'}}
68
- preview={{
69
- visible: previewOpen,
70
- onVisibleChange: (visible) => setPreviewOpen(visible),
71
- afterOpenChange: (visible) => !visible && setPreviewImage(''),
72
- }}
73
- src={previewImage}
74
- />
75
- )}
76
- </Spin>
77
- </>
1
+ import {ColumnReadonlyProps} from "./types";
2
+ import {Image, UploadFile} from "antd";
3
+ import {FileType, getBase64} from "../../../lib/upload";
4
+ import React, {useState} from "react";
5
+ import File from "./File";
6
+
7
+ export default function (props: ColumnReadonlyProps) {
8
+
9
+ const [previewImage, setPreviewImage] = useState('');
10
+ const [previewOpen, setPreviewOpen] = useState(false);
11
+
12
+ const handlePreview = async (file: UploadFile) => {
13
+ if (!file.url && !file.preview) {
14
+ file.preview = await getBase64(file.originFileObj as FileType);
15
+ }
16
+
17
+ setPreviewImage(file.url || (file.preview as string));
18
+ setPreviewOpen(true);
19
+ };
20
+
21
+
22
+ return <>
23
+ <File {...props}
24
+ listType="picture-card"
25
+ onPreview={handlePreview}
26
+ ></File>
27
+ {previewImage && (
28
+ <Image
29
+ wrapperStyle={{display: 'none'}}
30
+ preview={{
31
+ visible: previewOpen,
32
+ onVisibleChange: (visible) => setPreviewOpen(visible),
33
+ afterOpenChange: (visible) => !visible && setPreviewImage(''),
34
+ }}
35
+ src={previewImage}
36
+ />
37
+ )}
38
+ </>
78
39
  }
@@ -0,0 +1,18 @@
1
+ import {ColumnReadonlyProps} from "./types";
2
+ import {useEffect, useState} from "react";
3
+
4
+ export default function (props: ColumnReadonlyProps) {
5
+
6
+ const [value, setValue] = useState(props.entity.value);
7
+
8
+ useEffect(() => {
9
+ const div = document.createElement('div');
10
+ div.innerHTML = props.entity.value;
11
+ setValue(div.innerText);
12
+ }, []);
13
+
14
+
15
+ return <>
16
+ <div className={'article-content'} dangerouslySetInnerHTML={{__html: value}}/>
17
+ </>
18
+ }
@@ -1,9 +1,10 @@
1
- import {ProSchema} from "@ant-design/pro-components";
2
- import {ReactNode} from "react";
3
-
4
- export type ColumnReadonlyProps = {
5
- dom: ReactNode,
6
- entity: any,
7
- schema: ProSchema,
8
- record?: any,
1
+ import {ProSchema} from "@ant-design/pro-components";
2
+ import {ReactNode} from "react";
3
+
4
+ export type ColumnReadonlyProps = {
5
+ dom: ReactNode,
6
+ entity: any,
7
+ schema: ProSchema,
8
+ record?: any,
9
+ index: number,
9
10
  }