@befly-addon/admin 1.8.7 → 1.8.8
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/apis/admin/cacheRefresh.ts +15 -3
- package/apis/api/all.ts +7 -14
- package/apis/menu/all.ts +21 -34
- package/apis/role/apis.ts +4 -12
- package/apis/role/menuSave.ts +10 -2
- package/apis/role/menus.ts +4 -11
- package/package.json +3 -3
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* 功能:
|
|
5
5
|
* 1. 刷新接口缓存(apis:all)
|
|
6
6
|
* 2. 刷新菜单缓存(menus:all)
|
|
7
|
-
* 3.
|
|
7
|
+
* 3. 刷新角色缓存(role:info:{code})
|
|
8
|
+
* 4. 重建角色接口权限缓存(role:apis:{code},Set)
|
|
9
|
+
* 5. 重建角色菜单权限缓存(role:menus:{code},Set)
|
|
8
10
|
*
|
|
9
11
|
* 使用场景:
|
|
10
12
|
* - 执行数据库同步后
|
|
@@ -22,7 +24,8 @@ const route: ApiRoute = {
|
|
|
22
24
|
apis: { success: false, count: 0 },
|
|
23
25
|
menus: { success: false, count: 0 },
|
|
24
26
|
roles: { success: false, count: 0 },
|
|
25
|
-
roleApiPermissions: { success: false }
|
|
27
|
+
roleApiPermissions: { success: false },
|
|
28
|
+
roleMenuPermissions: { success: false }
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
// 1. 刷新接口缓存
|
|
@@ -89,8 +92,17 @@ const route: ApiRoute = {
|
|
|
89
92
|
results["roleApiPermissions"] = { success: false, error: error.message };
|
|
90
93
|
}
|
|
91
94
|
|
|
95
|
+
// 5. 重建角色菜单权限缓存
|
|
96
|
+
try {
|
|
97
|
+
await befly.cache.rebuildRoleMenuPermissions();
|
|
98
|
+
results["roleMenuPermissions"] = { success: true };
|
|
99
|
+
} catch (error: any) {
|
|
100
|
+
befly.logger.error({ err: error, msg: "重建角色菜单权限缓存失败" });
|
|
101
|
+
results["roleMenuPermissions"] = { success: false, error: error.message };
|
|
102
|
+
}
|
|
103
|
+
|
|
92
104
|
// 检查是否全部成功
|
|
93
|
-
const allSuccess = results["apis"].success && results["menus"].success && results["roles"].success && results["roleApiPermissions"].success;
|
|
105
|
+
const allSuccess = results["apis"].success && results["menus"].success && results["roles"].success && results["roleApiPermissions"].success && results["roleMenuPermissions"].success;
|
|
94
106
|
|
|
95
107
|
if (allSuccess) {
|
|
96
108
|
return befly.tool.Yes("全部缓存刷新成功", results);
|
package/apis/api/all.ts
CHANGED
|
@@ -1,28 +1,21 @@
|
|
|
1
|
-
import type { DbJsonRow } from "../../utils/dbJsonRow";
|
|
2
1
|
import type { ApiRoute } from "befly/types/api";
|
|
2
|
+
import type { JsonValue, KeyValue } from "befly/types/common";
|
|
3
|
+
|
|
4
|
+
type ApiRow = KeyValue<JsonValue>;
|
|
3
5
|
|
|
4
6
|
const route: ApiRoute = {
|
|
5
7
|
name: "获取所有接口",
|
|
6
8
|
handler: async (befly) => {
|
|
7
9
|
try {
|
|
8
10
|
// 从缓存获取所有接口
|
|
9
|
-
|
|
11
|
+
const allApis = (await befly.cache.getApis()) as ApiRow[];
|
|
10
12
|
|
|
11
|
-
//
|
|
13
|
+
// 强制缓存:不回退 DB
|
|
12
14
|
if (allApis.length === 0) {
|
|
13
|
-
|
|
14
|
-
table: "addon_admin_api",
|
|
15
|
-
orderBy: ["id#ASC"]
|
|
16
|
-
});
|
|
17
|
-
allApis = result.data.lists;
|
|
18
|
-
|
|
19
|
-
// 缓存到 Redis
|
|
20
|
-
if (allApis.length > 0) {
|
|
21
|
-
await befly.cache.cacheApis();
|
|
22
|
-
}
|
|
15
|
+
return befly.tool.No("接口缓存不存在,请刷新缓存", { lists: [] });
|
|
23
16
|
}
|
|
24
17
|
|
|
25
|
-
const lists = allApis.filter((api)
|
|
18
|
+
const lists = allApis.filter((api) => api && typeof api === "object");
|
|
26
19
|
|
|
27
20
|
return befly.tool.Yes("操作成功", { lists: lists });
|
|
28
21
|
} catch (error: unknown) {
|
package/apis/menu/all.ts
CHANGED
|
@@ -1,61 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 获取当前用户的菜单权限
|
|
3
3
|
* 说明:
|
|
4
|
-
* 1. 从 Redis
|
|
5
|
-
* 2.
|
|
6
|
-
* 3.
|
|
7
|
-
* 4.
|
|
4
|
+
* 1. 从 Redis 缓存读取所有菜单(强制:不回退 DB)
|
|
5
|
+
* 2. 从 Redis Set 读取角色菜单权限(role:menus:{roleCode}),拿到该角色可访问的菜单 path 列表
|
|
6
|
+
* 3. 根据角色菜单 path 列表过滤可访问的菜单
|
|
7
|
+
* 4. 返回一维数组(由前端构建树形结构)
|
|
8
|
+
* 5. 仅返回状态为启用的菜单
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
|
-
import type { DbJsonRow } from "../../utils/dbJsonRow";
|
|
11
11
|
import type { ApiRoute } from "befly/types/api";
|
|
12
|
+
import type { JsonValue, KeyValue } from "befly/types/common";
|
|
13
|
+
|
|
14
|
+
type MenuRow = KeyValue<JsonValue>;
|
|
12
15
|
|
|
13
16
|
const route: ApiRoute = {
|
|
14
17
|
name: "获取用户菜单",
|
|
15
18
|
handler: async (befly, ctx) => {
|
|
16
19
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
where: { code: ctx.user["roleCode"] }
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
if (!role.data?.id) {
|
|
24
|
-
return befly.tool.No("角色不存在", { lists: [] });
|
|
20
|
+
const roleCode = typeof ctx.user["roleCode"] === "string" ? ctx.user["roleCode"] : "";
|
|
21
|
+
if (roleCode.length === 0) {
|
|
22
|
+
return befly.tool.No("角色缺失", { lists: [] });
|
|
25
23
|
}
|
|
26
24
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
const menuPaths =
|
|
25
|
+
// 2. 从 Redis Set 读取角色菜单权限(由 core 的 cache 体系维护)
|
|
26
|
+
// 约定:key = role:menus:{roleCode}(会自动加上 Redis prefix)
|
|
27
|
+
const menuPaths = await befly.cache.getRoleMenuPermissions(roleCode);
|
|
30
28
|
|
|
31
29
|
if (menuPaths.length === 0) {
|
|
32
30
|
return befly.tool.Yes("菜单为空", { lists: [] });
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
// 4.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// 如果缓存不存在,从数据库查询
|
|
39
|
-
if (allMenus.length === 0) {
|
|
40
|
-
const result = await befly.db.getAll<DbJsonRow>({
|
|
41
|
-
table: "addon_admin_menu"
|
|
42
|
-
});
|
|
43
|
-
allMenus = result.data.lists;
|
|
44
|
-
}
|
|
33
|
+
// 4. 从缓存获取所有菜单(强制:不回退 DB)
|
|
34
|
+
const allMenus = (await befly.cache.getMenus()) as MenuRow[];
|
|
45
35
|
|
|
46
36
|
if (allMenus.length === 0) {
|
|
47
|
-
return befly.tool.
|
|
37
|
+
return befly.tool.No("菜单缓存不存在,请刷新缓存", { lists: [] });
|
|
48
38
|
}
|
|
49
39
|
|
|
50
40
|
// 5. 根据角色权限过滤菜单(按 menu.path)
|
|
51
41
|
const menuPathSet = new Set<string>(menuPaths);
|
|
52
|
-
const authorizedMenus = allMenus
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
return typeof path === "string" && menuPathSet.has(path);
|
|
57
|
-
})
|
|
58
|
-
.map((menu) => menu as DbJsonRow);
|
|
42
|
+
const authorizedMenus = allMenus.filter((menu) => {
|
|
43
|
+
const path = menu["path"];
|
|
44
|
+
return typeof path === "string" && menuPathSet.has(path);
|
|
45
|
+
});
|
|
59
46
|
|
|
60
47
|
// 6. 返回一维数组(由前端构建树形结构)
|
|
61
48
|
return befly.tool.Yes("获取菜单成功", { lists: authorizedMenus });
|
package/apis/role/apis.ts
CHANGED
|
@@ -8,20 +8,12 @@ const route: ApiRoute = {
|
|
|
8
8
|
roleCode: adminRoleTable.code
|
|
9
9
|
},
|
|
10
10
|
handler: async (befly, ctx) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
where: { code: ctx.body.roleCode }
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
if (!role.data?.id) {
|
|
18
|
-
return befly.tool.No("角色不存在");
|
|
11
|
+
const roleCode = typeof ctx.body.roleCode === "string" ? ctx.body.roleCode : "";
|
|
12
|
+
if (roleCode.length === 0) {
|
|
13
|
+
return befly.tool.No("参数不合法");
|
|
19
14
|
}
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
const rawApiPaths = Array.isArray(role.data.apis) ? role.data.apis : [];
|
|
23
|
-
const apiPaths = rawApiPaths.map((p: unknown) => (typeof p === "string" ? p.trim() : "")).filter((p: string) => p.length > 0);
|
|
24
|
-
|
|
16
|
+
const apiPaths = await befly.cache.getRolePermissions(roleCode);
|
|
25
17
|
return befly.tool.Yes("操作成功", { apiPaths: apiPaths });
|
|
26
18
|
}
|
|
27
19
|
};
|
package/apis/role/menuSave.ts
CHANGED
|
@@ -10,6 +10,11 @@ const route: ApiRoute = {
|
|
|
10
10
|
menuPaths: adminRoleTable.menus
|
|
11
11
|
},
|
|
12
12
|
handler: async (befly, ctx) => {
|
|
13
|
+
const roleCode = typeof ctx.body.roleCode === "string" ? ctx.body.roleCode : "";
|
|
14
|
+
if (roleCode.length === 0) {
|
|
15
|
+
return befly.tool.No("参数不合法");
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
let menuPaths: string[] = [];
|
|
14
19
|
try {
|
|
15
20
|
menuPaths = normalizePathnameListInput(ctx.body.menuPaths, "menuPaths", false);
|
|
@@ -20,7 +25,7 @@ const route: ApiRoute = {
|
|
|
20
25
|
// 查询角色是否存在
|
|
21
26
|
const role = await befly.db.getOne({
|
|
22
27
|
table: "addon_admin_role",
|
|
23
|
-
where: { code:
|
|
28
|
+
where: { code: roleCode }
|
|
24
29
|
});
|
|
25
30
|
|
|
26
31
|
if (!role.data?.id) {
|
|
@@ -30,12 +35,15 @@ const route: ApiRoute = {
|
|
|
30
35
|
// 直接使用数组,数据库会自动处理存储
|
|
31
36
|
await befly.db.updData({
|
|
32
37
|
table: "addon_admin_role",
|
|
33
|
-
where: { code:
|
|
38
|
+
where: { code: roleCode },
|
|
34
39
|
data: {
|
|
35
40
|
menus: menuPaths
|
|
36
41
|
}
|
|
37
42
|
});
|
|
38
43
|
|
|
44
|
+
// 增量刷新 Redis 菜单权限缓存
|
|
45
|
+
await befly.cache.refreshRoleMenuPermissions(roleCode, menuPaths);
|
|
46
|
+
|
|
39
47
|
return befly.tool.Yes("操作成功");
|
|
40
48
|
}
|
|
41
49
|
};
|
package/apis/role/menus.ts
CHANGED
|
@@ -8,19 +8,12 @@ const route: ApiRoute = {
|
|
|
8
8
|
roleCode: adminRoleTable.code
|
|
9
9
|
},
|
|
10
10
|
handler: async (befly, ctx) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
where: { code: ctx.body.roleCode }
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
if (!role.data?.id) {
|
|
18
|
-
return befly.tool.No("角色不存在");
|
|
11
|
+
const roleCode = typeof ctx.body.roleCode === "string" ? ctx.body.roleCode : "";
|
|
12
|
+
if (roleCode.length === 0) {
|
|
13
|
+
return befly.tool.No("参数不合法");
|
|
19
14
|
}
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
const menuPaths = Array.isArray(role.data.menus) ? role.data.menus : [];
|
|
23
|
-
|
|
16
|
+
const menuPaths = await befly.cache.getRoleMenuPermissions(roleCode);
|
|
24
17
|
return befly.tool.Yes("操作成功", menuPaths);
|
|
25
18
|
}
|
|
26
19
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@befly-addon/admin",
|
|
3
|
-
"version": "1.8.
|
|
4
|
-
"gitHead": "
|
|
3
|
+
"version": "1.8.8",
|
|
4
|
+
"gitHead": "8397629cd2bc2e37d91c3b15773af52ac8ff7681",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Befly - 管理后台功能组件",
|
|
7
7
|
"keywords": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"ua-parser-js": "^2.0.8"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"befly": "^3.16.
|
|
57
|
+
"befly": "^3.16.6"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"befly": "^3.14.0"
|