@jiangood/open-admin 2.5.5 → 2.5.6

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 (108) hide show
  1. package/package.json +3 -2
  2. package/src/.umi-production/appData.json +75 -74
  3. package/src/.umi-production/core/route.tsx +6 -6
  4. package/src/framework/GlobalData.d.ts +8 -0
  5. package/src/framework/GlobalData.js +33 -0
  6. package/src/framework/{components/system → biz}/HasPerm.tsx +1 -1
  7. package/src/framework/{components/OrgTree/index.tsx → biz/OrgTree.tsx} +12 -2
  8. package/src/framework/{components/system/ButtonList.tsx → biz/PermActions.tsx} +6 -5
  9. package/src/framework/{components/RoleTree/index.tsx → biz/RoleTree.tsx} +13 -3
  10. package/src/framework/{components/system → biz}/index.tsx +4 -2
  11. package/src/framework/components/ContextMenu/index.tsx +1 -1
  12. package/src/framework/components/DownloadModal/index.tsx +332 -0
  13. package/src/framework/components/ErrorBoundary/index.tsx +18 -0
  14. package/src/framework/components/NamedIcon/{index.jsx → index.tsx} +8 -3
  15. package/src/framework/components/Page/index.tsx +2 -2
  16. package/src/framework/components/ProTable/index.tsx +3 -10
  17. package/src/framework/components/index.ts +2 -6
  18. package/src/framework/fields/BaseRemoteSelect/index.tsx +2 -3
  19. package/src/framework/fields/FieldEditor/index.tsx +35 -44
  20. package/src/framework/fields/FieldNumberRange/index.tsx +2 -2
  21. package/src/framework/fields/FieldRemoteTree/index.tsx +1 -1
  22. package/src/framework/fields/FieldTable/index.tsx +20 -22
  23. package/src/framework/fields/FieldUploadFile/index.tsx +3 -3
  24. package/src/framework/fields/index.ts +1 -3
  25. package/src/framework/index.ts +2 -0
  26. package/src/framework/utils/ArrayUtils.d.ts +6 -0
  27. package/src/framework/utils/ArrayUtils.js +30 -0
  28. package/src/framework/utils/DateUtils.d.ts +20 -0
  29. package/src/framework/utils/DateUtils.js +81 -0
  30. package/src/framework/utils/DeviceUtils.d.ts +3 -0
  31. package/src/framework/utils/DeviceUtils.js +10 -0
  32. package/src/framework/utils/EventBus.d.ts +6 -0
  33. package/src/framework/utils/EventBus.js +51 -0
  34. package/src/framework/utils/MessageUtils.d.ts +10 -0
  35. package/src/framework/utils/MessageUtils.js +43 -0
  36. package/src/framework/utils/ObjectUtils.d.ts +14 -0
  37. package/src/framework/utils/ObjectUtils.js +12 -0
  38. package/src/framework/utils/StorageUtils.d.ts +4 -0
  39. package/src/framework/utils/{StorageUtils.ts → StorageUtils.js} +7 -11
  40. package/src/framework/utils/StringUtils.d.ts +17 -0
  41. package/src/framework/utils/StringUtils.js +107 -0
  42. package/src/framework/utils/TreeUtils.d.ts +13 -0
  43. package/src/framework/utils/TreeUtils.js +63 -0
  44. package/src/framework/utils/UrlUtils.d.ts +6 -0
  45. package/src/framework/utils/UrlUtils.js +71 -0
  46. package/src/framework/utils/index.ts +1 -5
  47. package/src/framework/utils/system/DictUtils.d.ts +20 -0
  48. package/src/framework/utils/system/DictUtils.js +31 -0
  49. package/src/framework/utils/system/FormRegistry.d.ts +8 -0
  50. package/src/framework/utils/system/FormRegistry.js +31 -0
  51. package/src/framework/utils/system/HttpUtils.d.ts +14 -0
  52. package/src/framework/utils/system/HttpUtils.js +87 -0
  53. package/src/framework/utils/system/PageUtils.d.ts +14 -0
  54. package/src/framework/utils/system/PageUtils.js +59 -0
  55. package/src/framework/utils/system/PermUtils.d.ts +5 -0
  56. package/src/framework/utils/system/PermUtils.js +27 -0
  57. package/src/framework/utils/system/ThemeUtils.d.ts +6 -0
  58. package/src/framework/utils/system/{ThemeUtils.ts → ThemeUtils.js} +19 -19
  59. package/src/framework/utils/system/index.ts +1 -2
  60. package/src/framework/views/ViewFile/index.tsx +1 -2
  61. package/src/framework/views/ViewImage/index.tsx +3 -3
  62. package/src/framework/views/{ViewBooleanEnableDisable → ViewSwitch}/index.tsx +1 -1
  63. package/src/framework/views/index.ts +3 -4
  64. package/src/layouts/admin/HeaderRight.jsx +32 -44
  65. package/src/layouts/admin/index.jsx +5 -29
  66. package/src/layouts/index.jsx +26 -17
  67. package/src/pages/about.jsx +24 -4
  68. package/src/pages/{userCenter/ChangePassword.jsx → account/changePassword.jsx} +1 -2
  69. package/src/pages/{userCenter → account}/index.jsx +2 -6
  70. package/src/pages/forceUpdatePwd.jsx +89 -0
  71. package/src/pages/login.jsx +5 -5
  72. package/src/pages/system/dict/index.jsx +6 -6
  73. package/src/pages/system/file/index.jsx +4 -4
  74. package/src/pages/system/job/index.jsx +2 -2
  75. package/src/pages/system/org/index.jsx +2 -2
  76. package/src/pages/system/role/index.jsx +4 -4
  77. package/src/pages/system/role/{perm.jsx → rolePerm.jsx} +2 -2
  78. package/src/pages/system/user/index.jsx +4 -4
  79. package/src/framework/components/DownloadFileButton/index.tsx +0 -33
  80. package/src/framework/components/NamedIcon/index.d.ts +0 -7
  81. package/src/framework/components/ProTable/utils/index.ts +0 -62
  82. package/src/framework/fields/FieldRemoteSelectMultipleInline/index.tsx +0 -33
  83. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.tsx +0 -43
  84. package/src/framework/utils/ArrayUtils.ts +0 -186
  85. package/src/framework/utils/ColorsUtils.ts +0 -378
  86. package/src/framework/utils/DateUtils.ts +0 -187
  87. package/src/framework/utils/DeviceUtils.ts +0 -46
  88. package/src/framework/utils/DomUtils.ts +0 -50
  89. package/src/framework/utils/EventBusUtils.ts +0 -143
  90. package/src/framework/utils/Logger.ts +0 -40
  91. package/src/framework/utils/MessageUtils.tsx +0 -90
  92. package/src/framework/utils/ObjectUtils.ts +0 -118
  93. package/src/framework/utils/StringUtils.ts +0 -436
  94. package/src/framework/utils/TreeUtils.ts +0 -251
  95. package/src/framework/utils/UrlUtils.ts +0 -152
  96. package/src/framework/utils/UuidUtils.ts +0 -88
  97. package/src/framework/utils/ValidateUtils.ts +0 -28
  98. package/src/framework/utils/system/DictUtils.ts +0 -96
  99. package/src/framework/utils/system/FormRegistryUtils.ts +0 -76
  100. package/src/framework/utils/system/HttpUtils.ts +0 -251
  101. package/src/framework/utils/system/PageUtils.ts +0 -163
  102. package/src/framework/utils/system/PermUtils.ts +0 -79
  103. package/src/framework/utils/system/SysUtils.ts +0 -105
  104. package/src/framework/views/ViewProcessInstanceProgress/index.tsx +0 -98
  105. package/src/framework/views/ViewProcessInstanceProgressButton/index.tsx +0 -23
  106. package/src/pages/userCenter/message.jsx +0 -105
  107. /package/src/framework/{components → views}/ViewRange/index.tsx +0 -0
  108. /package/src/pages/system/user/{UserPerm.jsx → userPerm.jsx} +0 -0
