befly 3.8.27 → 3.8.30
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 +8 -6
- package/checks/checkApi.ts +2 -1
- package/checks/checkTable.ts +3 -2
- package/hooks/parser.ts +5 -3
- package/hooks/permission.ts +12 -5
- package/lib/cacheHelper.ts +76 -62
- package/lib/connect.ts +8 -35
- package/lib/dbHelper.ts +14 -11
- package/lib/jwt.ts +58 -437
- package/lib/logger.ts +76 -197
- package/lib/redisHelper.ts +163 -1
- package/lib/sqlBuilder.ts +2 -1
- package/lib/validator.ts +9 -8
- package/loader/loadApis.ts +4 -7
- package/loader/loadHooks.ts +2 -2
- package/loader/loadPlugins.ts +4 -4
- package/main.ts +4 -17
- package/package.json +10 -9
- package/paths.ts +0 -6
- package/plugins/db.ts +2 -2
- package/plugins/jwt.ts +5 -5
- package/plugins/redis.ts +1 -1
- package/router/api.ts +2 -2
- package/router/static.ts +1 -2
- package/sync/syncAll.ts +2 -2
- package/sync/syncApi.ts +10 -7
- package/sync/syncDb/apply.ts +11 -11
- package/sync/syncDb/constants.ts +61 -12
- package/sync/syncDb/ddl.ts +7 -7
- package/sync/syncDb/helpers.ts +3 -3
- package/sync/syncDb/schema.ts +16 -19
- package/sync/syncDb/table.ts +6 -5
- package/sync/syncDb/tableCreate.ts +7 -7
- package/sync/syncDb/types.ts +3 -2
- package/sync/syncDb/version.ts +4 -4
- package/sync/syncDb.ts +11 -10
- package/sync/syncDev.ts +10 -48
- package/sync/syncMenu.ts +11 -8
- package/tests/cacheHelper.test.ts +327 -0
- package/tests/dbHelper-columns.test.ts +5 -20
- package/tests/dbHelper-execute.test.ts +14 -68
- package/tests/fields-redis-cache.test.ts +5 -3
- package/tests/integration.test.ts +15 -26
- package/tests/jwt.test.ts +36 -94
- package/tests/logger.test.ts +32 -34
- package/tests/redisHelper.test.ts +270 -0
- package/tests/redisKeys.test.ts +76 -0
- package/tests/sync-connection.test.ts +0 -6
- package/tests/syncDb-apply.test.ts +3 -2
- package/tests/syncDb-constants.test.ts +15 -14
- package/tests/syncDb-ddl.test.ts +3 -2
- package/tests/syncDb-helpers.test.ts +3 -2
- package/tests/syncDb-schema.test.ts +3 -3
- package/tests/syncDb-types.test.ts +3 -2
- package/tests/util.test.ts +5 -1
- package/types/befly.d.ts +2 -15
- package/types/common.d.ts +11 -93
- package/types/database.d.ts +216 -5
- package/types/index.ts +1 -0
- package/types/logger.d.ts +11 -41
- package/types/table.d.ts +213 -0
- package/hooks/_rateLimit.ts +0 -64
- package/lib/regexAliases.ts +0 -59
- package/lib/xml.ts +0 -383
- package/tests/xml.test.ts +0 -101
package/sync/syncDb/table.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { snakeCase } from 'es-toolkit/string';
|
|
11
11
|
import { Logger } from '../../lib/logger.js';
|
|
12
|
-
import {
|
|
12
|
+
import { isMySQL, isPG, CHANGE_TYPE_LABELS, getTypeMapping } from './constants.js';
|
|
13
13
|
import { logFieldChange, resolveDefaultValue, generateDefaultSql, isStringOrArrayType } from './helpers.js';
|
|
14
14
|
import { generateDDLClause, isPgCompatibleTypeChange } from './ddl.js';
|
|
15
15
|
import { getTableColumns, getTableIndexes } from './schema.js';
|
|
@@ -92,9 +92,9 @@ export async function modifyTable(sql: SQL, tableName: string, fields: Record<st
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
if (v !== null && v !== '') {
|
|
95
|
-
if (
|
|
95
|
+
if (isPG()) {
|
|
96
96
|
defaultClauses.push(`ALTER COLUMN "${dbFieldName}" SET DEFAULT ${v}`);
|
|
97
|
-
} else if (
|
|
97
|
+
} else if (isMySQL() && onlyDefaultChanged) {
|
|
98
98
|
// MySQL 的 TEXT/BLOB 不允许 DEFAULT,跳过 text 类型
|
|
99
99
|
if (fieldDef.type !== 'text') {
|
|
100
100
|
defaultClauses.push(`ALTER COLUMN \`${dbFieldName}\` SET DEFAULT ${v}`);
|
|
@@ -112,7 +112,8 @@ export async function modifyTable(sql: SQL, tableName: string, fields: Record<st
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
if (hasTypeChange) {
|
|
115
|
-
|
|
115
|
+
const typeMapping = getTypeMapping();
|
|
116
|
+
if (isPG() && isPgCompatibleTypeChange(existingColumns[dbFieldName].type, typeMapping[fieldDef.type].toLowerCase())) {
|
|
116
117
|
Logger.debug(`[PG兼容类型变更] ${tableName}.${dbFieldName} ${existingColumns[dbFieldName].type} -> ${typeMapping[fieldDef.type].toLowerCase()} 允许执行`);
|
|
117
118
|
}
|
|
118
119
|
}
|
|
@@ -155,7 +156,7 @@ export async function modifyTable(sql: SQL, tableName: string, fields: Record<st
|
|
|
155
156
|
|
|
156
157
|
// PG 列注释处理
|
|
157
158
|
const commentActions = [];
|
|
158
|
-
if (
|
|
159
|
+
if (isPG()) {
|
|
159
160
|
for (const [fieldKey, fieldDef] of Object.entries(fields)) {
|
|
160
161
|
// 转换字段名为下划线格式
|
|
161
162
|
const dbFieldName = snakeCase(fieldKey);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { snakeCase } from 'es-toolkit/string';
|
|
12
12
|
import { Logger } from '../../lib/logger.js';
|
|
13
|
-
import {
|
|
13
|
+
import { isMySQL, isPG, IS_PLAN, MYSQL_TABLE_CONFIG } from './constants.js';
|
|
14
14
|
import { quoteIdentifier } from './helpers.js';
|
|
15
15
|
import { buildSystemColumnDefs, buildBusinessColumnDefs, buildIndexSQL } from './ddl.js';
|
|
16
16
|
import { getTableIndexes } from './schema.js';
|
|
@@ -73,7 +73,7 @@ async function createTableIndexes(sql: SQL, tableName: string, fields: Record<st
|
|
|
73
73
|
|
|
74
74
|
// 获取现有索引(MySQL 不支持 IF NOT EXISTS,需要先检查)
|
|
75
75
|
let existingIndexes: Record<string, string[]> = {};
|
|
76
|
-
if (
|
|
76
|
+
if (isMySQL()) {
|
|
77
77
|
existingIndexes = await getTableIndexes(sql, tableName, dbName);
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -81,7 +81,7 @@ async function createTableIndexes(sql: SQL, tableName: string, fields: Record<st
|
|
|
81
81
|
for (const sysField of systemIndexFields) {
|
|
82
82
|
const indexName = `idx_${sysField}`;
|
|
83
83
|
// MySQL 跳过已存在的索引
|
|
84
|
-
if (
|
|
84
|
+
if (isMySQL() && existingIndexes[indexName]) {
|
|
85
85
|
continue;
|
|
86
86
|
}
|
|
87
87
|
const stmt = buildIndexSQL(tableName, indexName, sysField, 'create');
|
|
@@ -100,7 +100,7 @@ async function createTableIndexes(sql: SQL, tableName: string, fields: Record<st
|
|
|
100
100
|
if (fieldDef.index === true) {
|
|
101
101
|
const indexName = `idx_${dbFieldName}`;
|
|
102
102
|
// MySQL 跳过已存在的索引
|
|
103
|
-
if (
|
|
103
|
+
if (isMySQL() && existingIndexes[indexName]) {
|
|
104
104
|
continue;
|
|
105
105
|
}
|
|
106
106
|
const stmt = buildIndexSQL(tableName, indexName, dbFieldName, 'create');
|
|
@@ -135,7 +135,7 @@ export async function createTable(sql: SQL, tableName: string, fields: Record<st
|
|
|
135
135
|
const cols = colDefs.join(',\n ');
|
|
136
136
|
const tableQuoted = quoteIdentifier(tableName);
|
|
137
137
|
const { ENGINE, CHARSET, COLLATE } = MYSQL_TABLE_CONFIG;
|
|
138
|
-
const createSQL =
|
|
138
|
+
const createSQL = isMySQL()
|
|
139
139
|
? `CREATE TABLE ${tableQuoted} (
|
|
140
140
|
${cols}
|
|
141
141
|
) ENGINE=${ENGINE} DEFAULT CHARSET=${CHARSET} COLLATE=${COLLATE}`
|
|
@@ -150,9 +150,9 @@ export async function createTable(sql: SQL, tableName: string, fields: Record<st
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
// PostgreSQL: 添加列注释
|
|
153
|
-
if (
|
|
153
|
+
if (isPG() && !IS_PLAN) {
|
|
154
154
|
await addPostgresComments(sql, tableName, fields);
|
|
155
|
-
} else if (
|
|
155
|
+
} else if (isPG() && IS_PLAN) {
|
|
156
156
|
// 计划模式也要输出注释语句
|
|
157
157
|
await addPostgresComments(sql, tableName, fields);
|
|
158
158
|
}
|
package/sync/syncDb/types.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - 类型判断工具
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { isMySQL, getTypeMapping } from './constants.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* 判断是否为字符串或数组类型(需要长度参数)
|
|
@@ -42,12 +42,13 @@ export function isStringOrArrayType(fieldType: string): boolean {
|
|
|
42
42
|
* getSqlType('array_text', null) // => 'MEDIUMTEXT'
|
|
43
43
|
*/
|
|
44
44
|
export function getSqlType(fieldType: string, fieldMax: number | null, unsigned: boolean = false): string {
|
|
45
|
+
const typeMapping = getTypeMapping();
|
|
45
46
|
if (isStringOrArrayType(fieldType)) {
|
|
46
47
|
return `${typeMapping[fieldType]}(${fieldMax})`;
|
|
47
48
|
}
|
|
48
49
|
// 处理 UNSIGNED 修饰符(仅 MySQL number 类型)
|
|
49
50
|
const baseType = typeMapping[fieldType] || 'TEXT';
|
|
50
|
-
if (
|
|
51
|
+
if (isMySQL() && fieldType === 'number' && unsigned) {
|
|
51
52
|
return `${baseType} UNSIGNED`;
|
|
52
53
|
}
|
|
53
54
|
return baseType;
|
package/sync/syncDb/version.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Logger } from '../../lib/logger.js';
|
|
9
|
-
import { DB_VERSION_REQUIREMENTS,
|
|
9
|
+
import { DB_VERSION_REQUIREMENTS, isMySQL, isPG, isSQLite } from './constants.js';
|
|
10
10
|
import type { SQL } from 'bun';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -23,7 +23,7 @@ import type { SQL } from 'bun';
|
|
|
23
23
|
export async function ensureDbVersion(sql: SQL): Promise<void> {
|
|
24
24
|
if (!sql) throw new Error('SQL 客户端未初始化');
|
|
25
25
|
|
|
26
|
-
if (
|
|
26
|
+
if (isMySQL()) {
|
|
27
27
|
const r = await sql`SELECT VERSION() AS version`;
|
|
28
28
|
if (!r || r.length === 0 || !r[0]?.version) {
|
|
29
29
|
throw new Error('无法获取 MySQL 版本信息');
|
|
@@ -36,7 +36,7 @@ export async function ensureDbVersion(sql: SQL): Promise<void> {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
if (
|
|
39
|
+
if (isPG()) {
|
|
40
40
|
const r = await sql`SELECT version() AS version`;
|
|
41
41
|
if (!r || r.length === 0 || !r[0]?.version) {
|
|
42
42
|
throw new Error('无法获取 PostgreSQL 版本信息');
|
|
@@ -50,7 +50,7 @@ export async function ensureDbVersion(sql: SQL): Promise<void> {
|
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
if (
|
|
53
|
+
if (isSQLite()) {
|
|
54
54
|
const r = await sql`SELECT sqlite_version() AS version`;
|
|
55
55
|
if (!r || r.length === 0 || !r[0]?.version) {
|
|
56
56
|
throw new Error('无法获取 SQLite 版本信息');
|
package/sync/syncDb.ts
CHANGED
|
@@ -13,7 +13,9 @@ import { snakeCase } from 'es-toolkit/string';
|
|
|
13
13
|
import { Connect } from '../lib/connect.js';
|
|
14
14
|
import { RedisHelper } from '../lib/redisHelper.js';
|
|
15
15
|
import { checkTable } from '../checks/checkTable.js';
|
|
16
|
-
import { scanFiles
|
|
16
|
+
import { scanFiles } from 'befly-shared/scanFiles';
|
|
17
|
+
import { scanAddons, addonDirExists, getAddonDir } from 'befly-shared/addonHelper';
|
|
18
|
+
import { RedisKeys } from 'befly-shared/redisKeys';
|
|
17
19
|
import { Logger } from '../lib/logger.js';
|
|
18
20
|
import { projectDir } from '../paths.js';
|
|
19
21
|
|
|
@@ -23,6 +25,7 @@ import { tableExists } from './syncDb/schema.js';
|
|
|
23
25
|
import { modifyTable } from './syncDb/table.js';
|
|
24
26
|
import { createTable } from './syncDb/tableCreate.js';
|
|
25
27
|
import { applyFieldDefaults } from './syncDb/helpers.js';
|
|
28
|
+
import { setDbType } from './syncDb/constants.js';
|
|
26
29
|
import type { SQL } from 'bun';
|
|
27
30
|
import type { BeflyOptions, SyncDbOptions } from '../types/index.js';
|
|
28
31
|
|
|
@@ -46,6 +49,10 @@ export async function syncDbCommand(config: BeflyOptions, options: SyncDbOptions
|
|
|
46
49
|
// 清空处理记录
|
|
47
50
|
processedTables.length = 0;
|
|
48
51
|
|
|
52
|
+
// 设置数据库类型(从配置获取)
|
|
53
|
+
const dbType = config.db?.type || 'mysql';
|
|
54
|
+
setDbType(dbType);
|
|
55
|
+
|
|
49
56
|
// 验证表定义文件
|
|
50
57
|
await checkTable();
|
|
51
58
|
|
|
@@ -129,17 +136,11 @@ export async function syncDbCommand(config: BeflyOptions, options: SyncDbOptions
|
|
|
129
136
|
// 清理 Redis 缓存(如果有表被处理)
|
|
130
137
|
if (processedTables.length > 0) {
|
|
131
138
|
const redisHelper = new RedisHelper();
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
await redisHelper.del(cacheKey);
|
|
136
|
-
} catch (error: any) {
|
|
137
|
-
Logger.warn(`清理表 ${tableName} 的缓存失败: ${error.message}`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
139
|
+
const cacheKeys = processedTables.map((tableName) => RedisKeys.tableColumns(tableName));
|
|
140
|
+
await redisHelper.delBatch(cacheKeys);
|
|
140
141
|
}
|
|
141
142
|
} catch (error: any) {
|
|
142
|
-
Logger.error('数据库同步失败'
|
|
143
|
+
Logger.error({ err: error }, '数据库同步失败');
|
|
143
144
|
throw error;
|
|
144
145
|
} finally {
|
|
145
146
|
if (sql) {
|
package/sync/syncDev.ts
CHANGED
|
@@ -7,12 +7,15 @@
|
|
|
7
7
|
* - 表名: addon_admin_admin
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { scanAddons, getAddonDir, normalizeModuleForSync } from 'befly-
|
|
10
|
+
import { scanAddons, getAddonDir, normalizeModuleForSync } from 'befly-shared/addonHelper';
|
|
11
11
|
|
|
12
12
|
import { Logger } from '../lib/logger.js';
|
|
13
13
|
import { Cipher } from '../lib/cipher.js';
|
|
14
14
|
import { Connect } from '../lib/connect.js';
|
|
15
15
|
import { DbHelper } from '../lib/dbHelper.js';
|
|
16
|
+
import { RedisHelper } from '../lib/redisHelper.js';
|
|
17
|
+
import { CacheHelper } from '../lib/cacheHelper.js';
|
|
18
|
+
|
|
16
19
|
import type { SyncDevOptions, SyncDevStats, BeflyOptions } from '../types/index.js';
|
|
17
20
|
|
|
18
21
|
/**
|
|
@@ -33,7 +36,7 @@ export async function syncDevCommand(config: BeflyOptions, options: SyncDevOptio
|
|
|
33
36
|
// 连接数据库(SQL + Redis)
|
|
34
37
|
await Connect.connect(config);
|
|
35
38
|
|
|
36
|
-
const helper = Connect.
|
|
39
|
+
const helper = new DbHelper({ redis: new RedisHelper() } as any, Connect.getSql());
|
|
37
40
|
|
|
38
41
|
// 检查 addon_admin_admin 表是否存在
|
|
39
42
|
const existAdmin = await helper.tableExists('addon_admin_admin');
|
|
@@ -152,57 +155,16 @@ export async function syncDevCommand(config: BeflyOptions, options: SyncDevOptio
|
|
|
152
155
|
});
|
|
153
156
|
}
|
|
154
157
|
|
|
155
|
-
// 缓存角色权限数据到 Redis
|
|
158
|
+
// 缓存角色权限数据到 Redis(复用 CacheHelper 逻辑)
|
|
156
159
|
try {
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (apiTableExists && roleTableExists) {
|
|
162
|
-
// 查询所有角色
|
|
163
|
-
const roles = await helper.getAll({
|
|
164
|
-
table: 'addon_admin_role',
|
|
165
|
-
fields: ['id', 'code', 'apis']
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// 查询所有接口
|
|
169
|
-
const allApis = await helper.getAll({
|
|
170
|
-
table: 'addon_admin_api',
|
|
171
|
-
fields: ['id', 'name', 'path', 'method', 'description', 'addonName']
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const redis = Connect.getRedis();
|
|
175
|
-
|
|
176
|
-
// 为每个角色缓存接口权限
|
|
177
|
-
for (const role of roles) {
|
|
178
|
-
if (!role.apis) continue;
|
|
179
|
-
|
|
180
|
-
// 解析角色的接口 ID 列表
|
|
181
|
-
const apiIds = role.apis
|
|
182
|
-
.split(',')
|
|
183
|
-
.map((id: string) => parseInt(id.trim()))
|
|
184
|
-
.filter((id: number) => !isNaN(id));
|
|
185
|
-
|
|
186
|
-
// 根据 ID 过滤出接口路径
|
|
187
|
-
const roleApiPaths = allApis.filter((api: any) => apiIds.includes(api.id)).map((api: any) => `${api.method}${api.path}`);
|
|
188
|
-
|
|
189
|
-
if (roleApiPaths.length === 0) continue;
|
|
190
|
-
|
|
191
|
-
// 使用 Redis Set 缓存角色权限
|
|
192
|
-
const redisKey = `role:apis:${role.code}`;
|
|
193
|
-
|
|
194
|
-
// 先删除旧数据
|
|
195
|
-
await redis.del(redisKey);
|
|
196
|
-
|
|
197
|
-
// 批量添加到 Set(使用扩展运算符展开数组)
|
|
198
|
-
await redis.sadd(redisKey, ...roleApiPaths);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
160
|
+
const tempBefly = { db: helper, redis: new RedisHelper() } as any;
|
|
161
|
+
const cacheHelper = new CacheHelper(tempBefly);
|
|
162
|
+
await cacheHelper.cacheRolePermissions();
|
|
201
163
|
} catch (error: any) {
|
|
202
164
|
// 忽略缓存错误
|
|
203
165
|
}
|
|
204
166
|
} catch (error: any) {
|
|
205
|
-
Logger.error('同步开发者管理员失败'
|
|
167
|
+
Logger.error({ err: error }, '同步开发者管理员失败');
|
|
206
168
|
throw error;
|
|
207
169
|
} finally {
|
|
208
170
|
await Connect.disconnect();
|
package/sync/syncMenu.ts
CHANGED
|
@@ -17,8 +17,11 @@
|
|
|
17
17
|
import { join } from 'pathe';
|
|
18
18
|
import { cloneDeep } from 'es-toolkit';
|
|
19
19
|
import { Connect } from '../lib/connect.js';
|
|
20
|
+
import { DbHelper } from '../lib/dbHelper.js';
|
|
20
21
|
import { RedisHelper } from '../lib/redisHelper.js';
|
|
21
|
-
import {
|
|
22
|
+
import { RedisKeys } from 'befly-shared/redisKeys';
|
|
23
|
+
import { scanAddons, getAddonDir } from 'befly-shared/addonHelper';
|
|
24
|
+
import { scanConfig } from 'befly-shared/scanConfig';
|
|
22
25
|
import { Logger } from '../lib/logger.js';
|
|
23
26
|
import { projectDir } from '../paths.js';
|
|
24
27
|
|
|
@@ -204,7 +207,7 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<void> {
|
|
|
204
207
|
try {
|
|
205
208
|
await syncMenuRecursive(helper, menu, 0, existingMenuMap, 1);
|
|
206
209
|
} catch (error: any) {
|
|
207
|
-
Logger.error(
|
|
210
|
+
Logger.error({ err: error, menu: menu.name }, '同步菜单失败');
|
|
208
211
|
throw error;
|
|
209
212
|
}
|
|
210
213
|
}
|
|
@@ -257,7 +260,7 @@ async function loadMenuConfigs(): Promise<Array<{ menus: MenuConfig[]; addonName
|
|
|
257
260
|
allMenus.push({ menus: menusWithPrefix, addonName: addonName });
|
|
258
261
|
}
|
|
259
262
|
} catch (error: any) {
|
|
260
|
-
Logger.warn(
|
|
263
|
+
Logger.warn({ err: error, addon: addonName }, '读取 addon 配置失败');
|
|
261
264
|
}
|
|
262
265
|
}
|
|
263
266
|
|
|
@@ -276,7 +279,7 @@ async function loadMenuConfigs(): Promise<Array<{ menus: MenuConfig[]; addonName
|
|
|
276
279
|
allMenus.push({ menus: appMenus, addonName: 'app' });
|
|
277
280
|
}
|
|
278
281
|
} catch (error: any) {
|
|
279
|
-
Logger.warn(
|
|
282
|
+
Logger.warn({ err: error }, '读取项目配置失败');
|
|
280
283
|
}
|
|
281
284
|
|
|
282
285
|
return allMenus;
|
|
@@ -301,7 +304,7 @@ export async function syncMenuCommand(config: BeflyOptions, options: SyncMenuOpt
|
|
|
301
304
|
// 连接数据库(SQL + Redis)
|
|
302
305
|
await Connect.connect(config);
|
|
303
306
|
|
|
304
|
-
const helper = Connect.
|
|
307
|
+
const helper = new DbHelper({ redis: new RedisHelper() } as any, Connect.getSql());
|
|
305
308
|
|
|
306
309
|
// 3. 检查表是否存在(addon_admin_menu 来自 addon-admin 组件)
|
|
307
310
|
const exists = await helper.tableExists('addon_admin_menu');
|
|
@@ -330,12 +333,12 @@ export async function syncMenuCommand(config: BeflyOptions, options: SyncMenuOpt
|
|
|
330
333
|
// 8. 缓存菜单数据到 Redis
|
|
331
334
|
try {
|
|
332
335
|
const redisHelper = new RedisHelper();
|
|
333
|
-
await redisHelper.setObject(
|
|
336
|
+
await redisHelper.setObject(RedisKeys.menusAll(), allMenusData);
|
|
334
337
|
} catch (error: any) {
|
|
335
|
-
Logger.warn(
|
|
338
|
+
Logger.warn({ err: error }, 'Redis 缓存菜单数据失败');
|
|
336
339
|
}
|
|
337
340
|
} catch (error: any) {
|
|
338
|
-
Logger.error('菜单同步失败'
|
|
341
|
+
Logger.error({ err: error }, '菜单同步失败');
|
|
339
342
|
throw error;
|
|
340
343
|
} finally {
|
|
341
344
|
await Connect.disconnect();
|