befly-tpl 3.2.2 → 3.2.3
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 +240 -14
- package/package.json +21 -3
- package/addon-loader.example.ts +0 -99
- package/bun.lock +0 -140
- package/logs/2025-08-22.0.log +0 -197
- package/logs/2025-08-23.0.log +0 -151
- package/logs/2025-08-24.0.log +0 -296
- package/logs/2025-08-25.0.log +0 -162
- package/logs/2025-08-26.0.log +0 -19
- package/logs/2025-08-27.0.log +0 -63
- package/logs/2025-08-28.0.log +0 -286
- package/logs/2025-08-30.0.log +0 -1
- package/logs/2025-09-01.0.log +0 -296
- package/logs/2025-09-02.0.log +0 -298
- package/logs/2025-10-11.0.log +0 -2718
- package/logs/2025-10-12.0.log +0 -4374
- package/logs/2025-10-13.0.log +0 -759
- package/logs/2025-10-14.0.log +0 -2350
- package/logs/2025-10-15.0.log +0 -2386
- package/logs/2025-10-16.0.log +0 -2807
- package/logs/2025-10-17.0.log +0 -1143
- package/logs/2025-10-18.0.log +0 -1292
- package/logs/2025-10-19.0.log +0 -1752
- package/logs/2025-10-20.0.log +0 -722
- package/logs/2025-10-21.0.log +0 -1075
- package/logs/2025-10-23.0.log +0 -3291
- package/logs/2025-10-24.0.log +0 -2341
- package/logs/2025-10-25.0.log +0 -1367
- package/logs/debug.0.log +0 -25174
- package/temp/addon-route-prefix-migration.md +0 -400
- package/temp/api-route-conflict-analysis.md +0 -441
- package/temp/interactive-cli-guide.md +0 -199
- package/temp/missing-apis-fix.md +0 -362
- package/temp/remove-status-field.md +0 -239
- package/temp/roleid-to-rolecode-optimization.md +0 -321
- package/temp/status-to-state-migration-complete.md +0 -176
- package/temp/syncMenu-guide.md +0 -235
- package/temp/test-admin-menus-cache.ts +0 -125
- package/temp/test-admin-menus.ts +0 -110
- package/temp/test-interactive-cli.ps1 +0 -14
package/temp/syncMenu-guide.md
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
# syncMenu 脚本使用说明
|
|
2
|
-
|
|
3
|
-
## 功能描述
|
|
4
|
-
|
|
5
|
-
`syncMenu` 脚本用于将 `menu.json` 配置文件中的菜单数据同步到数据库,采用**增量更新**模式。
|
|
6
|
-
|
|
7
|
-
## 核心特性
|
|
8
|
-
|
|
9
|
-
### 1. 增量更新机制
|
|
10
|
-
|
|
11
|
-
- **判断依据**:根据菜单的 `path` 字段判断菜单是否存在
|
|
12
|
-
- **存在则更新**:更新菜单的其他字段(name、icon、sort、type、status、pid)
|
|
13
|
-
- **不存在则新增**:插入新的菜单记录
|
|
14
|
-
- **不会删除**:配置文件中没有的菜单不会被删除
|
|
15
|
-
|
|
16
|
-
### 2. 支持层级结构
|
|
17
|
-
|
|
18
|
-
- 自动维护父子关系(通过 `pid` 字段)
|
|
19
|
-
- 递归处理子菜单
|
|
20
|
-
- 支持无限层级嵌套
|
|
21
|
-
|
|
22
|
-
### 3. 预演模式
|
|
23
|
-
|
|
24
|
-
支持 `--plan` 参数,只显示执行计划,不实际修改数据库。
|
|
25
|
-
|
|
26
|
-
## 使用方式
|
|
27
|
-
|
|
28
|
-
### 方式一:交互式执行
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
bunx befly
|
|
32
|
-
# 选择对应的数字(如:5. syncMenu)
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### 方式二:直接执行
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
# 实际执行
|
|
39
|
-
bun packages/tpl/addons/admin/scripts/syncMenu.ts
|
|
40
|
-
|
|
41
|
-
# 预演模式
|
|
42
|
-
bun packages/tpl/addons/admin/scripts/syncMenu.ts --plan
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## 配置文件格式
|
|
46
|
-
|
|
47
|
-
配置文件路径:`packages/tpl/addons/admin/config/menu.json`
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
[
|
|
51
|
-
{
|
|
52
|
-
"name": "首页", // 菜单名称
|
|
53
|
-
"path": "/", // 菜单路径(唯一标识)
|
|
54
|
-
"icon": "DashboardIcon", // 图标
|
|
55
|
-
"sort": 1, // 排序
|
|
56
|
-
"type": 1, // 类型:0=目录,1=菜单
|
|
57
|
-
"status": 1 // 状态:0=禁用,1=启用
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"name": "系统管理",
|
|
61
|
-
"path": "/system",
|
|
62
|
-
"icon": "SettingIcon",
|
|
63
|
-
"sort": 4,
|
|
64
|
-
"type": 0,
|
|
65
|
-
"status": 1,
|
|
66
|
-
"children": [
|
|
67
|
-
// 子菜单
|
|
68
|
-
{
|
|
69
|
-
"name": "菜单管理",
|
|
70
|
-
"path": "/system/menu",
|
|
71
|
-
"icon": "ViewListIcon",
|
|
72
|
-
"sort": 1,
|
|
73
|
-
"type": 1,
|
|
74
|
-
"status": 1
|
|
75
|
-
}
|
|
76
|
-
]
|
|
77
|
-
}
|
|
78
|
-
]
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## 字段说明
|
|
82
|
-
|
|
83
|
-
| 字段 | 类型 | 必填 | 说明 |
|
|
84
|
-
| -------- | ------ | ---- | ------------------------------ |
|
|
85
|
-
| name | string | 是 | 菜单名称 |
|
|
86
|
-
| path | string | 是 | 菜单路径,作为唯一标识 |
|
|
87
|
-
| icon | string | 否 | 图标名称,默认为空 |
|
|
88
|
-
| sort | number | 否 | 排序号,默认为 0 |
|
|
89
|
-
| type | number | 否 | 类型:0=目录,1=菜单,默认为 1 |
|
|
90
|
-
| status | number | 否 | 状态:0=禁用,1=启用,默认为 1 |
|
|
91
|
-
| children | array | 否 | 子菜单数组 |
|
|
92
|
-
|
|
93
|
-
## 执行流程
|
|
94
|
-
|
|
95
|
-
1. 检查 `addon_admin_menu` 表是否存在
|
|
96
|
-
2. 读取 `menu.json` 配置文件
|
|
97
|
-
3. 遍历菜单配置:
|
|
98
|
-
- 根据 `path` 查询数据库中是否存在
|
|
99
|
-
- 存在 → 更新其他字段
|
|
100
|
-
- 不存在 → 插入新记录
|
|
101
|
-
4. 递归处理子菜单
|
|
102
|
-
5. 显示菜单树形结构预览
|
|
103
|
-
6. 输出统计信息(新增数量、更新数量)
|
|
104
|
-
|
|
105
|
-
## 使用场景
|
|
106
|
-
|
|
107
|
-
### 场景 1:初始化菜单
|
|
108
|
-
|
|
109
|
-
第一次运行时,所有菜单都是新增:
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
bun packages/tpl/addons/admin/scripts/syncMenu.ts
|
|
113
|
-
|
|
114
|
-
# 输出:
|
|
115
|
-
# ✅ 新增菜单: 6 个
|
|
116
|
-
# ✅ 更新菜单: 0 个
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### 场景 2:修改菜单名称
|
|
120
|
-
|
|
121
|
-
修改 `menu.json` 中某个菜单的 `name` 字段后:
|
|
122
|
-
|
|
123
|
-
```json
|
|
124
|
-
{
|
|
125
|
-
"name": "首页2024", // 修改了名称
|
|
126
|
-
"path": "/", // path 不变
|
|
127
|
-
...
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
bun packages/tpl/addons/admin/scripts/syncMenu.ts
|
|
133
|
-
|
|
134
|
-
# 输出:
|
|
135
|
-
# ✅ 新增菜单: 0 个
|
|
136
|
-
# ✅ 更新菜单: 6 个(包含这个修改的菜单)
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### 场景 3:添加新菜单
|
|
140
|
-
|
|
141
|
-
在 `menu.json` 中添加新菜单:
|
|
142
|
-
|
|
143
|
-
```json
|
|
144
|
-
[
|
|
145
|
-
...,
|
|
146
|
-
{
|
|
147
|
-
"name": "用户管理",
|
|
148
|
-
"path": "/user", // 新的 path
|
|
149
|
-
...
|
|
150
|
-
}
|
|
151
|
-
]
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
bun packages/tpl/addons/admin/scripts/syncMenu.ts
|
|
156
|
-
|
|
157
|
-
# 输出:
|
|
158
|
-
# ✅ 新增菜单: 1 个
|
|
159
|
-
# ✅ 更新菜单: 6 个
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### 场景 4:预演模式
|
|
163
|
-
|
|
164
|
-
在实际执行前,先查看执行计划:
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
bun packages/tpl/addons/admin/scripts/syncMenu.ts --plan
|
|
168
|
-
|
|
169
|
-
# 输出:
|
|
170
|
-
# [计划] 同步菜单配置到数据库(plan 模式不执行)
|
|
171
|
-
# [计划] 1. 读取 menu.json 配置文件
|
|
172
|
-
# [计划] 2. 根据 path 检查菜单是否存在
|
|
173
|
-
# [计划] 3. 存在则更新,不存在则新增
|
|
174
|
-
# [计划] 4. 递归处理子菜单
|
|
175
|
-
# [计划] 5. 显示菜单结构预览
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## 注意事项
|
|
179
|
-
|
|
180
|
-
### 1. path 是唯一标识
|
|
181
|
-
|
|
182
|
-
- `path` 字段是菜单的唯一标识
|
|
183
|
-
- 修改 `path` 会导致创建新菜单,而不是更新现有菜单
|
|
184
|
-
- 建议:确定 `path` 后不要轻易修改
|
|
185
|
-
|
|
186
|
-
### 2. 不会删除菜单
|
|
187
|
-
|
|
188
|
-
- 从配置文件中移除某个菜单,不会删除数据库中的对应记录
|
|
189
|
-
- 如需删除,请手动在数据库中软删除(设置 `deleted_at` 字段)
|
|
190
|
-
|
|
191
|
-
### 3. 父子关系自动维护
|
|
192
|
-
|
|
193
|
-
- 子菜单的 `pid` 会自动设置为父菜单的 `id`
|
|
194
|
-
- 修改菜单层级关系时,`pid` 会自动更新
|
|
195
|
-
|
|
196
|
-
### 4. 必须先运行 syncDb
|
|
197
|
-
|
|
198
|
-
- 首次使用前,必须先运行 `syncDb` 脚本创建 `addon_admin_menu` 表
|
|
199
|
-
- 否则会提示:`跳过菜单同步:未检测到 addon_admin_menu 表`
|
|
200
|
-
|
|
201
|
-
## 常见问题
|
|
202
|
-
|
|
203
|
-
### Q: 如何删除某个菜单?
|
|
204
|
-
|
|
205
|
-
A: 有两种方式:
|
|
206
|
-
|
|
207
|
-
1. **软删除**(推荐):直接在数据库中将 `deleted_at` 字段设置为当前时间戳
|
|
208
|
-
2. **硬删除**:直接在数据库中删除记录(不推荐)
|
|
209
|
-
|
|
210
|
-
### Q: 修改了 path 会怎样?
|
|
211
|
-
|
|
212
|
-
A: 会创建新菜单,旧菜单仍然存在。如需更换路径,建议:
|
|
213
|
-
|
|
214
|
-
1. 先软删除旧菜单(设置 `deleted_at`)
|
|
215
|
-
2. 在配置文件中使用新 path
|
|
216
|
-
3. 运行 syncMenu 创建新菜单
|
|
217
|
-
|
|
218
|
-
### Q: 如何调整菜单顺序?
|
|
219
|
-
|
|
220
|
-
A: 修改配置文件中的 `sort` 字段,然后运行 syncMenu 即可。
|
|
221
|
-
|
|
222
|
-
### Q: 子菜单的层级关系如何确定?
|
|
223
|
-
|
|
224
|
-
A: 通过配置文件中的 `children` 数组嵌套关系自动确定,无需手动设置 `pid`。
|
|
225
|
-
|
|
226
|
-
## 开发建议
|
|
227
|
-
|
|
228
|
-
1. **版本控制**:将 `menu.json` 纳入版本控制
|
|
229
|
-
2. **备份**:修改前备份配置文件
|
|
230
|
-
3. **预演先行**:重要修改前先用 `--plan` 模式预览
|
|
231
|
-
4. **增量更新**:充分利用增量更新特性,避免重复操作
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
**最后更新**: 2025-10-19
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* 测试从 Redis 缓存读取菜单并按角色过滤
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { initDatabase, closeDatabase } from 'befly';
|
|
7
|
-
import { RedisHelper } from 'befly/utils/redisHelper';
|
|
8
|
-
|
|
9
|
-
async function testAdminMenusWithCache() {
|
|
10
|
-
const { helper } = await initDatabase({ max: 1 });
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
console.log('=== 测试 adminMenus API(使用 Redis 缓存)===\n');
|
|
14
|
-
|
|
15
|
-
// 模拟当前登录用户
|
|
16
|
-
const userId = '1760695696283001'; // dev 管理员的 ID
|
|
17
|
-
|
|
18
|
-
// 1. 查询用户信息获取角色ID
|
|
19
|
-
const admin = await helper.getOne({
|
|
20
|
-
table: 'addon_admin_admin',
|
|
21
|
-
where: { id: userId }
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
console.log('1. 查询用户信息:');
|
|
25
|
-
console.log(' roleId:', admin?.roleId);
|
|
26
|
-
|
|
27
|
-
if (!admin || !admin.roleId) {
|
|
28
|
-
console.log(' 结果: 用户无角色,返回空菜单');
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// 2. 查询角色信息获取菜单权限
|
|
33
|
-
const role = await helper.getOne({
|
|
34
|
-
table: 'addon_admin_role',
|
|
35
|
-
where: { id: admin.roleId }
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
console.log('\n2. 查询角色信息:');
|
|
39
|
-
console.log(' menus:', role?.menus);
|
|
40
|
-
|
|
41
|
-
if (!role || !role.menus) {
|
|
42
|
-
console.log(' 结果: 角色无菜单权限,返回空菜单');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// 3. 解析菜单ID列表
|
|
47
|
-
const menuIds = role.menus
|
|
48
|
-
.split(',')
|
|
49
|
-
.map((id: string) => parseInt(id.trim()))
|
|
50
|
-
.filter((id: number) => !isNaN(id));
|
|
51
|
-
|
|
52
|
-
console.log('\n3. 解析菜单ID:');
|
|
53
|
-
console.log(' 菜单ID数组:', menuIds);
|
|
54
|
-
console.log(' 共计:', menuIds.length, '个');
|
|
55
|
-
|
|
56
|
-
if (menuIds.length === 0) {
|
|
57
|
-
console.log(' 结果: 无有效菜单ID,返回空菜单');
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// 4. 从 Redis 缓存读取所有菜单
|
|
62
|
-
console.log('\n4. 从 Redis 缓存读取菜单:');
|
|
63
|
-
let allMenus = await RedisHelper.getObject<any[]>('befly:menus:all');
|
|
64
|
-
|
|
65
|
-
if (!allMenus || allMenus.length === 0) {
|
|
66
|
-
console.log(' ⚠️ 缓存未命中,从数据库查询');
|
|
67
|
-
allMenus = await helper.getAll({
|
|
68
|
-
table: 'addon_admin_menu',
|
|
69
|
-
fields: ['id', 'pid', 'name', 'path', 'icon', 'type', 'sort', 'status'],
|
|
70
|
-
where: { status: 1 },
|
|
71
|
-
orderBy: ['sort#ASC', 'id#ASC']
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// 回写缓存
|
|
75
|
-
if (allMenus.length > 0) {
|
|
76
|
-
await RedisHelper.setObject('befly:menus:all', allMenus);
|
|
77
|
-
console.log(' ✅ 已缓存', allMenus.length, '个菜单到 Redis');
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
console.log(' ✅ 从 Redis 缓存读取', allMenus.length, '个菜单');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// 5. 根据角色权限过滤菜单
|
|
84
|
-
console.log('\n5. 根据角色权限过滤菜单:');
|
|
85
|
-
const menuIdSet = new Set(menuIds.map(String));
|
|
86
|
-
const authorizedMenus = allMenus.filter((menu: any) => menuIdSet.has(String(menu.id)));
|
|
87
|
-
console.log(' 过滤后:', authorizedMenus.length, '个菜单');
|
|
88
|
-
|
|
89
|
-
// 6. 构建树形结构
|
|
90
|
-
const buildTree = (items: any[], pid = 0) => {
|
|
91
|
-
const tree: any[] = [];
|
|
92
|
-
for (const item of items) {
|
|
93
|
-
if (item.pid === pid) {
|
|
94
|
-
const children = buildTree(items, item.id);
|
|
95
|
-
const node = {
|
|
96
|
-
id: item.id,
|
|
97
|
-
name: item.name,
|
|
98
|
-
path: item.path,
|
|
99
|
-
icon: item.icon,
|
|
100
|
-
type: item.type,
|
|
101
|
-
sort: item.sort
|
|
102
|
-
};
|
|
103
|
-
if (children.length > 0) {
|
|
104
|
-
node.children = children;
|
|
105
|
-
}
|
|
106
|
-
tree.push(node);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return tree;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const menuTree = buildTree(authorizedMenus);
|
|
113
|
-
|
|
114
|
-
console.log('\n6. 构建树形结构:');
|
|
115
|
-
console.log(JSON.stringify(menuTree, null, 2));
|
|
116
|
-
|
|
117
|
-
console.log('\n✅ 测试完成!菜单数据从 Redis 缓存读取成功');
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.error('❌ 测试失败:', error);
|
|
120
|
-
} finally {
|
|
121
|
-
await closeDatabase();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
testAdminMenusWithCache();
|
package/temp/test-admin-menus.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* 测试 adminMenus API 的逻辑
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { initDatabase, closeDatabase } from 'befly';
|
|
7
|
-
|
|
8
|
-
async function testAdminMenus() {
|
|
9
|
-
const { helper } = await initDatabase({ max: 1 });
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
// 模拟当前登录用户
|
|
13
|
-
const userId = '1760695696283001'; // dev 管理员的 ID
|
|
14
|
-
|
|
15
|
-
// 1. 查询用户信息获取角色ID
|
|
16
|
-
const admin = await helper.getOne({
|
|
17
|
-
table: 'addon_admin_admin',
|
|
18
|
-
where: { id: userId }
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
console.log('1. 查询用户信息:');
|
|
22
|
-
console.log(' roleId:', admin?.roleId);
|
|
23
|
-
|
|
24
|
-
if (!admin || !admin.roleId) {
|
|
25
|
-
console.log(' 结果: 用户无角色,返回空菜单');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// 2. 查询角色信息获取菜单权限
|
|
30
|
-
const role = await helper.getOne({
|
|
31
|
-
table: 'addon_admin_role',
|
|
32
|
-
where: { id: admin.roleId }
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
console.log('\n2. 查询角色信息:');
|
|
36
|
-
console.log(' menus:', role?.menus);
|
|
37
|
-
|
|
38
|
-
if (!role || !role.menus) {
|
|
39
|
-
console.log(' 结果: 角色无菜单权限,返回空菜单');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 3. 解析菜单ID列表
|
|
44
|
-
const menuIds = role.menus
|
|
45
|
-
.split(',')
|
|
46
|
-
.map((id: string) => parseInt(id.trim()))
|
|
47
|
-
.filter((id: number) => !isNaN(id));
|
|
48
|
-
|
|
49
|
-
console.log('\n3. 解析菜单ID:');
|
|
50
|
-
console.log(' 菜单ID数组:', menuIds);
|
|
51
|
-
console.log(' 共计:', menuIds.length, '个');
|
|
52
|
-
|
|
53
|
-
if (menuIds.length === 0) {
|
|
54
|
-
console.log(' 结果: 无有效菜单ID,返回空菜单');
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// 4. 查询菜单详情
|
|
59
|
-
const menus = await helper.getAll({
|
|
60
|
-
table: 'addon_admin_menu',
|
|
61
|
-
where: {
|
|
62
|
-
id$in: menuIds,
|
|
63
|
-
status: 1
|
|
64
|
-
},
|
|
65
|
-
orderBy: ['sort#ASC', 'id#ASC']
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
console.log('\n4. 查询菜单详情:');
|
|
69
|
-
console.log(' 查询到:', menus.length, '个菜单');
|
|
70
|
-
menus.forEach((m: any) => {
|
|
71
|
-
console.log(' -', m.name, '(ID:', m.id, ', PID:', m.pid, ', Path:', m.path, ')');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// 5. 构建树形结构
|
|
75
|
-
const buildTree = (items: any[], pid = 0) => {
|
|
76
|
-
const tree: any[] = [];
|
|
77
|
-
for (const item of items) {
|
|
78
|
-
if (item.pid === pid) {
|
|
79
|
-
const children = buildTree(items, item.id);
|
|
80
|
-
const node = {
|
|
81
|
-
id: item.id,
|
|
82
|
-
name: item.name,
|
|
83
|
-
path: item.path,
|
|
84
|
-
icon: item.icon,
|
|
85
|
-
type: item.type,
|
|
86
|
-
sort: item.sort
|
|
87
|
-
};
|
|
88
|
-
if (children.length > 0) {
|
|
89
|
-
node.children = children;
|
|
90
|
-
}
|
|
91
|
-
tree.push(node);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return tree;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const menuTree = buildTree(menus);
|
|
98
|
-
|
|
99
|
-
console.log('\n5. 构建树形结构:');
|
|
100
|
-
console.log(JSON.stringify(menuTree, null, 2));
|
|
101
|
-
|
|
102
|
-
console.log('\n✅ 测试完成!菜单数据正常返回');
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error('❌ 测试失败:', error);
|
|
105
|
-
} finally {
|
|
106
|
-
await closeDatabase();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
testAdminMenus();
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
Write-Host "测试交互式 CLI 菜单" -ForegroundColor Green
|
|
2
|
-
Write-Host ""
|
|
3
|
-
Write-Host "步骤 1: 启动交互式菜单(输入 bunx befly)" -ForegroundColor Yellow
|
|
4
|
-
Write-Host "步骤 2: 看到带数字的脚本列表" -ForegroundColor Yellow
|
|
5
|
-
Write-Host "步骤 3: 输入脚本编号(例如: 5 表示选择 admin:syncDev)" -ForegroundColor Yellow
|
|
6
|
-
Write-Host "步骤 4: 选择是否添加 --plan 参数" -ForegroundColor Yellow
|
|
7
|
-
Write-Host "步骤 5: 确认执行" -ForegroundColor Yellow
|
|
8
|
-
Write-Host ""
|
|
9
|
-
Write-Host "提示: 输入 0 或直接回车可退出" -ForegroundColor Cyan
|
|
10
|
-
Write-Host ""
|
|
11
|
-
|
|
12
|
-
# 启动交互式菜单
|
|
13
|
-
Set-Location "D:\codes\befly\packages\tpl"
|
|
14
|
-
bunx befly
|