@@ -1,152 +0,0 @@
1
- // 假设 StrUtil 已经转换为 StrUtils 或有一个对应的类型定义
2
- // 如果 StrUtil 是一个工具对象,这里可能需要导入它
3
- import {StringUtils} from "./StringUtils";
4
-
5
- /**
6
- * URL 相关操作的工具类
7
- */
8
- export class UrlUtils {
9
-
10
- /**
11
- * 定义一个类型别名,用于 URL 参数对象
12
- */
13
- public type
14
- ParamsObject = Record<string, string | number | boolean | null | undefined>;
15
-
16
- /**
17
- * 获取 URL 的参数对象。
18
- * 如果不传参数,则使用当前路径 (location.href)。
19
- * @param url 完整的 URL 字符串,可选。
20
- * @returns 包含 URL 参数的键值对对象。
21
- */
22
- public static getParams(url: string | null = null): UrlUtils.ParamsObject {
23
- // 1. 确定要解析的 URL
24
- let targetUrl: string;
25
- if (url === null || url === undefined) {
26
- targetUrl = location.href;
27
- } else {
28
- targetUrl = url;
29
- }
30
-
31
- // 2. 检查是否有查询参数
32
- if (!StringUtils.contains(targetUrl, '?')) {
33
- return {};
34
- }
35
-
36
- // 3. 提取查询字符串 (问号后面的部分)
37
- // 假设 StrUtil.subAfter 能够正确获取 '?' 之后的部分
38
- const search = StringUtils.subAfter(targetUrl, '?');
39
-
40
- // 4. 使用 URLSearchParams 进行解析 (现代浏览器环境)
41
- // 注意:在某些旧环境或非浏览器环境中,可能需要不同的解析逻辑
42
- const params = new URLSearchParams(search);
43
-
44
- // 5. 转换为普通对象
45
- const result: UrlUtils.ParamsObject = {} as UrlUtils.ParamsObject;
46
- for (const [key, value] of params.entries()) {
47
- // URLSearchParams 的值总是 string,因此这里赋值为 string
48
- result[key] = value;
49
- }
50
-
51
- return result;
52
- }
53
-
54
- /**
55
- * 获取不带参数的基础 URL (pathname)。
56
- * @param url 完整的 URL 字符串。
57
- * @returns 不包含查询参数的 URL 部分,如果 url 为 null/undefined,则返回 null。
58
- */
59
- public static getPathname(url: string | null | undefined): string | null {
60
- if (!url) {
61
- return null;
62
- }
63
- // 假设 StrUtil.subBefore 能够正确获取 '?' 之前的部分
64
- return StringUtils.subBefore(url, '?');
65
- }
66
-
67
- /**
68
- * 将参数对象转换为 URL 中的查询字符串(例如 k1=v1&k2=v2)。
69
- * @param params 包含参数的键值对对象。
70
- * @returns 查询字符串,不包含开头的问号 (?)。如果 params 为空,则返回空字符串。
71
- */
72
- public static paramsToSearch(params: UrlUtils.ParamsObject | null | undefined): string {
73
- if (!params) {
74
- return "";
75
- }
76
-
77
- const buffer: string[] = [];
78
- // 迭代对象的自身属性
79
- for (const k in params) {
80
- // 确保只处理对象自身的属性,排除原型链上的属性
81
- if (Object.prototype.hasOwnProperty.call(params, k)) {
82
- const v = params[k];
83
- // 忽略值为 null 或 undefined 的参数,或根据需要进行编码
84
- if (v !== null && v !== undefined) {
85
- // 这里对值进行简单的连接,实际应用中建议使用 encodeURIComponent
86
- buffer.push(`${k}=${v}`);
87
- }
88
- }
89
- }
90
- return buffer.join('&');
91
- }
92
-
93
- /**
94
- * 设置或删除 URL 中的一个参数,并返回新的 URL。
95
- * @param url 原始 URL 字符串。
96
- * @param key 要设置或删除的参数名。
97
- * @param value 要设置的参数值。如果传入 null 或 undefined,则删除该参数。
98
- * @returns 带有新参数的新 URL 字符串。
99
- */
100
- public static setParam(url: string, key: string, value: string | number | boolean | null | undefined): string {
101
- // 1. 获取现有参数
102
- const currentParams = this.getParams(url);
103
-
104
- // 2. 根据 value 设置或删除参数
105
- if (value === null || value === undefined) {
106
- delete currentParams[key];
107
- } else {
108
- // 强制转换为 string 存储,以符合 URL 参数的惯例
109
- currentParams[key] = String(value);
110
- }
111
-
112
- // 3. 获取基础路径
113
- const pathname = this.getPathname(url);
114
-
115
- // 4. 将新的参数对象转换为查询字符串
116
- const newSearch = this.paramsToSearch(currentParams);
117
-
118
- // 5. 组合新的 URL
119
- if (newSearch.length > 0) {
120
- return `${pathname}?${newSearch}`;
121
- }
122
- // 如果没有参数,则不带问号
123
- return pathname || url; // 如果 pathname 为 null,则返回原始 url
124
- }
125
-
126
- /**
127
- * @deprecated 使用 setParam 代替。
128
- * 设置或替换 URL 中的一个参数,功能与 setParam 相同。
129
- * @param url 原始 URL 字符串。
130
- * @param key 要替换的参数名。
131
- * @param value 要替换的参数值。
132
- * @returns 带有新参数的新 URL 字符串。
133
- */
134
- public static replaceParam(url: string, key: string, value: string | number | boolean | null | undefined): string {
135
- // 直接调用 setParam,并返回结果
136
- return this.setParam(url, key, value);
137
- }
138
-
139
- /**
140
- * 连接两个路径片段,确保中间只有一个斜杠 (/)。
141
- * @param path1 第一个路径片段。
142
- * @param path2 第二个路径片段。
143
- * @returns 连接后的路径字符串。
144
- */
145
- public static join(path1: string, path2: string): string {
146
- // 假设 StrUtil.removeSuffix/removePrefix 能够处理字符串前后的斜杠
147
- const cleanPath1 = StringUtils.removeSuffix(path1, "/");
148
- const cleanPath2 = StringUtils.removePrefix(path2, "/");
149
-
150
- return `${cleanPath1}/${cleanPath2}`;
151
- }
152
- }
@@ -1,88 +0,0 @@
1
- /**
2
- * 基于 https://github.com/jchook/uuid-random 的工作进行封装
3
- */
4
- export class UuidUtils {
5
- // 静态属性用于存储随机字节缓冲区和索引
6
- private static buf: Uint8Array | undefined = undefined;
7
- private static bufIdx: number = 0;
8
-
9
- // 预计算 toString(16) 以提高速度
10
- private static readonly hexBytes: string[] = (() => {
11
- const bytes = new Array<string>(256);
12
- for (let i = 0; i < 256; i++) {
13
- // (i + 0x100).toString(16).substring(1) 确保总是两位十六进制
14
- bytes[i] = (i + 0x100).toString(16).substring(1);
15
- }
16
- return bytes;
17
- })();
18
-
19
- // 缓冲区大小,可调整
20
- private static readonly BUFFER_SIZE: number = 4096;
21
-
22
- // 随机字节生成函数,使用最佳可用 PRNG
23
- private static readonly randomBytes = ((n: number): Uint8Array => {
24
- // Node & Browser 支持
25
- const lib = typeof crypto !== 'undefined'
26
- ? crypto
27
- : (
28
- typeof window !== 'undefined'
29
- ? window.crypto || (window as any).msCrypto // window.msCrypto 在 TypeScript 中可能不存在
30
- : undefined
31
- );
32
-
33
- if (lib !== undefined) {
34
- // Node.js 支持
35
- if ((lib as any).randomBytes !== undefined) {
36
- return (lib as any).randomBytes(n);
37
- }
38
- // 浏览器支持
39
- if (lib.getRandomValues !== undefined) {
40
- return (() => {
41
- const bytes = new Uint8Array(n);
42
- lib.getRandomValues(bytes);
43
- return bytes;
44
- })();
45
- }
46
- }
47
-
48
- // 降级使用 Math.random
49
- const r = new Uint8Array(n);
50
- for (let i = 0; i < n; i++) {
51
- r[i] = Math.floor(Math.random() * 256);
52
- }
53
- return r;
54
- });
55
-
56
- /**
57
- * 生成一个符合 v4 标准的 UUID。
58
- * @returns 一个 UUID 字符串。
59
- */
60
- public static uuidV4(): string {
61
- // 为加速而缓冲一些随机字节
62
- if (UuidUtils.buf === undefined || (UuidUtils.bufIdx + 16 > UuidUtils.BUFFER_SIZE)) {
63
- UuidUtils.bufIdx = 0;
64
- // randomBytes 的返回类型已确定为 Uint8Array
65
- UuidUtils.buf = UuidUtils.randomBytes(UuidUtils.BUFFER_SIZE);
66
- }
67
-
68
- // 提取 16 个字节。使用 Array.prototype.slice.call 转化为 Array 并不能保证性能,
69
- // 且 TypeScript 中操作 Uint8Array 更直接。我们直接使用 subarray 提取,性能更优。
70
- const b = UuidUtils.buf.subarray(UuidUtils.bufIdx, (UuidUtils.bufIdx += 16));
71
-
72
- // 设置 UUID 版本 (Version 4: 0100)
73
- b[6] = (b[6] & 0x0f) | 0x40;
74
- // 设置时钟序列高位 (Variant 1: 10xx)
75
- b[8] = (b[8] & 0x3f) | 0x80;
76
-
77
- // 将字节转换为十六进制字符串格式
78
- const h = UuidUtils.hexBytes;
79
- return h[b[0]] + h[b[1]]
80
- + h[b[2]] + h[b[3]] + '-'
81
- + h[b[4]] + h[b[5]] + '-'
82
- + h[b[6]] + h[b[7]] + '-'
83
- + h[b[8]] + h[b[9]] + '-'
84
- + h[b[10]] + h[b[11]]
85
- + h[b[12]] + h[b[13]]
86
- + h[b[14]] + h[b[15]];
87
- }
88
- }
@@ -1,28 +0,0 @@
1
- /**
2
- * 验证工具类
3
- */
4
- export class ValidateUtils {
5
-
6
- /**
7
- * 检查给定的字符串是否为有效的电子邮件地址。
8
- * @param emailStr 要检查的字符串。
9
- * @returns 如果是有效的电子邮件地址,则返回 true;否则返回 false。
10
- */
11
- public static isEmail(emailStr: string): boolean {
12
- // 匹配大多数常见电子邮件格式的正则表达式
13
- const reg = /^([\w+.-])+@\w+([.]\w+)+$/;
14
- return reg.test(emailStr);
15
- }
16
-
17
- // 可以在这里添加其他验证方法,例如:
18
- /*
19
- public static isPhone(phoneStr: string): boolean {
20
- // ... 手机号验证逻辑
21
- return /^\d{10}$/.test(phoneStr);
22
- }
23
- */
24
- }
25
-
26
- // 示例用法:
27
- // const isValid = ValidateUtils.isEmail("test@example.com");
28
- // console.log(isValid); // true
@@ -1,96 +0,0 @@
1
- // 假设的类型定义,你需要确保与你的实际数据结构匹配
2
- import {SysUtils} from "./SysUtils";
3
- // 假设 SysUtil 和 StrUtil 的引入和类型
4
- // 实际使用时需要确保路径和模块存在
5
- import {Tag} from 'antd';
6
- import React from 'react';
7
- import {StringUtils} from "../StringUtils";
8
-
9
- export interface DictItem {
10
- code: string | number;
11
- label: string;
12
- color?: string;
13
- }
14
-
15
-
16
- // 字典选项的格式
17
- export interface DictOption {
18
- value: string | number;
19
- label: string;
20
- }
21
-
22
- /**
23
- * 字典相关的工具类
24
- */
25
- export class DictUtils {
26
-
27
- /**
28
- * 根据字典类型code返回字典数据列表。
29
- * code 支持 驼峰或下划线(都转为下划线进行匹配)。
30
- * @param code 字典类型编码 (如 'userStatus', 'USER_STATUS')
31
- * @returns 对应的字典项列表,未找到返回空数组
32
- */
33
- public static dictList(code: string): DictItem[] {
34
- const info = SysUtils.getDictInfo();
35
- if (!info) {
36
- return [];
37
- }
38
-
39
- let list = info.filter(e=>e.typeCode === code);
40
-
41
- return list
42
- }
43
-
44
- /**
45
- * 将字典列表转换为 Ant Design Select/Options 格式
46
- * @param typeCode 字典类型编码
47
- * @returns 包含 value/label 的选项列表
48
- */
49
- public static dictOptions(typeCode: string): DictOption[] {
50
- const list: DictItem[] = DictUtils.dictList(typeCode);
51
- return list.map(i => {
52
- return {
53
- value: i.code,
54
- label: i.label,
55
- }
56
- });
57
- }
58
-
59
-
60
- /**
61
- * 根据字典类型和字典项code获取对应的名称(name)
62
- * @param typeCode 字典类型编码
63
- * @param code 字典项编码
64
- * @returns 对应的名称,未找到返回 undefined
65
- */
66
- public static dictLabel(typeCode: string, code: string | number): string | undefined {
67
- const items = DictUtils.dictList(typeCode);
68
- const item = items.find(i => i.code === code);
69
- return item ? item.label : undefined;
70
- }
71
-
72
- /**
73
- * 根据字典类型和字典项code获取对应的名称,并使用 Ant Design Tag 组件包装 (如果存在 color 属性)
74
- * @param typeCode 字典类型编码
75
- * @param code 字典项编码
76
- * @returns Antd Tag 元素或纯字符串名称或空字符串
77
- */
78
- public static dictTag(typeCode: string, code: string | number): React.ReactElement | string {
79
- if (typeCode == null || code == null) {
80
- return null;
81
- }
82
- const item = DictUtils.dictList(typeCode).find(i => i.code === code);
83
-
84
- if (item == null) {
85
- return null;
86
- }
87
- const {label, color} = item;
88
-
89
- if (color == null) {
90
- // 如果没有颜色,返回纯文本
91
- return label;
92
- }
93
-
94
- return React.createElement(Tag, {color: color.toLowerCase()}, label);
95
- }
96
- }
@@ -1,76 +0,0 @@
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
- }
43
-
44
- /**
45
- * 静态方法:获取表单组件
46
- * @param formKey - 表单唯一标识
47
- * @returns React 表单组件,如果不存在则返回 null
48
- */
49
- public static get(formKey: string): FormComponent | null {
50
- const formComponent = FormRegistryUtils.forms.get(formKey);
51
-
52
- if (!formComponent) {
53
- console.warn(`⚠️ 【FormRegistryUtils】表单 "${formKey}" 未注册!`);
54
- }
55
-
56
- return formComponent ?? null;
57
- }
58
-
59
- /**
60
- * 静态方法:检查表单是否已注册
61
- * @param formKey - 表单唯一标识
62
- * @returns boolean
63
- */
64
- public static has(formKey: string): boolean {
65
- return FormRegistryUtils.forms.has(formKey);
66
- }
67
-
68
- /**
69
- * 静态方法:获取所有已注册的表单 Key
70
- * @returns string[] - 所有表单 Key 的数组
71
- */
72
- public static getAllKeys(): string[] {
73
- return Array.from(FormRegistryUtils.forms.keys());
74
- }
75
- }
76
-
@@ -1,251 +0,0 @@
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
- baseURL: (typeof SERVLET_CONTEXT !== 'undefined' && SERVLET_CONTEXT) || '',
10
- withCredentials: true,
11
- headers: {
12
- 'Content-Type': 'application/json'
13
- },
14
- // 解决get请求时,数组参数的问题
15
- paramsSerializer: (params) => {
16
- return qs.stringify(params, {indices: false});
17
- }
18
- })
19
-
20
-
21
- /**
22
- * @description HTTP请求工具类
23
- */
24
- export class HttpUtils {
25
-
26
-
27
- /**
28
- * 核心请求函数,处理请求发送、加载状态、响应解析和错误捕获
29
- * @param config AxiosRequestConfig & RequestOptions
30
- * @param transformData 是否返回最总的data字段
31
- * @returns Promise<any>
32
- */
33
- // ... existing code ...
34
- private static coreRequest(config: AxiosRequestConfig, transformData: boolean = true): Promise<any> {
35
- const url = config.url;
36
- config.url = url.startsWith('admin') ? '/' + url : url;
37
-
38
- return new Promise((resolve, reject) => {
39
- axiosInstance(config).then((response: AxiosResponse) => {
40
- const body = response.data;
41
- // 假设后端响应结构为 { success: boolean | null, message: string, data: any, code: number }
42
- let {success, message, data} = body;
43
- if (success == undefined) { // 如果没有success字段,说明非标准接口
44
- resolve(response);
45
- return ;
46
- }
47
-
48
- if (!success) {
49
- console.error(`[HttpUtils] 请求失败: ${url}`, {code: body.code, message, data: body});
50
- MessageUtils.error(message || '操作失败');
51
- reject('操作失败');
52
- return
53
- }
54
-
55
- // 自动消息提示
56
- if (message) {
57
- MessageUtils.success(message);
58
- }
59
- resolve(transformData ? data : response);
60
- }).catch((e: unknown) => {
61
- // 统一异常处理
62
- console.error(`[HttpUtils] 请求异常: ${url}`, e);
63
- let msg = '操作失败';
64
-
65
- if (axios.isAxiosError(e)) {
66
- const status = e.response?.status;
67
- const responseData = e.response?.data;
68
-
69
- if (status === 401) {
70
- // 登录过期处理
71
- MessageUtils.confirm('登录已过期,请重新登录').then(() => {
72
- PageUtils.redirectToLogin();
73
- });
74
- // 阻止后续的错误提示,返回一个特殊 Promise.reject
75
- reject('登录过期');
76
- return
77
- }
78
- if (status === 504) {
79
- msg = '504 请求后端服务失败';
80
- } else if (responseData && responseData.message) {
81
- msg = responseData.message;
82
- } else if (e.message) {
83
- msg = e.message;
84
- }
85
- } else if (e instanceof Error) {
86
- // 可能是后端success=false抛出的自定义错误
87
- msg = e.message;
88
- }
89
-
90
- MessageUtils.error(msg);
91
-
92
- // 将原始错误或处理后的错误信息向外抛出
93
- reject(e);
94
- });
95
- })
96
-
97
- }
98
-
99
-
100
- /**
101
- * 处理文件下载后的blob流
102
- * @param res AxiosResponse 文件下载响应
103
- */
104
- private static handleDownloadBlob(res: AxiosResponse): Promise<void> {
105
- return new Promise((resolve, reject) => {
106
- const {data: blob, headers} = res;
107
-
108
- // 1. 检查是否为错误JSON
109
- if (blob.type === 'application/json') {
110
- const reader = new FileReader();
111
- reader.readAsText(blob, 'utf-8');
112
- reader.onload = function () {
113
- try {
114
- let rs = JSON.parse(reader.result as string);
115
- Modal.error({
116
- title: '下载文件失败',
117
- content: rs.message || '不支持下载'
118
- });
119
- reject(new Error(rs.message || '下载错误'));
120
- } catch (e) {
121
- Modal.error({title: '下载文件失败', content: '解析错误响应失败'});
122
- reject(e);
123
- }
124
- };
125
- return;
126
- }
127
-
128
- // 2. 获取文件名称
129
- const contentDisposition = headers['content-disposition'] || headers['Content-Disposition'];
130
- if (!contentDisposition) {
131
- Modal.error({title: '获取文件名称失败', content: "缺少Content-Disposition响应头"});
132
- reject(new Error("缺少Content-Disposition响应头"));
133
- return;
134
- }
135
-
136
- const match = /filename\*?=(?:['"]?)(?:UTF-8''|)(.+?)(?:['"]?$|;)/i.exec(contentDisposition);
137
- let filename = match && match[1] ? match[1].trim() : 'download.file';
138
-
139
- try {
140
- // 尝试进行URI解码
141
- filename = decodeURIComponent(filename.replace(/"/g, ''));
142
- } catch (e) {
143
- // 如果解码失败,保持原样
144
- filename = filename.replace(/"/g, '');
145
- }
146
-
147
- // 3. 开始下载
148
- const url = window.URL.createObjectURL(new Blob([blob]));
149
- const link = document.createElement('a');
150
- link.style.display = 'none';
151
-
152
- link.href = url;
153
- link.download = filename;
154
-
155
- document.body.appendChild(link);
156
- link.click();
157
-
158
- document.body.removeChild(link);
159
- window.URL.revokeObjectURL(url);
160
- resolve();
161
- });
162
- }
163
-
164
-
165
- /**
166
- * 发送GET请求
167
- * @param url 请求地址
168
- * @param params URL参数
169
- * @param options 自定义配置 (transformData等)
170
- * @returns Promise<any> 后端返回的 data 字段
171
- */
172
- public static get(url: string, params: any = null, options: Partial<AxiosRequestConfig> = {}): Promise<any> {
173
- return HttpUtils.coreRequest({
174
- ...options,
175
- url,
176
- method: 'GET',
177
- params,
178
- });
179
- }
180
-
181
- /**
182
- * 发送POST请求 (Content-Type: application/json)
183
- * @param url 请求地址
184
- * @param data 请求体数据
185
- * @param params URL参数
186
- * @param options 自定义配置
187
- * @returns Promise<any> 后端返回的 data 字段
188
- */
189
- public static post(url: string, data: any = null, params: any = null, options: Partial<RequestOptions> = {}): Promise<any> {
190
- return HttpUtils.coreRequest({
191
- ...options,
192
- url,
193
- method: 'POST',
194
- data,
195
- params,
196
- });
197
- }
198
-
199
- /**
200
- * 发送POST表单请求 (Content-Type: application/x-www-form-urlencoded)
201
- * @param url 请求地址
202
- * @param data 表单数据
203
- * @param options 自定义配置
204
- * @returns Promise<any> 后端返回的 data 字段
205
- */
206
- public static postForm(url: string, data: any, options: Partial<AxiosRequestConfig> = {}): Promise<any> {
207
- return HttpUtils.coreRequest({
208
- ...options,
209
- url,
210
- method: 'POST',
211
- data: qs.stringify(data), // 转换为表单格式
212
- headers: {
213
- 'Content-Type': 'application/x-www-form-urlencoded'
214
- },
215
- });
216
- }
217
-
218
- /**
219
- * 下载文件
220
- * @param url 请求地址
221
- * @param data 请求体数据 (POST时使用)
222
- * @param params URL参数
223
- * @param method 请求方法,默认为GET
224
- * @param options 自定义配置
225
- * @returns Promise<void>
226
- */
227
- public static async downloadFile(url: string, data: any = null, params: any = null, method: Method = 'GET', options: Partial<AxiosRequestConfig> = {}): Promise<void> {
228
-
229
- // 下载请求默认设置:不转换数据,响应类型为 blob
230
- const downloadConfig: AxiosRequestConfig = {
231
- responseType: 'blob', // 关键设置
232
- ...options,
233
- url,
234
- method,
235
- params,
236
- data,
237
- };
238
-
239
- try {
240
- // coreRequest返回的是完整的 AxiosResponse,因此需要类型断言
241
- const response = await HttpUtils.coreRequest(downloadConfig, false) as AxiosResponse;
242
- await HttpUtils.handleDownloadBlob(response);
243
- } catch (error) {
244
- console.error('[HttpUtils] 下载文件失败:', error);
245
- // coreRequest已经处理了401、504和通用的错误提示
246
- return Promise.reject(error);
247
- }
248
- }
249
-
250
-
251
- }