@jiangood/open-admin 2.5.5 → 2.5.7

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 (112) hide show
  1. package/config/common-plugin.js +2 -2
  2. package/package.json +3 -2
  3. package/src/.umi-production/appData.json +91 -90
  4. package/src/.umi-production/core/route.tsx +6 -6
  5. package/src/.umi-production/umi.ts +1 -1
  6. package/src/framework/GlobalData.d.ts +8 -0
  7. package/src/framework/GlobalData.js +33 -0
  8. package/src/framework/{components/system → biz}/HasPerm.tsx +1 -1
  9. package/src/framework/{components/OrgTree/index.tsx → biz/OrgTree.tsx} +12 -2
  10. package/src/framework/{components/system/ButtonList.tsx → biz/PermActions.tsx} +6 -5
  11. package/src/framework/{components/RoleTree/index.tsx → biz/RoleTree.tsx} +13 -3
  12. package/src/framework/{components/system → biz}/index.tsx +4 -2
  13. package/src/framework/components/ContextMenu/index.tsx +12 -4
  14. package/src/framework/components/DownloadModal/index.tsx +332 -0
  15. package/src/framework/components/ErrorBoundary/index.tsx +18 -0
  16. package/src/framework/components/NamedIcon/{index.jsx → index.tsx} +8 -3
  17. package/src/framework/components/Page/index.tsx +2 -2
  18. package/src/framework/components/ProTable/index.tsx +3 -10
  19. package/src/framework/components/index.ts +2 -6
  20. package/src/framework/fields/BaseRemoteSelect/index.tsx +2 -3
  21. package/src/framework/fields/FieldBoolean/index.tsx +3 -4
  22. package/src/framework/fields/FieldDate/index.tsx +0 -21
  23. package/src/framework/fields/FieldEditor/index.tsx +35 -44
  24. package/src/framework/fields/FieldNumberRange/index.tsx +2 -2
  25. package/src/framework/fields/FieldRemoteTree/index.tsx +1 -1
  26. package/src/framework/fields/FieldTable/index.tsx +24 -27
  27. package/src/framework/fields/FieldUploadFile/index.tsx +10 -3
  28. package/src/framework/fields/index.ts +1 -3
  29. package/src/framework/index.ts +2 -0
  30. package/src/framework/utils/ArrayUtils.d.ts +6 -0
  31. package/src/framework/utils/ArrayUtils.js +30 -0
  32. package/src/framework/utils/DateUtils.d.ts +20 -0
  33. package/src/framework/utils/DateUtils.js +81 -0
  34. package/src/framework/utils/DeviceUtils.d.ts +3 -0
  35. package/src/framework/utils/DeviceUtils.js +10 -0
  36. package/src/framework/utils/EventBus.d.ts +6 -0
  37. package/src/framework/utils/EventBus.js +51 -0
  38. package/src/framework/utils/MessageUtils.d.ts +10 -0
  39. package/src/framework/utils/MessageUtils.js +43 -0
  40. package/src/framework/utils/ObjectUtils.d.ts +14 -0
  41. package/src/framework/utils/ObjectUtils.js +12 -0
  42. package/src/framework/utils/StorageUtils.d.ts +4 -0
  43. package/src/framework/utils/{StorageUtils.ts → StorageUtils.js} +7 -11
  44. package/src/framework/utils/StringUtils.d.ts +17 -0
  45. package/src/framework/utils/StringUtils.js +107 -0
  46. package/src/framework/utils/TreeUtils.d.ts +13 -0
  47. package/src/framework/utils/TreeUtils.js +64 -0
  48. package/src/framework/utils/UrlUtils.d.ts +6 -0
  49. package/src/framework/utils/UrlUtils.js +71 -0
  50. package/src/framework/utils/index.ts +1 -5
  51. package/src/framework/utils/system/DictUtils.d.ts +20 -0
  52. package/src/framework/utils/system/DictUtils.js +31 -0
  53. package/src/framework/utils/system/FormRegistry.d.ts +8 -0
  54. package/src/framework/utils/system/FormRegistry.js +31 -0
  55. package/src/framework/utils/system/HttpUtils.d.ts +14 -0
  56. package/src/framework/utils/system/HttpUtils.js +87 -0
  57. package/src/framework/utils/system/PageUtils.d.ts +14 -0
  58. package/src/framework/utils/system/PageUtils.js +59 -0
  59. package/src/framework/utils/system/PermUtils.d.ts +5 -0
  60. package/src/framework/utils/system/PermUtils.js +27 -0
  61. package/src/framework/utils/system/ThemeUtils.d.ts +6 -0
  62. package/src/framework/utils/system/{ThemeUtils.ts → ThemeUtils.js} +19 -19
  63. package/src/framework/utils/system/index.ts +1 -2
  64. package/src/framework/views/ViewFile/index.tsx +3 -3
  65. package/src/framework/views/ViewImage/index.tsx +3 -3
  66. package/src/framework/views/{ViewBooleanEnableDisable → ViewSwitch}/index.tsx +1 -1
  67. package/src/framework/views/index.ts +3 -4
  68. package/src/layouts/admin/HeaderRight.jsx +32 -47
  69. package/src/layouts/admin/index.jsx +5 -29
  70. package/src/layouts/index.jsx +29 -19
  71. package/src/pages/about.jsx +0 -1
  72. package/src/pages/{userCenter/ChangePassword.jsx → account/changePassword.jsx} +1 -2
  73. package/src/pages/{userCenter → account}/index.jsx +2 -6
  74. package/src/pages/forceUpdatePwd.jsx +89 -0
  75. package/src/pages/login.jsx +5 -5
  76. package/src/pages/system/dict/index.jsx +6 -6
  77. package/src/pages/system/file/index.jsx +4 -4
  78. package/src/pages/system/job/index.jsx +2 -2
  79. package/src/pages/system/org/index.jsx +2 -2
  80. package/src/pages/system/role/index.jsx +4 -4
  81. package/src/pages/system/role/{perm.jsx → rolePerm.jsx} +2 -2
  82. package/src/pages/system/user/index.jsx +4 -4
  83. package/src/framework/components/DownloadFileButton/index.tsx +0 -33
  84. package/src/framework/components/NamedIcon/index.d.ts +0 -7
  85. package/src/framework/components/ProTable/utils/index.ts +0 -62
  86. package/src/framework/fields/FieldRemoteSelectMultipleInline/index.tsx +0 -33
  87. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.tsx +0 -43
  88. package/src/framework/utils/ArrayUtils.ts +0 -186
  89. package/src/framework/utils/ColorsUtils.ts +0 -378
  90. package/src/framework/utils/DateUtils.ts +0 -187
  91. package/src/framework/utils/DeviceUtils.ts +0 -46
  92. package/src/framework/utils/DomUtils.ts +0 -50
  93. package/src/framework/utils/EventBusUtils.ts +0 -143
  94. package/src/framework/utils/Logger.ts +0 -40
  95. package/src/framework/utils/MessageUtils.tsx +0 -90
  96. package/src/framework/utils/ObjectUtils.ts +0 -118
  97. package/src/framework/utils/StringUtils.ts +0 -436
  98. package/src/framework/utils/TreeUtils.ts +0 -251
  99. package/src/framework/utils/UrlUtils.ts +0 -152
  100. package/src/framework/utils/UuidUtils.ts +0 -88
  101. package/src/framework/utils/ValidateUtils.ts +0 -28
  102. package/src/framework/utils/system/DictUtils.ts +0 -96
  103. package/src/framework/utils/system/FormRegistryUtils.ts +0 -76
  104. package/src/framework/utils/system/HttpUtils.ts +0 -251
  105. package/src/framework/utils/system/PageUtils.ts +0 -163
  106. package/src/framework/utils/system/PermUtils.ts +0 -79
  107. package/src/framework/utils/system/SysUtils.ts +0 -105
  108. package/src/framework/views/ViewProcessInstanceProgress/index.tsx +0 -98
  109. package/src/framework/views/ViewProcessInstanceProgressButton/index.tsx +0 -23
  110. package/src/pages/userCenter/message.jsx +0 -105
  111. /package/src/framework/{components → views}/ViewRange/index.tsx +0 -0
  112. /package/src/pages/system/user/{UserPerm.jsx → userPerm.jsx} +0 -0
