Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba284922e5 |
@@ -9,6 +9,11 @@
|
|||||||
- 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节
|
- 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节
|
||||||
- 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段
|
- 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段
|
||||||
|
|
||||||
|
## 1.0.63
|
||||||
|
|
||||||
|
- 数据管理支持字段级 lookup:`options_json` 可声明同库关联表(`ref_table` / `value_column` / `label_column`),宿主新建/编辑时渲染下拉
|
||||||
|
- 更新 SCHEMA.md 与元数据校验,兼容静态枚举数组与 lookup 对象两种形态
|
||||||
|
|
||||||
## 1.0.62
|
## 1.0.62
|
||||||
|
|
||||||
- Skill Action 新增 `interaction` / `interactionByPlacement`:声明数据管理点击是直通、轻确认还是参数表单(与 `executionProfile` 正交)
|
- Skill Action 新增 `interaction` / `interactionByPlacement`:声明数据管理点击是直通、轻确认还是参数表单(与 `executionProfile` 正交)
|
||||||
|
|||||||
2
SKILL.md
2
SKILL.md
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: 技能开发模板(通用业务版)
|
name: 技能开发模板(通用业务版)
|
||||||
description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。"
|
description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。"
|
||||||
version: 1.0.62
|
version: 1.0.63
|
||||||
author: 深圳匠厂科技有限公司
|
author: 深圳匠厂科技有限公司
|
||||||
metadata:
|
metadata:
|
||||||
openclaw:
|
openclaw:
|
||||||
|
|||||||
@@ -354,7 +354,11 @@ CREATE TABLE demo_items (
|
|||||||
|
|
||||||
## 枚举字段 options_json
|
## 枚举字段 options_json
|
||||||
|
|
||||||
`options_json` 为 JSON 数组,每项包含 `value` 与 `label`:
|
`options_json` 支持两种形态:
|
||||||
|
|
||||||
|
### 1)静态枚举(数组)
|
||||||
|
|
||||||
|
每项包含 `value` 与 `label`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
@@ -366,6 +370,31 @@ CREATE TABLE demo_items (
|
|||||||
|
|
||||||
宿主据此渲染选择框;技能侧负责保证 JSON 合法且与物理字段取值一致。
|
宿主据此渲染选择框;技能侧负责保证 JSON 合法且与物理字段取值一致。
|
||||||
|
|
||||||
|
### 2)表关联 lookup(对象,推荐用于外键式字段)
|
||||||
|
|
||||||
|
当字段取值依赖同库另一张业务表时,`display_type` 设为 `lookup`,`options_json` 写对象(**不是**数组):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ref_table": "platforms",
|
||||||
|
"value_column": "platform_key",
|
||||||
|
"label_column": "display_name",
|
||||||
|
"filter_column": "enabled",
|
||||||
|
"filter_value": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 必填 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `ref_table` | 是 | 同库被引用表名(snake_case 标识符) |
|
||||||
|
| `value_column` | 是 | 写入当前字段的值列 |
|
||||||
|
| `label_column` | 是 | 下拉展示名列 |
|
||||||
|
| `filter_column` / `filter_value` | 否 | 等值过滤(如只列出 `enabled=1`) |
|
||||||
|
|
||||||
|
宿主在加载表 schema 时查询 `ref_table`,把结果展开成 `{value,label}` 下拉选项;**物理列仍存标量**(如 `platform_key` 文本、`account_id` 整数),不做嵌套子表。
|
||||||
|
|
||||||
|
示例:账号表的平台字段 → 平台信息表;凭据表的账号编号 → 账号信息表。
|
||||||
|
|
||||||
## 幂等初始化标准
|
## 幂等初始化标准
|
||||||
|
|
||||||
- `_jiangchang_tables` 和 `_jiangchang_columns` 必须通过 upsert 初始化
|
- `_jiangchang_tables` 和 `_jiangchang_columns` 必须通过 upsert 初始化
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ def _default_uses_unixepoch(default_value: object) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
def validate_options_json(options_json: str | None) -> tuple[list[str], list[str]]:
|
def validate_options_json(options_json: str | None) -> tuple[list[str], list[str]]:
|
||||||
"""校验枚举 options_json 可被解析为 [{value, label}, ...] 结构。"""
|
"""校验 options_json:静态枚举数组,或 lookup 对象。"""
|
||||||
errors: list[str] = []
|
errors: list[str] = []
|
||||||
warnings: list[str] = []
|
warnings: list[str] = []
|
||||||
if options_json is None or str(options_json).strip() == "":
|
if options_json is None or str(options_json).strip() == "":
|
||||||
@@ -206,8 +206,24 @@ def validate_options_json(options_json: str | None) -> tuple[list[str], list[str
|
|||||||
except json.JSONDecodeError as exc:
|
except json.JSONDecodeError as exc:
|
||||||
errors.append(f"options_json 不是合法 JSON:{exc}")
|
errors.append(f"options_json 不是合法 JSON:{exc}")
|
||||||
return errors, warnings
|
return errors, warnings
|
||||||
|
|
||||||
|
if isinstance(parsed, dict):
|
||||||
|
for key in ("ref_table", "value_column", "label_column"):
|
||||||
|
if not str(parsed.get(key) or "").strip():
|
||||||
|
errors.append(f"options_json lookup 必须包含非空 {key}")
|
||||||
|
ident = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||||
|
for key in ("ref_table", "value_column", "label_column", "filter_column"):
|
||||||
|
raw = parsed.get(key)
|
||||||
|
if raw is None or raw == "":
|
||||||
|
continue
|
||||||
|
if not ident.match(str(raw)):
|
||||||
|
errors.append(f"options_json.{key} 必须是安全标识符,当前为 {raw!r}")
|
||||||
|
if parsed.get("filter_column") not in (None, "") and "filter_value" not in parsed:
|
||||||
|
warnings.append("options_json lookup 声明了 filter_column 但未提供 filter_value")
|
||||||
|
return errors, warnings
|
||||||
|
|
||||||
if not isinstance(parsed, list):
|
if not isinstance(parsed, list):
|
||||||
errors.append("options_json 必须是 JSON 数组")
|
errors.append("options_json 必须是 JSON 数组(静态枚举)或对象(lookup)")
|
||||||
return errors, warnings
|
return errors, warnings
|
||||||
for index, item in enumerate(parsed):
|
for index, item in enumerate(parsed):
|
||||||
if not isinstance(item, dict):
|
if not isinstance(item, dict):
|
||||||
|
|||||||
Reference in New Issue
Block a user