@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.
- package/config/common-plugin.js +94 -0
- package/config/config.js +58 -0
- package/config/utils.js +73 -0
- package/package.json +42 -0
- package/src/.umi-production/appData.json +2365 -0
- package/src/.umi-production/core/EmptyRoute.tsx +9 -0
- package/src/.umi-production/core/defineApp.ts +16 -0
- package/src/.umi-production/core/helmet.ts +10 -0
- package/src/.umi-production/core/helmetContext.ts +4 -0
- package/src/.umi-production/core/history.ts +72 -0
- package/src/.umi-production/core/historyIntelli.ts +132 -0
- package/src/.umi-production/core/plugin.ts +40 -0
- package/src/.umi-production/core/pluginConfig.ts +324 -0
- package/src/.umi-production/core/pluginConfigJoi.d.ts +7 -0
- package/src/.umi-production/core/polyfill.ts +220 -0
- package/src/.umi-production/core/route.tsx +54 -0
- package/src/.umi-production/core/routeProps.js +5 -0
- package/src/.umi-production/core/routeProps.ts +6 -0
- package/src/.umi-production/core/terminal.ts +37 -0
- package/src/.umi-production/exports.ts +17 -0
- package/src/.umi-production/testBrowser.tsx +90 -0
- package/src/.umi-production/tsconfig.json +44 -0
- package/src/.umi-production/typings.d.ts +136 -0
- package/src/.umi-production/umi.ts +83 -0
- package/src/framework/components/DownloadFileButton/index.d.ts +11 -0
- package/src/framework/components/DownloadFileButton/index.jsx +33 -0
- package/src/framework/components/Gap/index.d.ts +23 -0
- package/src/framework/components/Gap/index.jsx +46 -0
- package/src/framework/components/LinkButton/index.d.ts +14 -0
- package/src/framework/components/LinkButton/index.jsx +10 -0
- package/src/framework/components/NamedIcon/index.d.ts +5 -0
- package/src/framework/components/NamedIcon/index.jsx +11 -0
- package/src/framework/components/OrgTree/index.d.ts +4 -0
- package/src/framework/components/OrgTree/index.jsx +58 -0
- package/src/framework/components/Page/index.d.ts +17 -0
- package/src/framework/components/Page/index.jsx +30 -0
- package/src/framework/components/Page/index.less +10 -0
- package/src/framework/components/PageLoading/index.d.ts +1 -0
- package/src/framework/components/PageLoading/index.jsx +25 -0
- package/src/framework/components/ProModal/index.tsx +66 -0
- package/src/framework/components/ProTable/components/ToolBar/index.jsx +123 -0
- package/src/framework/components/ProTable/components/ToolBar/index.less +53 -0
- package/src/framework/components/ProTable/index.d.ts +42 -0
- package/src/framework/components/ProTable/index.jsx +260 -0
- package/src/framework/components/ProTable/index.less +14 -0
- package/src/framework/components/ProTable/utils/index.js +43 -0
- package/src/framework/components/RoleTree/index.d.ts +4 -0
- package/src/framework/components/RoleTree/index.jsx +50 -0
- package/src/framework/components/ValueType/index.jsx +34 -0
- package/src/framework/components/ValueType/registry.jsx +26 -0
- package/src/framework/components/ViewRange/index.d.ts +14 -0
- package/src/framework/components/ViewRange/index.jsx +20 -0
- package/src/framework/components/index.ts +13 -0
- package/src/framework/components/system/ButtonList.d.ts +8 -0
- package/src/framework/components/system/ButtonList.jsx +42 -0
- package/src/framework/components/system/HasPerm.tsx +14 -0
- package/src/framework/components/system/index.tsx +29 -0
- package/src/framework/fields/FieldBoolean/index.d.ts +9 -0
- package/src/framework/fields/FieldBoolean/index.jsx +73 -0
- package/src/framework/fields/FieldDate/index.d.ts +23 -0
- package/src/framework/fields/FieldDate/index.jsx +116 -0
- package/src/framework/fields/FieldDateRange/index.d.ts +22 -0
- package/src/framework/fields/FieldDateRange/index.jsx +103 -0
- package/src/framework/fields/FieldDictSelect/index.d.ts +12 -0
- package/src/framework/fields/FieldDictSelect/index.jsx +16 -0
- package/src/framework/fields/FieldEditor/index.d.ts +14 -0
- package/src/framework/fields/FieldEditor/index.jsx +59 -0
- package/src/framework/fields/FieldNumberRange/index.d.ts +10 -0
- package/src/framework/fields/FieldNumberRange/index.jsx +55 -0
- package/src/framework/fields/FieldPercent/index.d.ts +8 -0
- package/src/framework/fields/FieldPercent/index.jsx +30 -0
- package/src/framework/fields/FieldRemoteSelect/index.d.ts +44 -0
- package/src/framework/fields/FieldRemoteSelect/index.jsx +125 -0
- package/src/framework/fields/FieldRemoteSelectMultiple/index.d.ts +20 -0
- package/src/framework/fields/FieldRemoteSelectMultiple/index.jsx +85 -0
- package/src/framework/fields/FieldRemoteSelectMultipleInline/index.d.ts +21 -0
- package/src/framework/fields/FieldRemoteSelectMultipleInline/index.jsx +88 -0
- package/src/framework/fields/FieldRemoteTree/index.d.ts +20 -0
- package/src/framework/fields/FieldRemoteTree/index.jsx +50 -0
- package/src/framework/fields/FieldRemoteTreeCascader/index.d.ts +18 -0
- package/src/framework/fields/FieldRemoteTreeCascader/index.jsx +59 -0
- package/src/framework/fields/FieldRemoteTreeSelect/index.d.ts +19 -0
- package/src/framework/fields/FieldRemoteTreeSelect/index.jsx +57 -0
- package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.d.ts +20 -0
- package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.jsx +62 -0
- package/src/framework/fields/FieldSysOrgTree/index.d.ts +9 -0
- package/src/framework/fields/FieldSysOrgTree/index.jsx +20 -0
- package/src/framework/fields/FieldSysOrgTreeSelect/index.d.ts +9 -0
- package/src/framework/fields/FieldSysOrgTreeSelect/index.jsx +22 -0
- package/src/framework/fields/FieldTable/index.d.ts +14 -0
- package/src/framework/fields/FieldTable/index.jsx +108 -0
- package/src/framework/fields/FieldTable/styles.less +29 -0
- package/src/framework/fields/FieldTableSelect/index.d.ts +19 -0
- package/src/framework/fields/FieldTableSelect/index.jsx +60 -0
- package/src/framework/fields/FieldUploadFile/index.d.ts +31 -0
- package/src/framework/fields/FieldUploadFile/index.jsx +139 -0
- package/src/framework/fields/index.ts +22 -0
- package/src/framework/fields/types.ts +16 -0
- package/src/framework/index.ts +5 -0
- package/src/framework/pages/LoginPage.d.ts +16 -0
- package/src/framework/pages/LoginPage.jsx +135 -0
- package/src/framework/pages/LoginPage.less +53 -0
- package/src/framework/pages/LoginPageUtils.ts +36 -0
- package/src/framework/pages/index.ts +2 -0
- package/src/framework/utils/ArrUtils.ts +229 -0
- package/src/framework/utils/ColorsUtils.ts +378 -0
- package/src/framework/utils/DateUtils.ts +187 -0
- package/src/framework/utils/DeviceUtils.ts +46 -0
- package/src/framework/utils/DomUtils.ts +50 -0
- package/src/framework/utils/EventBusUtils.ts +144 -0
- package/src/framework/utils/Logger.ts +40 -0
- package/src/framework/utils/MessageUtils.tsx +170 -0
- package/src/framework/utils/ObjectUtils.ts +118 -0
- package/src/framework/utils/StorageUtils.ts +50 -0
- package/src/framework/utils/StringUtils.ts +436 -0
- package/src/framework/utils/TreeUtils.ts +251 -0
- package/src/framework/utils/UrlUtils.ts +152 -0
- package/src/framework/utils/UuidUtils.ts +88 -0
- package/src/framework/utils/ValidateUtils.ts +28 -0
- package/src/framework/utils/index.ts +15 -0
- package/src/framework/utils/system/DictUtils.ts +97 -0
- package/src/framework/utils/system/FormRegistryUtils.ts +77 -0
- package/src/framework/utils/system/HttpUtils.ts +247 -0
- package/src/framework/utils/system/PageUtils.ts +163 -0
- package/src/framework/utils/system/PermUtils.ts +79 -0
- package/src/framework/utils/system/SysUtils.ts +97 -0
- package/src/framework/utils/system/ThemeUtils.ts +27 -0
- package/src/framework/utils/system/index.ts +7 -0
- package/src/framework/views/ViewApproveStatus/index.d.ts +3 -0
- package/src/framework/views/ViewApproveStatus/index.jsx +21 -0
- package/src/framework/views/ViewBoolean/index.d.ts +3 -0
- package/src/framework/views/ViewBoolean/index.jsx +4 -0
- package/src/framework/views/ViewBooleanEnableDisable/index.d.ts +5 -0
- package/src/framework/views/ViewBooleanEnableDisable/index.jsx +15 -0
- package/src/framework/views/ViewFile/index.d.ts +10 -0
- package/src/framework/views/ViewFile/index.jsx +49 -0
- package/src/framework/views/ViewFileButton/index.d.ts +10 -0
- package/src/framework/views/ViewFileButton/index.jsx +22 -0
- package/src/framework/views/ViewImage/index.d.ts +6 -0
- package/src/framework/views/ViewImage/index.jsx +60 -0
- package/src/framework/views/ViewPassword/index.d.ts +5 -0
- package/src/framework/views/ViewPassword/index.jsx +24 -0
- package/src/framework/views/ViewProcessInstanceProgress/index.d.ts +12 -0
- package/src/framework/views/ViewProcessInstanceProgress/index.jsx +97 -0
- package/src/framework/views/ViewProcessInstanceProgressButton/index.d.ts +6 -0
- package/src/framework/views/ViewProcessInstanceProgressButton/index.jsx +24 -0
- package/src/framework/views/ViewText/index.d.ts +16 -0
- package/src/framework/views/ViewText/index.jsx +42 -0
- package/src/framework/views/index.ts +12 -0
- package/src/framework/views/types.ts +26 -0
- package/src/index.ts +2 -0
- package/src/layouts/PageRender.d.ts +22 -0
- package/src/layouts/PageRender.jsx +90 -0
- package/src/layouts/admin/HeaderRight.jsx +104 -0
- package/src/layouts/admin/TabPageRender.jsx +158 -0
- package/src/layouts/admin/index.jsx +159 -0
- package/src/layouts/admin/index.less +65 -0
- package/src/layouts/index.jsx +187 -0
- package/src/layouts/index.less +24 -0
- package/src/loading.jsx +18 -0
- package/src/pages/404.jsx +13 -0
- package/src/pages/about.jsx +12 -0
- package/src/pages/index.jsx +10 -0
- package/src/pages/login.jsx +16 -0
- package/src/pages/system/api/ApiDoc.jsx +148 -0
- package/src/pages/system/api/index.jsx +267 -0
- package/src/pages/system/api/perm.jsx +69 -0
- package/src/pages/system/dict/Dict.jsx +67 -0
- package/src/pages/system/dict/DictItem.jsx +175 -0
- package/src/pages/system/dict/index.jsx +25 -0
- package/src/pages/system/file/index.jsx +147 -0
- package/src/pages/system/job/index.jsx +324 -0
- package/src/pages/system/log/index.jsx +77 -0
- package/src/pages/system/org/index.jsx +260 -0
- package/src/pages/system/role/index.jsx +302 -0
- package/src/pages/system/role/perm.jsx +107 -0
- package/src/pages/system/sysManual/index.jsx +126 -0
- package/src/pages/system/user/UserPerm.jsx +94 -0
- package/src/pages/system/user/index.jsx +253 -0
- package/src/pages/test/views.jsx +95 -0
- package/src/pages/ureport/index.jsx +16 -0
- package/src/pages/userCenter/ChangePassword.jsx +64 -0
- package/src/pages/userCenter/index.jsx +90 -0
- package/src/pages/userCenter/manual.jsx +57 -0
- package/src/pages/userCenter/message.jsx +103 -0
- package/src/style/global.less +51 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import {ArrUtils} from "./ArrUtils"; // 假设 ArrUtil 已经被正确定义和导出
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 🌳 通用树节点接口
|
|
5
|
+
* 假设默认的 id, pid, children 字段存在,但支持其他字段
|
|
6
|
+
* @template T 节点数据的类型
|
|
7
|
+
*/
|
|
8
|
+
export interface TreeNode<T = any> {
|
|
9
|
+
/** 节点的唯一标识 */
|
|
10
|
+
id: string | number;
|
|
11
|
+
/** 父节点的标识 */
|
|
12
|
+
pid: string | number | null;
|
|
13
|
+
/** 子节点数组 */
|
|
14
|
+
children?: TreeNode<T>[];
|
|
15
|
+
|
|
16
|
+
/** 节点携带的额外数据 */
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 🌲 树结构操作工具类
|
|
22
|
+
* 将数组和树结构互相转换,并提供常用的遍历、查找功能。
|
|
23
|
+
*/
|
|
24
|
+
export class TreeUtils {
|
|
25
|
+
|
|
26
|
+
// --- 内部辅助函数 ---
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 递归将树转换为列表的实现。
|
|
30
|
+
* @param tree 树节点数组
|
|
31
|
+
* @param level 当前层级
|
|
32
|
+
* @param result 结果列表,用于累积结果
|
|
33
|
+
* @returns 包含层级信息的列表
|
|
34
|
+
*/
|
|
35
|
+
private static _treeToList<T extends TreeNode>(tree: T[], level: number, result: (T & { level: number })[]): (T & {
|
|
36
|
+
level: number
|
|
37
|
+
})[] {
|
|
38
|
+
for (const node of tree) {
|
|
39
|
+
// 复制节点并添加 level 字段
|
|
40
|
+
const newNode = {...node, level: level} as T & { level: number };
|
|
41
|
+
result.push(newNode);
|
|
42
|
+
|
|
43
|
+
if (node.children && node.children.length > 0) {
|
|
44
|
+
// 递归调用,层级加 1
|
|
45
|
+
this._treeToList(node.children as T[], level + 1, result);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// --- 核心工具方法 ---
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 🌲 将树结构转换为列表结构 (扁平化)。
|
|
55
|
+
* 节点会被添加一个 `level` 字段表示其层级 (从 1 开始)。
|
|
56
|
+
* @param tree 树节点数组
|
|
57
|
+
* @returns 包含层级信息的扁平化列表
|
|
58
|
+
*/
|
|
59
|
+
public static treeToList<T extends TreeNode>(tree: T[]): (T & { level: number }) {
|
|
60
|
+
return TreeUtils._treeToList(tree, 1, []);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 🔎 根据层级查找所有节点的 ID 列表。
|
|
65
|
+
* @param tree 树节点数组
|
|
66
|
+
* @param level 要查找的层级,-1 表示所有层级的 ID。
|
|
67
|
+
* @returns 匹配层级的 ID 数组。
|
|
68
|
+
*/
|
|
69
|
+
public static findKeysByLevel<T extends TreeNode>(tree: T[], level: number): (string | number)[] {
|
|
70
|
+
const list = TreeUtils.treeToList(tree);
|
|
71
|
+
// 如果 level 为 -1,则返回所有节点的 id;否则返回匹配 level 的节点 id
|
|
72
|
+
return list
|
|
73
|
+
.filter(t => level === -1 || t.level === level)
|
|
74
|
+
.map(t => t.id);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 🏗️ 将扁平数组转换为树结构。
|
|
79
|
+
* 默认使用 `id` 作为节点标识,`pid` 作为父节点标识。
|
|
80
|
+
* @param list 扁平化节点数组
|
|
81
|
+
* @param idKey 节点 ID 的字段名,默认为 'id'
|
|
82
|
+
* @param pidKey 父节点 ID 的字段名,默认为 'pid'
|
|
83
|
+
* @returns 根节点数组
|
|
84
|
+
*/
|
|
85
|
+
public static buildTree<T extends TreeNode>(list: T[], idKey: keyof T | 'id' = 'id', pidKey: keyof T | 'pid' = 'pid'): T[] {
|
|
86
|
+
// 使用 Map 存储所有节点,方便通过 ID 查找
|
|
87
|
+
const map = new Map<string | number, T>();
|
|
88
|
+
list.forEach(node => {
|
|
89
|
+
const id = node[idKey] as string | number;
|
|
90
|
+
map.set(id, node);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const root: T[] = [];
|
|
94
|
+
for (const node of list) {
|
|
95
|
+
const pid = node[pidKey] as string | number | null | undefined;
|
|
96
|
+
// 通过 pidKey 查找父节点
|
|
97
|
+
const parent = pid ? map.get(pid) : undefined;
|
|
98
|
+
|
|
99
|
+
if (parent) {
|
|
100
|
+
// 如果找到父节点,将当前节点挂载到父节点的 children 数组
|
|
101
|
+
if (!parent.children) {
|
|
102
|
+
parent.children = [];
|
|
103
|
+
}
|
|
104
|
+
// TypeScript 确保 children 数组的类型正确
|
|
105
|
+
(parent.children as T[]).push(node);
|
|
106
|
+
} else {
|
|
107
|
+
// 如果没有父节点 (或找不到),则视为根节点
|
|
108
|
+
root.push(node);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return root;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 深度优先遍历树节点。
|
|
117
|
+
* @param tree 树节点数组
|
|
118
|
+
* @param callback 对每个节点执行的回调函数
|
|
119
|
+
*/
|
|
120
|
+
public static walk<T extends TreeNode>(tree: T[], callback: (node: T) => void): void {
|
|
121
|
+
if(tree == null){
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
for (const node of tree) {
|
|
125
|
+
callback(node); // 执行回调函数
|
|
126
|
+
|
|
127
|
+
// 遍历子节点
|
|
128
|
+
if (node.children && node.children.length > 0) {
|
|
129
|
+
TreeUtils.walk(node.children as T[], callback);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 根据键值深度查找单个节点。
|
|
136
|
+
* @param key 要查找的键值 (例如: 节点的 id)
|
|
137
|
+
* @param list 树节点数组
|
|
138
|
+
* @param keyName 要匹配的字段名,默认为 'id'
|
|
139
|
+
* @returns 找到的节点,如果未找到则返回 undefined
|
|
140
|
+
*/
|
|
141
|
+
public static findByKey<T extends TreeNode>(key: string | number, list: T[], keyName: keyof T | 'id' = 'id'): T | undefined {
|
|
142
|
+
for (const item of list) {
|
|
143
|
+
// 匹配当前节点
|
|
144
|
+
if (item[keyName] === key) {
|
|
145
|
+
return item;
|
|
146
|
+
}
|
|
147
|
+
// 递归查找子节点
|
|
148
|
+
if (item.children && item.children.length) {
|
|
149
|
+
const rs = TreeUtils.findByKey(key, item.children as T[], keyName);
|
|
150
|
+
if (rs) {
|
|
151
|
+
return rs;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 📜 根据键值列表查找所有匹配的节点列表。
|
|
161
|
+
* @param treeData 树节点数组
|
|
162
|
+
* @param keyList 要查找的键值列表
|
|
163
|
+
* @returns 匹配的节点数组
|
|
164
|
+
*/
|
|
165
|
+
public static findByKeyList<T extends TreeNode>(treeData: T[], keyList: (string | number)[]): T[] {
|
|
166
|
+
const itemList: T[] = [];
|
|
167
|
+
|
|
168
|
+
TreeUtils.walk(treeData, (item) => {
|
|
169
|
+
// 优先使用 key 字段,其次使用 id 字段
|
|
170
|
+
const key = item.key || item.id;
|
|
171
|
+
|
|
172
|
+
if (ArrUtils.contains(keyList, key)) {
|
|
173
|
+
itemList.push(item);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
return itemList;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 获得指定节点下的所有子节点 (扁平化列表,包含自身)。
|
|
182
|
+
* @param treeNode 树节点
|
|
183
|
+
* @param buffer 结果列表,用于递归累积
|
|
184
|
+
* @returns 包含所有子节点的扁平化列表 (包含自身)
|
|
185
|
+
*/
|
|
186
|
+
private static _getChild<T extends TreeNode>(treeNode: T, buffer: T[]): T[] {
|
|
187
|
+
if (treeNode.children != null && treeNode.children.length > 0) {
|
|
188
|
+
treeNode.children.forEach((c) => {
|
|
189
|
+
buffer.push(c as T);
|
|
190
|
+
TreeUtils._getChild(c as T, buffer);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return buffer;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* 获得给定根节点列表下的所有节点 (扁平化列表)。
|
|
198
|
+
* @param treeNodeList 树节点数组
|
|
199
|
+
* @returns 包含所有节点的扁平化列表
|
|
200
|
+
*/
|
|
201
|
+
public static getSimpleList<T extends TreeNode>(treeNodeList: T[]): T[] {
|
|
202
|
+
const buffer: T[] = [];
|
|
203
|
+
|
|
204
|
+
if (treeNodeList != null) {
|
|
205
|
+
treeNodeList.forEach((t) => {
|
|
206
|
+
buffer.push(t);
|
|
207
|
+
TreeUtils._getChild(t, buffer);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return buffer;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 向上追溯,获取从根节点到指定值节点的完整 Key 路径。
|
|
216
|
+
* 假设节点包含 `id` / `key` 和 `pid` / `parentKey` 字段。
|
|
217
|
+
* @param tree 完整的树结构数组
|
|
218
|
+
* @param value 目标节点的 ID 或 Key
|
|
219
|
+
* @returns 从根节点开始到目标节点的 ID/Key 数组 (包含根和目标节点)
|
|
220
|
+
*/
|
|
221
|
+
public static getKeyList<T extends TreeNode>(tree: T[], value: string | number): (string | number)[] {
|
|
222
|
+
const list = TreeUtils.getSimpleList(tree);
|
|
223
|
+
|
|
224
|
+
// 使用 Map 快速通过 ID/Key 查找节点
|
|
225
|
+
const map = new Map<string | number, T>();
|
|
226
|
+
list.forEach((t) => {
|
|
227
|
+
const key = t.key || t.id;
|
|
228
|
+
map.set(key, t);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const targetNode = map.get(value);
|
|
232
|
+
if (targetNode == null) {
|
|
233
|
+
return []; // 未找到目标节点
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const keys: (string | number)[] = [targetNode.key || targetNode.id];
|
|
237
|
+
let parentKey = targetNode.parentKey || targetNode.pid;
|
|
238
|
+
|
|
239
|
+
// 向上追溯
|
|
240
|
+
while (parentKey != null) {
|
|
241
|
+
const parent = map.get(parentKey);
|
|
242
|
+
if (parent == null) {
|
|
243
|
+
break; // 找不到父节点,停止追溯
|
|
244
|
+
}
|
|
245
|
+
keys.push(parent.key || parent.id);
|
|
246
|
+
parentKey = parent.parentKey || parent.pid;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return keys.reverse(); // 从根节点到目标节点的路径
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
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
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./DateUtils";
|
|
2
|
+
export * from "./ArrUtils";
|
|
3
|
+
export * from "./UrlUtils"
|
|
4
|
+
export * from "./StringUtils"
|
|
5
|
+
export * from "./EventBusUtils";
|
|
6
|
+
export * from "./ColorsUtils"
|
|
7
|
+
export * from "./DomUtils"
|
|
8
|
+
export * from "./UuidUtils";
|
|
9
|
+
export * from "./TreeUtils";
|
|
10
|
+
export * from './StorageUtils'
|
|
11
|
+
export * from './DeviceUtils'
|
|
12
|
+
export * from './ObjectUtils'
|
|
13
|
+
export * from './ValidateUtils'
|
|
14
|
+
export * from './system'
|
|
15
|
+
export * from './MessageUtils'
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// 假设的类型定义,你需要确保与你的实际数据结构匹配
|
|
2
|
+
import {SysUtils} from "./SysUtils";
|
|
3
|
+
|
|
4
|
+
export interface DictItem {
|
|
5
|
+
value: string | number;
|
|
6
|
+
label: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// 假设 SysUtil 和 StrUtil 的引入和类型
|
|
12
|
+
// 实际使用时需要确保路径和模块存在
|
|
13
|
+
import {Tag} from 'antd';
|
|
14
|
+
import React from 'react';
|
|
15
|
+
import {StringUtils} from "../StringUtils";
|
|
16
|
+
|
|
17
|
+
// 字典选项的格式
|
|
18
|
+
export interface DictOption {
|
|
19
|
+
value: string|number;
|
|
20
|
+
label: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 字典相关的工具类
|
|
25
|
+
*/
|
|
26
|
+
export class DictUtils {
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 根据字典类型code返回字典数据列表。
|
|
30
|
+
* code 支持 驼峰或下划线(都转为下划线进行匹配)。
|
|
31
|
+
* @param code 字典类型编码 (如 'userStatus', 'USER_STATUS')
|
|
32
|
+
* @returns 对应的字典项列表,未找到返回空数组
|
|
33
|
+
*/
|
|
34
|
+
public static dictList(code: string): DictItem[] {
|
|
35
|
+
const map = SysUtils.getDictInfo();
|
|
36
|
+
if (!map) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
code = StringUtils.toUnderlineCase(code).toUpperCase();
|
|
41
|
+
|
|
42
|
+
return map[code] || [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 将字典列表转换为 Ant Design Select/Options 格式
|
|
47
|
+
* @param typeCode 字典类型编码
|
|
48
|
+
* @returns 包含 value/label 的选项列表
|
|
49
|
+
*/
|
|
50
|
+
public static dictOptions(typeCode: string): DictOption[] {
|
|
51
|
+
const list: DictItem[] = DictUtils.dictList(typeCode);
|
|
52
|
+
return list.map(i => {
|
|
53
|
+
return {
|
|
54
|
+
value: i.value,
|
|
55
|
+
label: i.label,
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 根据字典类型和字典项code获取对应的名称(name)
|
|
63
|
+
* @param typeCode 字典类型编码
|
|
64
|
+
* @param code 字典项编码
|
|
65
|
+
* @returns 对应的名称,未找到返回 undefined
|
|
66
|
+
*/
|
|
67
|
+
public static dictLabel(typeCode: string, code: string | number): string | undefined {
|
|
68
|
+
const items = DictUtils.dictList(typeCode);
|
|
69
|
+
const item = items.find(i => i.value === code);
|
|
70
|
+
return item ? item.label : undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 根据字典类型和字典项code获取对应的名称,并使用 Ant Design Tag 组件包装 (如果存在 color 属性)
|
|
75
|
+
* @param typeCode 字典类型编码
|
|
76
|
+
* @param code 字典项编码
|
|
77
|
+
* @returns Antd Tag 元素或纯字符串名称或空字符串
|
|
78
|
+
*/
|
|
79
|
+
public static dictTag(typeCode: string, code: string | number ): React.ReactElement | string {
|
|
80
|
+
if (typeCode == null || code == null) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const item = DictUtils.dictList(typeCode).find(i => i.value === code);
|
|
84
|
+
|
|
85
|
+
if (item == null) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const {label, color} = item;
|
|
89
|
+
|
|
90
|
+
if (color == null) {
|
|
91
|
+
// 如果没有颜色,返回纯文本
|
|
92
|
+
return label;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return React.createElement(Tag, {color: color}, label);
|
|
96
|
+
}
|
|
97
|
+
}
|