mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-10-29 08:58:22 +08:00
docs(skills): 技能文档更新为全局权限判定协议
This commit is contained in:
@@ -41,28 +41,26 @@ CURD 生成器生成列表页骨架后,所有业务定制(按钮、字段渲
|
|||||||
|
|
||||||
```
|
```
|
||||||
app/admin/view/<module>/
|
app/admin/view/<module>/
|
||||||
├── index.html # 极简 HTML,仅 table 元素 + data-auth-* 权限标记
|
├── index.html # 纯结构零权限声明,权限由 layout 全局 UA_AUTH 注入
|
||||||
├── _common.js # init 对象(URL 配置等)
|
├── _common.js # init 对象(URL 配置等)
|
||||||
└── index.js # ua.table.render({init, cols, toolbar?})
|
└── index.js # ua.table.render({init, cols, toolbar?})
|
||||||
```
|
```
|
||||||
|
|
||||||
**index.html**(典型示例,仅 11 行):
|
**index.html**(典型示例):
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div class="layuimini-container">
|
<div class="layuimini-container">
|
||||||
<div class="layuimini-main">
|
<div class="layuimini-main">
|
||||||
<table id="currentTable" class="layui-table layui-hide"
|
<table id="currentTable" class="layui-table layui-hide"
|
||||||
data-auth-index="{:auth('system.timer_config/index')}"
|
|
||||||
data-auth-edit="{:auth('system.timer_config/edit')}"
|
|
||||||
data-auth-export="{:auth('system.timer_config/export')}"
|
|
||||||
data-auth-modify="{:auth('system.timer_config/modify')}"
|
|
||||||
lay-filter="currentTable">
|
lay-filter="currentTable">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
**`data-auth-X` 是按钮权限显隐的关键**:JS 里的 `auth: 'X'` 必须能在 HTML 找到对应的 `data-auth-X`,且值为 1 才显示。详见第六章。
|
**权限判定协议**:index.html 不写任何权限声明。页面加载时 layout 注入全局载荷 `window.UA_AUTH = {all, controller, nodes}`(服务端一次性构建,超管 `all:true`),前端 `ua.auth(node)` 据此全局判定按钮显隐:短名(不含 `/`)自动补当前控制器前缀,跨控制器直接写全节点(如 `'app.code_bind/scan'`,与注册节点逐字一致,动作段大小写敏感)。详见 5.4 与 5.7。
|
||||||
|
|
||||||
|
> **升级注意**:本机制的判定实现位于 admin-core.js,其静态引用带框架版本号缓存键(下游部署为 site_version)。升级框架后若按钮显隐异常,先强制刷新浏览器缓存(Ctrl+F5)再排查,避免旧缓存 JS 与新页面叠加造成误判。
|
||||||
|
|
||||||
### 1.3 前后端链路
|
### 1.3 前后端链路
|
||||||
|
|
||||||
@@ -241,7 +239,7 @@ ua.table.render({
|
|||||||
text: '导入',
|
text: '导入',
|
||||||
url: 'demo.index/import',
|
url: 'demo.index/import',
|
||||||
method: 'open', // 见 5.3 method 表
|
method: 'open', // 见 5.3 method 表
|
||||||
auth: 'import', // 对应 data-auth-import
|
auth: 'import', // 短名=当前控制器动作(等价 'demo.index/import')
|
||||||
class: 'layui-btn layui-btn-warm layui-btn-sm',
|
class: 'layui-btn layui-btn-warm layui-btn-sm',
|
||||||
icon: 'fa fa-upload',
|
icon: 'fa fa-upload',
|
||||||
title: '导入数据',
|
title: '导入数据',
|
||||||
@@ -308,7 +306,7 @@ ua.table.render({
|
|||||||
| `url` | string \| function | `''` | 请求 URL;为 function 时接收 `(data, operat)` 动态构造 |
|
| `url` | string \| function | `''` | 请求 URL;为 function 时接收 `(data, operat)` 动态构造 |
|
||||||
| `method` | string | `'open'` | 见 5.3 method 表 |
|
| `method` | string | `'open'` | 见 5.3 method 表 |
|
||||||
| `field` | string \| function | `'id'` | URL 拼接的主键字段名;为 function 时可动态构造 URL |
|
| `field` | string \| function | `'id'` | URL 拼接的主键字段名;为 function 时可动态构造 URL |
|
||||||
| `auth` | string | `'add'` | 权限节点名(对应 HTML 的 `data-auth-X`) |
|
| `auth` | string | `'add'` | 权限节点:短名=当前控制器动作,跨控制器写全节点(与注册节点逐字一致,详见 5.7) |
|
||||||
| `class` | string | `''` | HTML class(layui-btn 样式) |
|
| `class` | string | `''` | HTML class(layui-btn 样式) |
|
||||||
| `icon` | string | `''` | 图标 class |
|
| `icon` | string | `''` | 图标 class |
|
||||||
| `extend` | string | `''` | 额外 HTML 属性(如 `data-full="true"`) |
|
| `extend` | string | `''` | 额外 HTML 属性(如 `data-full="true"`) |
|
||||||
@@ -338,7 +336,7 @@ operat: [
|
|||||||
text: '触发',
|
text: '触发',
|
||||||
url: init.triggerUrl,
|
url: init.triggerUrl,
|
||||||
method: 'request',
|
method: 'request',
|
||||||
auth: 'trigger',
|
auth: 'trigger', // 短名=当前控制器动作(等价 'system.timer_config/trigger')
|
||||||
class: 'layui-btn layui-btn-warm layui-btn-xs',
|
class: 'layui-btn layui-btn-warm layui-btn-xs',
|
||||||
// 仅 run_type='manual' 时显示
|
// 仅 run_type='manual' 时显示
|
||||||
_if: function(data) {
|
_if: function(data) {
|
||||||
@@ -356,15 +354,7 @@ operat: [
|
|||||||
|
|
||||||
### 5.7 跨控制器权限检查
|
### 5.7 跨控制器权限检查
|
||||||
|
|
||||||
按钮跳转到**其他控制器**的页面时(如 box_sn 页面的"绑定"按钮跳转 `code_bind/scan`),`auth` 的权限节点不在当前控制器下。需要在 HTML 用自定义 key 声明跨控制器的 `data-auth` 属性。
|
按钮跳转到**其他控制器**的页面时(如 box_sn 页面的"绑定"按钮跳转 `code_bind/scan`),`auth` 直接写全节点即可,无需任何 HTML 中转声明:
|
||||||
|
|
||||||
**HTML**:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<table ... data-auth-bind="{:auth('app.code_bind/scan')}" ...>
|
|
||||||
```
|
|
||||||
|
|
||||||
**JS**:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
[{
|
[{
|
||||||
@@ -372,13 +362,21 @@ operat: [
|
|||||||
method: 'tab',
|
method: 'tab',
|
||||||
text: '绑定',
|
text: '绑定',
|
||||||
title: '扫码绑定',
|
title: '扫码绑定',
|
||||||
auth: 'bind', // 对应 HTML 中的 data-auth-bind
|
auth: 'app.code_bind/scan', // 全节点,与注册节点逐字一致
|
||||||
url: 'app.code_bind/scan', // 跨控制器 URL
|
url: 'app.code_bind/scan', // 跨控制器 URL
|
||||||
icon: 'fa fa-link'
|
icon: 'fa fa-link'
|
||||||
}]
|
}]
|
||||||
```
|
```
|
||||||
|
|
||||||
框架通过 `data-auth-{auth值}` 查找 HTML 属性做权限校验:有权限显示按钮,无权限自动隐藏。
|
`ua.auth` 按全局允许集(layout 注入的 `window.UA_AUTH`)判定:有权限显示按钮,无权限自动隐藏。
|
||||||
|
|
||||||
|
**全节点写法约定**:
|
||||||
|
|
||||||
|
- 与 `@NodeAnnotation` 注册的节点**逐字一致**:`ua.auth` 做字符串匹配,前端不做任何规范化转换
|
||||||
|
- 动作段**大小写敏感**:注册为 `setMaster` 就写 `'system.host/setMaster'`,禁止 snake 化写成 `set-master`(parseNodeStr 只规范控制器段,动作段原样保留)
|
||||||
|
- 短名(不含 `/`)自动按"当前控制器/短名"解析,只适用于本控制器动作
|
||||||
|
|
||||||
|
**未注册动作的行为差异**:权限载荷不含 default_pass,前端对"不在允许集"的按钮一律保守隐藏。在 `default_auth_check=true` 的部署中,未注册动作后端仍按真实规则放行,即前端隐藏而后端放行,此时应前后端核对并补注册节点。旧协议(HTML `data-auth` 属性中转)仅作为下游旧页面的回退通道保留,新页面不使用。
|
||||||
|
|
||||||
### 5.8 operat 数组结构
|
### 5.8 operat 数组结构
|
||||||
|
|
||||||
@@ -518,7 +516,7 @@ public function index()
|
|||||||
| `$selectWhere` | array 属性,`selectList()` 方法的过滤条件 |
|
| `$selectWhere` | array 属性,`selectList()` 方法的过滤条件 |
|
||||||
| `modify()` | 状态开关接口,`switch` 渲染器自动调用,接收 `id`/`field`/`value` |
|
| `modify()` | 状态开关接口,`switch` 渲染器自动调用,接收 `id`/`field`/`value` |
|
||||||
| `selectList()` | 下拉数据源接口,接收 `selectFields` 参数 |
|
| `selectList()` | 下拉数据源接口,接收 `selectFields` 参数 |
|
||||||
| `@NodeAnnotation` | 控制器方法注解,生成权限节点(与 `data-auth-X` 对应) |
|
| `@NodeAnnotation` | 控制器方法注解,生成权限节点(前端 `ua.auth` 全局判定按钮显隐的依据) |
|
||||||
|
|
||||||
**关联搜索示例**(`extend/base/admin/controller/mall/GoodsBase.php`):
|
**关联搜索示例**(`extend/base/admin/controller/mall/GoodsBase.php`):
|
||||||
|
|
||||||
@@ -594,9 +592,9 @@ CURD 生成时会将关联模型的全部字段(如 `systemAdmin.*`)输出
|
|||||||
|
|
||||||
**错误 6:权限节点不匹配(按钮不显示)**
|
**错误 6:权限节点不匹配(按钮不显示)**
|
||||||
|
|
||||||
- HTML 的 `data-auth-X` 必须存在
|
- JS 里的 auth 值解析出的节点必须与控制器 `@NodeAnnotation` 注册的节点一致:短名等于"当前控制器/动作",跨控制器直接写全节点
|
||||||
- JS 里的 `auth: 'X'` 必须能找到对应的 `data-auth-X`
|
- 全节点与注册节点逐字比对,动作段大小写敏感(注册 `setMaster` 写成 `set-master` 即失配隐藏)
|
||||||
- `{:auth('controller/action')}` 的节点路径必须与控制器 `@NodeAnnotation` 一致
|
- 未注册动作前端保守隐藏;`default_auth_check=true` 部署下后端仍按真实规则放行,前后端核对后补注册节点
|
||||||
|
|
||||||
排查工具:`php think admin:permission:nodes`(见 [ulthon-permission-cli](./ulthon-permission-cli/SKILL.md))
|
排查工具:`php think admin:permission:nodes`(见 [ulthon-permission-cli](./ulthon-permission-cli/SKILL.md))
|
||||||
|
|
||||||
@@ -604,10 +602,11 @@ CURD 生成时会将关联模型的全部字段(如 `systemAdmin.*`)输出
|
|||||||
|
|
||||||
**"按钮不显示"排查步骤**:
|
**"按钮不显示"排查步骤**:
|
||||||
|
|
||||||
1. 检查 HTML 是否声明了对应的 `data-auth-X`(用浏览器开发者工具看 table 元素)
|
1. 浏览器控制台核对 `window.UA_AUTH`:确认按钮 auth 值解析出的节点在允许集内(短名自动补当前控制器前缀,全节点逐字匹配)
|
||||||
2. 检查 `{:auth('xxx/yyy')}` 的返回值是否为 1(用超管账号测试排除权限问题)
|
2. 检查 JS 里 auth 值与 `@NodeAnnotation` 注册节点是否逐字一致(动作段大小写敏感,禁止 snake 化动作段)
|
||||||
3. 检查 JS 里 `auth: 'X'` 的 X 与 HTML `data-auth-X` 是否完全一致(大小写)
|
3. 用超管账号测试排除账号权限配置问题(超管 `all:true` 恒显)
|
||||||
4. 查看权限节点列表:`php think admin:permission:nodes`
|
4. 查看权限节点列表:`php think admin:permission:nodes`
|
||||||
|
5. 下游旧页面(data-auth 回退通道):检查 HTML 是否声明了对应的 `data-auth-X` 属性且值为 1。仅旧页面有此声明,新协议页面 index.html 无权限声明
|
||||||
|
|
||||||
**"搜索不生效"排查步骤**:
|
**"搜索不生效"排查步骤**:
|
||||||
|
|
||||||
@@ -787,6 +786,6 @@ layoutDefault: true, // 旧协议"自动判断",视
|
|||||||
- [ulthon-scheme-curd-workflow](./ulthon-scheme-curd-workflow/SKILL.md):CURD 代码生成流程(生成本技能所定制的列表页骨架)
|
- [ulthon-scheme-curd-workflow](./ulthon-scheme-curd-workflow/SKILL.md):CURD 代码生成流程(生成本技能所定制的列表页骨架)
|
||||||
- [ulthon-scheme-definition](./ulthon-scheme-definition/SKILL.md):Scheme 定义(决定生成哪些字段、字段类型)
|
- [ulthon-scheme-definition](./ulthon-scheme-definition/SKILL.md):Scheme 定义(决定生成哪些字段、字段类型)
|
||||||
- [ulthon-page-api-dual-mode](./ulthon-page-api-dual-mode/SKILL.md):页面/接口同体机制(列表接口的 JSON 返回模式)
|
- [ulthon-page-api-dual-mode](./ulthon-page-api-dual-mode/SKILL.md):页面/接口同体机制(列表接口的 JSON 返回模式)
|
||||||
- [ulthon-permission-cli](./ulthon-permission-cli/SKILL.md):权限节点核对(`data-auth-X` 与 `@NodeAnnotation` 对不上时)
|
- [ulthon-permission-cli](./ulthon-permission-cli/SKILL.md):权限节点核对(按钮 auth 值与 `@NodeAnnotation` 注册节点对不上时)
|
||||||
- [ulthon-tools-http-call](./ulthon-tools-http-call/SKILL.md):CLI 模拟请求验证列表接口
|
- [ulthon-tools-http-call](./ulthon-tools-http-call/SKILL.md):CLI 模拟请求验证列表接口
|
||||||
- [ulthon-page-qa](./ulthon-page-qa/SKILL.md):页面验证(AI 自测)与浏览器断言要点
|
- [ulthon-page-qa](./ulthon-page-qa/SKILL.md):页面验证(AI 自测)与浏览器断言要点
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ Vue 形态的 `v-for="d in rows"` 里的 `d`:
|
|||||||
|------|------|
|
|------|------|
|
||||||
| `...row` | 行原始字段全部可用(username、title、price、create_time 等) |
|
| `...row` | 行原始字段全部可用(username、title、price、create_time 等) |
|
||||||
| `_cells` | 对象,field 到该列 templet 渲染产物 HTML 的映射。只有配了渲染器的列才有内容;纯文本列恒为空串,**勿引用,直接用原始字段**;隐藏列(col.hide)不产出对应键 |
|
| `_cells` | 对象,field 到该列 templet 渲染产物 HTML 的映射。只有配了渲染器的列才有内容;纯文本列恒为空串,**勿引用,直接用原始字段**;隐藏列(col.hide)不产出对应键 |
|
||||||
| `_operatHtml` | 操作列渲染产物(编辑/删除等按钮 HTML,已按 `data-auth-*` 裁剪权限) |
|
| `_operatHtml` | 操作列渲染产物(编辑/删除等按钮 HTML,已按当前登录者权限裁剪) |
|
||||||
| `_checked` | 该行是否选中(store 选中集合) |
|
| `_checked` | 该行是否选中(store 选中集合) |
|
||||||
| `_disabled` | 该行是否禁选 |
|
| `_disabled` | 该行是否禁选 |
|
||||||
|
|
||||||
|
|||||||
@@ -82,27 +82,25 @@ cols: [[
|
|||||||
|
|
||||||
完整 searchOp 操作符表见 [ulthon-admin-table](./ulthon-admin-table/SKILL.md) 第七章。
|
完整 searchOp 操作符表见 [ulthon-admin-table](./ulthon-admin-table/SKILL.md) 第七章。
|
||||||
|
|
||||||
### 1.4 按钮显隐:`data-auth-*`(按权限节点)
|
### 1.4 按钮显隐:UA_AUTH 全局权限判定
|
||||||
|
|
||||||
权限按钮由两处配合控制:
|
按钮显隐由全局权限载荷决定,index.html 纯结构零权限声明:
|
||||||
|
|
||||||
1. **HTML 写入权限标记**:表格容器上以 `data-auth-{动作}="{:auth('控制器/动作')}"` 形式声明每个动作的权限值(1 有权限 / 0 无)
|
1. **layout 注入全局载荷**:页面加载时服务端一次性注入 `window.UA_AUTH = {all, controller, nodes}`(`all`=超管标记;`controller`=当前控制器节点名;`nodes`=允许集 `{'控制器': ['动作', ...]}`,超管 `all:true` 时 nodes 为空数组)
|
||||||
- 实测:`extend/base/admin/view/system/admin/index.html:3`:
|
- 实测:`extend/base/admin/view/layout/default.html`(内联 script,与 window.CONFIG 同级)
|
||||||
```html
|
- 同体 JSON 模式(get_page_data)不携带该载荷,仅在页面 HTML 中存在
|
||||||
<table id="currentTable" ...
|
2. **ua.auth(node) 全局判定**:按钮对象带 `auth` 值,框架经 `ua.checkAuth` 依序判定:`'1'` 恒显 → `CONFIG.IS_SUPER_ADMIN` → `ua.auth(node)` → `data-auth-{node}` 属性回退(仅旧页面)
|
||||||
data-auth-add="{:auth('system.admin/add')}"
|
- 短名(不含 `/`)自动补 `UA_AUTH.controller` 前缀;全节点逐字匹配,动作段大小写敏感(如 `system.host/setMaster` 禁止写成 `set-master`)
|
||||||
data-auth-edit="{:auth('system.admin/edit')}"
|
|
||||||
data-auth-delete="{:auth('system.admin/delete')}"
|
|
||||||
data-auth-password="{:auth('system.admin/password')}"
|
|
||||||
data-auth-modify="{:auth('system.admin/modify')}"
|
|
||||||
lay-filter="currentTable">
|
|
||||||
```
|
|
||||||
- `{:auth(...)}` 是模板函数,返回当前登录账号对该权限节点的布尔判定
|
|
||||||
2. **JS 按 auth 匹配显隐**:cols/toolbar 里的按钮对象带 `auth: '{动作}'`,框架读取对应 `data-auth-{动作}` 值决定渲染与否
|
|
||||||
- 实测:`system/admin/index.js`(toolbar 默认含 add;操作列含 `password` 自定义按钮 + edit + delete)
|
|
||||||
- 默认值:`operat.auth = operat.auth || 'add'`(`admin-table.js:1105`)——未写 `auth` 的按钮按 `add` 节点判定
|
- 默认值:`operat.auth = operat.auth || 'add'`(`admin-table.js:1105`)——未写 `auth` 的按钮按 `add` 节点判定
|
||||||
|
|
||||||
> 验证口诀:**`auth: 'X'`**(JS)必须能在表格容器找到对应的 **`data-auth-X`**(HTML),且该值=1,按钮才会出现。节点路径必须和控制器 `@NodeAnnotation` 注解一致。
|
**QA 校验口径**:
|
||||||
|
|
||||||
|
- 页面源码断言 `window.UA_AUTH` 存在且形状正确(`{all, controller, nodes}` 三键齐全)
|
||||||
|
- 按钮显隐对应用户允许集:允许集内的按钮出现,不在允许集的消失,超管全显
|
||||||
|
- 未注册动作按钮前端保守隐藏(载荷无 default_pass);`default_auth_check=true` 部署下后端仍按真实规则放行,属已知差异,以前后端核对为准
|
||||||
|
- `data-auth-*` HTML 属性是下游旧页面的回退通道,新协议页面无此声明
|
||||||
|
|
||||||
|
> 验证口诀:按钮节点在 `UA_AUTH.nodes` 允许集内则显示,不在则隐藏(超管恒显)。节点路径必须和控制器 `@NodeAnnotation` 注解逐字一致(动作段大小写敏感)。
|
||||||
|
|
||||||
### 1.5 按钮显隐:`_if`(按数据状态)
|
### 1.5 按钮显隐:`_if`(按数据状态)
|
||||||
|
|
||||||
@@ -179,7 +177,7 @@ php think tools:http:call --url="/admin/system.admin/index?get_page_data=1" --me
|
|||||||
- 用智能体自带浏览器能力(Playwright MCP / agent-browser)打开页面(需登录态),逐项核对:
|
- 用智能体自带浏览器能力(Playwright MCP / agent-browser)打开页面(需登录态),逐项核对:
|
||||||
1. 表格表头/列按 cols 渲染(字段、标题、关联字段显示正确)
|
1. 表格表头/列按 cols 渲染(字段、标题、关联字段显示正确)
|
||||||
2. 搜索区下拉选项 = Page Data 模式里 `select_list_*` 的内容(对照步骤 3 结果)
|
2. 搜索区下拉选项 = Page Data 模式里 `select_list_*` 的内容(对照步骤 3 结果)
|
||||||
3. 工具栏按钮:`data-auth-X=1` 的按钮出现、`=0` 的消失;`auth: 'X'`(JS)与 `data-auth-X`(HTML)一一对应
|
3. 工具栏按钮:显隐与用户允许集一致(`window.UA_AUTH`),有权限的出现、无权限的消失;旧页面回退通道才存在 `data-auth` 属性
|
||||||
4. 操作列按钮:`_if` 条件成立才出现
|
4. 操作列按钮:`_if` 条件成立才出现
|
||||||
|
|
||||||
### 步骤 5 — 搜索提交验证(网络抓包)
|
### 步骤 5 — 搜索提交验证(网络抓包)
|
||||||
@@ -287,8 +285,8 @@ visual-qa 技能(视觉对比 / 回归断言)
|
|||||||
| `#data-brage` 隐藏元素 | `extend/base/admin/view/layout/default.html` |
|
| `#data-brage` 隐藏元素 | `extend/base/admin/view/layout/default.html` |
|
||||||
| `data_brage` assign | `extend/base/common/controller/AdminControllerBase.php:273` |
|
| `data_brage` assign | `extend/base/common/controller/AdminControllerBase.php:273` |
|
||||||
| 后端 assign `select_list_*` | `extend/base/admin/controller/system/HostBase.php` |
|
| 后端 assign `select_list_*` | `extend/base/admin/controller/system/HostBase.php` |
|
||||||
| `data-auth-{动作}` HTML 标记 | `extend/base/admin/view/system/admin/index.html:3` |
|
| `window.UA_AUTH` 载荷注入(layout 内联) | `extend/base/admin/view/layout/default.html` |
|
||||||
| `data-auth-set-master` 跨控制器权限示例 | `extend/base/admin/view/system/host/index.html:5` |
|
| set-master 按钮全节点写法(勘正:旧 `data-auth-set-master` 属性是"自定义键/驼峰动作段"样例而非跨控制器样例,auth() 参数与本页同控制器;属性已随新协议清理,JS 现写全节点) | `extend/base/admin/view/system/host/index.js:33` |
|
||||||
| toolbar/auth(默认 add) | `extend/base/admin/view/system/admin/index.js` |
|
| toolbar/auth(默认 add) | `extend/base/admin/view/system/admin/index.js` |
|
||||||
| 操作列 auth(password 自定义按钮) | `extend/base/admin/view/system/admin/index.js:24-31` |
|
| 操作列 auth(password 自定义按钮) | `extend/base/admin/view/system/admin/index.js:24-31` |
|
||||||
| `operat.auth` 默认 'add' | `admin-table.js:1105` |
|
| `operat.auth` 默认 'add' | `admin-table.js:1105` |
|
||||||
@@ -305,7 +303,7 @@ visual-qa 技能(视觉对比 / 回归断言)
|
|||||||
- [ulthon-page-api-dual-mode](./ulthon-page-api-dual-mode/SKILL.md):页面/接口同体的触发条件与机制(本技能 1.6 节的依据)
|
- [ulthon-page-api-dual-mode](./ulthon-page-api-dual-mode/SKILL.md):页面/接口同体的触发条件与机制(本技能 1.6 节的依据)
|
||||||
- [ulthon-tools-http-call](./ulthon-tools-http-call/SKILL.md):CLI HTTP 调用工具用法(本技能三模式的执行工具)
|
- [ulthon-tools-http-call](./ulthon-tools-http-call/SKILL.md):CLI HTTP 调用工具用法(本技能三模式的执行工具)
|
||||||
- [ulthon-scheme-curd-workflow](./ulthon-scheme-curd-workflow/SKILL.md):标准开发流程,本技能是其「功能验证」环节的页面级细则
|
- [ulthon-scheme-curd-workflow](./ulthon-scheme-curd-workflow/SKILL.md):标准开发流程,本技能是其「功能验证」环节的页面级细则
|
||||||
- [ulthon-permission-cli](./ulthon-permission-cli/SKILL.md):`data-auth-*` / `auth` 注解节点对不上时,用它核对节点
|
- [ulthon-permission-cli](./ulthon-permission-cli/SKILL.md):按钮 auth 值与注解注册节点对不上时,用它核对节点
|
||||||
- `playwright` / `visual-qa`(内置技能):前端浏览器验证与视觉对比
|
- `playwright` / `visual-qa`(内置技能):前端浏览器验证与视觉对比
|
||||||
|
|
||||||
### 5.3 计划假设修正记录
|
### 5.3 计划假设修正记录
|
||||||
|
|||||||
Reference in New Issue
Block a user