@jiangood/open-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 (164) hide show
  1. package/config/dist/common-plugin.js +148 -0
  2. package/config/dist/config.js +45 -0
  3. package/config/dist/index.js +18 -0
  4. package/package.json +41 -0
  5. package/src/app.js +1 -0
  6. package/src/asserts/welcome.png +0 -0
  7. package/src/forms/demoForm.jsx +16 -0
  8. package/src/framework/components/DownloadFileButton.d.ts +11 -0
  9. package/src/framework/components/DownloadFileButton.jsx +33 -0
  10. package/src/framework/components/Ellipsis.jsx +39 -0
  11. package/src/framework/components/Ellipsis.less +8 -0
  12. package/src/framework/components/Gap/index.d.ts +23 -0
  13. package/src/framework/components/Gap/index.jsx +46 -0
  14. package/src/framework/components/LinkButton.d.ts +14 -0
  15. package/src/framework/components/LinkButton.jsx +10 -0
  16. package/src/framework/components/NamedIcon.tsx +15 -0
  17. package/src/framework/components/Page/index.d.ts +17 -0
  18. package/src/framework/components/Page/index.jsx +30 -0
  19. package/src/framework/components/Page/index.less +10 -0
  20. package/src/framework/components/PageLoading.tsx +27 -0
  21. package/src/framework/components/ProModal/index.tsx +66 -0
  22. package/src/framework/components/ProTable/components/ToolBar/index.jsx +123 -0
  23. package/src/framework/components/ProTable/components/ToolBar/index.less +53 -0
  24. package/src/framework/components/ProTable/index.d.ts +42 -0
  25. package/src/framework/components/ProTable/index.jsx +260 -0
  26. package/src/framework/components/ProTable/index.less +14 -0
  27. package/src/framework/components/ProTable/utils/index.js +43 -0
  28. package/src/framework/components/ValueType/index.jsx +34 -0
  29. package/src/framework/components/ValueType/registry.jsx +27 -0
  30. package/src/framework/components/index.ts +17 -0
  31. package/src/framework/components/system/ButtonList.d.ts +8 -0
  32. package/src/framework/components/system/ButtonList.jsx +42 -0
  33. package/src/framework/components/system/HasPerm.tsx +14 -0
  34. package/src/framework/components/system/index.tsx +29 -0
  35. package/src/framework/components/view/ViewBooleanEnableDisable.tsx +20 -0
  36. package/src/framework/components/view/ViewEllipsis.d.ts +11 -0
  37. package/src/framework/components/view/ViewEllipsis.jsx +30 -0
  38. package/src/framework/components/view/ViewFile.d.ts +10 -0
  39. package/src/framework/components/view/ViewFile.jsx +49 -0
  40. package/src/framework/components/view/ViewFileButton.d.ts +10 -0
  41. package/src/framework/components/view/ViewFileButton.jsx +0 -0
  42. package/src/framework/components/view/ViewImage.d.ts +9 -0
  43. package/src/framework/components/view/ViewImage.jsx +60 -0
  44. package/src/framework/components/view/ViewRange/index.d.ts +16 -0
  45. package/src/framework/components/view/ViewRange/index.jsx +20 -0
  46. package/src/framework/components/view/ViewText.tsx +16 -0
  47. package/src/framework/components/view/index.ts +10 -0
  48. package/src/framework/field-components/FieldBoolean.d.ts +13 -0
  49. package/src/framework/field-components/FieldBoolean.jsx +76 -0
  50. package/src/framework/field-components/FieldDate.d.ts +27 -0
  51. package/src/framework/field-components/FieldDate.jsx +114 -0
  52. package/src/framework/field-components/FieldDateRange.d.ts +6 -0
  53. package/src/framework/field-components/FieldDateRange.jsx +104 -0
  54. package/src/framework/field-components/FieldDictSelect.d.ts +13 -0
  55. package/src/framework/field-components/FieldDictSelect.jsx +16 -0
  56. package/src/framework/field-components/FieldEditor.d.ts +10 -0
  57. package/src/framework/field-components/FieldEditor.jsx +58 -0
  58. package/src/framework/field-components/FieldNumberRange.d.ts +13 -0
  59. package/src/framework/field-components/FieldNumberRange.jsx +59 -0
  60. package/src/framework/field-components/FieldPercent.d.ts +12 -0
  61. package/src/framework/field-components/FieldPercent.jsx +27 -0
  62. package/src/framework/field-components/FieldRemoteSelect.d.ts +13 -0
  63. package/src/framework/field-components/FieldRemoteSelect.jsx +87 -0
  64. package/src/framework/field-components/FieldRemoteSelectMultiple.d.ts +13 -0
  65. package/src/framework/field-components/FieldRemoteSelectMultiple.jsx +86 -0
  66. package/src/framework/field-components/FieldRemoteSelectMultipleInline.d.ts +20 -0
  67. package/src/framework/field-components/FieldRemoteSelectMultipleInline.jsx +86 -0
  68. package/src/framework/field-components/FieldRemoteTree.d.ts +21 -0
  69. package/src/framework/field-components/FieldRemoteTree.jsx +45 -0
  70. package/src/framework/field-components/FieldRemoteTreeCascader.d.ts +23 -0
  71. package/src/framework/field-components/FieldRemoteTreeCascader.jsx +61 -0
  72. package/src/framework/field-components/FieldRemoteTreeSelect.d.ts +17 -0
  73. package/src/framework/field-components/FieldRemoteTreeSelect.jsx +67 -0
  74. package/src/framework/field-components/FieldRemoteTreeSelectMultiple.d.ts +17 -0
  75. package/src/framework/field-components/FieldRemoteTreeSelectMultiple.jsx +72 -0
  76. package/src/framework/field-components/FieldSysOrgTree.d.ts +12 -0
  77. package/src/framework/field-components/FieldSysOrgTree.jsx +23 -0
  78. package/src/framework/field-components/FieldSysOrgTreeSelect.d.ts +12 -0
  79. package/src/framework/field-components/FieldSysOrgTreeSelect.jsx +23 -0
  80. package/src/framework/field-components/FieldTable.d.ts +17 -0
  81. package/src/framework/field-components/FieldTable.jsx +108 -0
  82. package/src/framework/field-components/FieldTable.less +29 -0
  83. package/src/framework/field-components/FieldTableSelect.d.ts +19 -0
  84. package/src/framework/field-components/FieldTableSelect.jsx +59 -0
  85. package/src/framework/field-components/FieldUploadFile.d.ts +34 -0
  86. package/src/framework/field-components/FieldUploadFile.jsx +141 -0
  87. package/src/framework/field-components/index.ts +21 -0
  88. package/src/framework/field-components/system/OrgTree.tsx +61 -0
  89. package/src/framework/field-components/system/RoleTree.tsx +53 -0
  90. package/src/framework/field-components/system/index.ts +2 -0
  91. package/src/framework/index.ts +5 -0
  92. package/src/framework/pages/LoginPage.d.ts +16 -0
  93. package/src/framework/pages/LoginPage.jsx +135 -0
  94. package/src/framework/pages/LoginPage.less +53 -0
  95. package/src/framework/pages/LoginPageUtils.ts +36 -0
  96. package/src/framework/pages/index.ts +2 -0
  97. package/src/framework/utils/ArrUtils.ts +229 -0
  98. package/src/framework/utils/ColorsUtils.ts +378 -0
  99. package/src/framework/utils/DateUtils.ts +187 -0
  100. package/src/framework/utils/DeviceUtils.ts +46 -0
  101. package/src/framework/utils/DomUtils.ts +50 -0
  102. package/src/framework/utils/EventBusUtils.ts +144 -0
  103. package/src/framework/utils/Logger.ts +40 -0
  104. package/src/framework/utils/MessageUtils.tsx +170 -0
  105. package/src/framework/utils/ObjectUtils.ts +118 -0
  106. package/src/framework/utils/StorageUtils.ts +50 -0
  107. package/src/framework/utils/StringUtils.ts +436 -0
  108. package/src/framework/utils/TreeUtils.ts +251 -0
  109. package/src/framework/utils/UrlUtils.ts +152 -0
  110. package/src/framework/utils/UuidUtils.ts +88 -0
  111. package/src/framework/utils/ValidateUtils.ts +28 -0
  112. package/src/framework/utils/index.ts +16 -0
  113. package/src/framework/utils/system/DictUtils.ts +97 -0
  114. package/src/framework/utils/system/FormRegistryUtils.ts +77 -0
  115. package/src/framework/utils/system/HttpUtils.ts +247 -0
  116. package/src/framework/utils/system/PageUtils.ts +163 -0
  117. package/src/framework/utils/system/PermUtils.ts +79 -0
  118. package/src/framework/utils/system/SysUtils.ts +97 -0
  119. package/src/framework/utils/system/ThemeUtils.ts +27 -0
  120. package/src/framework/utils/system/index.ts +7 -0
  121. package/src/framework/view-components/ViewApproveStatus.tsx +26 -0
  122. package/src/framework/view-components/ViewBoolean.tsx +6 -0
  123. package/src/framework/view-components/ViewFlowableInstanceProgress.d.ts +12 -0
  124. package/src/framework/view-components/ViewFlowableInstanceProgress.jsx +97 -0
  125. package/src/framework/view-components/ViewFlowableInstanceProgressButton.tsx +26 -0
  126. package/src/framework/view-components/ViewPassword.tsx +25 -0
  127. package/src/framework/view-components/ViewProps.ts +11 -0
  128. package/src/framework/view-components/index.ts +6 -0
  129. package/src/index.ts +2 -0
  130. package/src/layouts/PageRender.d.ts +22 -0
  131. package/src/layouts/PageRender.jsx +90 -0
  132. package/src/layouts/admin/HeaderRight.jsx +104 -0
  133. package/src/layouts/admin/TabPageRender.jsx +158 -0
  134. package/src/layouts/admin/index.jsx +161 -0
  135. package/src/layouts/admin/index.less +65 -0
  136. package/src/layouts/index.jsx +165 -0
  137. package/src/layouts/index.less +24 -0
  138. package/src/loading.jsx +18 -0
  139. package/src/pages/404.jsx +13 -0
  140. package/src/pages/about.jsx +14 -0
  141. package/src/pages/index.jsx +25 -0
  142. package/src/pages/login.jsx +21 -0
  143. package/src/pages/system/api/ApiDoc.jsx +144 -0
  144. package/src/pages/system/api/index.jsx +268 -0
  145. package/src/pages/system/api/perm.jsx +69 -0
  146. package/src/pages/system/dict/Dict.jsx +72 -0
  147. package/src/pages/system/dict/DictItem.jsx +177 -0
  148. package/src/pages/system/dict/index.jsx +25 -0
  149. package/src/pages/system/file/index.jsx +160 -0
  150. package/src/pages/system/job/index.jsx +324 -0
  151. package/src/pages/system/log/index.jsx +78 -0
  152. package/src/pages/system/org/index.jsx +262 -0
  153. package/src/pages/system/role/index.jsx +308 -0
  154. package/src/pages/system/role/perm.jsx +108 -0
  155. package/src/pages/system/sysManual/index.jsx +127 -0
  156. package/src/pages/system/user/UserPerm.jsx +97 -0
  157. package/src/pages/system/user/index.jsx +258 -0
  158. package/src/pages/test.jsx +200 -0
  159. package/src/pages/ureport/index.jsx +16 -0
  160. package/src/pages/userCenter/ChangePassword.jsx +63 -0
  161. package/src/pages/userCenter/index.jsx +90 -0
  162. package/src/pages/userCenter/manual.jsx +59 -0
  163. package/src/pages/userCenter/message.jsx +105 -0
  164. package/src/style/global.less +51 -0
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+
3
+ export interface FieldEditProps {
4
+ value ?: string;
5
+ onChange ?: (value: string) => void;
6
+ height ?: number;
7
+ }
8
+
9
+ export class FieldEditor extends React.Component<FieldEditProps, any> {}
10
+
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import {Editor as TinyMceEditor} from '@tinymce/tinymce-react';
3
+
4
+
5
+ /**
6
+ * 富文本编辑器
7
+ *
8
+ * 图片上传相关配置 https://www.tiny.cloud/docs/tinymce/7/image/
9
+ */
10
+ export class FieldEditor extends React.Component {
11
+ render() {
12
+ let uploadUrl = 'admin/sysFile/upload'
13
+ let jsUrl = 'admin/tinymce/tinymce.min.js';
14
+ const {value,onChange,height} = this.props
15
+
16
+ return <>
17
+ <TinyMceEditor
18
+ initialValue={value}
19
+ tinymceScriptSrc={jsUrl}
20
+ init={{
21
+ min_height: 300,
22
+ language: 'zh_CN',
23
+ height: height,
24
+
25
+ // 上传图片
26
+ images_upload_url: uploadUrl,
27
+ promotion: false, // 不显示升级按钮(右上角)
28
+ cache_suffix: '?v=v7.7',
29
+
30
+ plugins: [
31
+ 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
32
+ 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
33
+ 'insertdatetime', 'media', 'table', 'code', 'help', 'wordcount',
34
+ 'emoticons'
35
+ ],
36
+ image_description:false,
37
+
38
+ // 设置图片上传对话框默认选中上传Tab
39
+ setup: function (editor) {
40
+ editor.on('OpenWindow', function(e) {
41
+ const dialog = e.dialog;
42
+ // 包含 dimensions 属性应该就是 上传图片的对话框
43
+ if (dialog && dialog.getData().dimensions) {
44
+ dialog.showTab("upload")
45
+ }
46
+ });
47
+ },
48
+
49
+ }}
50
+ onChange={e => {
51
+ if (onChange) {
52
+ onChange(e.target.getContent())
53
+ }
54
+ }}
55
+ />
56
+ </>;
57
+ }
58
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+
3
+ export interface FieldNumberRangeProps {
4
+ value?: string;
5
+ onChange?: (value: string) => void;
6
+ }
7
+
8
+ /**
9
+ * 数字的百分数输入框
10
+ */
11
+ export class FieldNumberRange extends React.Component<FieldNumberRangeProps, any> {
12
+ }
13
+
@@ -0,0 +1,59 @@
1
+ import React from "react";
2
+ import {InputNumber} from "antd";
3
+ import {StringUtils} from "../utils";
4
+
5
+
6
+ const SP = StringUtils.ISO_SPLITTER;
7
+
8
+ export class FieldNumberRange extends React.Component {
9
+
10
+
11
+ onChangeA = (a) => {
12
+ const {b} = this.parse(this.props.value)
13
+ this.props.onChange && this.props.onChange(this.merge(a, b))
14
+ }
15
+ onChangeB = (b) => {
16
+ const {a} = this.parse(this.props.value)
17
+ this.props.onChange && this.props.onChange(this.merge(a, b))
18
+ }
19
+
20
+ merge(a, b) {
21
+ if (a == null) {
22
+ a = ''
23
+ }
24
+ if (b == null) {
25
+ b = ''
26
+ }
27
+ return a + SP + b;
28
+ }
29
+
30
+ parse(v) {
31
+ if (v == null) {
32
+ return {a: null, b: null}
33
+ }
34
+ const arr = v.split(SP);
35
+ return {a: arr[0], b: arr[1]}
36
+ }
37
+
38
+ componentDidMount() {
39
+ let {value, defaultValue} = this.props
40
+ if (value == null) {
41
+ this.props.onChange && this.props.onChange(defaultValue)
42
+ }
43
+
44
+ }
45
+
46
+
47
+ render() {
48
+ let {value, defaultValue} = this.props
49
+ if (value == null) {
50
+ value = defaultValue
51
+ }
52
+ const {a, b} = this.parse(value)
53
+
54
+ return <div style={{display: 'flex', alignItems: 'center'}}>
55
+ <InputNumber value={a} onChange={this.onChangeA}/> - <InputNumber value={b} onChange={this.onChangeB}/>
56
+ </div>
57
+ }
58
+
59
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+
3
+ export interface FieldPercentProps {
4
+ value ?: number;
5
+ onChange ?: (number: string) => void;
6
+ }
7
+
8
+ /**
9
+ * 数字的百分数输入框
10
+ */
11
+ export class FieldPercent extends React.Component<FieldPercentProps, any> {}
12
+
@@ -0,0 +1,27 @@
1
+ import {InputNumber, Space} from 'antd';
2
+ import React from 'react';
3
+
4
+ export class FieldPercent extends React.Component {
5
+ render() {
6
+ const {value, onChange, ...rest} = this.props;
7
+
8
+
9
+ return (
10
+ <Space.Compact>
11
+ <InputNumber
12
+ min={0}
13
+ max={100}
14
+ value={ Number((value * 100).toFixed(0))}
15
+ onChange={v => {
16
+ v = (v / 100).toFixed(2);
17
+ onChange(Number(v))
18
+ }}
19
+ {...rest}
20
+ />
21
+ <Space.Addon>%</Space.Addon>
22
+ </Space.Compact>
23
+
24
+ );
25
+ }
26
+ }
27
+
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { SelectProps } from 'antd/es/select';
3
+
4
+ export interface FieldRemoteSelectProps extends Omit<SelectProps, 'options' | 'children'|'mode'> {
5
+
6
+ /**
7
+ * 请求地址
8
+ */
9
+ url: string ;
10
+ }
11
+
12
+ export class FieldRemoteSelect extends React.Component<FieldRemoteSelectProps, any> {}
13
+
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import {Select, Spin, message} from 'antd';
3
+ import {debounce} from 'lodash';
4
+ import {HttpUtils} from "../utils";
5
+
6
+ export class FieldRemoteSelect extends React.Component {
7
+ constructor(props) {
8
+ super(props);
9
+
10
+ this.state = {
11
+ options: [],
12
+ loading: false,
13
+ };
14
+
15
+ this.fetchIdRef = 0;
16
+ this.loadDataDebounce = debounce(this.loadData, 800);
17
+ }
18
+
19
+ static defaultProps = {
20
+ placeholder: '请搜索选择'
21
+ };
22
+
23
+ componentDidMount() {
24
+ this.loadData('')
25
+ }
26
+
27
+ componentWillUnmount() {
28
+ this.loadDataDebounce.cancel();
29
+ }
30
+
31
+ loadData = async (searchText) => {
32
+ const {url, value} = this.props;
33
+ const fetchId = ++this.fetchIdRef;
34
+
35
+ this.setState({loading: true});
36
+
37
+ try {
38
+ const data = await HttpUtils.get(url, {searchText, selected: value});
39
+
40
+ if (fetchId === this.fetchIdRef) {
41
+ this.setState({options: data || []});
42
+ }
43
+ } catch (error) {
44
+ console.error('远程搜索失败:', error);
45
+ message.error('搜索失败,请重试');
46
+ this.setState({options: []});
47
+ } finally {
48
+ if (fetchId === this.fetchIdRef) {
49
+ this.setState({loading: false});
50
+ }
51
+ }
52
+ };
53
+
54
+ handleSearch = (value) => {
55
+ if (value.trim() === '') {
56
+ this.setState({options: []});
57
+ return;
58
+ }
59
+ this.loadDataDebounce(value.trim());
60
+ };
61
+
62
+ render() {
63
+ const {options, loading} = this.state;
64
+ const {value, onChange, url, ...selectProps} = this.props;
65
+
66
+ return (
67
+ <Select
68
+ showSearch={
69
+ {
70
+ filterOption: false,
71
+ onSearch: this.handleSearch,
72
+ }
73
+ }
74
+ value={value}
75
+ onChange={onChange}
76
+ options={options}
77
+ notFoundContent={loading ? <Spin size="small"/> : '数据为空'}
78
+ style={{width: '100%', minWidth: 200}}
79
+ allowClear
80
+
81
+ {...selectProps}
82
+ >
83
+ </Select>
84
+ );
85
+ }
86
+ }
87
+
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { SelectProps } from 'antd/es/select';
3
+
4
+ export interface FieldRemoteSelectMultipleProps extends Omit<SelectProps, 'options' | 'children'| 'mode'> {
5
+
6
+ /**
7
+ * 请求地址
8
+ */
9
+ url: string ;
10
+ }
11
+
12
+ export class FieldRemoteSelectMultiple extends React.Component<FieldRemoteSelectMultipleProps, any> {}
13
+
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import {Select, Spin, message} from 'antd';
3
+ import {debounce} from 'lodash';
4
+ import {HttpUtils} from "../utils";
5
+
6
+ export class FieldRemoteSelectMultiple extends React.Component {
7
+ constructor(props) {
8
+ super(props);
9
+
10
+ this.state = {
11
+ options: [],
12
+ loading: false,
13
+ };
14
+
15
+ this.fetchIdRef = 0;
16
+ this.loadDataDebounce = debounce(this.loadData, 800);
17
+ }
18
+
19
+ static defaultProps = {
20
+ placeholder: '请搜索选择'
21
+ };
22
+
23
+ componentDidMount() {
24
+ this.loadData('')
25
+ }
26
+
27
+ componentWillUnmount() {
28
+ this.loadDataDebounce.cancel();
29
+ }
30
+
31
+ loadData = async (searchText) => {
32
+ const {url, value} = this.props;
33
+ const fetchId = ++this.fetchIdRef;
34
+
35
+ this.setState({loading: true});
36
+
37
+ try {
38
+ const data = await HttpUtils.get(url, {searchText, selected: value});
39
+
40
+ if (fetchId === this.fetchIdRef) {
41
+ this.setState({options: data || []});
42
+ }
43
+ } catch (error) {
44
+ console.error('远程搜索失败:', error);
45
+ message.error('搜索失败,请重试');
46
+ this.setState({options: []});
47
+ } finally {
48
+ if (fetchId === this.fetchIdRef) {
49
+ this.setState({loading: false});
50
+ }
51
+ }
52
+ };
53
+
54
+ handleSearch = (value) => {
55
+ if (value.trim() === '') {
56
+ this.setState({options: []});
57
+ return;
58
+ }
59
+ this.loadDataDebounce(value.trim());
60
+ };
61
+
62
+ render() {
63
+ const {options, loading} = this.state;
64
+ const {value, onChange, url, ...selectProps} = this.props;
65
+ return (
66
+ <Select
67
+ showSearch={
68
+ {
69
+ filterOption: false,
70
+ onSearch: this.handleSearch,
71
+ }
72
+ }
73
+ value={value}
74
+ onChange={onChange}
75
+ options={options}
76
+ notFoundContent={loading ? <Spin size="small"/> : '数据为空'}
77
+ style={{width: '100%', minWidth: 200}}
78
+ allowClear
79
+ mode='multiple'
80
+ {...selectProps}
81
+ >
82
+ </Select>
83
+ );
84
+ }
85
+ }
86
+
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * 多选,但是值是字符串,逗号破解的
5
+ */
6
+ export interface FieldRemoteSelectMultipleInlineProps {
7
+
8
+ /**
9
+ * 请求地址
10
+ */
11
+ url: string ;
12
+
13
+ /**
14
+ * 默认展开所有
15
+ */
16
+ treeDefaultExpandAll?: boolean ;
17
+ }
18
+
19
+ export class FieldRemoteSelectMultipleInline extends React.Component<FieldRemoteSelectMultipleInlineProps, any> {}
20
+
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import {Select, Spin, message} from 'antd';
3
+ import {debounce} from 'lodash';
4
+ import {HttpUtils, StringUtils} from "../utils";
5
+
6
+ export class FieldRemoteSelectMultipleInline extends React.Component {
7
+ constructor(props) {
8
+ super(props);
9
+
10
+ this.state = {
11
+ options: [],
12
+ loading: false,
13
+ };
14
+
15
+ this.fetchIdRef = 0;
16
+ this.loadDataDebounce = debounce(this.loadData, 800);
17
+ }
18
+
19
+ static defaultProps = {
20
+ placeholder: '请搜索选择'
21
+ };
22
+
23
+ componentDidMount() {
24
+ this.loadData('')
25
+ }
26
+
27
+ componentWillUnmount() {
28
+ this.loadDataDebounce.cancel();
29
+ }
30
+
31
+ loadData = async (searchText) => {
32
+ const {url, value} = this.props;
33
+ const fetchId = ++this.fetchIdRef;
34
+
35
+ this.setState({loading: true});
36
+
37
+ try {
38
+ const data = await HttpUtils.get(url, {searchText, selected: value});
39
+
40
+ if (fetchId === this.fetchIdRef) {
41
+ this.setState({options: data || []});
42
+ }
43
+ } catch (error) {
44
+ console.error('远程搜索失败:', error);
45
+ message.error('搜索失败,请重试');
46
+ this.setState({options: []});
47
+ } finally {
48
+ if (fetchId === this.fetchIdRef) {
49
+ this.setState({loading: false});
50
+ }
51
+ }
52
+ };
53
+
54
+ handleSearch = (value) => {
55
+ if (value.trim() === '') {
56
+ this.setState({options: []});
57
+ return;
58
+ }
59
+ this.loadDataDebounce(value.trim());
60
+ };
61
+
62
+ render() {
63
+ const {options, loading} = this.state;
64
+ const {value, onChange, url, ...selectProps} = this.props;
65
+ return (
66
+ <Select
67
+ showSearch={
68
+ {
69
+ filterOption: false,
70
+ onSearch: this.handleSearch,
71
+ }
72
+ }
73
+ value={StringUtils.split(value, ',')}
74
+ onChange={arr=>onChange(StringUtils.join(arr, ','))}
75
+ options={options}
76
+ notFoundContent={loading ? <Spin size="small"/> : '数据为空'}
77
+ style={{width: '100%', minWidth: 200}}
78
+ allowClear
79
+ mode='multiple'
80
+ {...selectProps}
81
+ >
82
+ </Select>
83
+ );
84
+ }
85
+ }
86
+
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { SelectProps } from 'antd/es/select';
3
+ import {TreeProps} from "antd";
4
+
5
+ export interface FieldRemoteTreeProps {
6
+
7
+ /**
8
+ * 请求地址
9
+ */
10
+ url: string ;
11
+ }
12
+
13
+ /**
14
+ * 多选树
15
+ *
16
+ * 区别于下拉框,是扁平展示的树
17
+ * 这种需要扁平展示的树,通常都是多选。
18
+ *
19
+ */
20
+ export class FieldRemoteTree extends React.Component<FieldRemoteTreeProps, any> {}
21
+
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ import {Spin, Tree} from "antd";
3
+ import {HttpUtils} from "../utils";
4
+
5
+ export class FieldRemoteTree extends React.Component {
6
+
7
+ state = {
8
+ treeLoading: true,
9
+ treeData: [],
10
+ }
11
+
12
+ componentDidMount() {
13
+ this.loadData();
14
+ }
15
+
16
+
17
+ loadData = async () => {
18
+ this.setState({treeLoading: true})
19
+ let url = this.props.url;
20
+ try {
21
+ const treeData = await HttpUtils.get(url)
22
+ this.setState({treeData})
23
+ } catch (e) {
24
+ console.log(e)
25
+ } finally {
26
+ this.setState({treeLoading: false})
27
+ }
28
+ };
29
+
30
+ render() {
31
+ if (this.state.treeLoading) {
32
+ return <Spin/>
33
+ }
34
+ return <Tree
35
+ multiple
36
+ checkable
37
+ onCheck={e => this.props.onChange(e.checked)}
38
+ checkedKeys={this.props.value}
39
+ treeData={this.state.treeData}
40
+ defaultExpandAll
41
+ checkStrictly
42
+ >
43
+ </Tree>
44
+ }
45
+ }
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { SelectProps } from 'antd/es/select';
3
+ import {TreeProps} from "antd";
4
+
5
+ export interface FieldRemoteTreeCascaderProps {
6
+
7
+ /**
8
+ * 请求地址
9
+ * 要求返回数据格式为:tree
10
+ */
11
+ url: string ;
12
+
13
+ value?: string;
14
+ onChange?: (value: string) => void;
15
+ }
16
+
17
+ /**
18
+ * 远程树级联选择器, 类似select,但是树级联
19
+ *
20
+ * 注意,value为非数组形式,区别于cascader组件
21
+ */
22
+ export class FieldRemoteTreeCascader extends React.Component<FieldRemoteTreeCascaderProps, any> {}
23
+
@@ -0,0 +1,61 @@
1
+ import {Cascader, message, Spin} from 'antd';
2
+
3
+ import React from 'react';
4
+ import {HttpUtils, TreeUtils} from "../utils";
5
+
6
+
7
+ export class FieldRemoteTreeCascader extends React.Component {
8
+
9
+ state = {
10
+ data: [],
11
+ value: [],
12
+ loading: false,
13
+ };
14
+
15
+ componentDidMount() {
16
+ this.loadData();
17
+ }
18
+
19
+
20
+ loadData = async () => {
21
+ const {url} = this.props;
22
+ this.setState({loading: true});
23
+
24
+ try {
25
+ const list = await HttpUtils.get(url);
26
+ this.setState({data: list});
27
+ } catch (e) {
28
+ console.log(e)
29
+ } finally {
30
+ this.setState({loading: false});
31
+ }
32
+
33
+ };
34
+
35
+
36
+
37
+ render() {
38
+ const {data} = this.state;
39
+ if (this.state.loading) {
40
+ return <Spin/>;
41
+ }
42
+ let {value, onChange,...rest} = this.props;
43
+
44
+ let arr = [];
45
+ if (value != null) {
46
+ arr = TreeUtils.getKeyList(data, value);
47
+ }
48
+
49
+ return (
50
+ <Cascader
51
+ options={this.state.data}
52
+ onChange={arr=>{
53
+ onChange(arr[arr.length - 1]);
54
+ }}
55
+ value={arr}
56
+ fieldNames={{label: 'title', value: 'key'}}
57
+ {...rest}
58
+ />
59
+ );
60
+ }
61
+ }
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+
3
+ export interface FieldRemoteTreeSelectProps {
4
+
5
+ /**
6
+ * 请求地址
7
+ */
8
+ url: string ;
9
+
10
+ /**
11
+ * 默认展开所有
12
+ */
13
+ treeDefaultExpandAll?: boolean ;
14
+ }
15
+
16
+ export class FieldRemoteTreeSelect extends React.Component<FieldRemoteTreeSelectProps, any> {}
17
+