@jiangood/open-admin 1.0.0-beta.5

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 (186) hide show
  1. package/config/common-plugin.js +94 -0
  2. package/config/config.js +58 -0
  3. package/config/utils.js +73 -0
  4. package/package.json +42 -0
  5. package/src/.umi-production/appData.json +2365 -0
  6. package/src/.umi-production/core/EmptyRoute.tsx +9 -0
  7. package/src/.umi-production/core/defineApp.ts +16 -0
  8. package/src/.umi-production/core/helmet.ts +10 -0
  9. package/src/.umi-production/core/helmetContext.ts +4 -0
  10. package/src/.umi-production/core/history.ts +72 -0
  11. package/src/.umi-production/core/historyIntelli.ts +132 -0
  12. package/src/.umi-production/core/plugin.ts +40 -0
  13. package/src/.umi-production/core/pluginConfig.ts +324 -0
  14. package/src/.umi-production/core/pluginConfigJoi.d.ts +7 -0
  15. package/src/.umi-production/core/polyfill.ts +220 -0
  16. package/src/.umi-production/core/route.tsx +54 -0
  17. package/src/.umi-production/core/routeProps.js +5 -0
  18. package/src/.umi-production/core/routeProps.ts +6 -0
  19. package/src/.umi-production/core/terminal.ts +37 -0
  20. package/src/.umi-production/exports.ts +17 -0
  21. package/src/.umi-production/testBrowser.tsx +90 -0
  22. package/src/.umi-production/tsconfig.json +44 -0
  23. package/src/.umi-production/typings.d.ts +136 -0
  24. package/src/.umi-production/umi.ts +83 -0
  25. package/src/framework/components/DownloadFileButton/index.d.ts +11 -0
  26. package/src/framework/components/DownloadFileButton/index.jsx +33 -0
  27. package/src/framework/components/Gap/index.d.ts +23 -0
  28. package/src/framework/components/Gap/index.jsx +46 -0
  29. package/src/framework/components/LinkButton/index.d.ts +14 -0
  30. package/src/framework/components/LinkButton/index.jsx +10 -0
  31. package/src/framework/components/NamedIcon/index.d.ts +5 -0
  32. package/src/framework/components/NamedIcon/index.jsx +11 -0
  33. package/src/framework/components/OrgTree/index.d.ts +4 -0
  34. package/src/framework/components/OrgTree/index.jsx +58 -0
  35. package/src/framework/components/Page/index.d.ts +17 -0
  36. package/src/framework/components/Page/index.jsx +30 -0
  37. package/src/framework/components/Page/index.less +10 -0
  38. package/src/framework/components/PageLoading/index.d.ts +1 -0
  39. package/src/framework/components/PageLoading/index.jsx +25 -0
  40. package/src/framework/components/ProModal/index.tsx +66 -0
  41. package/src/framework/components/ProTable/components/ToolBar/index.jsx +123 -0
  42. package/src/framework/components/ProTable/components/ToolBar/index.less +53 -0
  43. package/src/framework/components/ProTable/index.d.ts +42 -0
  44. package/src/framework/components/ProTable/index.jsx +260 -0
  45. package/src/framework/components/ProTable/index.less +14 -0
  46. package/src/framework/components/ProTable/utils/index.js +43 -0
  47. package/src/framework/components/RoleTree/index.d.ts +4 -0
  48. package/src/framework/components/RoleTree/index.jsx +50 -0
  49. package/src/framework/components/ValueType/index.jsx +34 -0
  50. package/src/framework/components/ValueType/registry.jsx +26 -0
  51. package/src/framework/components/ViewRange/index.d.ts +14 -0
  52. package/src/framework/components/ViewRange/index.jsx +20 -0
  53. package/src/framework/components/index.ts +13 -0
  54. package/src/framework/components/system/ButtonList.d.ts +8 -0
  55. package/src/framework/components/system/ButtonList.jsx +42 -0
  56. package/src/framework/components/system/HasPerm.tsx +14 -0
  57. package/src/framework/components/system/index.tsx +29 -0
  58. package/src/framework/fields/FieldBoolean/index.d.ts +9 -0
  59. package/src/framework/fields/FieldBoolean/index.jsx +73 -0
  60. package/src/framework/fields/FieldDate/index.d.ts +23 -0
  61. package/src/framework/fields/FieldDate/index.jsx +116 -0
  62. package/src/framework/fields/FieldDateRange/index.d.ts +22 -0
  63. package/src/framework/fields/FieldDateRange/index.jsx +103 -0
  64. package/src/framework/fields/FieldDictSelect/index.d.ts +12 -0
  65. package/src/framework/fields/FieldDictSelect/index.jsx +16 -0
  66. package/src/framework/fields/FieldEditor/index.d.ts +14 -0
  67. package/src/framework/fields/FieldEditor/index.jsx +59 -0
  68. package/src/framework/fields/FieldNumberRange/index.d.ts +10 -0
  69. package/src/framework/fields/FieldNumberRange/index.jsx +55 -0
  70. package/src/framework/fields/FieldPercent/index.d.ts +8 -0
  71. package/src/framework/fields/FieldPercent/index.jsx +30 -0
  72. package/src/framework/fields/FieldRemoteSelect/index.d.ts +44 -0
  73. package/src/framework/fields/FieldRemoteSelect/index.jsx +125 -0
  74. package/src/framework/fields/FieldRemoteSelectMultiple/index.d.ts +20 -0
  75. package/src/framework/fields/FieldRemoteSelectMultiple/index.jsx +85 -0
  76. package/src/framework/fields/FieldRemoteSelectMultipleInline/index.d.ts +21 -0
  77. package/src/framework/fields/FieldRemoteSelectMultipleInline/index.jsx +88 -0
  78. package/src/framework/fields/FieldRemoteTree/index.d.ts +20 -0
  79. package/src/framework/fields/FieldRemoteTree/index.jsx +50 -0
  80. package/src/framework/fields/FieldRemoteTreeCascader/index.d.ts +18 -0
  81. package/src/framework/fields/FieldRemoteTreeCascader/index.jsx +59 -0
  82. package/src/framework/fields/FieldRemoteTreeSelect/index.d.ts +19 -0
  83. package/src/framework/fields/FieldRemoteTreeSelect/index.jsx +57 -0
  84. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.d.ts +20 -0
  85. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.jsx +62 -0
  86. package/src/framework/fields/FieldSysOrgTree/index.d.ts +9 -0
  87. package/src/framework/fields/FieldSysOrgTree/index.jsx +20 -0
  88. package/src/framework/fields/FieldSysOrgTreeSelect/index.d.ts +9 -0
  89. package/src/framework/fields/FieldSysOrgTreeSelect/index.jsx +22 -0
  90. package/src/framework/fields/FieldTable/index.d.ts +14 -0
  91. package/src/framework/fields/FieldTable/index.jsx +108 -0
  92. package/src/framework/fields/FieldTable/styles.less +29 -0
  93. package/src/framework/fields/FieldTableSelect/index.d.ts +19 -0
  94. package/src/framework/fields/FieldTableSelect/index.jsx +60 -0
  95. package/src/framework/fields/FieldUploadFile/index.d.ts +31 -0
  96. package/src/framework/fields/FieldUploadFile/index.jsx +139 -0
  97. package/src/framework/fields/index.ts +22 -0
  98. package/src/framework/fields/types.ts +16 -0
  99. package/src/framework/index.ts +5 -0
  100. package/src/framework/pages/LoginPage.d.ts +16 -0
  101. package/src/framework/pages/LoginPage.jsx +135 -0
  102. package/src/framework/pages/LoginPage.less +53 -0
  103. package/src/framework/pages/LoginPageUtils.ts +36 -0
  104. package/src/framework/pages/index.ts +2 -0
  105. package/src/framework/utils/ArrUtils.ts +229 -0
  106. package/src/framework/utils/ColorsUtils.ts +378 -0
  107. package/src/framework/utils/DateUtils.ts +187 -0
  108. package/src/framework/utils/DeviceUtils.ts +46 -0
  109. package/src/framework/utils/DomUtils.ts +50 -0
  110. package/src/framework/utils/EventBusUtils.ts +144 -0
  111. package/src/framework/utils/Logger.ts +40 -0
  112. package/src/framework/utils/MessageUtils.tsx +170 -0
  113. package/src/framework/utils/ObjectUtils.ts +118 -0
  114. package/src/framework/utils/StorageUtils.ts +50 -0
  115. package/src/framework/utils/StringUtils.ts +436 -0
  116. package/src/framework/utils/TreeUtils.ts +251 -0
  117. package/src/framework/utils/UrlUtils.ts +152 -0
  118. package/src/framework/utils/UuidUtils.ts +88 -0
  119. package/src/framework/utils/ValidateUtils.ts +28 -0
  120. package/src/framework/utils/index.ts +15 -0
  121. package/src/framework/utils/system/DictUtils.ts +97 -0
  122. package/src/framework/utils/system/FormRegistryUtils.ts +77 -0
  123. package/src/framework/utils/system/HttpUtils.ts +247 -0
  124. package/src/framework/utils/system/PageUtils.ts +163 -0
  125. package/src/framework/utils/system/PermUtils.ts +79 -0
  126. package/src/framework/utils/system/SysUtils.ts +97 -0
  127. package/src/framework/utils/system/ThemeUtils.ts +27 -0
  128. package/src/framework/utils/system/index.ts +7 -0
  129. package/src/framework/views/ViewApproveStatus/index.d.ts +3 -0
  130. package/src/framework/views/ViewApproveStatus/index.jsx +21 -0
  131. package/src/framework/views/ViewBoolean/index.d.ts +3 -0
  132. package/src/framework/views/ViewBoolean/index.jsx +4 -0
  133. package/src/framework/views/ViewBooleanEnableDisable/index.d.ts +5 -0
  134. package/src/framework/views/ViewBooleanEnableDisable/index.jsx +15 -0
  135. package/src/framework/views/ViewFile/index.d.ts +10 -0
  136. package/src/framework/views/ViewFile/index.jsx +49 -0
  137. package/src/framework/views/ViewFileButton/index.d.ts +10 -0
  138. package/src/framework/views/ViewFileButton/index.jsx +22 -0
  139. package/src/framework/views/ViewImage/index.d.ts +6 -0
  140. package/src/framework/views/ViewImage/index.jsx +60 -0
  141. package/src/framework/views/ViewPassword/index.d.ts +5 -0
  142. package/src/framework/views/ViewPassword/index.jsx +24 -0
  143. package/src/framework/views/ViewProcessInstanceProgress/index.d.ts +12 -0
  144. package/src/framework/views/ViewProcessInstanceProgress/index.jsx +97 -0
  145. package/src/framework/views/ViewProcessInstanceProgressButton/index.d.ts +6 -0
  146. package/src/framework/views/ViewProcessInstanceProgressButton/index.jsx +24 -0
  147. package/src/framework/views/ViewText/index.d.ts +16 -0
  148. package/src/framework/views/ViewText/index.jsx +42 -0
  149. package/src/framework/views/index.ts +12 -0
  150. package/src/framework/views/types.ts +26 -0
  151. package/src/index.ts +2 -0
  152. package/src/layouts/PageRender.d.ts +22 -0
  153. package/src/layouts/PageRender.jsx +90 -0
  154. package/src/layouts/admin/HeaderRight.jsx +104 -0
  155. package/src/layouts/admin/TabPageRender.jsx +158 -0
  156. package/src/layouts/admin/index.jsx +159 -0
  157. package/src/layouts/admin/index.less +65 -0
  158. package/src/layouts/index.jsx +187 -0
  159. package/src/layouts/index.less +24 -0
  160. package/src/loading.jsx +18 -0
  161. package/src/pages/404.jsx +13 -0
  162. package/src/pages/about.jsx +12 -0
  163. package/src/pages/index.jsx +10 -0
  164. package/src/pages/login.jsx +16 -0
  165. package/src/pages/system/api/ApiDoc.jsx +148 -0
  166. package/src/pages/system/api/index.jsx +267 -0
  167. package/src/pages/system/api/perm.jsx +69 -0
  168. package/src/pages/system/dict/Dict.jsx +67 -0
  169. package/src/pages/system/dict/DictItem.jsx +175 -0
  170. package/src/pages/system/dict/index.jsx +25 -0
  171. package/src/pages/system/file/index.jsx +147 -0
  172. package/src/pages/system/job/index.jsx +324 -0
  173. package/src/pages/system/log/index.jsx +77 -0
  174. package/src/pages/system/org/index.jsx +260 -0
  175. package/src/pages/system/role/index.jsx +302 -0
  176. package/src/pages/system/role/perm.jsx +107 -0
  177. package/src/pages/system/sysManual/index.jsx +126 -0
  178. package/src/pages/system/user/UserPerm.jsx +94 -0
  179. package/src/pages/system/user/index.jsx +253 -0
  180. package/src/pages/test/views.jsx +95 -0
  181. package/src/pages/ureport/index.jsx +16 -0
  182. package/src/pages/userCenter/ChangePassword.jsx +64 -0
  183. package/src/pages/userCenter/index.jsx +90 -0
  184. package/src/pages/userCenter/manual.jsx +57 -0
  185. package/src/pages/userCenter/message.jsx +103 -0
  186. package/src/style/global.less +51 -0
