befly 3.17.0 → 3.17.2
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/README.md +6 -0
- package/apis/admin/cacheRefresh.js +122 -0
- package/apis/admin/del.js +34 -0
- package/apis/admin/detail.js +23 -0
- package/apis/admin/ins.js +69 -0
- package/apis/admin/list.js +28 -0
- package/apis/admin/upd.js +95 -0
- package/apis/api/all.js +24 -0
- package/apis/api/list.js +31 -0
- package/apis/auth/login.js +123 -0
- package/apis/auth/sendSmsCode.js +24 -0
- package/apis/dashboard/configStatus.js +39 -0
- package/apis/dashboard/environmentInfo.js +43 -0
- package/apis/dashboard/performanceMetrics.js +20 -0
- package/apis/dashboard/permissionStats.js +27 -0
- package/apis/dashboard/serviceStatus.js +75 -0
- package/apis/dashboard/systemInfo.js +19 -0
- package/apis/dashboard/systemOverview.js +30 -0
- package/apis/dashboard/systemResources.js +106 -0
- package/apis/dict/all.js +23 -0
- package/apis/dict/del.js +16 -0
- package/apis/dict/detail.js +27 -0
- package/apis/dict/ins.js +51 -0
- package/apis/dict/items.js +30 -0
- package/apis/dict/list.js +36 -0
- package/apis/dict/upd.js +74 -0
- package/apis/dictType/all.js +16 -0
- package/apis/dictType/del.js +38 -0
- package/apis/dictType/detail.js +20 -0
- package/apis/dictType/ins.js +37 -0
- package/apis/dictType/list.js +26 -0
- package/apis/dictType/upd.js +51 -0
- package/apis/email/config.js +25 -0
- package/apis/email/logList.js +23 -0
- package/apis/email/send.js +66 -0
- package/apis/email/verify.js +21 -0
- package/apis/loginLog/list.js +23 -0
- package/apis/menu/all.js +41 -0
- package/apis/menu/list.js +25 -0
- package/apis/operateLog/list.js +23 -0
- package/apis/role/all.js +21 -0
- package/apis/role/apiSave.js +43 -0
- package/apis/role/apis.js +22 -0
- package/apis/role/del.js +49 -0
- package/apis/role/detail.js +32 -0
- package/apis/role/ins.js +46 -0
- package/apis/role/list.js +27 -0
- package/apis/role/menuSave.js +42 -0
- package/apis/role/menus.js +22 -0
- package/apis/role/save.js +40 -0
- package/apis/role/upd.js +50 -0
- package/apis/sysConfig/all.js +16 -0
- package/apis/sysConfig/del.js +36 -0
- package/apis/sysConfig/get.js +49 -0
- package/apis/sysConfig/ins.js +50 -0
- package/apis/sysConfig/list.js +24 -0
- package/apis/sysConfig/upd.js +62 -0
- package/checks/api.js +55 -0
- package/checks/config.js +107 -0
- package/checks/hook.js +38 -0
- package/checks/menu.js +58 -0
- package/checks/plugin.js +38 -0
- package/checks/table.js +78 -0
- package/configs/beflyConfig.json +61 -0
- package/configs/beflyMenus.json +85 -0
- package/configs/constConfig.js +34 -0
- package/configs/regexpAlias.json +55 -0
- package/hooks/auth.js +34 -0
- package/hooks/cors.js +39 -0
- package/hooks/parser.js +90 -0
- package/hooks/permission.js +71 -0
- package/hooks/validator.js +43 -0
- package/index.js +326 -0
- package/lib/cacheHelper.js +483 -0
- package/lib/cacheKeys.js +42 -0
- package/lib/connect.js +120 -0
- package/lib/dbHelper/builders.js +698 -0
- package/lib/dbHelper/context.js +131 -0
- package/lib/dbHelper/dataOps.js +505 -0
- package/lib/dbHelper/execute.js +65 -0
- package/lib/dbHelper/index.js +27 -0
- package/lib/dbHelper/transaction.js +43 -0
- package/lib/dbHelper/util.js +58 -0
- package/lib/dbHelper/validate.js +549 -0
- package/lib/emailHelper.js +110 -0
- package/lib/logger.js +604 -0
- package/lib/redisHelper.js +684 -0
- package/lib/sqlBuilder/batch.js +113 -0
- package/lib/sqlBuilder/check.js +150 -0
- package/lib/sqlBuilder/compiler.js +347 -0
- package/lib/sqlBuilder/errors.js +60 -0
- package/lib/sqlBuilder/index.js +218 -0
- package/lib/sqlBuilder/parser.js +296 -0
- package/lib/sqlBuilder/util.js +260 -0
- package/lib/validator.js +303 -0
- package/package.json +19 -12
- package/paths.js +112 -0
- package/plugins/cache.js +16 -0
- package/plugins/config.js +11 -0
- package/plugins/email.js +27 -0
- package/plugins/logger.js +20 -0
- package/plugins/mysql.js +36 -0
- package/plugins/redis.js +34 -0
- package/plugins/tool.js +155 -0
- package/router/api.js +140 -0
- package/router/static.js +71 -0
- package/sql/admin.sql +18 -0
- package/sql/api.sql +12 -0
- package/sql/dict.sql +13 -0
- package/sql/dictType.sql +12 -0
- package/sql/emailLog.sql +20 -0
- package/sql/loginLog.sql +25 -0
- package/sql/menu.sql +12 -0
- package/sql/operateLog.sql +22 -0
- package/sql/role.sql +14 -0
- package/sql/sysConfig.sql +16 -0
- package/sync/api.js +93 -0
- package/sync/cache.js +13 -0
- package/sync/dev.js +171 -0
- package/sync/menu.js +99 -0
- package/tables/admin.json +56 -0
- package/tables/api.json +26 -0
- package/tables/dict.json +30 -0
- package/tables/dictType.json +24 -0
- package/tables/emailLog.json +61 -0
- package/tables/loginLog.json +86 -0
- package/tables/menu.json +24 -0
- package/tables/operateLog.json +68 -0
- package/tables/role.json +32 -0
- package/tables/sysConfig.json +43 -0
- package/utils/calcPerfTime.js +13 -0
- package/utils/cors.js +17 -0
- package/utils/deepMerge.js +78 -0
- package/utils/fieldClear.js +65 -0
- package/utils/formatYmdHms.js +23 -0
- package/utils/formatZodIssues.js +109 -0
- package/utils/getClientIp.js +47 -0
- package/utils/importDefault.js +51 -0
- package/utils/is.js +462 -0
- package/utils/loggerUtils.js +185 -0
- package/utils/processInfo.js +39 -0
- package/utils/regexpUtil.js +52 -0
- package/utils/response.js +114 -0
- package/utils/scanFiles.js +124 -0
- package/utils/scanSources.js +68 -0
- package/utils/sortModules.js +75 -0
- package/utils/toSessionTtlSeconds.js +14 -0
- package/utils/util.js +374 -0
- package/befly.js +0 -16413
- package/befly.min.js +0 -72
package/sql/emailLog.sql
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS `email_log` (
|
|
2
|
+
`id` BIGINT NOT NULL,
|
|
3
|
+
`admin_id` BIGINT NOT NULL DEFAULT 0,
|
|
4
|
+
`username` VARCHAR(100) NOT NULL DEFAULT '',
|
|
5
|
+
`nickname` VARCHAR(100) NOT NULL DEFAULT '',
|
|
6
|
+
`to_email` VARCHAR(200) NOT NULL DEFAULT '',
|
|
7
|
+
`subject` VARCHAR(200) NOT NULL DEFAULT '',
|
|
8
|
+
`content` TEXT NULL,
|
|
9
|
+
`cc_email` VARCHAR(500) NOT NULL DEFAULT '',
|
|
10
|
+
`bcc_email` VARCHAR(500) NOT NULL DEFAULT '',
|
|
11
|
+
`send_time` BIGINT NOT NULL DEFAULT 0,
|
|
12
|
+
`send_result` TINYINT NOT NULL DEFAULT 0,
|
|
13
|
+
`message_id` VARCHAR(200) NOT NULL DEFAULT '',
|
|
14
|
+
`fail_reason` VARCHAR(500) NOT NULL DEFAULT '',
|
|
15
|
+
`state` TINYINT NOT NULL DEFAULT 1,
|
|
16
|
+
`created_at` BIGINT NOT NULL DEFAULT 0,
|
|
17
|
+
`updated_at` BIGINT NOT NULL DEFAULT 0,
|
|
18
|
+
`deleted_at` BIGINT NULL DEFAULT NULL,
|
|
19
|
+
PRIMARY KEY (`id`)
|
|
20
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
package/sql/loginLog.sql
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS `login_log` (
|
|
2
|
+
`id` BIGINT NOT NULL,
|
|
3
|
+
`admin_id` BIGINT NOT NULL DEFAULT 0,
|
|
4
|
+
`username` VARCHAR(50) NOT NULL DEFAULT '',
|
|
5
|
+
`nickname` VARCHAR(50) NOT NULL DEFAULT '',
|
|
6
|
+
`ip` VARCHAR(50) NOT NULL DEFAULT '',
|
|
7
|
+
`user_agent` VARCHAR(500) NOT NULL DEFAULT '',
|
|
8
|
+
`browser_name` VARCHAR(50) NOT NULL DEFAULT '',
|
|
9
|
+
`browser_version` VARCHAR(50) NOT NULL DEFAULT '',
|
|
10
|
+
`os_name` VARCHAR(50) NOT NULL DEFAULT '',
|
|
11
|
+
`os_version` VARCHAR(50) NOT NULL DEFAULT '',
|
|
12
|
+
`device_type` VARCHAR(20) NOT NULL DEFAULT '',
|
|
13
|
+
`device_vendor` VARCHAR(50) NOT NULL DEFAULT '',
|
|
14
|
+
`device_model` VARCHAR(50) NOT NULL DEFAULT '',
|
|
15
|
+
`engine_name` VARCHAR(50) NOT NULL DEFAULT '',
|
|
16
|
+
`cpu_architecture` VARCHAR(20) NOT NULL DEFAULT '',
|
|
17
|
+
`login_time` BIGINT NOT NULL DEFAULT 0,
|
|
18
|
+
`login_result` TINYINT NOT NULL DEFAULT 0,
|
|
19
|
+
`fail_reason` VARCHAR(200) NOT NULL DEFAULT '',
|
|
20
|
+
`state` TINYINT NOT NULL DEFAULT 1,
|
|
21
|
+
`created_at` BIGINT NOT NULL DEFAULT 0,
|
|
22
|
+
`updated_at` BIGINT NOT NULL DEFAULT 0,
|
|
23
|
+
`deleted_at` BIGINT NULL DEFAULT NULL,
|
|
24
|
+
PRIMARY KEY (`id`)
|
|
25
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
package/sql/menu.sql
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS `menu` (
|
|
2
|
+
`id` BIGINT NOT NULL,
|
|
3
|
+
`name` VARCHAR(50) NOT NULL DEFAULT '',
|
|
4
|
+
`path` VARCHAR(150) NOT NULL DEFAULT '',
|
|
5
|
+
`sort` INT NOT NULL DEFAULT 0,
|
|
6
|
+
`parent_path` VARCHAR(200) NOT NULL DEFAULT '',
|
|
7
|
+
`state` TINYINT NOT NULL DEFAULT 1,
|
|
8
|
+
`created_at` BIGINT NOT NULL DEFAULT 0,
|
|
9
|
+
`updated_at` BIGINT NOT NULL DEFAULT 0,
|
|
10
|
+
`deleted_at` BIGINT NULL DEFAULT NULL,
|
|
11
|
+
PRIMARY KEY (`id`)
|
|
12
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS `operate_log` (
|
|
2
|
+
`id` BIGINT NOT NULL,
|
|
3
|
+
`admin_id` BIGINT NOT NULL DEFAULT 0,
|
|
4
|
+
`username` VARCHAR(50) NOT NULL DEFAULT '',
|
|
5
|
+
`nickname` VARCHAR(50) NOT NULL DEFAULT '',
|
|
6
|
+
`ip` VARCHAR(50) NOT NULL DEFAULT '',
|
|
7
|
+
`module` VARCHAR(50) NOT NULL DEFAULT '',
|
|
8
|
+
`action` VARCHAR(50) NOT NULL DEFAULT '',
|
|
9
|
+
`method` VARCHAR(10) NOT NULL DEFAULT '',
|
|
10
|
+
`path` VARCHAR(200) NOT NULL DEFAULT '',
|
|
11
|
+
`params` TEXT NULL,
|
|
12
|
+
`result` TINYINT NOT NULL DEFAULT 0,
|
|
13
|
+
`response` TEXT NULL,
|
|
14
|
+
`duration` BIGINT NOT NULL DEFAULT 0,
|
|
15
|
+
`operate_time` BIGINT NOT NULL DEFAULT 0,
|
|
16
|
+
`remark` VARCHAR(500) NOT NULL DEFAULT '',
|
|
17
|
+
`state` TINYINT NOT NULL DEFAULT 1,
|
|
18
|
+
`created_at` BIGINT NOT NULL DEFAULT 0,
|
|
19
|
+
`updated_at` BIGINT NOT NULL DEFAULT 0,
|
|
20
|
+
`deleted_at` BIGINT NULL DEFAULT NULL,
|
|
21
|
+
PRIMARY KEY (`id`)
|
|
22
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
package/sql/role.sql
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS `role` (
|
|
2
|
+
`id` BIGINT NOT NULL,
|
|
3
|
+
`name` VARCHAR(50) NOT NULL DEFAULT '',
|
|
4
|
+
`code` VARCHAR(50) NOT NULL DEFAULT '',
|
|
5
|
+
`description` VARCHAR(200) NOT NULL DEFAULT '',
|
|
6
|
+
`menus` JSON NULL,
|
|
7
|
+
`apis` JSON NULL,
|
|
8
|
+
`sort` INT NOT NULL DEFAULT 0,
|
|
9
|
+
`state` TINYINT NOT NULL DEFAULT 1,
|
|
10
|
+
`created_at` BIGINT NOT NULL DEFAULT 0,
|
|
11
|
+
`updated_at` BIGINT NOT NULL DEFAULT 0,
|
|
12
|
+
`deleted_at` BIGINT NULL DEFAULT NULL,
|
|
13
|
+
PRIMARY KEY (`id`)
|
|
14
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS `sys_config` (
|
|
2
|
+
`id` BIGINT NOT NULL,
|
|
3
|
+
`name` VARCHAR(50) NOT NULL DEFAULT '',
|
|
4
|
+
`code` VARCHAR(100) NOT NULL DEFAULT '',
|
|
5
|
+
`value` TEXT NULL,
|
|
6
|
+
`value_type` VARCHAR(20) NOT NULL DEFAULT '',
|
|
7
|
+
`group` VARCHAR(50) NOT NULL DEFAULT '',
|
|
8
|
+
`sort` INT NOT NULL DEFAULT 0,
|
|
9
|
+
`is_system` TINYINT NOT NULL DEFAULT 0,
|
|
10
|
+
`description` VARCHAR(500) NOT NULL DEFAULT '',
|
|
11
|
+
`state` TINYINT NOT NULL DEFAULT 1,
|
|
12
|
+
`created_at` BIGINT NOT NULL DEFAULT 0,
|
|
13
|
+
`updated_at` BIGINT NOT NULL DEFAULT 0,
|
|
14
|
+
`deleted_at` BIGINT NULL DEFAULT NULL,
|
|
15
|
+
PRIMARY KEY (`id`)
|
|
16
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
package/sync/api.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const API_TABLE_NAME = "beflyApi";
|
|
2
|
+
|
|
3
|
+
const getApiParentPath = (apiPath) => {
|
|
4
|
+
const segments = apiPath
|
|
5
|
+
.split("/")
|
|
6
|
+
.map((s) => s.trim())
|
|
7
|
+
.filter((s) => s.length > 0);
|
|
8
|
+
|
|
9
|
+
// segments 示例:
|
|
10
|
+
// - /api/app/test/hi -> ["api","app","test","hi"]
|
|
11
|
+
const take = 3;
|
|
12
|
+
const parentSegments = segments.slice(0, Math.min(take, segments.length));
|
|
13
|
+
if (parentSegments.length === 0) return "";
|
|
14
|
+
return `/${parentSegments.join("/")}`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const normalizeAuthForDb = (value) => {
|
|
18
|
+
if (value === false) {
|
|
19
|
+
return "否";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
return value.join(",");
|
|
24
|
+
}
|
|
25
|
+
return "是";
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export async function syncApi(ctx, apis) {
|
|
29
|
+
const allDbApis = await ctx.mysql.getAll({
|
|
30
|
+
table: API_TABLE_NAME,
|
|
31
|
+
fields: ["id", "path", "parentPath", "name", "auth", "state"],
|
|
32
|
+
where: { state$gte: 0 }
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// 给接口根据接口路径进行映射
|
|
36
|
+
const dbLists = allDbApis.data.lists || [];
|
|
37
|
+
const existingApiMap = new Map();
|
|
38
|
+
for (const item of dbLists) {
|
|
39
|
+
if (!existingApiMap.has(item.path)) {
|
|
40
|
+
existingApiMap.set(item.path, item);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const insList = [];
|
|
45
|
+
const updList = [];
|
|
46
|
+
const scannedPathSet = new Set();
|
|
47
|
+
for (const api of apis) {
|
|
48
|
+
scannedPathSet.add(api.apiPath);
|
|
49
|
+
|
|
50
|
+
const auth = normalizeAuthForDb(api.auth);
|
|
51
|
+
const parentPath = getApiParentPath(api.apiPath);
|
|
52
|
+
const existing = existingApiMap.get(api.apiPath);
|
|
53
|
+
|
|
54
|
+
if (existing) {
|
|
55
|
+
updList.push({
|
|
56
|
+
id: existing.id,
|
|
57
|
+
data: {
|
|
58
|
+
name: api.name,
|
|
59
|
+
path: api.apiPath,
|
|
60
|
+
parentPath: parentPath,
|
|
61
|
+
auth: auth
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
insList.push({
|
|
68
|
+
name: api.name,
|
|
69
|
+
path: api.apiPath,
|
|
70
|
+
parentPath: parentPath,
|
|
71
|
+
auth: auth
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const delIdList = [];
|
|
76
|
+
for (const item of dbLists) {
|
|
77
|
+
if (!scannedPathSet.has(item.path)) {
|
|
78
|
+
delIdList.push(item.id);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (updList.length > 0) {
|
|
83
|
+
await ctx.mysql.updBatch(API_TABLE_NAME, updList);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (insList.length > 0) {
|
|
87
|
+
await ctx.mysql.insBatch(API_TABLE_NAME, insList);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (delIdList.length > 0) {
|
|
91
|
+
await ctx.mysql.delForceBatch(API_TABLE_NAME, delIdList);
|
|
92
|
+
}
|
|
93
|
+
}
|
package/sync/cache.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export async function syncCache(ctx) {
|
|
2
|
+
// 1) 缓存接口列表
|
|
3
|
+
await ctx.cache.cacheApis();
|
|
4
|
+
|
|
5
|
+
// 2) 缓存菜单列表
|
|
6
|
+
await ctx.cache.cacheMenus();
|
|
7
|
+
|
|
8
|
+
// 3) 重建角色权限缓存(严格模式下要求 role.apis 必须为 pathname 字符串数组)
|
|
9
|
+
await ctx.cache.cacheRoleApis();
|
|
10
|
+
|
|
11
|
+
// 4) 重建角色菜单权限缓存(role.menus 为 menu.path 字符串数组)
|
|
12
|
+
await ctx.cache.cacheRoleMenus();
|
|
13
|
+
}
|
package/sync/dev.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { isNumber } from "../utils/is.js";
|
|
2
|
+
|
|
3
|
+
export async function syncDev(ctx) {
|
|
4
|
+
try {
|
|
5
|
+
const allMenus = await ctx.mysql.getAll({
|
|
6
|
+
table: "beflyMenu",
|
|
7
|
+
fields: ["path"],
|
|
8
|
+
where: { state$gte: 0 },
|
|
9
|
+
orderBy: ["id#ASC"]
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const allApis = await ctx.mysql.getAll({
|
|
13
|
+
table: "beflyApi",
|
|
14
|
+
fields: ["path"],
|
|
15
|
+
where: { state$gte: 0 },
|
|
16
|
+
orderBy: ["id#ASC"]
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const devRole = await ctx.mysql.getOne({
|
|
20
|
+
table: "beflyRole",
|
|
21
|
+
where: { code: "dev", state$gte: 0 }
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const devAdmin = await ctx.mysql.getOne({
|
|
25
|
+
table: "beflyAdmin",
|
|
26
|
+
where: { username: "dev", state$gte: 0 }
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const menuPaths = [];
|
|
30
|
+
for (const item of allMenus.data.lists) {
|
|
31
|
+
menuPaths.push(item.path);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const apiPaths = [];
|
|
35
|
+
for (const item of allApis.data.lists) {
|
|
36
|
+
apiPaths.push(item.path);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const devRoleData = {
|
|
40
|
+
code: "dev",
|
|
41
|
+
name: "开发者角色",
|
|
42
|
+
description: "拥有所有菜单和接口权限的开发者角色",
|
|
43
|
+
menus: menuPaths,
|
|
44
|
+
apis: apiPaths,
|
|
45
|
+
sort: 0
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
if (isNumber(devRole.data.id)) {
|
|
49
|
+
await ctx.mysql.updData({
|
|
50
|
+
table: "beflyRole",
|
|
51
|
+
where: { code: "dev", state$gte: 0 },
|
|
52
|
+
data: {
|
|
53
|
+
name: devRoleData.name,
|
|
54
|
+
description: devRoleData.description,
|
|
55
|
+
menus: devRoleData.menus,
|
|
56
|
+
apis: devRoleData.apis,
|
|
57
|
+
sort: devRoleData.sort,
|
|
58
|
+
state: 1
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
} else {
|
|
62
|
+
await ctx.mysql.insData({
|
|
63
|
+
table: "beflyRole",
|
|
64
|
+
data: devRoleData
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const password = ctx.tool.sha256(ctx.tool.sha256(ctx.config.devPassword));
|
|
69
|
+
|
|
70
|
+
const devAdminData = {
|
|
71
|
+
nickname: "开发者",
|
|
72
|
+
email: ctx.config.devEmail || "dev@qq.com",
|
|
73
|
+
username: "dev",
|
|
74
|
+
password: password,
|
|
75
|
+
roleCode: "dev",
|
|
76
|
+
roleType: "admin"
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
if (isNumber(devAdmin.data.id)) {
|
|
80
|
+
await ctx.mysql.updData({
|
|
81
|
+
table: "beflyAdmin",
|
|
82
|
+
where: { username: "dev" },
|
|
83
|
+
data: {
|
|
84
|
+
nickname: devAdminData.nickname,
|
|
85
|
+
email: devAdminData.email,
|
|
86
|
+
password: devAdminData.password,
|
|
87
|
+
roleCode: devAdminData.roleCode,
|
|
88
|
+
roleType: devAdminData.roleType,
|
|
89
|
+
state: 1
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
await ctx.mysql.insData({
|
|
94
|
+
table: "beflyAdmin",
|
|
95
|
+
data: {
|
|
96
|
+
nickname: devAdminData.nickname,
|
|
97
|
+
email: devAdminData.email,
|
|
98
|
+
username: devAdminData.username,
|
|
99
|
+
password: devAdminData.password,
|
|
100
|
+
roleCode: devAdminData.roleCode,
|
|
101
|
+
roleType: devAdminData.roleType,
|
|
102
|
+
state: 1
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const roles = [
|
|
108
|
+
{
|
|
109
|
+
code: "user",
|
|
110
|
+
name: "用户角色",
|
|
111
|
+
description: "普通用户角色",
|
|
112
|
+
sort: 1
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
code: "admin",
|
|
116
|
+
name: "管理员角色",
|
|
117
|
+
description: "管理员角色",
|
|
118
|
+
sort: 2
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
code: "guest",
|
|
122
|
+
name: "访客角色",
|
|
123
|
+
description: "访客角色",
|
|
124
|
+
sort: 3
|
|
125
|
+
}
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
for (const roleConfig of roles) {
|
|
129
|
+
const existingRole = await ctx.mysql.getOne({
|
|
130
|
+
table: "beflyRole",
|
|
131
|
+
where: {
|
|
132
|
+
code: roleConfig.code,
|
|
133
|
+
state$gte: 0
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (existingRole.data?.id) {
|
|
138
|
+
// 角色存在则强制更新(不做差异判断)
|
|
139
|
+
await ctx.mysql.updData({
|
|
140
|
+
table: "beflyRole",
|
|
141
|
+
where: { code: roleConfig.code, state$gte: 0 },
|
|
142
|
+
data: {
|
|
143
|
+
name: roleConfig.name,
|
|
144
|
+
description: roleConfig.description,
|
|
145
|
+
sort: roleConfig.sort,
|
|
146
|
+
state: 1
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
await ctx.mysql.insData({
|
|
151
|
+
table: "beflyRole",
|
|
152
|
+
data: {
|
|
153
|
+
code: roleConfig.code,
|
|
154
|
+
name: roleConfig.name,
|
|
155
|
+
description: roleConfig.description,
|
|
156
|
+
menus: [],
|
|
157
|
+
apis: [],
|
|
158
|
+
sort: roleConfig.sort
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
throw new Error("同步开发者数据失败", {
|
|
165
|
+
cause: error,
|
|
166
|
+
code: "runtime",
|
|
167
|
+
subsystem: "sync",
|
|
168
|
+
operation: "syncDev"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
package/sync/menu.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export function flattenMenusToDefMap(menus) {
|
|
2
|
+
// 读取配置菜单:扁平化为 path => { name, sort, parentPath }
|
|
3
|
+
// - 以 path 为唯一键:后出现的覆盖先出现的(与旧逻辑“同 path 多次同步同一条记录”一致)
|
|
4
|
+
// parentPath 规则:
|
|
5
|
+
// 1) 顶级菜单 parentPath 为空
|
|
6
|
+
// 2) 子级菜单 parentPath 为其父级完整路径
|
|
7
|
+
const menuDefMap = new Map();
|
|
8
|
+
|
|
9
|
+
for (const menu of menus) {
|
|
10
|
+
const rootPath = menu.path;
|
|
11
|
+
const children = Array.isArray(menu.children) ? menu.children : [];
|
|
12
|
+
menuDefMap.set(rootPath, {
|
|
13
|
+
path: rootPath,
|
|
14
|
+
name: menu.name,
|
|
15
|
+
sort: menu.sort,
|
|
16
|
+
parentPath: "/"
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (children.length === 0) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const child of children) {
|
|
24
|
+
const fullPath = rootPath === "/" ? child.path : `${rootPath}${child.path}`;
|
|
25
|
+
menuDefMap.set(fullPath, {
|
|
26
|
+
path: fullPath,
|
|
27
|
+
name: child.name,
|
|
28
|
+
sort: child.sort,
|
|
29
|
+
parentPath: rootPath
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return menuDefMap;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function syncMenu(ctx, menus) {
|
|
38
|
+
const menuDefMap = flattenMenusToDefMap(menus);
|
|
39
|
+
|
|
40
|
+
// 2) 批量同步(事务内):按 path diff 执行批量 insert/update/delete
|
|
41
|
+
// 读取全部菜单
|
|
42
|
+
const allExistingMenus = await ctx.mysql.getAll({
|
|
43
|
+
table: "beflyMenu",
|
|
44
|
+
fields: ["id", "name", "path", "parentPath", "sort", "state"],
|
|
45
|
+
where: { state$gte: 0 }
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const existingList = allExistingMenus.data.lists || [];
|
|
49
|
+
|
|
50
|
+
const existingMenuMap = new Map();
|
|
51
|
+
const delIdSet = new Set();
|
|
52
|
+
for (const record of existingList) {
|
|
53
|
+
if (!existingMenuMap.has(record.path)) {
|
|
54
|
+
existingMenuMap.set(record.path, record);
|
|
55
|
+
delIdSet.add(record.id);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 2) 一次性算出 insert/update(仅依赖 path diff,不使用 pid,不预生成 id)
|
|
60
|
+
const updList = [];
|
|
61
|
+
const insList = [];
|
|
62
|
+
|
|
63
|
+
for (const def of menuDefMap.values()) {
|
|
64
|
+
const existing = existingMenuMap.get(def.path);
|
|
65
|
+
if (existing) {
|
|
66
|
+
delIdSet.delete(existing.id);
|
|
67
|
+
updList.push({
|
|
68
|
+
id: existing.id,
|
|
69
|
+
data: {
|
|
70
|
+
name: def.name,
|
|
71
|
+
path: def.path,
|
|
72
|
+
parentPath: def.parentPath,
|
|
73
|
+
sort: def.sort
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} else {
|
|
77
|
+
insList.push({
|
|
78
|
+
name: def.name,
|
|
79
|
+
path: def.path,
|
|
80
|
+
parentPath: def.parentPath,
|
|
81
|
+
sort: def.sort
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (updList.length > 0) {
|
|
87
|
+
await ctx.mysql.updBatch("beflyMenu", updList);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (insList.length > 0) {
|
|
91
|
+
await ctx.mysql.insBatch("beflyMenu", insList);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 3) 删除差集(DB - 配置)
|
|
95
|
+
const delIds = Array.from(delIdSet);
|
|
96
|
+
if (delIds.length > 0) {
|
|
97
|
+
await ctx.mysql.delForceBatch("beflyMenu", delIds);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nickname": {
|
|
3
|
+
"name": "昵称",
|
|
4
|
+
"input": "string",
|
|
5
|
+
"min": 1,
|
|
6
|
+
"max": 50
|
|
7
|
+
},
|
|
8
|
+
"username": {
|
|
9
|
+
"name": "用户名",
|
|
10
|
+
"input": "@alphanumeric_",
|
|
11
|
+
"min": 2,
|
|
12
|
+
"max": 30
|
|
13
|
+
},
|
|
14
|
+
"password": {
|
|
15
|
+
"name": "密码",
|
|
16
|
+
"input": "string",
|
|
17
|
+
"min": 6,
|
|
18
|
+
"max": 500
|
|
19
|
+
},
|
|
20
|
+
"email": {
|
|
21
|
+
"name": "邮箱",
|
|
22
|
+
"input": "@email",
|
|
23
|
+
"max": 100
|
|
24
|
+
},
|
|
25
|
+
"phone": {
|
|
26
|
+
"name": "手机号",
|
|
27
|
+
"input": "@phone",
|
|
28
|
+
"max": 20
|
|
29
|
+
},
|
|
30
|
+
"avatar": {
|
|
31
|
+
"name": "头像",
|
|
32
|
+
"input": "string",
|
|
33
|
+
"max": 500
|
|
34
|
+
},
|
|
35
|
+
"roleCode": {
|
|
36
|
+
"name": "角色编码",
|
|
37
|
+
"input": "@alphanumeric_",
|
|
38
|
+
"min": 2,
|
|
39
|
+
"max": 50
|
|
40
|
+
},
|
|
41
|
+
"roleType": {
|
|
42
|
+
"name": "角色类型",
|
|
43
|
+
"input": "admin|user",
|
|
44
|
+
"min": 4,
|
|
45
|
+
"max": 5
|
|
46
|
+
},
|
|
47
|
+
"lastLoginTime": {
|
|
48
|
+
"name": "最后登录时间",
|
|
49
|
+
"input": "number"
|
|
50
|
+
},
|
|
51
|
+
"lastLoginIp": {
|
|
52
|
+
"name": "最后登录IP",
|
|
53
|
+
"input": "string",
|
|
54
|
+
"max": 50
|
|
55
|
+
}
|
|
56
|
+
}
|
package/tables/api.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": {
|
|
3
|
+
"name": "接口名称",
|
|
4
|
+
"input": "string",
|
|
5
|
+
"min": 2,
|
|
6
|
+
"max": 100
|
|
7
|
+
},
|
|
8
|
+
"auth": {
|
|
9
|
+
"name": "是否需要登录",
|
|
10
|
+
"input": "string",
|
|
11
|
+
"min": 1,
|
|
12
|
+
"max": 200
|
|
13
|
+
},
|
|
14
|
+
"path": {
|
|
15
|
+
"name": "接口路径",
|
|
16
|
+
"input": "string",
|
|
17
|
+
"min": 1,
|
|
18
|
+
"max": 200
|
|
19
|
+
},
|
|
20
|
+
"parentPath": {
|
|
21
|
+
"name": "父级路径",
|
|
22
|
+
"input": "string",
|
|
23
|
+
"min": 1,
|
|
24
|
+
"max": 200
|
|
25
|
+
}
|
|
26
|
+
}
|
package/tables/dict.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"typeCode": {
|
|
3
|
+
"name": "字典类型代码",
|
|
4
|
+
"input": "@alphanumeric_",
|
|
5
|
+
"min": 2,
|
|
6
|
+
"max": 50
|
|
7
|
+
},
|
|
8
|
+
"key": {
|
|
9
|
+
"name": "字典键",
|
|
10
|
+
"input": "@alphanumeric_",
|
|
11
|
+
"min": 1,
|
|
12
|
+
"max": 50
|
|
13
|
+
},
|
|
14
|
+
"label": {
|
|
15
|
+
"name": "字典标签",
|
|
16
|
+
"input": "string",
|
|
17
|
+
"min": 1,
|
|
18
|
+
"max": 100
|
|
19
|
+
},
|
|
20
|
+
"sort": {
|
|
21
|
+
"name": "排序",
|
|
22
|
+
"input": "number",
|
|
23
|
+
"max": 9999
|
|
24
|
+
},
|
|
25
|
+
"remark": {
|
|
26
|
+
"name": "备注",
|
|
27
|
+
"input": "string",
|
|
28
|
+
"max": 200
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"code": {
|
|
3
|
+
"name": "类型代码",
|
|
4
|
+
"input": "@alphanumeric_",
|
|
5
|
+
"min": 2,
|
|
6
|
+
"max": 50
|
|
7
|
+
},
|
|
8
|
+
"name": {
|
|
9
|
+
"name": "类型名称",
|
|
10
|
+
"input": "string",
|
|
11
|
+
"min": 2,
|
|
12
|
+
"max": 50
|
|
13
|
+
},
|
|
14
|
+
"description": {
|
|
15
|
+
"name": "描述",
|
|
16
|
+
"input": "string",
|
|
17
|
+
"max": 200
|
|
18
|
+
},
|
|
19
|
+
"sort": {
|
|
20
|
+
"name": "排序",
|
|
21
|
+
"input": "number",
|
|
22
|
+
"max": 9999
|
|
23
|
+
}
|
|
24
|
+
}
|