@@ -1,14 +1,10 @@
1
- export * from './system'
2
1
  export * from './PageLoading'
3
2
  export * from './ProTable'
4
- export * from './DownloadFileButton'
5
3
  export * from './NamedIcon'
6
4
  export * from './LinkButton'
7
5
  export * from './Gap'
8
6
  export * from './Page'
9
7
  export * from './ValueType'
10
8
  export * from './ContextMenu'
11
- export * from './OrgTree'
12
- export * from './RoleTree'
13
- export * from './ViewRange'
14
- export { default as ErrorBoundary } from './ErrorBoundary'
9
+ export * from './DownloadModal'
10
+ export { default as ErrorBoundary } from './ErrorBoundary'
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Spin, message } from 'antd';
2
+ import { Spin } from 'antd';
3
3
  import { debounce } from 'lodash';
4
4
  import { HttpUtils } from '../../utils';
5
5
 
@@ -80,8 +80,7 @@ export class BaseRemoteSelect<P extends BaseRemoteSelectProps = BaseRemoteSelect
80
80
  this.setState({ data: data || [] });
81
81
  }
82
82
  } catch (error) {
83
- console.error('远程加载失败:', error);
84
- message.error('加载失败,请重试');
83
+ console.warn('[BaseRemoteSelect] 加载失败:', error);
85
84
  if (fetchId === this.fetchIdRef) {
86
85
  this.setState({ data: [] });
87
86
  }
@@ -25,10 +25,9 @@ export class FieldBoolean extends React.Component {
25
25
 
26
26
  switch (type) {
27
27
  case 'radio':
28
- return <Radio.Group value={v} onChange={onChange}>
28
+ return <Radio.Group value={v} onChange={e => onChange && onChange(e.target.value)}>
29
29
  <Radio value={true}>是</Radio>
30
30
  <Radio value={false}>否</Radio>
31
- <Radio value={undefined}>不确定</Radio>
32
31
  </Radio.Group>;
33
32
  case 'checkbox':
34
33
  return <Checkbox
@@ -43,7 +42,7 @@ export class FieldBoolean extends React.Component {
43
42
  {value: false, label: '否'},
44
43
  ]}
45
44
  value={v}
46
- onChange={onChange}
45
+ onChange={value => onChange && onChange(value)}
47
46
  style={{width: '100%'}}
48
47
  allowClear={true}
49
48
  placeholder={'请选择'}
@@ -51,7 +50,7 @@ export class FieldBoolean extends React.Component {
51
50
  case 'switch':
52
51
  return <Switch
53
52
  checked={v}
54
- onChange={onChange}
53
+ onChange={checked => onChange && onChange(checked)}
55
54
  />;
56
55
  default:
57
56
  return null;
@@ -77,27 +77,6 @@ export class FieldDate extends React.Component {
77
77
 
78
78
  }
79
79
 
80
- static getDefaultValue(type) {
81
- const year = dayjs().format("YYYY");
82
- const month = dayjs().format("YYYY-MM");
83
- const quarter = dayjs().format("YYYY-QQ");
84
-
85
- switch (type) {
86
- case 'YYYY':
87
- case 'YEAR':
88
- return year;
89
- case 'YYYY-MM':
90
- case 'YEAR_MONTH':
91
- return month;
92
- case 'YYYY-QQ':
93
- case 'YEAR_QUARTER':
94
- return quarter;
95
- default:
96
- return null;
97
- }
98
-
99
- }
100
-
101
80
  strToDate(value, fmt) {
102
81
  if (value != null && value !== '') {
103
82
  const type = typeof value;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import {Editor as TinyMceEditor} from '@tinymce/tinymce-react';
3
- import {SysUtils} from '../../utils';
3
+ import {UrlUtils} from '../../utils';
4
4
 
5
5
  /**
6
6
  * 富文本编辑器
@@ -9,52 +9,43 @@ import {SysUtils} from '../../utils';
9
9
  */
10
10
  export class FieldEditor extends React.Component {
11
11
  render() {
12
- const uploadUrl = SysUtils.contextPath('/admin/sysFile/upload');
13
- const jsUrl = SysUtils.contextPath('/admin/tinymce/tinymce.min.js');
12
+ const uploadUrl = UrlUtils.contextPath('/admin/sysFile/upload');
13
+ const jsUrl = UrlUtils.contextPath('/admin/tinymce/tinymce.min.js');
14
14
  const {value, onChange, height} = this.props;
15
15
 
16
16
  return (
17
- <>
18
- <TinyMceEditor
19
- initialValue={value}
20
- tinymceScriptSrc={jsUrl}
21
- init={{
22
- min_height: 300,
23
- language: 'zh_CN',
24
- height: height,
25
-
26
- // 上传图片
27
- images_upload_url: uploadUrl,
28
- promotion: false, // 不显示升级按钮(右上角)
29
- cache_suffix: '?v=v7.7',
30
-
31
- plugins: [
32
- 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
33
- 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
34
- 'insertdatetime', 'media', 'table', 'code', 'help', 'wordcount',
35
- 'emoticons'
36
- ],
37
- image_description: false,
38
-
39
- // 设置图片上传对话框默认选中上传Tab
40
- setup: function (editor) {
41
- editor.on('OpenWindow', function(e) {
42
- const dialog = e.dialog;
43
- // 包含 dimensions 属性应该就是 上传图片的对话框
44
- if (dialog && dialog.getData().dimensions) {
45
- dialog.showTab("upload");
46
- }
47
- });
48
- },
49
-
50
- }}
51
- onChange={e => {
52
- if (onChange) {
53
- onChange(e.target.getContent());
54
- }
55
- }}
56
- />
57
- </>
17
+ <TinyMceEditor
18
+ value={value}
19
+ tinymceScriptSrc={jsUrl}
20
+ init={{
21
+ min_height: 300,
22
+ language: 'zh_CN',
23
+ height: height,
24
+ images_upload_url: uploadUrl,
25
+ promotion: false,
26
+ cache_suffix: '?v=v7.7',
27
+ plugins: [
28
+ 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
29
+ 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
30
+ 'insertdatetime', 'media', 'table', 'code', 'help', 'wordcount',
31
+ 'emoticons'
32
+ ],
33
+ image_description: false,
34
+ setup: function (editor) {
35
+ editor.on('OpenWindow', function(e) {
36
+ const dialog = e.dialog;
37
+ if (dialog && dialog.getData().dimensions) {
38
+ dialog.showTab("upload");
39
+ }
40
+ });
41
+ },
42
+ }}
43
+ onEditorChange={content => {
44
+ if (onChange) {
45
+ onChange(content);
46
+ }
47
+ }}
48
+ />
58
49
  );
59
50
  }
60
51
  }
@@ -34,9 +34,9 @@ export class FieldNumberRange extends React.Component {
34
34
  }
35
35
 
36
36
  componentDidMount() {
37
- const {value, defaultValue} = this.props;
37
+ const {value, defaultValue, onChange} = this.props;
38
38
  if (value == null && defaultValue) {
39
- this.props.onChange && this.props.onChange(defaultValue);
39
+ onChange && onChange(defaultValue);
40
40
  }
41
41
  }
42
42
 
@@ -20,7 +20,7 @@ export class FieldRemoteTree extends BaseRemoteSelect {
20
20
  <Tree
21
21
  multiple
22
22
  checkable
23
- onCheck={(e) => this.props.onChange && this.props.onChange(e.checked)}
23
+ onCheck={(checkedInfo) => this.props.onChange && this.props.onChange(checkedInfo.checked)}
24
24
  checkedKeys={this.props.value}
25
25
  treeData={this.state.data}
26
26
  defaultExpandAll
@@ -2,7 +2,6 @@ import {Button, Input, Table} from 'antd'
2
2
  import React from 'react'
3
3
  import {DeleteOutlined, PlusOutlined} from "@ant-design/icons";
4
4
  import './styles.less'
5
- import {ArrayUtils} from "../../utils";
6
5
 
7
6
  /**
8
7
  * 可编辑表格
@@ -15,27 +14,27 @@ export class FieldTable extends React.Component {
15
14
  super(props);
16
15
 
17
16
  this.columns = this.props.columns.map(col => {
18
- if (col.render == null) {
19
- col.render = (v, record, index) => {
20
- return <Input value={v} onChange={(e) => this.onCellChange(index, col.dataIndex, e)}/>;
17
+ const newCol = { ...col };
18
+ const origRender = newCol.render;
19
+
20
+ if (origRender) {
21
+ newCol.render = (v, record, index) => {
22
+ const cmp = origRender(v, record, index);
23
+ return React.createElement(cmp.type, {
24
+ ...cmp.props,
25
+ value: v,
26
+ onChange: (e) => {
27
+ this.onCellChange(index, newCol.dataIndex, e);
28
+ }
29
+ });
21
30
  };
22
31
  } else {
23
- if (!col._oldRender) {
24
- col._oldRender = col.render;
25
- col.render = (v, record, index) => {
26
- const cmp = col._oldRender(v, record, index);
27
- return React.createElement(cmp.type,
28
- {
29
- ...cmp.props,
30
- value: v,
31
- onChange: (e) => {
32
- this.onCellChange(index, col.dataIndex, e);
33
- }
34
- });
35
- };
36
- }
32
+ newCol.render = (v, record, index) => {
33
+ return <Input value={v} onChange={(e) => this.onCellChange(index, newCol.dataIndex, e)}/>;
34
+ };
37
35
  }
38
- return col;
36
+
37
+ return newCol;
39
38
  });
40
39
 
41
40
  this.columns.push({
@@ -57,18 +56,17 @@ export class FieldTable extends React.Component {
57
56
  };
58
57
 
59
58
  onCellChange = (index, dataIndex, e) => {
60
- let {dataSource} = this.state;
59
+ const {dataSource} = this.state;
61
60
  const row = dataSource[index];
62
61
 
63
62
  let v = e;
64
- if (e != null && e.hasOwnProperty('target')) {
63
+ if (e != null && typeof e === 'object' && 'target' in e) {
65
64
  v = e.target.value;
66
65
  }
67
66
 
68
- row[dataIndex] = v;
69
-
70
- dataSource = [...dataSource];
71
- this.setState({dataSource}, this.notifyParent);
67
+ const next = [...dataSource];
68
+ next[index] = {...row, [dataIndex]: v};
69
+ this.setState({dataSource: next}, this.notifyParent);
72
70
  };
73
71
 
74
72
  add = () => {
@@ -79,8 +77,7 @@ export class FieldTable extends React.Component {
79
77
 
80
78
  remove = (record) => {
81
79
  const {dataSource} = this.state;
82
- ArrayUtils.remove(dataSource, record);
83
- this.setState({dataSource: [...dataSource]}, this.notifyParent);
80
+ this.setState({dataSource: dataSource.filter(item => item !== record)}, this.notifyParent);
84
81
  };
85
82
 
86
83
  notifyParent = () => {
@@ -3,7 +3,7 @@ import ImgCrop from "antd-img-crop";
3
3
  import {Modal, Upload, message} from "antd";
4
4
  import { UploadOutlined } from "@ant-design/icons";
5
5
  import {ViewFile} from "../../views";
6
- import {ObjectUtils, SysUtils} from "../../utils";
6
+ import {ObjectUtils, UrlUtils} from "../../utils";
7
7
 
8
8
  /**
9
9
  * 上传图片前裁切, 单张图片
@@ -28,12 +28,19 @@ export class FieldUploadFile extends React.Component {
28
28
  this.state.fileList = this.convertInputToComponentValue(this.state.value);
29
29
  }
30
30
 
31
+ componentDidUpdate(prevProps) {
32
+ const next = {};
33
+ if (this.props.maxCount !== prevProps.maxCount) next.maxCount = this.props.maxCount;
34
+ if (this.props.cropImage !== prevProps.cropImage) next.cropImage = this.props.cropImage;
35
+ if (Object.keys(next).length > 0) this.setState(next);
36
+ }
37
+
31
38
  convertInputToComponentValue(value) {
32
39
  const list = [];
33
40
  if (value && value.length > 0) {
34
41
  const arr = value.split(",");
35
42
  for (const id of arr) {
36
- const url = SysUtils.contextPath('/admin/sysFile/preview/' + id);
43
+ const url = UrlUtils.contextPath('/admin/sysFile/preview/' + id);
37
44
  const file = {id, url, uid: id, name: id, status: 'done', fileName: id};
38
45
  list.push(file);
39
46
  }
@@ -113,7 +120,7 @@ export class FieldUploadFile extends React.Component {
113
120
  const {accept, fileList, maxCount} = this.state;
114
121
 
115
122
  return <Upload
116
- action={SysUtils.contextPath('/admin/sysFile/upload')}
123
+ action={UrlUtils.contextPath('/admin/sysFile/upload')}
117
124
  listType={this.props.listType || 'picture-card'}
118
125
  fileList={fileList}
119
126
  onChange={this.handleChange}
@@ -2,13 +2,11 @@
2
2
  export * from './types';
3
3
  export * from './FieldRemoteSelect';
4
4
  export * from './FieldRemoteSelectMultiple';
5
- export * from './FieldRemoteSelectMultipleInline';
6
5
  export * from './FieldRemoteTree';
7
6
  export * from './FieldDictSelect';
8
7
  export * from './FieldEditor'
9
8
  export * from './FieldRemoteTreeCascader'
10
9
  export * from './FieldRemoteTreeSelect'
11
- export * from './FieldRemoteTreeSelectMultiple'
12
10
  export * from './FieldBoolean';
13
11
  export * from './FieldDate';
14
12
  export * from './FieldDateRange';
@@ -19,4 +17,4 @@ export * from './FieldSysOrgTreeSelect'
19
17
  export * from './FieldSysOrgTree'
20
18
  export * from './FieldPercent'
21
19
  export * from './FieldUploadFile';
22
- export * from '../components/OrgTree';
20
+ export * from '../biz/OrgTree';
@@ -1,4 +1,6 @@
1
+ export * from './biz'
1
2
  export * from './components'
2
3
  export * from './utils'
3
4
  export * from './fields'
4
5
  export * from './views'
6
+ export * from './GlobalData'
@@ -0,0 +1,6 @@
1
+ export class ArrayUtils {
2
+ static contains<T>(arr: T[], item: T): boolean;
3
+ static containsAny<T>(arr: T[], ...items: T[]): boolean;
4
+ static maxBy<T extends Record<K, any>, K extends keyof T>(arr: T[], key: K): T | undefined;
5
+ static unique<T>(arr: T[]): T[];
6
+ }
@@ -0,0 +1,30 @@
1
+ export class ArrayUtils {
2
+ static contains(arr, item) {
3
+ return arr.indexOf(item) !== -1;
4
+ }
5
+
6
+ static containsAny(arr, ...items) {
7
+ for (const item of items) {
8
+ if (ArrayUtils.contains(arr, item)) return true;
9
+ }
10
+ return false;
11
+ }
12
+
13
+ static maxBy(arr, key) {
14
+ if (arr == null || arr.length === 0) return undefined;
15
+ let maxElement = undefined;
16
+ let maxValue = -Infinity;
17
+ for (const element of arr) {
18
+ const value = element[key];
19
+ if (typeof value === 'number' && value > maxValue) {
20
+ maxValue = value;
21
+ maxElement = element;
22
+ }
23
+ }
24
+ return maxElement;
25
+ }
26
+
27
+ static unique(arr) {
28
+ return [...new Set(arr)];
29
+ }
30
+ }
@@ -0,0 +1,20 @@
1
+ export class DateUtils {
2
+ static convertTypeToFormat(type: string): string;
3
+ static year(date: Date): number;
4
+ static month(date: Date): string;
5
+ static date(date: Date): string;
6
+ static hour(date: Date): string;
7
+ static minute(date: Date): string;
8
+ static second(date: Date): string;
9
+ static formatDate(d: Date): string;
10
+ static formatTime(d: Date): string;
11
+ static formatDateTime(d: Date): string;
12
+ static formatDateCn(d: Date): string;
13
+ static now(): string;
14
+ static today(): string;
15
+ static thisYear(): number;
16
+ static thisMonth(): string;
17
+ static friendlyTime(pastDate: Date | string | number): string | undefined;
18
+ static friendlyTotalTime(time: number | string | null): string | null;
19
+ static beginOfMonth(): string;
20
+ }
@@ -0,0 +1,81 @@
1
+ import {StringUtils} from './StringUtils';
2
+
3
+ export class DateUtils {
4
+ static convertTypeToFormat(type) {
5
+ if (type === 'YEAR') type = 'YYYY';
6
+ else if (type === 'YEAR_MONTH') type = 'YYYY-MM';
7
+ else if (type === 'YEAR_QUARTER') type = 'YYYY-QQ';
8
+ else if (type === 'DAY') type = 'YYYY-MM-DD';
9
+ return type;
10
+ }
11
+
12
+ static year(date) { return date.getFullYear(); }
13
+ static month(date) { return StringUtils.pad(date.getMonth() + 1, 2); }
14
+ static date(date) { return StringUtils.pad(date.getDate(), 2); }
15
+ static hour(date) { return StringUtils.pad(date.getHours(), 2); }
16
+ static minute(date) { return StringUtils.pad(date.getMinutes(), 2); }
17
+ static second(date) { return StringUtils.pad(date.getSeconds(), 2); }
18
+
19
+ static formatDate(d) {
20
+ return this.year(d) + '-' + this.month(d) + '-' + this.date(d);
21
+ }
22
+
23
+ static formatTime(d) {
24
+ return this.hour(d) + ':' + this.minute(d) + ':' + this.second(d);
25
+ }
26
+
27
+ static formatDateTime(d) {
28
+ return this.formatDate(d) + ' ' + this.formatTime(d);
29
+ }
30
+
31
+ static formatDateCn(d) {
32
+ return this.year(d) + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日';
33
+ }
34
+
35
+ static now() { return this.formatDateTime(new Date()); }
36
+ static today() { return this.formatDate(new Date()); }
37
+ static thisYear() { return this.year(new Date()); }
38
+ static thisMonth() { return this.month(new Date()); }
39
+
40
+ static friendlyTime(pastDate) {
41
+ if (pastDate == null) return undefined;
42
+ if (!(pastDate instanceof Date)) pastDate = new Date(pastDate);
43
+ const currentDate = new Date();
44
+ let elapsedMilliseconds = currentDate.getTime() - pastDate.getTime();
45
+ const suffix = elapsedMilliseconds > 0 ? '前' : '后';
46
+ elapsedMilliseconds = Math.abs(elapsedMilliseconds);
47
+ const elapsedYears = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24 * 365));
48
+ const elapsedMonths = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24 * 30));
49
+ const elapsedDays = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24));
50
+ const elapsedHours = Math.floor(elapsedMilliseconds / (1000 * 60 * 60));
51
+ const elapsedMinutes = Math.floor(elapsedMilliseconds / (1000 * 60));
52
+ const elapsedSeconds = Math.floor(elapsedMilliseconds / 1000);
53
+ if (elapsedYears >= 1) return `${elapsedYears} 年${suffix}`;
54
+ if (elapsedMonths >= 1) return `${elapsedMonths} 个月${suffix}`;
55
+ if (elapsedDays >= 7) { const weeks = Math.floor(elapsedDays / 7); return `${weeks} 周${suffix}`; }
56
+ if (elapsedDays >= 1) return `${elapsedDays} 天${suffix}`;
57
+ if (elapsedHours >= 1) return `${elapsedHours} 小时${suffix}`;
58
+ if (elapsedMinutes >= 1) return `${elapsedMinutes} 分钟${suffix}`;
59
+ return `${elapsedSeconds} 秒${suffix}`;
60
+ }
61
+
62
+ static friendlyTotalTime(time) {
63
+ if (time == null || time === '-') return null;
64
+ let seconds;
65
+ if (typeof time === 'string') seconds = parseInt(time, 10) / 1000;
66
+ else seconds = time / 1000;
67
+ seconds = Math.floor(seconds);
68
+ if (seconds < 60) return seconds + '秒';
69
+ let min = seconds / 60;
70
+ seconds = seconds % 60;
71
+ min = Math.floor(min);
72
+ seconds = Math.floor(seconds);
73
+ return min + '分' + seconds + '秒';
74
+ }
75
+
76
+ static beginOfMonth() {
77
+ const d = new Date();
78
+ d.setDate(1);
79
+ return this.formatDate(d);
80
+ }
81
+ }
@@ -0,0 +1,3 @@
1
+ export class DeviceUtils {
2
+ static isMobileDevice(): boolean;
3
+ }
@@ -0,0 +1,10 @@
1
+ export class DeviceUtils {
2
+
3
+ static isMobileDevice() {
4
+ const userAgent = navigator?.userAgent || navigator?.vendor || window?.opera || '';
5
+ if (/windows phone/i.test(userAgent)) return true;
6
+ if (/android/i.test(userAgent)) return true;
7
+ if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) return true;
8
+ return false;
9
+ }
10
+ }
@@ -0,0 +1,6 @@
1
+ export class EventBus {
2
+ static on<T extends any[] = []>(name: string, callback: (...args: T) => void, ctx?: any): void;
3
+ static once<T extends any[] = []>(name: string, callback: (...args: T) => void, ctx?: any): void;
4
+ static emit<T extends any[] = []>(name: string, ...args: T): void;
5
+ static off<T extends any[] = []>(name: string, callback?: (...args: T) => void): void;
6
+ }
@@ -0,0 +1,51 @@
1
+ export class EventBus {
2
+ static __stack = {};
3
+
4
+ static on(name, callback, ctx) {
5
+ if (!EventBus.__stack[name]) {
6
+ EventBus.__stack[name] = [];
7
+ }
8
+ EventBus.__stack[name].push({ fn: callback, ctx });
9
+ return () => EventBus.off(name, callback);
10
+ }
11
+
12
+ static once(name, callback, ctx) {
13
+ const unsubscribe = () => EventBus.off(name, callback);
14
+ const listener = (...args) => {
15
+ EventBus.off(name, listener);
16
+ callback.apply(ctx, args);
17
+ };
18
+ listener.__callback = callback;
19
+ EventBus.__stack[name] = EventBus.__stack[name] || [];
20
+ EventBus.__stack[name].push({ fn: listener, ctx });
21
+ return unsubscribe;
22
+ }
23
+
24
+ static emit(name, ...args) {
25
+ const list = EventBus.__stack[name];
26
+ if (list !== undefined) {
27
+ list.slice(0).forEach(entry => {
28
+ entry.fn.apply(entry.ctx, args);
29
+ });
30
+ }
31
+ }
32
+
33
+ static off(name, callback) {
34
+ const list = EventBus.__stack[name];
35
+ if (list === undefined) return;
36
+ if (callback === undefined) {
37
+ delete EventBus.__stack[name];
38
+ return;
39
+ }
40
+ const liveEvents = list.filter(
41
+ entry =>
42
+ entry.fn !== callback &&
43
+ entry.fn.__callback !== callback
44
+ );
45
+ if (liveEvents.length !== 0) {
46
+ EventBus.__stack[name] = liveEvents;
47
+ } else {
48
+ delete EventBus.__stack[name];
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type {ModalFuncProps} from 'antd/es/modal/interface';
3
+
4
+ export class MessageUtils {
5
+ static alert(content: any, config?: Omit<ModalFuncProps, 'content' | 'icon' | 'onOk' | 'onCancel'>): Promise<void>;
6
+ static confirm(content: React.ReactNode, config?: Omit<ModalFuncProps, 'content' | 'icon' | 'onOk' | 'onCancel'>): Promise<boolean>;
7
+ static success(content: string, duration?: number): void;
8
+ static error(content: string, duration?: number): void;
9
+ static destroy(): void;
10
+ }
@@ -0,0 +1,43 @@
1
+ import {message, Modal} from 'antd';
2
+
3
+ export class MessageUtils {
4
+
5
+ static alert(content, config) {
6
+ return new Promise(resolve => {
7
+ Modal.info({
8
+ title: '提示',
9
+ content,
10
+ okText: '确定',
11
+ onOk: () => resolve(),
12
+ icon: null,
13
+ ...config,
14
+ });
15
+ });
16
+ }
17
+
18
+ static confirm(content, config) {
19
+ return new Promise((resolve) => {
20
+ Modal.confirm({
21
+ title: '确认操作',
22
+ content,
23
+ okText: '确定',
24
+ cancelText: '取消',
25
+ onOk: () => resolve(true),
26
+ onCancel: () => resolve(false),
27
+ ...config,
28
+ });
29
+ });
30
+ }
31
+
32
+ static success(content, duration = 3) {
33
+ message.success(content, duration);
34
+ }
35
+
36
+ static error(content, duration = 3) {
37
+ message.error(content, duration);
38
+ }
39
+
40
+ static destroy() {
41
+ message.destroy();
42
+ }
43
+ }
@@ -0,0 +1,14 @@
1
+ import {ObjectUtils} from './ObjectUtils';
2
+
3
+ declare module './ObjectUtils' {
4
+ interface ObjectUtils {
5
+ // Empty - no public methods to declare
6
+ }
7
+ }
8
+
9
+ export class ObjectUtils {
10
+ static copyPropertyIfPresent<TSource extends object, TTarget extends object>(
11
+ source: TSource | null | undefined,
12
+ target: TTarget | null | undefined
13
+ ): void;
14
+ }