zero-ai 1.0.85 → 1.0.86
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/.r2mo/.obsidian/plugins/terminal/manifest.json +14 -0
- package/.r2mo/.obsidian/plugins/terminal/styles.css +32 -0
- package/.r2mo/task/2026-03-07/2026-03-07.12-26-02-TASK@/345/274/200/345/217/221/346/226/260/345/221/275/344/273/244 ai ex-menu.md" +310 -0
- package/.r2mo/task/task-001.md +28 -294
- package/package.json +1 -1
- package/src/commander/auth.json +6 -0
- package/src/commander-ai/fn.ex.auth.js +136 -0
- package/src/commander-ai/index.js +2 -6
- package/.r2mo/.obsidian/themes/Comfort/manifest.json +0 -11
- package/.r2mo/.obsidian/themes/Comfort/theme.css +0 -218
- package/.r2mo/.obsidian/themes/Serenity/manifest.json +0 -7
- package/.r2mo/.obsidian/themes/Serenity/theme.css +0 -7258
- package/.r2mo/.obsidian/themes/W95/manifest.json +0 -8
- package/.r2mo/.obsidian/themes/W95/theme.css +0 -768
- package/src/commander/ex-api.json +0 -8
- package/src/commander/ex-crud.json +0 -1
- package/src/commander/ex-perm.json +0 -8
- package/src/commander-ai/fn.ex.api.js +0 -995
- package/src/commander-ai/fn.ex.crud.js +0 -545
- package/src/commander-ai/fn.ex.perm.js +0 -207
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "polyipseity",
|
|
3
|
+
"description": "Integrate consoles, shells, and terminals.",
|
|
4
|
+
"fundingUrl": {
|
|
5
|
+
"Buy Me a Coffee": "https://buymeacoffee.com/polyipseity",
|
|
6
|
+
"GitHub Sponsors": "https://github.com/sponsors/polyipseity"
|
|
7
|
+
},
|
|
8
|
+
"version": "3.22.0",
|
|
9
|
+
"authorUrl": "https://github.com/polyipseity",
|
|
10
|
+
"id": "terminal",
|
|
11
|
+
"isDesktopOnly": false,
|
|
12
|
+
"minAppVersion": "1.4.11",
|
|
13
|
+
"name": "Terminal"
|
|
14
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.obsidian-plugin-library\:icon{fill:none;stroke:currentColor}.obsidian-plugin-library\:await-css{display:unset!important}.obsidian-plugin-library\:hide-status-bar{display:none}/**
|
|
2
|
+
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
+
* https://github.com/chjj/term.js
|
|
5
|
+
* @license MIT
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
* Originally forked from (with the author's permission):
|
|
26
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
+
* http://bellard.org/jslinux/
|
|
28
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
+
* The original design remains. The terminal itself
|
|
30
|
+
* has been extended to include xterm CSI codes, among
|
|
31
|
+
* other features.
|
|
32
|
+
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.workspace-leaf-content[data-type="terminal:terminal"] .view-content{overflow:clip;display:flex;flex-direction:column}.terminal\:terminal{flex:1;min-width:0;min-height:0}.is-phone .workspace-leaf-content[data-type="terminal:terminal"] .view-content{padding-bottom:max(var(--size-4-4),calc(var(--icon-l) + var(--size-4-2) + max(var(--size-4-2),var(--safe-area-inset-bottom))))}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
runAt: 2026-03-05.11-05-38
|
|
3
|
+
completedAt: 2026-03-05.11-30-00
|
|
4
|
+
title: 开发新命令 ai ex-menu
|
|
5
|
+
status: completed
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 任务目标
|
|
9
|
+
|
|
10
|
+
将以下参考的执行记录转换成自动化命令 ai ex-menu
|
|
11
|
+
|
|
12
|
+
## 实施结果
|
|
13
|
+
|
|
14
|
+
### 已完成功能
|
|
15
|
+
|
|
16
|
+
#### 1. 新增 `ai ex-menu` 命令
|
|
17
|
+
|
|
18
|
+
**命令文件**:
|
|
19
|
+
- `src/commander/ex-menu.json` - 命令配置
|
|
20
|
+
- `src/commander-ai/fn.ex.menu.js` - 命令实现
|
|
21
|
+
- `src/commander-ai/index.js` - 已注册 executor
|
|
22
|
+
|
|
23
|
+
**执行流程**:
|
|
24
|
+
1. 加载 `.r2mo/app.env` 环境变量
|
|
25
|
+
2. 连接数据库查询 `S_ROLE` 表
|
|
26
|
+
3. 用户单选角色(提示:菜单全开放模式,建议选择开发人员角色)
|
|
27
|
+
4. 查询 `X_MENU` 生成两个 JSON 文件:
|
|
28
|
+
- `src/main/resources/init/permission/ui.menu/{CODE}.json` - NAME 数组
|
|
29
|
+
- `src/main/resources/init/permission/ui.menu/role/{CODE}.json` - 层级文本数组(带缩进)
|
|
30
|
+
|
|
31
|
+
**特性**:
|
|
32
|
+
- 自动过滤超级管理员角色(该角色在 `ai ex-api` 中固定输出)
|
|
33
|
+
- 支持任意角色 CODE 的文件生成
|
|
34
|
+
- 层级文本按 ORDER、NAME 排序,缩进规则:每层级 4 个空格
|
|
35
|
+
|
|
36
|
+
#### 2. 增强 `ai ex-api` 命令
|
|
37
|
+
|
|
38
|
+
**修改内容**:
|
|
39
|
+
- 超级管理员角色(ID: `e501b47a-c08b-4c83-b12b-95ad82873e96`)始终自动输出到 `ZERO_MODULE` 固定路径,不需要用户选择
|
|
40
|
+
- 用户选择角色时自动过滤掉超级管理员,避免重复
|
|
41
|
+
- 汇总输出增强:
|
|
42
|
+
- 🔒 固定输出角色:超级管理员(自动包含)
|
|
43
|
+
- 👤 用户选择角色:显示每个角色的 NAME、CODE、ID
|
|
44
|
+
- 📁 输出文件路径分流:
|
|
45
|
+
- 超级管理员 → `ZERO_MODULE/.../RBAC_ROLE/ADMIN.SUPER/`
|
|
46
|
+
- 其他角色 → `src/main/resources/init/oob/role/{CODE}/`
|
|
47
|
+
|
|
48
|
+
**输出示例**:
|
|
49
|
+
```
|
|
50
|
+
[ex-api] ✅ 执行完成(幂等)
|
|
51
|
+
[ex-api] 📋 汇总:
|
|
52
|
+
[ex-api] 🔑 ACTION_ID = xxx
|
|
53
|
+
[ex-api] 🔑 RESOURCE_ID = xxx
|
|
54
|
+
[ex-api] 🔑 PERMISSION_ID = xxx
|
|
55
|
+
[ex-api] 👥 授权角色总数 = 2
|
|
56
|
+
[ex-api] 🔒 固定输出角色:
|
|
57
|
+
[ex-api] [1] 超级管理员 (CODE: ADMIN.SUPER, ID: e501b47a-...)
|
|
58
|
+
[ex-api] 👤 用户选择角色:
|
|
59
|
+
[ex-api] [1] 开发人员 (CODE: ADMIN.DEVELOPER, ID: xxx)
|
|
60
|
+
[ex-api] 📁 RBAC_RESOURCE = /path/to/...
|
|
61
|
+
[ex-api] 📁 RBAC_ROLE = ...ZERO_MODULE.../ADMIN.SUPER/...
|
|
62
|
+
[ex-api] 📁 RBAC_ROLE = .../init/oob/role/ADMIN.DEVELOPER/...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 前置条件
|
|
66
|
+
|
|
67
|
+
### 环境变量配置
|
|
68
|
+
数据库连接信息存储在 `.r2mo/app.env` 文件中:
|
|
69
|
+
```bash
|
|
70
|
+
export Z_DB_HOST="127.0.0.1"
|
|
71
|
+
export Z_DB_PORT="3306"
|
|
72
|
+
export Z_DB_USERNAME="root"
|
|
73
|
+
export Z_DB_PASSWORD="pl,okmijn123"
|
|
74
|
+
export Z_DBS_INSTANCE="DB_HMS_001_APP" # 业务数据库实例名
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 数据库表结构
|
|
78
|
+
表名:`X_MENU`(位于 `DB_HMS_001_APP` 数据库)
|
|
79
|
+
|
|
80
|
+
关键字段:
|
|
81
|
+
- `ID` (varchar(36)) - 主键
|
|
82
|
+
- `NAME` (varchar(255)) - 菜单唯一标识符,如 `zero.desktop`, `hms.order.main`
|
|
83
|
+
- `TEXT` (varchar(255)) - 菜单中文显示文本,如 "工作台", "新增预定"
|
|
84
|
+
- `LEVEL` (bigint) - 菜单层级(1=一级菜单, 2=二级菜单, 3=三级菜单, 4=四级菜单)
|
|
85
|
+
- `PARENT_ID` (varchar(36)) - 父菜单 ID(NULL 表示顶级菜单)
|
|
86
|
+
- `ORDER` (bigint) - 同级菜单排序序号
|
|
87
|
+
- `SIGMA` (varchar(128)) - 租户/应用标识符
|
|
88
|
+
- `APP_ID` (varchar(36)) - 应用 ID
|
|
89
|
+
- `ACTIVE` (bit(1)) - 是否启用
|
|
90
|
+
|
|
91
|
+
## 执行步骤
|
|
92
|
+
|
|
93
|
+
### 步骤 1: 加载环境变量
|
|
94
|
+
```bash
|
|
95
|
+
source .r2mo/app.env
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 步骤 2: 查询数据库获取菜单 NAME 列表
|
|
99
|
+
查询所有菜单的 NAME 字段,按 ORDER 和 NAME 排序:
|
|
100
|
+
```bash
|
|
101
|
+
mysql -h"$Z_DB_HOST" -P"$Z_DB_PORT" -u"$Z_DB_USERNAME" -p"$Z_DB_PASSWORD" \
|
|
102
|
+
DB_HMS_001_APP \
|
|
103
|
+
-e "SELECT NAME FROM X_MENU ORDER BY \`ORDER\`, LEVEL, NAME;" \
|
|
104
|
+
2>/dev/null | tail -n +2
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**输出示例**:
|
|
108
|
+
```
|
|
109
|
+
zero.desktop
|
|
110
|
+
zero.desktop.my
|
|
111
|
+
zero.desktop.my.todo-pending
|
|
112
|
+
hms.order
|
|
113
|
+
hms.order.main
|
|
114
|
+
...
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 步骤 3: 生成 ADMIN.DEVELOPER.json(NAME 数组)
|
|
118
|
+
将查询结果转换为 JSON 数组格式:
|
|
119
|
+
```bash
|
|
120
|
+
mysql -h"$Z_DB_HOST" -P"$Z_DB_PORT" -u"$Z_DB_USERNAME" -p"$Z_DB_PASSWORD" \
|
|
121
|
+
DB_HMS_001_APP \
|
|
122
|
+
-e "SELECT NAME FROM X_MENU ORDER BY \`ORDER\`, LEVEL, NAME;" \
|
|
123
|
+
2>/dev/null | tail -n +2 | \
|
|
124
|
+
jq -R -s -c 'split("\n") | map(select(length > 0))'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**生成文件格式**:
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"name" : [ "zero.desktop", "zero.desktop.my", "zero.desktop.my.todo-pending", ... ]
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**写入文件**:
|
|
135
|
+
```
|
|
136
|
+
src/main/resources/init/permission/ui.menu/ADMIN.DEVELOPER.json
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 步骤 4: 查询数据库获取层级菜单结构
|
|
140
|
+
查询菜单的完整层级信息(ID, PARENT_ID, NAME, TEXT, ORDER):
|
|
141
|
+
```bash
|
|
142
|
+
mysql -h"$Z_DB_HOST" -P"$Z_DB_PORT" -u"$Z_DB_USERNAME" -p"$Z_DB_PASSWORD" \
|
|
143
|
+
DB_HMS_001_APP -B \
|
|
144
|
+
-e "SELECT ID, IFNULL(PARENT_ID,''), NAME, IFNULL(TEXT,NAME), IFNULL(\`ORDER\`,0) FROM X_MENU;" \
|
|
145
|
+
2>/dev/null
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**输出示例**:
|
|
149
|
+
```
|
|
150
|
+
ID PARENT_ID NAME TEXT ORDER
|
|
151
|
+
8aca2f19-9845-495a-bf39-b77514a20da5 zero.desktop 工作台 10000
|
|
152
|
+
613a2ae1-e066-4454-b5fb-efdcd6578f51 8aca2f19-9845-495a-bf39-b77514a20da5 zero.desktop.my 工作台 2000
|
|
153
|
+
...
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 步骤 5: 生成 role/ADMIN.DEVELOPER.json(层级文本数组)
|
|
157
|
+
使用 Python 脚本构建父子关系树,按层级生成带缩进的中文菜单文本:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
mysql -h"$Z_DB_HOST" -P"$Z_DB_PORT" -u"$Z_DB_USERNAME" -p"$Z_DB_PASSWORD" \
|
|
161
|
+
DB_HMS_001_APP -B \
|
|
162
|
+
-e "SELECT ID, IFNULL(PARENT_ID,''), NAME, IFNULL(TEXT,NAME), IFNULL(\`ORDER\`,0) FROM X_MENU;" \
|
|
163
|
+
2>/dev/null | python3 -c '
|
|
164
|
+
import sys, json
|
|
165
|
+
|
|
166
|
+
# 读取数据库输出
|
|
167
|
+
rows = []
|
|
168
|
+
lines = sys.stdin.read().splitlines()
|
|
169
|
+
for ln in lines[1:]: # 跳过表头
|
|
170
|
+
parts = ln.split("\t")
|
|
171
|
+
if len(parts) >= 5:
|
|
172
|
+
rows.append(parts[:5])
|
|
173
|
+
|
|
174
|
+
# 构建菜单字典(按 ID 索引)
|
|
175
|
+
by_id = {
|
|
176
|
+
r[0]: {
|
|
177
|
+
"id": r[0],
|
|
178
|
+
"pid": r[1] or None, # 父 ID(空字符串转为 None)
|
|
179
|
+
"name": r[2],
|
|
180
|
+
"text": r[3],
|
|
181
|
+
"order": int(r[4])
|
|
182
|
+
}
|
|
183
|
+
for r in rows
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# 构建父子关系映射
|
|
187
|
+
children = {}
|
|
188
|
+
for n in by_id.values():
|
|
189
|
+
children.setdefault(n["pid"], []).append(n)
|
|
190
|
+
|
|
191
|
+
# 对每个父节点的子节点按 ORDER 和 NAME 排序
|
|
192
|
+
for k in children:
|
|
193
|
+
children[k].sort(key=lambda x: (x["order"], x["name"]))
|
|
194
|
+
|
|
195
|
+
# 递归遍历生成带缩进的文本数组
|
|
196
|
+
out = []
|
|
197
|
+
def walk(pid, depth):
|
|
198
|
+
for n in children.get(pid, []):
|
|
199
|
+
# 缩进规则:每层级增加 4 个空格(depth-1 是因为顶级菜单不缩进)
|
|
200
|
+
out.append((" " * (4 * (depth - 1))) + n["text"])
|
|
201
|
+
walk(n["id"], depth + 1)
|
|
202
|
+
|
|
203
|
+
# 从顶级菜单(pid=None)开始遍历
|
|
204
|
+
walk(None, 1)
|
|
205
|
+
|
|
206
|
+
# 输出 JSON 数组
|
|
207
|
+
print(json.dumps(out, ensure_ascii=False, indent=2))
|
|
208
|
+
'
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**生成文件格式**:
|
|
212
|
+
```json
|
|
213
|
+
[
|
|
214
|
+
"工作台",
|
|
215
|
+
" 工作台",
|
|
216
|
+
" 我的待办",
|
|
217
|
+
" 个人报表",
|
|
218
|
+
" 帮助",
|
|
219
|
+
"酒店管理",
|
|
220
|
+
" 预定",
|
|
221
|
+
" 新增预定",
|
|
222
|
+
...
|
|
223
|
+
]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**缩进规则**:
|
|
227
|
+
- 一级菜单(LEVEL=1):无缩进
|
|
228
|
+
- 二级菜单(LEVEL=2):4 个空格
|
|
229
|
+
- 三级菜单(LEVEL=3):8 个空格
|
|
230
|
+
- 四级菜单(LEVEL=4):12 个空格
|
|
231
|
+
|
|
232
|
+
**写入文件**:
|
|
233
|
+
```
|
|
234
|
+
src/main/resources/init/permission/ui.menu/role/ADMIN.DEVELOPER.json
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 数据验证
|
|
238
|
+
|
|
239
|
+
### 验证点 1: NAME 数组完整性
|
|
240
|
+
检查 `ADMIN.DEVELOPER.json` 中的 name 数组是否包含数据库中所有菜单:
|
|
241
|
+
```bash
|
|
242
|
+
# 统计数据库中的菜单数量
|
|
243
|
+
mysql -h"$Z_DB_HOST" -P"$Z_DB_PORT" -u"$Z_DB_USERNAME" -p"$Z_DB_PASSWORD" \
|
|
244
|
+
DB_HMS_001_APP \
|
|
245
|
+
-e "SELECT COUNT(*) FROM X_MENU;" 2>/dev/null
|
|
246
|
+
|
|
247
|
+
# 统计 JSON 文件中的菜单数量
|
|
248
|
+
jq '.name | length' src/main/resources/init/permission/ui.menu/ADMIN.DEVELOPER.json
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### 验证点 2: 层级结构正确性
|
|
252
|
+
检查 `role/ADMIN.DEVELOPER.json` 中的缩进是否符合父子关系:
|
|
253
|
+
- 子菜单的缩进必须比父菜单多 4 个空格
|
|
254
|
+
- 同级菜单的缩进必须相同
|
|
255
|
+
|
|
256
|
+
### 验证点 3: 排序正确性
|
|
257
|
+
菜单顺序应按照数据库中的 `ORDER` 字段排序,同 ORDER 值按 NAME 字母序排序。
|
|
258
|
+
|
|
259
|
+
## 关键注意事项
|
|
260
|
+
|
|
261
|
+
1. **字段处理**:
|
|
262
|
+
- `PARENT_ID` 为 NULL 时表示顶级菜单,需转换为空字符串或 None
|
|
263
|
+
- `TEXT` 为 NULL 时使用 `NAME` 作为显示文本
|
|
264
|
+
- `ORDER` 为 NULL 时默认为 0
|
|
265
|
+
|
|
266
|
+
2. **排序逻辑**:
|
|
267
|
+
- 主排序:`ORDER` 字段(升序)
|
|
268
|
+
- 次排序:`LEVEL` 字段(升序)
|
|
269
|
+
- 第三排序:`NAME` 字段(字母序)
|
|
270
|
+
|
|
271
|
+
3. **层级构建**:
|
|
272
|
+
- 使用递归算法从顶级菜单(PARENT_ID=NULL)开始遍历
|
|
273
|
+
- 每递归一层,缩进增加 4 个空格
|
|
274
|
+
- 深度从 1 开始(顶级菜单 depth=1,无缩进)
|
|
275
|
+
|
|
276
|
+
4. **字符编码**:
|
|
277
|
+
- 确保 JSON 输出使用 UTF-8 编码
|
|
278
|
+
- Python 脚本中使用 `ensure_ascii=False` 保留中文字符
|
|
279
|
+
|
|
280
|
+
5. **数据库连接**:
|
|
281
|
+
- 使用 `2>/dev/null` 抑制 MySQL 密码警告
|
|
282
|
+
- 使用 `-B` 参数输出 TSV 格式(制表符分隔)
|
|
283
|
+
- 使用 `tail -n +2` 跳过表头行
|
|
284
|
+
|
|
285
|
+
## 执行结果
|
|
286
|
+
|
|
287
|
+
本次更新(2026-03-05):
|
|
288
|
+
- **ADMIN.DEVELOPER.json**:更新了 196 个菜单项的 NAME 数组
|
|
289
|
+
- **role/ADMIN.DEVELOPER.json**:更新了 196 个菜单项的中文显示文本(带层级缩进)
|
|
290
|
+
|
|
291
|
+
主要变化:
|
|
292
|
+
- 移除已废弃的菜单前缀(`hm.*` → `hms.*`)
|
|
293
|
+
- 新增流程管理模块(`zero.wm.*`)
|
|
294
|
+
- 新增权限细分配置(`zero.ssm.rbac.authority.*`)
|
|
295
|
+
- 新增仪表盘快捷入口(`zero.bsm.dash.*`, `zero.cm.dash.*`)
|
|
296
|
+
- 财务模块结构调整(`zero.fms.admin.*` → `zero.fms.process.*`)
|
|
297
|
+
|
|
298
|
+
## 相关文件
|
|
299
|
+
|
|
300
|
+
- 环境配置:`.r2mo/app.env`
|
|
301
|
+
- 目标文件 1:`src/main/resources/init/permission/ui.menu/ADMIN.DEVELOPER.json`
|
|
302
|
+
- 目标文件 2:`src/main/resources/init/permission/ui.menu/role/ADMIN.DEVELOPER.json`
|
|
303
|
+
- 数据库表:`DB_HMS_001_APP.X_MENU`
|
|
304
|
+
|
|
305
|
+
## 依赖工具
|
|
306
|
+
|
|
307
|
+
- MySQL Client 8.0+
|
|
308
|
+
- jq 1.6+
|
|
309
|
+
- Python 3.7+
|
|
310
|
+
- Bash 4.0+
|