Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 571c135114 |
@@ -9,6 +9,12 @@
|
|||||||
- 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节
|
- 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节
|
||||||
- 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段
|
- 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段
|
||||||
|
|
||||||
|
## 1.0.90
|
||||||
|
|
||||||
|
- 沉淀数据管理表格说明契约:`_jiangchang_tables.grid_help` / `_jiangchang_columns.grid_help`
|
||||||
|
- 有内容才显示表上方说明和列头「?」;不写则与今日一致
|
||||||
|
- 与新增/编辑表单的 `description` 独立,禁止互拷(见 `references/SCHEMA.md`)
|
||||||
|
|
||||||
## 1.0.89
|
## 1.0.89
|
||||||
|
|
||||||
- 仓库增加 MIT 许可证,版权归属深圳匠厂科技有限公司
|
- 仓库增加 MIT 许可证,版权归属深圳匠厂科技有限公司
|
||||||
|
|||||||
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.89
|
version: 1.0.90
|
||||||
author: 深圳匠厂科技有限公司
|
author: 深圳匠厂科技有限公司
|
||||||
metadata:
|
metadata:
|
||||||
openclaw:
|
openclaw:
|
||||||
|
|||||||
@@ -658,6 +658,7 @@ Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件
|
|||||||
| URL(薄层) | `display_type` 或 `format`: `url` | `display_type: url` |
|
| URL(薄层) | `display_type` 或 `format`: `url` | `display_type: url` |
|
||||||
| Email(薄层) | `display_type` 或 `format`: `email` | `display_type: email` |
|
| Email(薄层) | `display_type` 或 `format`: `email` | `display_type: email` |
|
||||||
| 说明灰字 | `description` | `_jiangchang_columns.description` |
|
| 说明灰字 | `description` | `_jiangchang_columns.description` |
|
||||||
|
| 表格横幅 / 列头「?」 | (无;Action 不用) | `_jiangchang_tables.grid_help` / `_jiangchang_columns.grid_help` |
|
||||||
| 默认值 | `default` | SQLite 列 `DEFAULT` |
|
| 默认值 | `default` | SQLite 列 `DEFAULT` |
|
||||||
| 只读 | `readOnly: true` | 列 `editable: 0` / 宿主只读规则 |
|
| 只读 | `readOnly: true` | 列 `editable: 0` / 宿主只读规则 |
|
||||||
| **条件显隐** | **`visibleWhen`**(见下节) | **本版 CRUD 无对称**;仅 Action / 定时任务参数表单 |
|
| **条件显隐** | **`visibleWhen`**(见下节) | **本版 CRUD 无对称**;仅 Action / 定时任务参数表单 |
|
||||||
@@ -727,6 +728,8 @@ Skill Action 弹窗与数据管理「新增 / 编辑」使用**同一套控件
|
|||||||
| Skill Action 弹窗 | `inputSchema.title` | `inputSchema.description` | `inputSchema.default` | `type` + `display_type`/`format` |
|
| Skill Action 弹窗 | `inputSchema.title` | `inputSchema.description` | `inputSchema.default` | `type` + `display_type`/`format` |
|
||||||
| 数据管理新增/编辑 | `_jiangchang_columns.display_name` | `_jiangchang_columns.description` | 物理列 SQLite `DEFAULT` | `display_type` + 物理类型推断 |
|
| 数据管理新增/编辑 | `_jiangchang_columns.display_name` | `_jiangchang_columns.description` | 物理列 SQLite `DEFAULT` | `display_type` + 物理类型推断 |
|
||||||
|
|
||||||
|
数据管理**表格**上方说明与列头「?」用 `_jiangchang_tables.grid_help` / `_jiangchang_columns.grid_help`(空则不渲染),**不要**用 `description`。见 [`SCHEMA.md`](SCHEMA.md)「表格说明 `grid_help`」。
|
||||||
|
|
||||||
CRUD 侧宿主义务与禁止事项见 [`SCHEMA.md`](SCHEMA.md)「表单与展示:稳定字段类型」「新增/编辑表单:字段说明与默认值」。同一业务含义两边文案与控件应对齐,但分别配置。
|
CRUD 侧宿主义务与禁止事项见 [`SCHEMA.md`](SCHEMA.md)「表单与展示:稳定字段类型」「新增/编辑表单:字段说明与默认值」。同一业务含义两边文案与控件应对齐,但分别配置。
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
- 定义真实 SQLite 表结构
|
- 定义真实 SQLite 表结构
|
||||||
- 使用英文 `snake_case` 表名和字段名
|
- 使用英文 `snake_case` 表名和字段名
|
||||||
- 使用 `_jiangchang_tables` 提供表级展示元数据
|
- 使用 `_jiangchang_tables` 提供表级展示元数据
|
||||||
- 使用 `_jiangchang_columns` 提供字段级展示元数据(含可选 `description` 字段说明)
|
- 使用 `_jiangchang_columns` 提供字段级展示元数据(含可选 `description` 表单说明、可选 `grid_help` 表格说明)
|
||||||
- 需要「新增表单预填」时,在物理列上声明 SQLite `DEFAULT`(勿把默认值只写在文案里)
|
- 需要「新增表单预填」时,在物理列上声明 SQLite `DEFAULT`(勿把默认值只写在文案里)
|
||||||
- 定义哪些字段可见、可搜索、可创建、可编辑
|
- 定义哪些字段可见、可搜索、可创建、可编辑
|
||||||
- 定义字段展示类型和枚举选项
|
- 定义字段展示类型和枚举选项
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
- 根据 schema 渲染数据管理页面
|
- 根据 schema 渲染数据管理页面
|
||||||
- 根据 `editable` 推导字段是否可创建或编辑
|
- 根据 `editable` 推导字段是否可创建或编辑
|
||||||
- 在**新增 / 编辑**表单中,若列有 `_jiangchang_columns.description`,在标签下方展示该说明(灰字;空则不显示)
|
- 在**新增 / 编辑**表单中,若列有 `_jiangchang_columns.description`,在标签下方展示该说明(灰字;空则不显示)
|
||||||
|
- 在数据管理**表格**中,若表有 `_jiangchang_tables.grid_help` 则在表上方展示可折叠说明;若列有 `_jiangchang_columns.grid_help` 则在列头显示「?」;空/未写则不渲染。**不**把 `description` 当作表格说明
|
||||||
- 打开**新增**表单时,对可创建字段用 SQLite 列 `DEFAULT`(`PRAGMA table_info.dflt_value`)预填;无 DEFAULT 则留空
|
- 打开**新增**表单时,对可创建字段用 SQLite 列 `DEFAULT`(`PRAGMA table_info.dflt_value`)预填;无 DEFAULT 则留空
|
||||||
- 执行通用查询、新增、编辑、删除、导入、导出
|
- 执行通用查询、新增、编辑、删除、导入、导出
|
||||||
- 对字段名、表名、类型和权限进行最终校验
|
- 对字段名、表名、类型和权限进行最终校验
|
||||||
@@ -138,7 +139,8 @@ metadata:
|
|||||||
|------|------|------|
|
|------|------|------|
|
||||||
| `table_name` | 是 | 真实英文表名 |
|
| `table_name` | 是 | 真实英文表名 |
|
||||||
| `display_name` | 是 | 用户可见的中文业务名称 |
|
| `display_name` | 是 | 用户可见的中文业务名称 |
|
||||||
| `description` | 否 | 表说明 |
|
| `description` | 否 | 表说明(表单/备注用途);**不**用于表格上方横幅 |
|
||||||
|
| `grid_help` | 否 | 数据管理表格上方说明;空/未写则不出横幅。与 `description` 独立,禁止互拷(见下节) |
|
||||||
| `sort_order` | 否 | 兼容保留字段,不用于替代物理字段顺序 |
|
| `sort_order` | 否 | 兼容保留字段,不用于替代物理字段顺序 |
|
||||||
| `visible` | 是 | `1` 在宿主数据管理中展示 / `0` 隐藏 |
|
| `visible` | 是 | `1` 在宿主数据管理中展示 / `0` 隐藏 |
|
||||||
| `readonly` | 是 | `1` 整张表只读;`0` 允许宿主根据字段权限执行写操作 |
|
| `readonly` | 是 | `1` 整张表只读;`0` 允许宿主根据字段权限执行写操作 |
|
||||||
@@ -212,6 +214,43 @@ upsert_table_metadata(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 表格说明 `grid_help`(宿主支持)
|
||||||
|
|
||||||
|
技能可给数据管理**表格**写说明,与新增/编辑表单的 `description` **完全独立**:
|
||||||
|
|
||||||
|
| 写在哪 | 宿主做什么 | 空/未写 |
|
||||||
|
|--------|------------|---------|
|
||||||
|
| `_jiangchang_tables.grid_help` | 表格上方可折叠横幅(首行摘要;有后续行才出展开) | 不出横幅 |
|
||||||
|
| `_jiangchang_columns.grid_help` | 列头「?」,点击查看该列说明 | 不出「?」 |
|
||||||
|
|
||||||
|
规则:
|
||||||
|
|
||||||
|
- **opt-in**:大多数表/列不需要写;不写则行为与今日一致
|
||||||
|
- **禁止**把 `description` 拷进 `grid_help`,也禁止把表格规则写进 `description`(`description` 只给表单灰字)
|
||||||
|
- 多行文本时:第一行是摘要,其余行点「展开」后可见
|
||||||
|
- 通过 `upsert_table_metadata(..., grid_help=...)` / `upsert_column_metadata(..., grid_help=...)` 写入;旧库由 `init_display_metadata_tables` 幂等 `ALTER` 补列
|
||||||
|
- 需已支持该字段的匠厂宿主;更旧版本会忽略未知列,不写则无影响
|
||||||
|
|
||||||
|
示例(仅在确有表格规则时写;模板默认业务表不要预填):
|
||||||
|
|
||||||
|
```python
|
||||||
|
upsert_table_metadata(
|
||||||
|
cursor,
|
||||||
|
table_name="timeliness_records",
|
||||||
|
display_name="时效登记",
|
||||||
|
readonly=1,
|
||||||
|
grid_help="超时按环节规则判定。\n交单:预计到港日前 3 天须交单",
|
||||||
|
)
|
||||||
|
upsert_column_metadata(
|
||||||
|
cursor,
|
||||||
|
table_name="timeliness_records",
|
||||||
|
column_name="submit_date",
|
||||||
|
display_name="交单日期",
|
||||||
|
grid_help="预计到港日前 3 天须交单",
|
||||||
|
editable=0,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
禁止:
|
禁止:
|
||||||
|
|
||||||
- 使用中文真实表名
|
- 使用中文真实表名
|
||||||
@@ -228,6 +267,7 @@ upsert_table_metadata(
|
|||||||
| `column_name` | 是 | 真实英文字段名 |
|
| `column_name` | 是 | 真实英文字段名 |
|
||||||
| `display_name` | 是 | 用户可见的中文字段名(表头与表单标签);保持简短 |
|
| `display_name` | 是 | 用户可见的中文字段名(表头与表单标签);保持简短 |
|
||||||
| `description` | 否 | 字段说明(给人看的短文案);**宿主在新增/编辑表单标签下方展示**(见下节);不要塞进 `display_name` |
|
| `description` | 否 | 字段说明(给人看的短文案);**宿主在新增/编辑表单标签下方展示**(见下节);不要塞进 `display_name` |
|
||||||
|
| `grid_help` | 否 | 数据管理表头「?」;空/未写则不出。与表单 `description` 独立,禁止互拷 |
|
||||||
| `display_order` | 否 | 兼容字段,默认保持 `NULL` |
|
| `display_order` | 否 | 兼容字段,默认保持 `NULL` |
|
||||||
| `visible` | 是 | 是否进入数据管理 schema /「列」面板(`0` = **硬隐藏**,用户无法勾回;默认不展示但可勾回请用表级 `default_visible_columns_json`) |
|
| `visible` | 是 | 是否进入数据管理 schema /「列」面板(`0` = **硬隐藏**,用户无法勾回;默认不展示但可勾回请用表级 `default_visible_columns_json`) |
|
||||||
| `searchable` | 是 | 是否参与搜索 |
|
| `searchable` | 是 | 是否参与搜索 |
|
||||||
@@ -277,7 +317,9 @@ upsert_table_metadata(
|
|||||||
| 字段说明 | `_jiangchang_columns.description`(可选) | 新增/编辑表单中,在标签下方以灰字展示;空则不显示 |
|
| 字段说明 | `_jiangchang_columns.description`(可选) | 新增/编辑表单中,在标签下方以灰字展示;空则不显示 |
|
||||||
| 创建默认值 | 物理列 SQLite `DEFAULT`(如 `limit_n INTEGER NOT NULL DEFAULT 0`) | 打开「新增」时,对可创建字段预填该默认值;无 DEFAULT 则留空 |
|
| 创建默认值 | 物理列 SQLite `DEFAULT`(如 `limit_n INTEGER NOT NULL DEFAULT 0`) | 打开「新增」时,对可创建字段预填该默认值;无 DEFAULT 则留空 |
|
||||||
| 编辑已有行 | — | **不**用 DEFAULT 覆盖已有行数据 |
|
| 编辑已有行 | — | **不**用 DEFAULT 覆盖已有行数据 |
|
||||||
| 表格列头 | 只用 `display_name` | 长说明**不**进入列头 |
|
| 表格列头标题 | `display_name` | 短名;不要把长说明塞进列头文字 |
|
||||||
|
| 表格列头「?」 | `_jiangchang_columns.grid_help`(可选) | 有内容才显示「?」;**不**回退 `description` |
|
||||||
|
| 表格上方说明 | `_jiangchang_tables.grid_help`(可选) | 有内容才显示横幅;**不**回退表级 `description` |
|
||||||
|
|
||||||
规则与禁止:
|
规则与禁止:
|
||||||
|
|
||||||
@@ -552,7 +594,7 @@ Action 弹窗内联 Lookup 与上表 **同构**(字段名一致),见 [`ACT
|
|||||||
|
|
||||||
- `_jiangchang_tables` 和 `_jiangchang_columns` 必须通过 upsert 初始化
|
- `_jiangchang_tables` 和 `_jiangchang_columns` 必须通过 upsert 初始化
|
||||||
- 多次执行初始化不能重复记录
|
- 多次执行初始化不能重复记录
|
||||||
- 重新初始化可以更新展示名、描述、`visible`、`searchable`、`editable`、`display_type`、`options_json`
|
- 重新初始化可以更新展示名、描述、`grid_help`、`visible`、`searchable`、`editable`、`display_type`、`options_json`
|
||||||
- 元数据不能残留旧字段(删除或重命名字段时必须同步清理)
|
- 元数据不能残留旧字段(删除或重命名字段时必须同步清理)
|
||||||
- 元数据不能引用不存在的表或字段
|
- 元数据不能引用不存在的表或字段
|
||||||
- 新增字段或表时必须同步增加元数据
|
- 新增字段或表时必须同步增加元数据
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS _jiangchang_tables (
|
|||||||
table_name TEXT PRIMARY KEY,
|
table_name TEXT PRIMARY KEY,
|
||||||
display_name TEXT NOT NULL,
|
display_name TEXT NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
|
grid_help TEXT,
|
||||||
sort_order INTEGER,
|
sort_order INTEGER,
|
||||||
visible INTEGER NOT NULL DEFAULT 1,
|
visible INTEGER NOT NULL DEFAULT 1,
|
||||||
readonly INTEGER NOT NULL DEFAULT 0,
|
readonly INTEGER NOT NULL DEFAULT 0,
|
||||||
@@ -35,6 +36,7 @@ CREATE TABLE IF NOT EXISTS _jiangchang_columns (
|
|||||||
column_name TEXT NOT NULL,
|
column_name TEXT NOT NULL,
|
||||||
display_name TEXT NOT NULL,
|
display_name TEXT NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
|
grid_help TEXT,
|
||||||
display_order INTEGER,
|
display_order INTEGER,
|
||||||
visible INTEGER NOT NULL DEFAULT 1,
|
visible INTEGER NOT NULL DEFAULT 1,
|
||||||
searchable INTEGER NOT NULL DEFAULT 1,
|
searchable INTEGER NOT NULL DEFAULT 1,
|
||||||
@@ -45,22 +47,35 @@ CREATE TABLE IF NOT EXISTS _jiangchang_columns (
|
|||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def _pragma_column_names(cursor, table_name: str) -> set[str]:
|
||||||
|
cursor.execute(f"PRAGMA table_info({table_name!r})")
|
||||||
|
return {str(row[1]) for row in cursor.fetchall()}
|
||||||
|
|
||||||
|
|
||||||
def _ensure_jiangchang_tables_columns(cursor) -> None:
|
def _ensure_jiangchang_tables_columns(cursor) -> None:
|
||||||
"""旧库补列:CREATE IF NOT EXISTS 不会给已有表加新字段。"""
|
"""旧库补列:CREATE IF NOT EXISTS 不会给已有表加新字段。"""
|
||||||
cursor.execute("PRAGMA table_info('_jiangchang_tables')")
|
cols = _pragma_column_names(cursor, "_jiangchang_tables")
|
||||||
cols = {str(row[1]) for row in cursor.fetchall()}
|
|
||||||
if "default_sort_json" not in cols:
|
if "default_sort_json" not in cols:
|
||||||
cursor.execute("ALTER TABLE _jiangchang_tables ADD COLUMN default_sort_json TEXT")
|
cursor.execute("ALTER TABLE _jiangchang_tables ADD COLUMN default_sort_json TEXT")
|
||||||
if "default_visible_columns_json" not in cols:
|
if "default_visible_columns_json" not in cols:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"ALTER TABLE _jiangchang_tables ADD COLUMN default_visible_columns_json TEXT"
|
"ALTER TABLE _jiangchang_tables ADD COLUMN default_visible_columns_json TEXT"
|
||||||
)
|
)
|
||||||
|
if "grid_help" not in cols:
|
||||||
|
cursor.execute("ALTER TABLE _jiangchang_tables ADD COLUMN grid_help TEXT")
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_jiangchang_columns_columns(cursor) -> None:
|
||||||
|
cols = _pragma_column_names(cursor, "_jiangchang_columns")
|
||||||
|
if "grid_help" not in cols:
|
||||||
|
cursor.execute("ALTER TABLE _jiangchang_columns ADD COLUMN grid_help TEXT")
|
||||||
|
|
||||||
|
|
||||||
def init_display_metadata_tables(cursor) -> None:
|
def init_display_metadata_tables(cursor) -> None:
|
||||||
cursor.execute(_JIANGCHANG_TABLES_DDL)
|
cursor.execute(_JIANGCHANG_TABLES_DDL)
|
||||||
cursor.execute(_JIANGCHANG_COLUMNS_DDL)
|
cursor.execute(_JIANGCHANG_COLUMNS_DDL)
|
||||||
_ensure_jiangchang_tables_columns(cursor)
|
_ensure_jiangchang_tables_columns(cursor)
|
||||||
|
_ensure_jiangchang_columns_columns(cursor)
|
||||||
|
|
||||||
|
|
||||||
def upsert_table_metadata(
|
def upsert_table_metadata(
|
||||||
@@ -69,6 +84,7 @@ def upsert_table_metadata(
|
|||||||
table_name: str,
|
table_name: str,
|
||||||
display_name: str,
|
display_name: str,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
grid_help: str | None = None,
|
||||||
visible: int = 1,
|
visible: int = 1,
|
||||||
readonly: int = 0,
|
readonly: int = 0,
|
||||||
default_sort_json: str | None = None,
|
default_sort_json: str | None = None,
|
||||||
@@ -83,17 +99,20 @@ def upsert_table_metadata(
|
|||||||
default_visible_columns_json: 宿主数据管理默认展示列,JSON 字符串数组,例如
|
default_visible_columns_json: 宿主数据管理默认展示列,JSON 字符串数组,例如
|
||||||
'["stat_type","period","stage"]'
|
'["stat_type","period","stage"]'
|
||||||
为空则全显;用户改过「列」后以本机偏好为准(软默认,区别于 visible=0 硬隐藏)。
|
为空则全显;用户改过「列」后以本机偏好为准(软默认,区别于 visible=0 硬隐藏)。
|
||||||
|
|
||||||
|
grid_help: 数据管理表格上方说明;空则不出横幅。与表单用的 description 独立,禁止互拷。
|
||||||
"""
|
"""
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO _jiangchang_tables (
|
INSERT INTO _jiangchang_tables (
|
||||||
table_name, display_name, description, visible, readonly,
|
table_name, display_name, description, grid_help, visible, readonly,
|
||||||
default_sort_json, default_visible_columns_json
|
default_sort_json, default_visible_columns_json
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
ON CONFLICT(table_name) DO UPDATE SET
|
ON CONFLICT(table_name) DO UPDATE SET
|
||||||
display_name = excluded.display_name,
|
display_name = excluded.display_name,
|
||||||
description = excluded.description,
|
description = excluded.description,
|
||||||
|
grid_help = excluded.grid_help,
|
||||||
visible = excluded.visible,
|
visible = excluded.visible,
|
||||||
readonly = excluded.readonly,
|
readonly = excluded.readonly,
|
||||||
default_sort_json = excluded.default_sort_json,
|
default_sort_json = excluded.default_sort_json,
|
||||||
@@ -103,6 +122,7 @@ def upsert_table_metadata(
|
|||||||
table_name,
|
table_name,
|
||||||
display_name,
|
display_name,
|
||||||
description,
|
description,
|
||||||
|
grid_help,
|
||||||
visible,
|
visible,
|
||||||
readonly,
|
readonly,
|
||||||
default_sort_json,
|
default_sort_json,
|
||||||
@@ -118,6 +138,7 @@ def upsert_column_metadata(
|
|||||||
column_name: str,
|
column_name: str,
|
||||||
display_name: str,
|
display_name: str,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
grid_help: str | None = None,
|
||||||
visible: int = 1,
|
visible: int = 1,
|
||||||
searchable: int = 1,
|
searchable: int = 1,
|
||||||
editable: int = 1,
|
editable: int = 1,
|
||||||
@@ -125,16 +146,18 @@ def upsert_column_metadata(
|
|||||||
options_json: str | None = None,
|
options_json: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
# display_order 保留为 NULL:宿主按 PRAGMA table_info cid 展示字段,不读 display_order。
|
# display_order 保留为 NULL:宿主按 PRAGMA table_info cid 展示字段,不读 display_order。
|
||||||
|
# grid_help: 表头「?」;空则不出。与表单用的 description 独立,禁止互拷。
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO _jiangchang_columns (
|
INSERT INTO _jiangchang_columns (
|
||||||
table_name, column_name, display_name, description,
|
table_name, column_name, display_name, description, grid_help,
|
||||||
display_order, visible, searchable, editable, display_type, options_json
|
display_order, visible, searchable, editable, display_type, options_json
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, NULL, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?)
|
||||||
ON CONFLICT(table_name, column_name) DO UPDATE SET
|
ON CONFLICT(table_name, column_name) DO UPDATE SET
|
||||||
display_name = excluded.display_name,
|
display_name = excluded.display_name,
|
||||||
description = excluded.description,
|
description = excluded.description,
|
||||||
|
grid_help = excluded.grid_help,
|
||||||
display_order = NULL,
|
display_order = NULL,
|
||||||
visible = excluded.visible,
|
visible = excluded.visible,
|
||||||
searchable = excluded.searchable,
|
searchable = excluded.searchable,
|
||||||
@@ -147,6 +170,7 @@ def upsert_column_metadata(
|
|||||||
column_name,
|
column_name,
|
||||||
display_name,
|
display_name,
|
||||||
description,
|
description,
|
||||||
|
grid_help,
|
||||||
visible,
|
visible,
|
||||||
searchable,
|
searchable,
|
||||||
editable,
|
editable,
|
||||||
@@ -171,6 +195,7 @@ def seed_column_metadata_batch(
|
|||||||
column_name=str(column["column_name"]),
|
column_name=str(column["column_name"]),
|
||||||
display_name=str(column["display_name"]),
|
display_name=str(column["display_name"]),
|
||||||
description=str(column["description"]) if column.get("description") else None,
|
description=str(column["description"]) if column.get("description") else None,
|
||||||
|
grid_help=str(column["grid_help"]) if column.get("grid_help") else None,
|
||||||
visible=int(column.get("visible", 1)),
|
visible=int(column.get("visible", 1)),
|
||||||
searchable=int(column.get("searchable", 1)),
|
searchable=int(column.get("searchable", 1)),
|
||||||
editable=int(column.get("editable", 1)),
|
editable=int(column.get("editable", 1)),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"""技能标识、版本与平台公共库约束(复制后请修改 slug/version/logger)。"""
|
"""技能标识、版本与平台公共库约束(复制后请修改 slug/version/logger)。"""
|
||||||
|
|
||||||
SKILL_SLUG = "your-skill-slug"
|
SKILL_SLUG = "your-skill-slug"
|
||||||
SKILL_VERSION = "1.0.89"
|
SKILL_VERSION = "1.0.90"
|
||||||
LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug"
|
LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug"
|
||||||
PLATFORM_KIT_MIN_VERSION = "1.2.11"
|
PLATFORM_KIT_MIN_VERSION = "1.2.11"
|
||||||
|
|||||||
@@ -578,6 +578,100 @@ metadata:
|
|||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def test_grid_help_upsert_and_migrate_from_legacy_schema(self) -> None:
|
||||||
|
conn = sqlite3.connect(":memory:")
|
||||||
|
try:
|
||||||
|
from db.display_metadata import (
|
||||||
|
init_display_metadata_tables,
|
||||||
|
upsert_column_metadata,
|
||||||
|
upsert_table_metadata,
|
||||||
|
)
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE _jiangchang_tables (
|
||||||
|
table_name TEXT PRIMARY KEY,
|
||||||
|
display_name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
sort_order INTEGER,
|
||||||
|
visible INTEGER NOT NULL DEFAULT 1,
|
||||||
|
readonly INTEGER NOT NULL DEFAULT 0,
|
||||||
|
default_sort_json TEXT,
|
||||||
|
default_visible_columns_json TEXT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE _jiangchang_columns (
|
||||||
|
table_name TEXT NOT NULL,
|
||||||
|
column_name TEXT NOT NULL,
|
||||||
|
display_name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
display_order INTEGER,
|
||||||
|
visible INTEGER NOT NULL DEFAULT 1,
|
||||||
|
searchable INTEGER NOT NULL DEFAULT 1,
|
||||||
|
editable INTEGER NOT NULL DEFAULT 1,
|
||||||
|
display_type TEXT,
|
||||||
|
options_json TEXT,
|
||||||
|
PRIMARY KEY (table_name, column_name)
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
init_display_metadata_tables(cur)
|
||||||
|
cur.execute("PRAGMA table_info('_jiangchang_tables')")
|
||||||
|
self.assertIn("grid_help", {str(row[1]) for row in cur.fetchall()})
|
||||||
|
cur.execute("PRAGMA table_info('_jiangchang_columns')")
|
||||||
|
self.assertIn("grid_help", {str(row[1]) for row in cur.fetchall()})
|
||||||
|
|
||||||
|
upsert_table_metadata(
|
||||||
|
cur,
|
||||||
|
table_name="demo_items",
|
||||||
|
display_name="示例记录",
|
||||||
|
description="表单备注,不应出现在表格横幅",
|
||||||
|
grid_help="表格横幅说明",
|
||||||
|
)
|
||||||
|
upsert_column_metadata(
|
||||||
|
cur,
|
||||||
|
table_name="demo_items",
|
||||||
|
column_name="title",
|
||||||
|
display_name="标题",
|
||||||
|
description="填标题",
|
||||||
|
grid_help="列头问号说明",
|
||||||
|
)
|
||||||
|
upsert_table_metadata(
|
||||||
|
cur,
|
||||||
|
table_name="empty_help",
|
||||||
|
display_name="无表格说明",
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT description, grid_help
|
||||||
|
FROM _jiangchang_tables
|
||||||
|
WHERE table_name = 'demo_items'
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
self.assertEqual(cur.fetchone(), ("表单备注,不应出现在表格横幅", "表格横幅说明"))
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT description, grid_help
|
||||||
|
FROM _jiangchang_columns
|
||||||
|
WHERE table_name = 'demo_items' AND column_name = 'title'
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
self.assertEqual(cur.fetchone(), ("填标题", "列头问号说明"))
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT grid_help FROM _jiangchang_tables
|
||||||
|
WHERE table_name = 'empty_help'
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
self.assertTrue(not cur.fetchone()[0])
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -348,6 +348,8 @@ class TestDocsStandards(unittest.TestCase):
|
|||||||
"文件 / 图片上传",
|
"文件 / 图片上传",
|
||||||
"default_visible_columns_json",
|
"default_visible_columns_json",
|
||||||
"默认展示列",
|
"默认展示列",
|
||||||
|
"grid_help",
|
||||||
|
"表格说明 `grid_help`",
|
||||||
):
|
):
|
||||||
self.assertIn(marker, text, msg=f"SCHEMA.md missing {marker!r}")
|
self.assertIn(marker, text, msg=f"SCHEMA.md missing {marker!r}")
|
||||||
|
|
||||||
@@ -365,6 +367,7 @@ class TestDocsStandards(unittest.TestCase):
|
|||||||
"SCHEMA.md",
|
"SCHEMA.md",
|
||||||
"字段条件显隐",
|
"字段条件显隐",
|
||||||
"visibleWhen",
|
"visibleWhen",
|
||||||
|
"grid_help",
|
||||||
):
|
):
|
||||||
self.assertIn(marker, text, msg=f"ACTIONS.md missing {marker!r}")
|
self.assertIn(marker, text, msg=f"ACTIONS.md missing {marker!r}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user