344 lines
14 KiB
Markdown
344 lines
14 KiB
Markdown
# 数据管理单元格呈现(Cell Presentation)契约(v1.0)
|
||
|
||
> **状态:正式契约 v1.0(`cells[]` 文档 `schemaVersion` 1)+ 加法 Grid Presentation。**
|
||
> **目标:** 冻结「技能声明语义呈现 → 宿主映射主题样式」的通用能力:某一格、整行、整列、若干行×若干列,供任意业务场景复用。
|
||
> **非目标:** 超时/SLA 专用字段;技能下发任意 CSS / 任意色值;宿主实现业务规则引擎。
|
||
> **配套 Schema:** [`../assets/schemas/skill-cell-presentation.schema.json`](../assets/schemas/skill-cell-presentation.schema.json)(格子)、[`../assets/schemas/skill-grid-presentation.schema.json`](../assets/schemas/skill-grid-presentation.schema.json)(行/列/区域)。
|
||
|
||
相关正交轴见 [`ACTIONS.md`](ACTIONS.md)、[`POLICY.md`](POLICY.md)、[`SCHEMA.md`](SCHEMA.md)。
|
||
|
||
---
|
||
|
||
## 0. 一句话
|
||
|
||
技能可以声明:**哪张业务表**上,**哪些行 × 哪些列**需要特殊标色/强调(语义 `tone` + 可选说明)。
|
||
|
||
| 想涂什么 | 怎么声明 |
|
||
|----------|----------|
|
||
| 某一格 | 一行 × 一列(v1 `cells[]` 或一条格子规则) |
|
||
| 整行 | 若干行 × 该轴全部列 |
|
||
| 整列 | 该轴全部行 × 若干列 |
|
||
| 区域 | 若干行 × 若干列 |
|
||
|
||
用途不限:时效超时未填、库存预警、状态异常、必填缺失、审核驳回等。
|
||
**不是**「再加一列超时文字」;强调落在**真正要关注的业务格子或行**上。
|
||
|
||
---
|
||
|
||
## 0.1 能力档位
|
||
|
||
| 档位 | 技能行为 | 宿主行为 |
|
||
|------|----------|----------|
|
||
| **P0(默认)** | 不写呈现数据 / 未启用 | 数据管理表格与今日一致,无特殊标色 |
|
||
| **P1** | 按规则写入呈现文档或推荐旁路表 | 渲染对应格子 / 行 / 列 / 区域的语义样式;可选汇总 `alert: true` 做进页提醒 |
|
||
|
||
多数技能保持 **P0**。需要视觉强调时再启用。模板 `actions.json` **默认不启用**。
|
||
|
||
---
|
||
|
||
## 0.2 宿主能力
|
||
|
||
| 能力 | 旁路表 | 宿主 |
|
||
|------|--------|------|
|
||
| 格子着色 | `_jiangchang_cell_presentation` | 既有宿主即可 |
|
||
| 整行 / 整列 / 区域 | `_jiangchang_grid_presentation` | 需已读取该表(匠厂数据管理已支持)。**旧宿主忽略该表**,格子着色仍有效 |
|
||
|
||
同一开关 `cellPresentation.enabled` 同时打开两张旁路表。未建表 = 该通道为空,宿主忽略。
|
||
|
||
---
|
||
|
||
## 1. 职责边界
|
||
|
||
| 角色 | 负责 | 不负责 |
|
||
|------|------|--------|
|
||
| **技能** | 按**当前业务数据**算出哪些格子/行/列要强调;在数据变更后**重算**并覆盖旧结果 | 不写宿主 CSS;不把强调文案污染进业务真值列冒充「变红」 |
|
||
| **宿主** | 读取呈现结果,按闭集 `tone` 映射主题样式;按几何涂表格;可选 Toast/提醒汇总 | 不理解「提前 3 天交单」等业务规则;不为单个技能写死样式 |
|
||
|
||
**派生状态(重要):** 呈现是计算结果,不是粘性开关。
|
||
用户补填数据 / 同步刷新后技能重算 → 该项消失 → **样式与提醒自然关闭**。不要单独维护「已关闭提醒」状态机(除非产品另做「忽略此条」能力,本契约不冻结)。
|
||
|
||
---
|
||
|
||
## 2. 格子文档形状(冻,`schemaVersion` 1)
|
||
|
||
技能产出一份 **Cell Presentation Document**(可落库、可 CLI 打印,形状相同),须符合格子 Schema。v1 **只描述某一格**;整行/整列用 §2.1。
|
||
|
||
```json
|
||
{
|
||
"schemaVersion": 1,
|
||
"skill": "your-skill-slug",
|
||
"table": "business_records",
|
||
"rowKey": "id",
|
||
"generatedAt": "2026-08-10T06:00:00Z",
|
||
"cells": [
|
||
{
|
||
"rowId": "42",
|
||
"column": "qty",
|
||
"tone": "danger",
|
||
"message": "库存低于安全线",
|
||
"alert": true
|
||
},
|
||
{
|
||
"rowId": "42",
|
||
"column": "status",
|
||
"tone": "warning",
|
||
"message": "待审核"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|------|------|------|
|
||
| `schemaVersion` | 是 | 固定 `1`(本形状不升版本) |
|
||
| `skill` | 是 | 与 slug 一致 |
|
||
| `table` | 是 | 当前文档作用的业务表 |
|
||
| `rowKey` | 是 | 行匹配列(`id` / `feishu_record_id` 等) |
|
||
| `generatedAt` | 否 | 排障用 |
|
||
| `cells` | 是 | 数组;**空数组 = 该表清除全部格子呈现** |
|
||
|
||
### 2.0 `cells[]` 项
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|------|------|------|
|
||
| `rowId` | 是 | `rowKey` 列值的字符串形式 |
|
||
| `column` | 是 | 要强调的**业务列**(snake_case),须真实存在 |
|
||
| `tone` | 是 | 见 §3 |
|
||
| `message` | 否 | 短说明(≤500);悬停 / 无障碍 |
|
||
| `alert` | 否 | 默认 `false`;`true` 可计入进页/同步提醒汇总 |
|
||
|
||
同一 `(rowId, column)` 多条:宿主可**后者覆盖前者**。
|
||
`column` 对用户不可见(policy 打码 / 列隐藏)时:宿主可仍应用样式,或跳过——**推荐跳过不可见列的强调**,避免泄露「有问题」的存在感(技能仍可写,宿主按可见性过滤)。
|
||
|
||
### 2.1 Grid 文档形状(加法,独立 Schema)
|
||
|
||
整行 / 整列 / 区域用 **Grid Presentation Document**(`rules[]`)。与 `cells[]` **并存**,不替代、不升 `cells` 的 `schemaVersion`。
|
||
|
||
统一几何:**`rows` × `columns`**。某一侧为 `"all"`(或省略,落库时写成 JSON `"all"`)= 该轴全部。禁止两侧都是全部(见 §4.2)。
|
||
|
||
```json
|
||
{
|
||
"schemaVersion": 1,
|
||
"skill": "your-skill-slug",
|
||
"table": "business_records",
|
||
"rowKey": "id",
|
||
"generatedAt": "2026-08-10T06:00:00Z",
|
||
"rules": [
|
||
{
|
||
"ruleKey": "qty-low-rows",
|
||
"rows": ["42", "99"],
|
||
"columns": "all",
|
||
"tone": "danger",
|
||
"message": "库存低于安全线",
|
||
"alert": true
|
||
},
|
||
{
|
||
"ruleKey": "status-column",
|
||
"rows": "all",
|
||
"columns": ["status"],
|
||
"tone": "warning",
|
||
"message": "待审核"
|
||
},
|
||
{
|
||
"ruleKey": "overdue-print-region",
|
||
"rows": ["7", "8"],
|
||
"columns": ["print_done_at", "ship_done_at"],
|
||
"tone": "danger",
|
||
"message": "环节到期未填",
|
||
"alert": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|------|------|------|
|
||
| `schemaVersion` | 是 | 固定 `1` |
|
||
| `skill` / `table` / `rowKey` | 是 | 同格子文档;`rowKey` 用于匹配 `rows` 里的 id |
|
||
| `rules` | 是 | 数组;**空数组 = 该表清除全部 grid 规则** |
|
||
|
||
#### `rules[]` 项
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|------|------|------|
|
||
| `ruleKey` | 是 | 本表内唯一(建议稳定业务键,便于重算覆盖) |
|
||
| `rows` | 是 | `"all"` 或行 id 字符串数组(对应 `rowKey` 列值) |
|
||
| `columns` | 是 | `"all"` 或业务列名数组 |
|
||
| `tone` | 是 | 见 §3 |
|
||
| `message` | 否 | ≤500 |
|
||
| `alert` | 否 | 默认 `false`;按**规则条数**计提醒,不按命中格子数 |
|
||
|
||
| `rows` × `columns` | 宿主 scope |
|
||
|--------------------|-----------|
|
||
| 1 行 × 1 列 | `cell` |
|
||
| 若干行 × 若干列(非单格) | `region` |
|
||
| 若干行 × `"all"` | `row`(整行) |
|
||
| `"all"` × 若干列 | `column`(整列) |
|
||
| `"all"` × `"all"` | **禁止**,宿主丢弃该规则 |
|
||
|
||
完整 JSON 例见 [`../assets/examples/skill-grid-presentation.example.json`](../assets/examples/skill-grid-presentation.example.json)。
|
||
|
||
---
|
||
|
||
## 3. `tone` 闭集(冻)
|
||
|
||
| tone | 语义(技能怎么选) | 宿主怎么呈现(示例,主题可调) |
|
||
|------|-------------------|-------------------------------|
|
||
| `danger` | 必须立刻处理 / 已违规 / 严重超时 | 强强调(如浅红底) |
|
||
| `warning` | 即将到期 / 需注意 | 中等强调(如浅黄) |
|
||
| `info` | 提示性标记 | 轻强调(如浅蓝) |
|
||
| `success` | 正向完成态(少用在「待填」场景) | 浅绿等 |
|
||
| `muted` | 弱化 / 次要 | 灰底或灰字 |
|
||
|
||
**禁止:** 技能下发原始 `#RRGGBB`、任意 CSS class、内联 style。
|
||
以后若扩展色板,只能**追加新 tone token** 并升契约,不能开放任意色值。
|
||
|
||
「技能配置什么就显示什么」在本契约中的含义是:技能选择 **哪一格/行/列 + 哪个 tone + 什么说明**;**像素级颜色由宿主主题决定**,以保证多技能 UI 一致与安全。
|
||
|
||
---
|
||
|
||
## 4. 推荐持久化(给宿主实现)
|
||
|
||
v1 **推荐**技能将「当前表」的**格子**呈现写入用户库旁路表(与业务表分离,**不是**多余业务超时列):
|
||
|
||
```sql
|
||
CREATE TABLE IF NOT EXISTS _jiangchang_cell_presentation (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
table_name TEXT NOT NULL,
|
||
row_key TEXT NOT NULL,
|
||
row_id TEXT NOT NULL,
|
||
column_name TEXT NOT NULL,
|
||
tone TEXT NOT NULL,
|
||
message TEXT,
|
||
alert INTEGER NOT NULL DEFAULT 0,
|
||
generated_at TEXT,
|
||
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
||
UNIQUE (table_name, row_id, column_name)
|
||
);
|
||
```
|
||
|
||
### 4.1 整行 / 整列 / 区域(`_jiangchang_grid_presentation`)
|
||
|
||
```sql
|
||
CREATE TABLE IF NOT EXISTS _jiangchang_grid_presentation (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
table_name TEXT NOT NULL,
|
||
rule_key TEXT NOT NULL,
|
||
row_key TEXT NOT NULL DEFAULT '',
|
||
rows_json TEXT NOT NULL,
|
||
columns_json TEXT NOT NULL,
|
||
tone TEXT NOT NULL,
|
||
message TEXT,
|
||
alert INTEGER NOT NULL DEFAULT 0,
|
||
generated_at TEXT,
|
||
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
||
UNIQUE (table_name, rule_key)
|
||
);
|
||
```
|
||
|
||
`rows_json` / `columns_json` 存 JSON:字符串 `"all"`,或 id / 列名数组(如 `["42","99"]`)。
|
||
`row_key`:有限行集合时必填(与文档 `rowKey` 相同,如 `id`);整列(`rows_json = "all"`)可空字符串。
|
||
|
||
两张表都列入技能 `INTERNAL_METADATA_TABLES`(见 `scripts/db/display_metadata.py`),**不得**作为业务表出现在数据管理侧栏。模板 **不**在 `init_db()` 里默认建这两张表;技能用到时再 `CREATE`。
|
||
|
||
### 4.2 冲突与特异性
|
||
|
||
同一格被多条规则命中时,宿主按 **格子 > 区域 > 行 > 列** 取胜。同级后者覆盖前者。
|
||
|
||
宿主先加载 grid 规则,再加载 v1 `cells[]`(同级时 **v1 格子仍赢**),因此旧技能只写 `cells[]` 的行为不变。
|
||
|
||
**禁止 `all` × `all`**(会把整张表涂满)。技能不要写;宿主遇到则丢弃该规则。
|
||
|
||
### 4.3 表格 vs 详情
|
||
|
||
| 表面 | 整行(scope=`row`) | 格子 / 列 / 区域 |
|
||
|------|-------------------|------------------|
|
||
| 数据管理表格 | 给整行(`<tr>`)上色 | 给对应单元格上色 |
|
||
| 行详情 | **不**把行色铺到每个字段 | 对应字段可保留 tone |
|
||
|
||
整行强调的是「这一行在表里扎眼」,不是「打开详情后每个值都变色」。
|
||
|
||
约定:
|
||
|
||
- 重算某表时:**先删该 `table_name` 在两张旁路表中的全部行,再插入新结果**(或等价事务替换),保证填完后旧 `danger` 不会残留。只维护其中一张时,至少清掉自己负责的那张,并删掉已迁走的旧行(例如从格子改成整行后,删掉对应 `_jiangchang_cell_presentation`)。
|
||
- 宿主打开数据管理某表时:若该技能启用了呈现(见 §5)且存在旁路表,则按当前页行的 `rowKey` 值匹配并着色。
|
||
- 也允许技能用 CLI 打印整份 Document 供调试;**运行时以库内旁路表为准**(除非后续宿主另定拉取入口)。
|
||
|
||
未创建该旁路表 = 该通道 P0,宿主忽略。
|
||
|
||
---
|
||
|
||
## 5. 在 `actions.json` 中启用(可选,推荐)
|
||
|
||
与 `policy` 类似,顶层可选。**一份开关同时启用格子与 grid:**
|
||
|
||
```json
|
||
{
|
||
"schemaVersion": 1,
|
||
"skill": "your-skill-slug",
|
||
"cellPresentation": {
|
||
"enabled": true
|
||
},
|
||
"actions": []
|
||
}
|
||
```
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `cellPresentation` | 省略 = P0 |
|
||
| `cellPresentation.enabled` | 仅 `true` 表示宿主应尝试加载呈现(两张旁路表);`false`/缺省等同 P0 |
|
||
|
||
v1 **不**要求单独 CLI entrypoint(与 policy 不同);技能在 `sync` / 写路径 / `init-db` 后自行维护旁路表即可。若未来需要「仅刷新呈现」Action,用普通 Skill Action 即可,不必扩展本启用块。
|
||
|
||
---
|
||
|
||
## 6. 何时重算(技能必须遵守)
|
||
|
||
至少在以下时机用**同一套 domain 规则**重算并覆盖该表呈现:
|
||
|
||
1. 全量/增量把外部数据写入本地投影之后(如同步成功)
|
||
2. 会改变「是否仍需强调」的写路径成功之后(新建、更新、登记等)
|
||
3. (可选)用户显式「刷新呈现」类 Action
|
||
|
||
进页 Toast:宿主可在加载表后统计当前页或全表 `alert=1` 的**规则条数**(grid 按规则计,不按命中格子数);**0 则不打扰**。
|
||
提醒关闭 = 重算后没有对应 cell/rule,而不是用户点「我知道了」写死关闭(除非另做忽略列表,本契约不冻)。
|
||
|
||
---
|
||
|
||
## 7. 与其它契约的关系
|
||
|
||
| 契约 | 关系 |
|
||
|------|------|
|
||
| **SCHEMA / `_jiangchang_columns`** | 管列是否可见、类型、中文名;**不管**条件标色。呈现旁路表须进内部隐藏表集合 |
|
||
| **POLICY Snapshot** | 管谁能看哪些 Action/行列;呈现仍建议按可见列过滤 |
|
||
| **hostEffects / steps** | 管 Action 跑完后是否 `reloadTable`;重载后宿主应重新读呈现 |
|
||
| **业务列真值** | 保持干净;不要把 `【超时】` 写进业务字段冒充变色 |
|
||
|
||
---
|
||
|
||
## 8. 反模式
|
||
|
||
- 为标色新增「超时环节」「时效状态」等**业务展示冗余列**当作终态方案
|
||
- 技能下发 CSS / 内联颜色
|
||
- 只在首次超时时打标、填完不重算导致红字残留
|
||
- 宿主写死某个技能 slug 的特殊染色逻辑
|
||
- 把 Cell Presentation 做成仅服务 SLA 的专用协议
|
||
- 写 `rows: "all"` 且 `columns: "all"` 企图整表变色
|
||
- 假定打开行详情后,整行色会铺到每一个字段
|
||
- 把某一业务技能的检查逻辑(例如「检查列 → 整行」)复制进模板当通用运行时
|
||
|
||
---
|
||
|
||
## 9. 示例场景(说明用途不限)
|
||
|
||
| 场景 | 几何 | tone | message 例 |
|
||
|------|------|------|------------|
|
||
| 打单超时未填 | 格子 `print_done_at` | `danger` | 打单已超 1 天未填 |
|
||
| 库存低于安全线 | **整行**(该行 × `all`) | `warning` | 低于安全库存 |
|
||
| 审核驳回 | 格子或整列 `status` | `danger` | 已驳回,请修改 |
|
||
| 选填备注缺失但不紧急 | 格子 `notes` | `muted` | 建议补充备注 |
|
||
| 两个日期列同时逾期 | 区域:若干行 × `print_done_at`+`ship_done_at` | `danger` | 环节到期未填 |
|
||
|
||
格子 JSON 例见 [`../assets/examples/skill-cell-presentation.example.json`](../assets/examples/skill-cell-presentation.example.json)。
|
||
Grid JSON 例见 [`../assets/examples/skill-grid-presentation.example.json`](../assets/examples/skill-grid-presentation.example.json)。
|