@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,77 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * 💡 类型定义同上
5
+ */
6
+ type FormComponent = React.ComponentType<any>;
7
+
8
+ /**
9
+ * 🛠️ FormRegistryUtils
10
+ * 一个静态工具类,用于注册、获取和管理表单组件。
11
+ * 调用时无需实例化,直接使用 FormRegistryUtils.methodName()。
12
+ */
13
+ export class FormRegistryUtils {
14
+ // 静态私有属性:存储表单组件的 Map
15
+ private static forms: Map<string, FormComponent> = new Map<string, FormComponent>();
16
+
17
+ /**
18
+ * 注意:
19
+ * 1. 私有构造函数可以防止该类被外部实例化(可选,但推荐用于纯静态类)。
20
+ * 2. 如果不定义构造函数,TypeScript 默认允许实例化,但因为所有成员都是静态的,实例化没有意义。
21
+ */
22
+ private constructor() {
23
+ // 阻止外部实例化
24
+ }
25
+
26
+ /**
27
+ * 静态方法:注册表单组件
28
+ * @param formKey - 表单唯一标识
29
+ * @param formComponent - React 表单组件
30
+ */
31
+ public static register(formKey: string, formComponent: FormComponent): void {
32
+ if (!formKey || !formComponent) {
33
+ throw new Error("【FormRegistryUtils】表单 Key 和组件不能为空!");
34
+ }
35
+
36
+ // 访问静态属性需要使用 'FormRegistryUtils.'
37
+ if (FormRegistryUtils.forms.has(formKey)) {
38
+ console.warn(`⚠️ 【FormRegistryUtils】表单 "${formKey}" 已存在,将被覆盖!`);
39
+ }
40
+
41
+ FormRegistryUtils.forms.set(formKey, formComponent);
42
+ console.log(`✅ 【FormRegistryUtils】表单 "${formKey}" 注册成功`);
43
+ }
44
+
45
+ /**
46
+ * 静态方法:获取表单组件
47
+ * @param formKey - 表单唯一标识
48
+ * @returns React 表单组件,如果不存在则返回 null
49
+ */
50
+ public static get(formKey: string): FormComponent | null {
51
+ const formComponent = FormRegistryUtils.forms.get(formKey);
52
+
53
+ if (!formComponent) {
54
+ console.warn(`⚠️ 【FormRegistryUtils】表单 "${formKey}" 未注册!`);
55
+ }
56
+
57
+ return formComponent ?? null;
58
+ }
59
+
60
+ /**
61
+ * 静态方法:检查表单是否已注册
62
+ * @param formKey - 表单唯一标识
63
+ * @returns boolean
64
+ */
65
+ public static has(formKey: string): boolean {
66
+ return FormRegistryUtils.forms.has(formKey);
67
+ }
68
+
69
+ /**
70
+ * 静态方法:获取所有已注册的表单 Key
71
+ * @returns string[] - 所有表单 Key 的数组
72
+ */
73
+ public static getAllKeys(): string[] {
74
+ return Array.from(FormRegistryUtils.forms.keys());
75
+ }
76
+ }
77
+
@@ -0,0 +1,247 @@
1
+ import axios, {AxiosRequestConfig, AxiosResponse, Method} from "axios";
2
+ import { Modal} from "antd";
3
+ import qs from 'qs';
4
+ import {PageUtils} from "./PageUtils";
5
+ import {MessageUtils} from "../MessageUtils";
6
+
7
+
8
+ const axiosInstance = axios.create({
9
+ withCredentials: true,
10
+ headers: {
11
+ 'Content-Type': 'application/json'
12
+ },
13
+ // 解决get请求时,数组参数的问题
14
+ paramsSerializer: (params) => {
15
+ return qs.stringify(params, {indices: false});
16
+ }
17
+ })
18
+
19
+
20
+ /**
21
+ * @description HTTP请求工具类
22
+ */
23
+ export class HttpUtils {
24
+
25
+
26
+ /**
27
+ * 核心请求函数,处理请求发送、加载状态、响应解析和错误捕获
28
+ * @param config AxiosRequestConfig & RequestOptions
29
+ * @param transformData 是否返回最总的data字段
30
+ * @returns Promise<any>
31
+ */
32
+ // ... existing code ...
33
+ private static coreRequest(config: AxiosRequestConfig, transformData: boolean = true): Promise<any> {
34
+ const url = config.url;
35
+ config.url = url.startsWith('admin') ? '/' + url : url;
36
+
37
+ return new Promise((resolve, reject) => {
38
+ axios(config).then((response: AxiosResponse) => {
39
+ const body = response.data;
40
+ // 假设后端响应结构为 { success: boolean | null, message: string, data: any, code: number }
41
+ let {success, message, data} = body;
42
+ if (success == undefined) { // 如果没有success字段,说明非标准接口
43
+ resolve(response);
44
+ return ;
45
+ }
46
+
47
+ if (!success) {
48
+ MessageUtils.error(message || '操作失败');
49
+ reject('操作失败');
50
+ return
51
+ }
52
+
53
+ // 自动消息提示
54
+ if (message) {
55
+ MessageUtils.success(message);
56
+ }
57
+ resolve(transformData ? data : response);
58
+ }).catch((e: unknown) => {
59
+ // 统一异常处理
60
+ let msg = '操作失败';
61
+
62
+ if (axios.isAxiosError(e)) {
63
+ const status = e.response?.status;
64
+ const responseData = e.response?.data;
65
+
66
+ if (status === 401) {
67
+ // 登录过期处理
68
+ MessageUtils.confirm('登录已过期,请重新登录').then(() => {
69
+ PageUtils.redirectToLogin();
70
+ });
71
+ // 阻止后续的错误提示,返回一个特殊 Promise.reject
72
+ reject('登录过期');
73
+ return
74
+ }
75
+ if (status === 504) {
76
+ msg = '504 请求后端服务失败';
77
+ } else if (responseData && responseData.message) {
78
+ msg = responseData.message;
79
+ } else if (e.message) {
80
+ msg = e.message;
81
+ }
82
+ } else if (e instanceof Error) {
83
+ // 可能是后端success=false抛出的自定义错误
84
+ msg = e.message;
85
+ }
86
+
87
+ MessageUtils.error(msg);
88
+
89
+ // 将原始错误或处理后的错误信息向外抛出
90
+ reject(e);
91
+ });
92
+ })
93
+
94
+ }
95
+
96
+
97
+ /**
98
+ * 处理文件下载后的blob流
99
+ * @param res AxiosResponse 文件下载响应
100
+ */
101
+ private static handleDownloadBlob(res: AxiosResponse): Promise<void> {
102
+ return new Promise((resolve, reject) => {
103
+ const {data: blob, headers} = res;
104
+
105
+ // 1. 检查是否为错误JSON
106
+ if (blob.type === 'application/json') {
107
+ const reader = new FileReader();
108
+ reader.readAsText(blob, 'utf-8');
109
+ reader.onload = function () {
110
+ try {
111
+ let rs = JSON.parse(reader.result as string);
112
+ Modal.error({
113
+ title: '下载文件失败',
114
+ content: rs.message || '不支持下载'
115
+ });
116
+ reject(new Error(rs.message || '下载错误'));
117
+ } catch (e) {
118
+ Modal.error({title: '下载文件失败', content: '解析错误响应失败'});
119
+ reject(e);
120
+ }
121
+ };
122
+ return;
123
+ }
124
+
125
+ // 2. 获取文件名称
126
+ const contentDisposition = headers['content-disposition'] || headers['Content-Disposition'];
127
+ if (!contentDisposition) {
128
+ Modal.error({title: '获取文件名称失败', content: "缺少Content-Disposition响应头"});
129
+ reject(new Error("缺少Content-Disposition响应头"));
130
+ return;
131
+ }
132
+
133
+ const match = /filename\*?=(?:['"]?)(?:UTF-8''|)(.+?)(?:['"]?$|;)/i.exec(contentDisposition);
134
+ let filename = match && match[1] ? match[1].trim() : 'download.file';
135
+
136
+ try {
137
+ // 尝试进行URI解码
138
+ filename = decodeURIComponent(filename.replace(/"/g, ''));
139
+ } catch (e) {
140
+ // 如果解码失败,保持原样
141
+ filename = filename.replace(/"/g, '');
142
+ }
143
+
144
+ // 3. 开始下载
145
+ const url = window.URL.createObjectURL(new Blob([blob]));
146
+ const link = document.createElement('a');
147
+ link.style.display = 'none';
148
+
149
+ link.href = url;
150
+ link.download = filename;
151
+
152
+ document.body.appendChild(link);
153
+ link.click();
154
+
155
+ document.body.removeChild(link);
156
+ window.URL.revokeObjectURL(url);
157
+ resolve();
158
+ });
159
+ }
160
+
161
+
162
+ /**
163
+ * 发送GET请求
164
+ * @param url 请求地址
165
+ * @param params URL参数
166
+ * @param options 自定义配置 (transformData等)
167
+ * @returns Promise<any> 后端返回的 data 字段
168
+ */
169
+ public static get(url: string, params: any = null, options: Partial<AxiosRequestConfig> = {}): Promise<any> {
170
+ return HttpUtils.coreRequest({
171
+ ...options,
172
+ url,
173
+ method: 'GET',
174
+ params,
175
+ });
176
+ }
177
+
178
+ /**
179
+ * 发送POST请求 (Content-Type: application/json)
180
+ * @param url 请求地址
181
+ * @param data 请求体数据
182
+ * @param params URL参数
183
+ * @param options 自定义配置
184
+ * @returns Promise<any> 后端返回的 data 字段
185
+ */
186
+ public static post(url: string, data: any = null, params: any = null, options: Partial<RequestOptions> = {}): Promise<any> {
187
+ return HttpUtils.coreRequest({
188
+ ...options,
189
+ url,
190
+ method: 'POST',
191
+ data,
192
+ params,
193
+ });
194
+ }
195
+
196
+ /**
197
+ * 发送POST表单请求 (Content-Type: application/x-www-form-urlencoded)
198
+ * @param url 请求地址
199
+ * @param data 表单数据
200
+ * @param options 自定义配置
201
+ * @returns Promise<any> 后端返回的 data 字段
202
+ */
203
+ public static postForm(url: string, data: any, options: Partial<AxiosRequestConfig> = {}): Promise<any> {
204
+ return HttpUtils.coreRequest({
205
+ ...options,
206
+ url,
207
+ method: 'POST',
208
+ data: qs.stringify(data), // 转换为表单格式
209
+ headers: {
210
+ 'Content-Type': 'application/x-www-form-urlencoded'
211
+ },
212
+ });
213
+ }
214
+
215
+ /**
216
+ * 下载文件
217
+ * @param url 请求地址
218
+ * @param data 请求体数据 (POST时使用)
219
+ * @param params URL参数
220
+ * @param method 请求方法,默认为GET
221
+ * @param options 自定义配置
222
+ * @returns Promise<void>
223
+ */
224
+ public static async downloadFile(url: string, data: any = null, params: any = null, method: Method = 'GET', options: Partial<AxiosRequestConfig> = {}): Promise<void> {
225
+
226
+ // 下载请求默认设置:不转换数据,响应类型为 blob
227
+ const downloadConfig: AxiosRequestConfig = {
228
+ responseType: 'blob', // 关键设置
229
+ ...options,
230
+ url,
231
+ method,
232
+ params,
233
+ data,
234
+ };
235
+
236
+ try {
237
+ // coreRequest返回的是完整的 AxiosResponse,因此需要类型断言
238
+ const response = await HttpUtils.coreRequest(downloadConfig, false) as AxiosResponse;
239
+ await HttpUtils.handleDownloadBlob(response);
240
+ } catch (error) {
241
+ // coreRequest已经处理了401、504和通用的错误提示
242
+ return Promise.reject(error);
243
+ }
244
+ }
245
+
246
+
247
+ }
@@ -0,0 +1,163 @@
1
+ import {history} from "umi";
2
+ import {StringUtils} from "../StringUtils";
3
+ import {UrlUtils} from "../UrlUtils";
4
+ import {MessageUtils} from "../MessageUtils";
5
+
6
+ /**
7
+ * 页面相关的工具类,主要用于路由、URL参数和页面跳转操作。
8
+ */
9
+ export class PageUtils {
10
+
11
+ /**
12
+ * 重定向到登录页,并携带当前页面的URL作为回跳参数。
13
+ */
14
+ static redirectToLogin(): void {
15
+ const url = PageUtils.currentUrl();
16
+ // 对URL进行编码,确保参数安全传递
17
+ const encodedUrl = encodeURIComponent(url);
18
+ history.push(`/login?redirect=${encodedUrl}`);
19
+ }
20
+
21
+ /**
22
+ * @deprecated 请使用 currentParams() 代替。
23
+ * 获取当前 URL 的查询参数对象。
24
+ * @returns {Record<string, string | undefined>} 包含查询参数的键值对对象。
25
+ */
26
+ static currentLocationQuery(): Record<string, string | undefined> {
27
+ return this.currentParams();
28
+ }
29
+
30
+ /**
31
+ * 获取当前 URL 的查询参数对象。
32
+ * @returns {Record<string, string | undefined>} 包含查询参数的键值对对象。
33
+ */
34
+ static currentParams(): Record<string, string | undefined> {
35
+ const url = window.location.href;
36
+
37
+ // 检查是否存在查询参数
38
+ const hasQuery = url.indexOf('?') > 0;
39
+ if (!hasQuery) {
40
+ return {};
41
+ }
42
+
43
+ // 提取问号后面的查询字符串
44
+ const search = url.substring(url.indexOf('?') + 1);
45
+ const kvs = search.split('&');
46
+
47
+ const rs: Record<string, string | undefined> = {};
48
+ for (const kv of kvs) {
49
+ const kvArr = kv.split('=');
50
+ const k = kvArr[0];
51
+ let v = kvArr[1];
52
+
53
+ // 值存在时才进行解码
54
+ if (v) {
55
+ // 使用 decodeURIComponent 更安全地处理 URL 编码的值
56
+ try {
57
+ v = decodeURIComponent(v);
58
+ } catch (e) {
59
+ console.error("Failed to decode URL parameter value:", v, e);
60
+ // 解码失败时保留原值
61
+ }
62
+ } else {
63
+ v = undefined; // 如果值为空,设置为 undefined
64
+ }
65
+ rs[k] = v;
66
+ }
67
+
68
+ return rs;
69
+ }
70
+
71
+ /**
72
+ * 获取当前 URL 的路径名(不带查询参数和 Hash 符号 #)。
73
+ * 例如:"http://localhost:8000/#/login?id=1" -> "/login"
74
+ * @returns {string} 不带参的路径。
75
+ */
76
+ static currentPathname(): string {
77
+ // window.location.hash.substring(1) 得到 "/login?id=1"
78
+ const path = window.location.hash.substring(1);
79
+ return StringUtils.subBefore(path, '?');
80
+ }
81
+
82
+ /**
83
+ * @deprecated 请使用 currentUrl() 代替。
84
+ * 获取 hash 后的完整路径 (带参数)。
85
+ * @returns {string} 例如:"/login?id=1"
86
+ */
87
+ static currentPath(): string {
88
+ // window.location.hash.substring(1) 得到 "/login?id=1"
89
+ return window.location.hash.substring(1);
90
+ }
91
+
92
+ /**
93
+ * 获取 hash 后的完整路径 (带参数)。
94
+ * @returns {string} 例如:"/login?id=1"
95
+ */
96
+ static currentUrl(): string {
97
+ return window.location.hash.substring(1);
98
+ }
99
+
100
+ /**
101
+ * 当前路由的最后一个斜杠后面的单词,通常用于基于路径的路由。
102
+ * 例如:"/user/detail/123" -> "123"
103
+ * @returns {string | undefined} 路径的最后一部分或 undefined。
104
+ */
105
+ static currentPathnameLastPart(): string | undefined {
106
+ const path = this.currentPathname();
107
+ return StringUtils.subAfterLast(path, '/') || undefined;
108
+ }
109
+
110
+ /**
111
+ * 打开一个新页面,可选择添加一个 '_label' 参数。
112
+ * @param path 要跳转的路径。
113
+ * @param label 可选,用于在 URL 中添加一个 '_label' 参数。
114
+ */
115
+ static open(path: string, label: string = '临时'): void {
116
+ let targetPath = path;
117
+ if (label) {
118
+ // 假设 UrlUtil.setParam(url, key, value) 存在并返回设置参数后的 URL
119
+ targetPath = UrlUtils.setParam(targetPath, '_label', label);
120
+ }
121
+ history.push(targetPath);
122
+ }
123
+
124
+
125
+ /**
126
+ * 打开一个不带菜单、Header 等布局元素的页面。
127
+ * 通过在 URL 中添加 '_noLayout=true' 参数实现。
128
+ * @param path 要跳转的路径。
129
+ */
130
+ static openNoLayout(path: string): void {
131
+ // 假设 UrlUtil.setParam(url, key, value) 存在
132
+ const targetPath = UrlUtils.setParam(path, '_noLayout', true);
133
+ history.push(targetPath);
134
+ }
135
+
136
+ /**
137
+ * 获取当前 URL 参数中名为 '_label' 的值。
138
+ * @returns {string | undefined} '_label' 参数的值。
139
+ */
140
+ static currentLabel(): string | undefined {
141
+ // currentParams 返回 Record<string, string | undefined>
142
+ return this.currentParams()['_label'];
143
+ }
144
+
145
+ /**
146
+ * 发送一个自定义事件来关闭当前页面。
147
+ * 依赖外部监听 'close-page-event' 事件的处理机制。
148
+ */
149
+ static closeCurrent() {
150
+ const event = new CustomEvent<{ url: string }>('close-page-event', {
151
+ detail: {url: PageUtils.currentUrl()}
152
+ });
153
+ document.dispatchEvent(event);
154
+ }
155
+
156
+ static closeCurrentAndOpenPage(alertMessage:string,path:string,label:string){
157
+ MessageUtils.alert(alertMessage).then(()=>{
158
+ this.closeCurrent()
159
+ this.open(path,label)
160
+ })
161
+ }
162
+
163
+ }
@@ -0,0 +1,79 @@
1
+ import {SysUtils} from "./SysUtils";
2
+ import {ArrUtils} from "../ArrUtils";
3
+
4
+ /**
5
+ * 登录用户信息接口,
6
+ */
7
+ interface LoginInfo {
8
+ // ... 其他登录信息字段
9
+ permissions: string[];
10
+ }
11
+
12
+ /**
13
+ * 权限控制工具类
14
+ */
15
+ export class PermUtils {
16
+
17
+ /**
18
+ * 获取当前用户的权限列表信息。
19
+ * @private
20
+ * @returns {string[]} 权限码数组。
21
+ */
22
+ private static getPermissions(): string[] {
23
+ // 假设 SysUtil.getLoginInfo() 返回 LoginInfo 类型的对象
24
+ const info: LoginInfo = SysUtils.getLoginInfo();
25
+ const { permissions } = info;
26
+
27
+ if (permissions == null || permissions.length === 0) {
28
+ return [];
29
+ }
30
+
31
+ return permissions;
32
+ }
33
+
34
+ /**
35
+ * 是否拥有权限
36
+ * * @param perm 权限码 (string)
37
+ * @returns {boolean} 如果拥有权限则为 true,否则为 false。
38
+ */
39
+ public static hasPermission(perm: string | null | undefined): boolean {
40
+ if (perm === null || perm === undefined || perm === '') {
41
+ return false;
42
+ }
43
+
44
+ const permissions: string[] = PermUtils.getPermissions();
45
+
46
+ if (permissions.length === 0) {
47
+ return false;
48
+ }
49
+
50
+ // 检查是否拥有超级权限 '*'
51
+ // 假设 ArrUtils.contains(array, item) 存在且返回 boolean
52
+ if (ArrUtils.contains(permissions, "*")) {
53
+ return true;
54
+ }
55
+
56
+ // 检查是否包含指定的权限码
57
+ return permissions.indexOf(perm) > -1;
58
+ }
59
+
60
+ /**
61
+ * 是否授权,功能上与 hasPermission 相同。
62
+ * * @param p 权限码 (string)
63
+ * @returns {boolean} 如果拥有权限则为 true,否则为 false。
64
+ */
65
+ public static isPermitted(p: string | null | undefined): boolean {
66
+ // 直接调用内部方法
67
+ return PermUtils.hasPermission(p);
68
+ }
69
+
70
+ /**
71
+ * 是否没有权限。
72
+ * * @param p 权限码 (string)
73
+ * @returns {boolean} 如果没有权限则为 true,否则为 false。
74
+ */
75
+ public static notPermitted(p: string | null | undefined): boolean {
76
+ // 使用!取反,并确保方法返回布尔值
77
+ return !PermUtils.isPermitted(p);
78
+ }
79
+ }
@@ -0,0 +1,97 @@
1
+
2
+ // --- 常量定义 ---
3
+ import {StorageUtils} from "../StorageUtils";
4
+
5
+ const SITE_INFO_KEY = "siteInfo";
6
+ const LOGIN_INFO_KEY = "loginInfo";
7
+ const DICT_INFO_KEY = "dictInfo";
8
+
9
+ // 假设 SiteInfo, LoginInfo, DictInfo 是工具类操作的数据结构。
10
+ // 请根据你的实际情况替换为正确的接口或类型。
11
+ interface SiteInfo {
12
+ // 示例属性
13
+ name: string;
14
+ version: string;
15
+ }
16
+
17
+ interface LoginInfo {
18
+ // 示例属性
19
+ token: string;
20
+ userId: number;
21
+ }
22
+
23
+ // 字典数据通常是键值对或数组,这里假设是 Record<string, any>
24
+ type DictInfo = Record<string, any> | null;
25
+
26
+ /**
27
+ * 系统工具类 (Utils Pattern)
28
+ */
29
+ export class SysUtils {
30
+
31
+ /**
32
+ * 获取请求头信息。
33
+ * @returns 一个包含请求头键值对的对象。
34
+ */
35
+ public static getHeaders(): Record<string, string> {
36
+ const headers: Record<string, string> = {};
37
+ // 实际的 headers 逻辑(如添加认证 token 等)应在此处实现
38
+ return headers;
39
+ }
40
+
41
+ /**
42
+ * 设置站点信息。
43
+ * @param data 要存储的站点信息数据。
44
+ * @returns StorageUtil.set 的返回值 (通常是 void 或 Promise<void>)
45
+ */
46
+ public static setSiteInfo(data: SiteInfo): void {
47
+ // 假设 StorageUtil.set 返回 void
48
+ // 请根据实际 StorageUtil 的实现调整返回值类型
49
+ StorageUtils.set(SITE_INFO_KEY, data);
50
+ }
51
+
52
+ /**
53
+ * 获取站点信息。
54
+ * @returns 站点信息对象,如果不存在则返回一个空对象。
55
+ */
56
+ public static getSiteInfo(): SiteInfo {
57
+ // 假设 StorageUtil.getDefinition 内部处理了 JSON.parse,并返回对应类型或 null
58
+ return StorageUtils.get(SITE_INFO_KEY) || {} as SiteInfo;
59
+ }
60
+
61
+ /**
62
+ * 设置登录信息。
63
+ * @param data 要存储的登录信息数据。
64
+ */
65
+ public static setLoginInfo(data: LoginInfo): void {
66
+ StorageUtils.set(LOGIN_INFO_KEY, data);
67
+ }
68
+
69
+ /**
70
+ * 获取登录信息。
71
+ * @returns 登录信息对象,如果不存在则返回一个空对象。
72
+ */
73
+ public static getLoginInfo(): LoginInfo {
74
+ return StorageUtils.get(LOGIN_INFO_KEY) || {} as LoginInfo;
75
+ }
76
+
77
+ /**
78
+ * 设置字典信息。
79
+ * @param data 要存储的字典信息数据。
80
+ */
81
+ public static setDictInfo(data: DictInfo): void {
82
+ StorageUtils.set(DICT_INFO_KEY, data);
83
+ }
84
+
85
+ /**
86
+ * 获取字典信息。
87
+ * @returns 字典信息对象,如果不存在则返回 null。
88
+ */
89
+ public static getDictInfo(): DictInfo {
90
+ return StorageUtils.get(DICT_INFO_KEY);
91
+ }
92
+ }
93
+
94
+ // 导出常量(保持不变,但通常将常量放在类内部作为 static readonly 属性更符合 class 模式,
95
+ // 不过为了兼容性,我先保留外部导出,同时建议在类中使用常量)
96
+
97
+ export { SITE_INFO_KEY, LOGIN_INFO_KEY, DICT_INFO_KEY };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 主题相关的工具类
3
+ */
4
+ export class ThemeUtils {
5
+ // 使用 readonly 属性来定义主题常量,保持其不可变性
6
+ public static readonly theme = {
7
+ "primary-color": "#1961AC",
8
+ "success-color": "#52c41a",
9
+ "warning-color": "#faad14",
10
+ "error-color": "#ff4d4f",
11
+ "background-color": "#f5f5f5",
12
+
13
+ "primary-color-hover": "#4990CD",
14
+ "primary-color-click": "#124B93"
15
+ };
16
+
17
+ /**
18
+ * @description 可选:提供一个获取主题颜色的静态方法,增强工具类的可用性
19
+ * @param key 主题颜色键名
20
+ * @returns 对应的颜色值,如果键名不存在则返回undefined
21
+ */
22
+ public static getColor(key: keyof typeof ThemeUtils.theme): string | undefined {
23
+ return ThemeUtils.theme[key];
24
+ }
25
+ }
26
+
27
+
@@ -0,0 +1,7 @@
1
+ export * from './DictUtils'
2
+ export * from './PermUtils'
3
+ export * from './PageUtils'
4
+ export * from "./SysUtils"
5
+ export * from './HttpUtils'
6
+ export * from './FormRegistryUtils'
7
+ export * from './ThemeUtils'