@@ -0,0 +1,187 @@
1
+ import {StringUtils} from './StringUtils';
2
+
3
+ export class DateUtils {
4
+
5
+ public static convertTypeToFormat(type) {
6
+ if (type === 'YEAR') {
7
+ type = 'YYYY'
8
+ } else if (type === 'YEAR_MONTH') {
9
+ type = 'YYYY-MM'
10
+ } else if (type === 'YEAR_QUARTER') {
11
+ type = 'YYYY-QQ'
12
+ } else if (type === 'DAY') {
13
+ type = 'YYYY-MM-DD'
14
+ }
15
+ return type;
16
+ }
17
+
18
+ public static year(date: Date): number {
19
+ return date.getFullYear();
20
+ }
21
+
22
+ /**
23
+ * 获取月份,自动补0
24
+ * @param date
25
+ * @returns {string}
26
+ */
27
+ public static month(date: Date): string {
28
+ const n = date.getMonth() + 1; // (注意月份从0开始,所以要加1)
29
+ return StringUtils.pad(n, 2);
30
+ }
31
+
32
+ /**
33
+ * 获取日期,
34
+ * @param date
35
+ */
36
+ public static date(date: Date): string {
37
+ return StringUtils.pad(date.getDate(), 2);
38
+ }
39
+
40
+ /**
41
+ * 小时,24进制
42
+ * @param date
43
+ * @returns {string}
44
+ */
45
+ public static hour(date: Date): string {
46
+ return StringUtils.pad(date.getHours(), 2);
47
+ }
48
+
49
+ public static minute(date: Date): string {
50
+ return StringUtils.pad(date.getMinutes(), 2);
51
+ }
52
+
53
+ public static second(date: Date): string {
54
+ return StringUtils.pad(date.getSeconds(), 2);
55
+ }
56
+
57
+ public static formatDate(d: Date): string {
58
+ return this.year(d) + '-' + this.month(d) + '-' + this.date(d);
59
+ }
60
+
61
+ public static formatTime(d: Date): string {
62
+ return this.hour(d) + ':' + this.minute(d) + ':' + this.second(d);
63
+ }
64
+
65
+ public static formatDateTime(d: Date): string {
66
+ return this.formatDate(d) + ' ' + this.formatTime(d);
67
+ }
68
+
69
+ /**
70
+ *
71
+ * @param d
72
+ * @returns {string} 2020年1月30日
73
+ */
74
+ public static formatDateCn(d: Date): string {
75
+ return this.year(d) + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日';
76
+ }
77
+
78
+ /***
79
+ 当前时间, 如 2022-01-23 11:59:59
80
+ */
81
+ public static now(): string {
82
+ return this.formatDateTime(new Date());
83
+ }
84
+
85
+ /**
86
+ * 当前日期 ,如 2022-01-23
87
+ *
88
+ */
89
+ public static today(): string {
90
+ return this.formatDate(new Date());
91
+ }
92
+
93
+ public static thisYear(): number {
94
+ return this.year(new Date());
95
+ }
96
+
97
+ public static thisMonth(): string {
98
+ return this.month(new Date());
99
+ }
100
+
101
+ /**
102
+ * 显示友好时间,如 2小时前,1周前
103
+ * @param pastDate 日期, 支持Date,String,Number
104
+ */
105
+ public static friendlyTime(pastDate: Date | string | number): string | undefined {
106
+ if (pastDate == null) {
107
+ return undefined;
108
+ }
109
+ if (!(pastDate instanceof Date)) {
110
+ pastDate = new Date(pastDate);
111
+ }
112
+
113
+ const currentDate = new Date();
114
+ let elapsedMilliseconds = currentDate.getTime() - pastDate.getTime();
115
+ const suffix = elapsedMilliseconds > 0 ? '前' : '后';
116
+ elapsedMilliseconds = Math.abs(elapsedMilliseconds);
117
+
118
+ // 计算年、月、日、小时、分钟和秒的差值
119
+ const elapsedYears = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24 * 365));
120
+ const elapsedMonths = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24 * 30));
121
+ const elapsedDays = Math.floor(elapsedMilliseconds / (1000 * 60 * 60 * 24));
122
+ const elapsedHours = Math.floor(elapsedMilliseconds / (1000 * 60 * 60));
123
+ const elapsedMinutes = Math.floor(elapsedMilliseconds / (1000 * 60));
124
+ const elapsedSeconds = Math.floor(elapsedMilliseconds / 1000);
125
+
126
+ // 根据差值选择友好的格式
127
+ if (elapsedYears >= 1) {
128
+ return `${elapsedYears} 年${suffix}`;
129
+ }
130
+ if (elapsedMonths >= 1) {
131
+ return `${elapsedMonths} 个月${suffix}`;
132
+ }
133
+ if (elapsedDays >= 7) {
134
+ const weeks = Math.floor(elapsedDays / 7);
135
+ return `${weeks} 周${suffix}`;
136
+ }
137
+ if (elapsedDays >= 1) {
138
+ const days = elapsedDays;
139
+ return `${days} 天${suffix}`;
140
+ }
141
+ if (elapsedHours >= 1) {
142
+ return `${elapsedHours} 小时${suffix}`;
143
+ }
144
+ if (elapsedMinutes >= 1) {
145
+ return `${elapsedMinutes} 分钟${suffix}`;
146
+ }
147
+ return `${elapsedSeconds} 秒${suffix}`;
148
+ }
149
+
150
+ /**
151
+ * 总共耗时, 如 3分5秒
152
+ * @param time 数字 (Date.getTime)
153
+ * @returns {string|null}
154
+ */
155
+ public static friendlyTotalTime(time: number | string | null): string | null {
156
+ if (time == null || time === '-') {
157
+ return null;
158
+ }
159
+
160
+ let seconds: number;
161
+ if (typeof time === 'string') {
162
+ seconds = parseInt(time, 10) / 1000;
163
+ } else {
164
+ seconds = time / 1000;
165
+ }
166
+
167
+ seconds = Math.floor(seconds);
168
+
169
+ if (seconds < 60) {
170
+ return seconds + '秒';
171
+ }
172
+
173
+ let min = seconds / 60;
174
+ seconds = seconds % 60;
175
+
176
+ min = Math.floor(min);
177
+ seconds = Math.floor(seconds);
178
+
179
+ return min + '分' + seconds + '秒';
180
+ }
181
+
182
+ public static beginOfMonth(): string {
183
+ const d = new Date();
184
+ d.setDate(1);
185
+ return this.formatDate(d);
186
+ }
187
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * 包含了常用的浏览器和网络工具函数。
3
+ */
4
+ export class DeviceUtils {
5
+
6
+ /**
7
+ * 判断当前设备是否为移动设备 (包括 Windows Phone, Android, iOS)。
8
+ * @returns {boolean} 如果是移动设备返回 true,否则返回 false。
9
+ */
10
+ public static isMobileDevice(): boolean {
11
+ // 使用可选链操作符来安全地访问 navigator 和 window 上的属性,
12
+ // 以防在非浏览器环境中运行 (尽管这个函数主要用于浏览器环境)。
13
+ const userAgent = navigator?.userAgent || navigator?.vendor || (window as any)?.opera || '';
14
+
15
+ // 1. Windows Phone 必须放在 Android 之前,因为它的 UA 也可能包含 "Android"
16
+ if (/windows phone/i.test(userAgent)) {
17
+ return true;
18
+ }
19
+
20
+ // 2. Android devices
21
+ if (/android/i.test(userAgent)) {
22
+ return true;
23
+ }
24
+
25
+ // 3. iOS devices
26
+ // window.MSStream 检查是为了排除旧版 IE 上的触控设备,确保只检测移动设备。
27
+ // 对于 TypeScript,需要断言 window.MSStream 可能不存在。
28
+ if (/iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream) {
29
+ return true;
30
+ }
31
+
32
+ return false;
33
+ }
34
+
35
+ /**
36
+ * 根据当前页面的协议 (http/https) 和主机名构造 WebSocket 的基础 URL (ws/wss)。
37
+ * @returns {string} WebSocket 的基础 URL,例如 "ws://localhost:8080" 或 "wss://example.com"。
38
+ */
39
+ public static getWebsocketBaseUrl(): string {
40
+ // 使用 location.protocol 来确定是 ws 还是 wss。
41
+ const protocol: string = location.protocol === 'http:' ? 'ws:' : 'wss:';
42
+
43
+ // location.host 包含主机名和端口号 (如果有)。
44
+ return `${protocol}//${location.host}`;
45
+ }
46
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @fileoverview DOM 操作工具类
3
+ */
4
+
5
+ /**
6
+ * 封装了获取元素位置和尺寸的工具方法。
7
+ */
8
+ export class DomUtils {
9
+ /**
10
+ * 获取元素相对于视口的偏移量(top 和 left)。
11
+ *
12
+ * @param el 目标 DOM 元素或 window 对象。
13
+ * @returns 包含 top 和 left 属性的对象。
14
+ */
15
+ static offset(el: Element | Window): { top: number; left: number } {
16
+ if (el === window) {
17
+ return { top: 0, left: 0 };
18
+ }
19
+
20
+ // 类型断言,确保 el 是 Element 类型,以便调用 getBoundingClientRect
21
+ const element = el as Element;
22
+ const { top, left } = element.getBoundingClientRect();
23
+
24
+ return { top, left };
25
+ }
26
+
27
+ /**
28
+ * 获取元素的外部高度(如果是 window,则返回视口高度)。
29
+ *
30
+ * @param el 目标 DOM 元素或 window 对象。
31
+ * @returns 元素的高度(以像素为单位)。
32
+ */
33
+ static height(el: Element | Window): number {
34
+ return el === window
35
+ ? window.innerHeight // 视口高度
36
+ : (el as Element).getBoundingClientRect().height; // 元素高度
37
+ }
38
+
39
+ /**
40
+ * 获取元素的外部宽度(如果是 window,则返回视口宽度)。
41
+ *
42
+ * @param el 目标 DOM 元素或 window 对象。
43
+ * @returns 元素的宽度(以像素为单位)。
44
+ */
45
+ static width(el: Element | Window): number {
46
+ return el === window
47
+ ? window.innerWidth // 视口宽度
48
+ : (el as Element).getBoundingClientRect().width; // 元素宽度
49
+ }
50
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * 事件总线工具类 (Static Utility Class 模式) - 所有方法和状态均为静态
3
+ * forked form https://github.com/scottcorgan/tiny-emitter
4
+ */
5
+
6
+ // --- 内部类型定义 ---
7
+
8
+ /** 定义事件回调的结构 */
9
+ interface StaticEventEntry<T extends any[]> {
10
+ fn: (...args: T) => void;
11
+ ctx?: any;
12
+ }
13
+
14
+ /** 定义用于 once 的特殊回调,用于在 off 时查找原始回调 */
15
+ type StaticOnceCallback<T extends any[]> = ((...args: T) => void) & {
16
+ __callback?: ((...args: T) => void);
17
+ };
18
+
19
+ /** 定义事件映射的类型 */
20
+ interface StaticEventStack {
21
+ [key: string]: StaticEventEntry<any[]>[];
22
+ }
23
+
24
+ /**
25
+ * 静态事件总线工具类
26
+ * 所有方法和状态均通过静态属性直接访问。
27
+ */
28
+ export class EventBusUtils {
29
+ // 静态内部状态
30
+ private static __stack: StaticEventStack = {};
31
+
32
+ /**
33
+ * 静态工具类,无需实例化,因此构造函数私有化防止意外创建实例。
34
+ */
35
+ private constructor() {
36
+ // 静态工具类,无须实现
37
+ }
38
+
39
+ /**
40
+ * 注册事件监听器
41
+ * @param name 事件名称
42
+ * @param callback 事件回调函数
43
+ * @param ctx 回调函数的 this 上下文
44
+ */
45
+ public static on<T extends any[] = []>(
46
+ name: string,
47
+ callback: (...args: T) => void,
48
+ ctx?: any
49
+ ): void { // 静态方法通常不返回 this
50
+ if (!EventBusUtils.__stack[name]) {
51
+ EventBusUtils.__stack[name] = [];
52
+ }
53
+
54
+ (EventBusUtils.__stack[name] as StaticEventEntry<T>[]).push({
55
+ fn: callback as (...args: any[]) => void,
56
+ ctx
57
+ });
58
+ }
59
+
60
+ /**
61
+ * 注册只触发一次的事件监听器
62
+ * @param name 事件名称
63
+ * @param callback 事件回调函数
64
+ * @param ctx 回调函数的 this 上下文
65
+ */
66
+ public static once<T extends any[] = []>(
67
+ name: string,
68
+ callback: (...args: T) => void,
69
+ ctx?: any
70
+ ): void {
71
+ const listener: StaticOnceCallback<T> = (...args) => {
72
+ // 触发后立即移除
73
+ EventBusUtils.off(name, listener as unknown as ((...args: T) => void));
74
+ callback.apply(ctx, args);
75
+ };
76
+
77
+ // 存储原始回调,方便 off 时查找
78
+ listener.__callback = callback;
79
+
80
+ return EventBusUtils.on(name, listener, ctx);
81
+ }
82
+
83
+ /**
84
+ * 触发事件
85
+ * @param name 事件名称
86
+ * @param args 传递给回调函数的参数
87
+ */
88
+ public static emit<T extends any[] = []>(
89
+ name: string,
90
+ ...args: T
91
+ ): void {
92
+ console.log('触发事件:',name, args)
93
+ const list = EventBusUtils.__stack[name] as StaticEventEntry<T>[];
94
+
95
+ if (list !== undefined) {
96
+ // 使用 slice(0) 确保在回调中 off 不会影响当前循环
97
+ list.slice(0).forEach(entry => {
98
+ entry.fn.apply(entry.ctx, args);
99
+ });
100
+ }
101
+ }
102
+
103
+ /**
104
+ * 移除事件监听器
105
+ * @param name 事件名称
106
+ * @param callback 可选:要移除的特定回调函数。如果省略,则移除该事件名的所有监听器。
107
+ */
108
+ public static off<T extends any[] = []>(
109
+ name: string,
110
+ callback?: ((...args: T) => void)
111
+ ): void {
112
+ const list = EventBusUtils.__stack[name];
113
+
114
+ if (list === undefined) {
115
+ return;
116
+ }
117
+
118
+ // 移除所有监听器
119
+ if (callback === undefined) {
120
+ delete EventBusUtils.__stack[name];
121
+ return;
122
+ }
123
+
124
+ // 移除特定监听器
125
+ const liveEvents = list.filter(
126
+ entry =>
127
+ // 排除当前回调
128
+ entry.fn !== callback &&
129
+ // 排除 once 包装的回调,通过 __callback 匹配原始回调
130
+ (entry.fn as StaticOnceCallback<T>).__callback !== callback
131
+ );
132
+
133
+ if (liveEvents.length !== 0) {
134
+ EventBusUtils.__stack[name] = liveEvents;
135
+ } else {
136
+ delete EventBusUtils.__stack[name];
137
+ }
138
+ }
139
+ }
140
+
141
+ /* 推荐的使用方式:直接通过类名调用静态方法 */
142
+ // import { EventBusUtils } from './EventBusUtils';
143
+ // EventBusUtils.on('myStaticEvent', (data) => console.log(data));
144
+ // EventBusUtils.emit('myStaticEvent', { status: 'ok' });
@@ -0,0 +1,40 @@
1
+ // logger.js
2
+ export class Logger {
3
+
4
+ private readonly module: string;
5
+
6
+
7
+ constructor(module) {
8
+ this.module = module;
9
+ }
10
+
11
+ public static getLogger(module) {
12
+ return new Logger(module);
13
+ }
14
+
15
+ debug(...args) {
16
+ this._log( console.log, args);
17
+ }
18
+
19
+ info(...args) {
20
+ this._log( console.info, args);
21
+ }
22
+
23
+ warn(...args) {
24
+ this._log(console.warn, args);
25
+ }
26
+
27
+ error(...args) {
28
+ this._log(console.error, args);
29
+ }
30
+
31
+ private _log( consoleMethod, args) {
32
+ const time = new Date().toLocaleTimeString();
33
+ consoleMethod(`[${time}] [${this.module}] `, ...args);
34
+ }
35
+
36
+
37
+ }
38
+
39
+
40
+
@@ -0,0 +1,170 @@
1
+ import {Form, Input, InputNumber, message, Modal} from 'antd';
2
+ import type {ModalFuncProps} from 'antd/es/modal/interface';
3
+ import React from 'react';
4
+ import {MessageInstance} from "antd/lib/message/interface";
5
+ import {HookAPI} from "antd/lib/modal/useModal";
6
+ import {Logger} from "./Logger";
7
+
8
+
9
+
10
+ /**
11
+ * 消息工具类 (MsgUtils)
12
+ * 封装了 Ant Design 的 Modal, message, 和 notification 静态方法
13
+ */
14
+ export class MessageUtils {
15
+
16
+ /**
17
+ * 弹出 Alert 提示框
18
+ */
19
+ static alert(content: any, config?: Omit<ModalFuncProps, 'content' | 'icon' | 'onOk' | 'onCancel'>) {
20
+ return new Promise(resolve => {
21
+ this.modalApi.info({
22
+ title: '提示',
23
+ content,
24
+ okText: '确定',
25
+ onOk: (close)=>{
26
+ close()
27
+ resolve()
28
+ },
29
+ icon: null,
30
+ ...config,
31
+ });
32
+ })
33
+
34
+ }
35
+
36
+ /**
37
+ * 弹出 Confirm 确认框
38
+ */
39
+ static confirm(content: React.ReactNode, config?: Omit<ModalFuncProps, 'content' | 'icon' | 'onOk' | 'onCancel'>) {
40
+ return new Promise((resolve) => {
41
+ this.modalApi.confirm({
42
+ title: '确认操作',
43
+ content,
44
+ okText: '确定',
45
+ cancelText: '取消',
46
+ onOk: () => resolve(true),
47
+ onCancel: () => resolve(false),
48
+ ...config,
49
+ });
50
+ })
51
+
52
+ }
53
+
54
+ /**
55
+ * 弹出 Prompt 输入框对话框, 如果默认值是数字, 则使用 InputNumber 输入框
56
+ */
57
+ static prompt(message: React.ReactNode, initialValue?: string|number, placeholder?: string, config?: Omit<ModalFuncProps, 'content' | 'title' | 'icon' | 'onOk'>) {
58
+ const isNumber = typeof initialValue === 'number';
59
+ return new Promise((resolve) => {
60
+ const ref = React.createRef()
61
+ let element:any = isNumber ? <InputNumber placeholder={placeholder}/> : <Input placeholder={placeholder}/>;
62
+ const content:any = <div>
63
+ <div style={{marginBottom: 4}}>{message}</div>
64
+ <Form ref={ref}>
65
+ <Form.Item name='inputValue' initialValue={initialValue}>
66
+ {element}
67
+ </Form.Item>
68
+ </Form>
69
+ </div>;
70
+ this.modalApi.confirm({
71
+ icon: null,
72
+ title: '提示',
73
+ content:content,
74
+ okText: '确定',
75
+ cancelText: '取消',
76
+ onOk: () => {
77
+ const form = ref.current;
78
+ const values = form.getFieldsValue()
79
+ resolve(values.inputValue)
80
+ },
81
+ onCancel: () => {
82
+ resolve()
83
+ },
84
+ ...config,
85
+ });
86
+ })
87
+ }
88
+
89
+ // --- Antd message 封装 (全局通知/Loading) ---
90
+
91
+ /**
92
+ * 成功消息
93
+ */
94
+ static success(content: String, duration: number = 3) {
95
+ if(!this.messageApi){
96
+ alert(content)
97
+ return
98
+ }
99
+ this.messageApi.success(content, duration);
100
+ }
101
+
102
+ /**
103
+ * 错误消息
104
+ */
105
+ static error(content: String, duration: number = 3) {
106
+ console.log('调用 MessageUtils.error',content)
107
+ if(!this.messageApi){
108
+ alert(content)
109
+ return
110
+ }
111
+ this.messageApi.error(content, duration);
112
+ }
113
+
114
+ /**
115
+ * 警告消息
116
+ */
117
+ static warning(content: String, duration: number = 3) {
118
+ if(!this.messageApi){
119
+ alert(content)
120
+ return
121
+ }
122
+ this.messageApi.warning(content, duration);
123
+ }
124
+
125
+ /**
126
+ * 通用消息
127
+ */
128
+ static info(content: React.ReactNode, duration: number = 3) {
129
+ if(!this.messageApi){
130
+ alert(content)
131
+ return
132
+ }
133
+ this.messageApi.info(content, duration);
134
+ }
135
+
136
+ /**
137
+ * 弹出 Loading 提示
138
+ */
139
+ static loading(content: string = '正在加载...', duration?: number) {
140
+ duration = duration === undefined ? 0 : duration;
141
+ return this.messageApi.loading(content, duration);
142
+ }
143
+
144
+ static config(messageApi: MessageInstance, modalApi: HookAPI) {
145
+ this.messageApi = messageApi;
146
+ this.modalApi = modalApi;
147
+ console.log('MessageUtils.config', messageApi, modalApi)
148
+ }
149
+
150
+ private static modalApi:HookAPI = null;
151
+ private static messageApi:MessageInstance = null;
152
+ }
153
+
154
+ /**
155
+ * antd6 推荐使用这个hooks,这里统一设置, 供公共layout使用
156
+ * @constructor
157
+ */
158
+ export function MessageHolder(props){
159
+ const [modalApi, modalContextHolder] = Modal.useModal();
160
+ const [messageApi, messageContextHolder] = message.useMessage();
161
+
162
+ React.useEffect(()=>{
163
+ Logger.getLogger("MessageHolder").debug('Rendered')
164
+ MessageUtils.config(messageApi,modalApi);
165
+ props.onFinish()
166
+ },[])
167
+ return <>
168
+ {modalContextHolder} {messageContextHolder}
169
+ </>
170
+ }