From cbebd19ab3853f5cd3bcb2cc2bb027777f066cab Mon Sep 17 00:00:00 2001 From: chendelian <116870791@qq.com> Date: Sat, 22 Aug 2026 16:35:05 +0800 Subject: [PATCH] =?UTF-8?q?docs(html):=20=E6=B2=89=E6=B7=80=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=AE=A1=E7=90=86=20iframe=20=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E5=B8=83=E5=B1=80=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 +++ SKILL.md | 2 +- assets/README.md | 2 +- assets/html/example-report.html | 67 ++++++++++++++++++++++++++-- development/CHECKLIST.md | 2 + development/DEVELOPMENT.md | 2 +- development/TESTING.md | 1 + references/ACTIONS.md | 21 ++++++++- scripts/service/html_page_service.py | 1 + scripts/util/constants.py | 2 +- tests/test_html_page_service.py | 9 ++++ 11 files changed, 106 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eaa6e1..4b540d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ - 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节 - 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段 +## 1.0.97 + +- 沉淀数据管理 HTML 预览**布局契约**:`references/ACTIONS.md` 新增「宿主预览布局」(流体铺满 iframe、禁横向滚动、表格断行等) +- 升级 `assets/html/example-report.html` 为通用布局基线;`test_html_page_service` 守护不退化 +- `DEVELOPMENT.md` / `CHECKLIST`(S0-12、A6-10)/ `TESTING.md` 交叉引用 + ## 1.0.96 - 在 `references/ACTIONS.md` 沉淀数据管理技能按钮中文名(`label`)参考表:同类通用动作用同一动词,不是白名单 diff --git a/SKILL.md b/SKILL.md index 1c7457f..6716908 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 技能开发模板(通用业务版) description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。" -version: 1.0.96 +version: 1.0.97 author: 深圳匠厂科技有限公司 metadata: openclaw: diff --git a/assets/README.md b/assets/README.md index 8b5c063..ed3fa6a 100644 --- a/assets/README.md +++ b/assets/README.md @@ -1,7 +1,7 @@ # assets - `actions.json`:Skill Action manifest 最小示例(按入口定位表决定是否保留/扩展;见 `development/PRODUCT_SURFACES.md`)。每个 action **必须**显式声明 `executionProfile`(`sync` \| `async`)。默认仅 `health` / `version` / `config-path`,不放 toolbar,故无 `bind` 示例。 -- `html/example-report.html`:HTML 报告页最小壳(`{{TITLE}}` / `{{GENERATED_AT}}` / `{{BODY}}`);渲染后须写入数据目录 `html/`,见 `references/ACTIONS.md`「HTML 页面报告」。 +- `html/example-report.html`:HTML 报告页最小壳(`{{TITLE}}` / `{{GENERATED_AT}}` / `{{BODY}}`);含数据管理 iframe 预览布局基线(流体铺满、禁横向滚动);渲染后须写入数据目录 `html/`,见 `references/ACTIONS.md`「HTML 页面报告」。 - `examples/`:CLI 成功输出形状示例、以及 `render-html.action.example.json`(虚构路径与数据)。 - `schemas/`:轻量 JSON Schema(`skill-actions.schema.json` 为**新技能严格规范**)。 diff --git a/assets/html/example-report.html b/assets/html/example-report.html index f5a7442..6d40dc0 100644 --- a/assets/html/example-report.html +++ b/assets/html/example-report.html @@ -11,17 +11,31 @@ --muted: #64748b; --card: #ffffff; --line: #e2e8f0; + --page-pad-x: clamp(14px, 2.5vw, 24px); + --page-pad-y: clamp(12px, 2vw, 20px); } * { box-sizing: border-box; } - html { overflow-y: auto; } - body { + html { + width: 100%; + height: 100%; margin: 0; + overflow-x: hidden; + overflow-y: auto; + } + body { + width: 100%; + min-height: 100%; + margin: 0; + overflow-x: hidden; font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; background: var(--bg); color: var(--ink); + line-height: 1.5; } header { - padding: 20px 24px 8px; + padding: var(--page-pad-y) var(--page-pad-x) 8px; + background: var(--card); + border-bottom: 1px solid var(--line); } header h1 { margin: 0 0 6px; @@ -34,7 +48,23 @@ font-size: 13px; } main { - padding: 8px 24px 28px; + width: 100%; + min-width: 0; + padding: var(--page-pad-y) var(--page-pad-x) 28px; + } + .section { + margin-bottom: 18px; + } + .section h2 { + margin: 0 0 8px; + font-size: 13px; + font-weight: 650; + color: var(--muted); + } + .meta { + margin: 0 0 10px; + color: var(--muted); + font-size: 12px; } .card { background: var(--card); @@ -44,6 +74,35 @@ line-height: 1.6; font-size: 14px; } + table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; + background: var(--card); + border: 1px solid var(--line); + border-radius: 8px; + overflow: hidden; + font-size: 13px; + } + th, td { + padding: 8px 10px; + border-bottom: 1px solid var(--line); + text-align: left; + vertical-align: top; + word-break: break-word; + overflow-wrap: anywhere; + } + th { + background: #f8fafc; + font-weight: 600; + color: var(--muted); + font-size: 12px; + } + tr:last-child td { border-bottom: none; } + /* + 宿主数据管理在 iframe 内预览本页:应横向铺满可用宽度,仅纵向滚动。 + 复杂看板可在 {{BODY}} 内使用 .section / table;布局底线见 references/ACTIONS.md「宿主预览布局」。 + */ diff --git a/development/CHECKLIST.md b/development/CHECKLIST.md index 3951e21..eb83fb4 100644 --- a/development/CHECKLIST.md +++ b/development/CHECKLIST.md @@ -60,6 +60,7 @@ checklist_version: 1.0 - [ ] S0-9 **入口定位表**(见 `PRODUCT_SURFACES.md` / `REQUIREMENTS` §0.1):已填写 / 未填写 - [ ] S0-10 本技能宣称的主用户路径涉及:对话 / 数据管理(执行或仅展示) / 定时(可多选;与定位表一致) - [ ] S0-11 **业务行生命周期**(见 `references/WORK_ITEM_STATUS.md` / `REQUIREMENTS` §0.3):有处理队列且已声明状态→角色映射 / 不适用 +- [ ] S0-12 **HTML 页面报告**(见 `references/ACTIONS.md`「HTML 页面报告」):有侧栏可预览的 `html/*.html` + `render-html` / 不适用 --- @@ -134,6 +135,7 @@ checklist_version: 1.0 - [ ] A6-7 **P0** 有「处理业务行」类 Action 时(见 `WORK_ITEM_STATUS.md`):默认只处理**可操作**角色状态;成功/失败/跳过/进行中再点处理应拒绝或跳过且不产生重复副作用;重做须人工改回可操作。无处理队列 → **N/A** - [ ] A6-8 **P0** 同上适用时:开始处理后业务表进入**进行中**;成功回写成功类终态;失败回写失败类终态且**失败原因**可读(任务成功但业务行仍停在可操作/进行中 → **FAIL**) - [ ] A6-9 **P1** 同上适用时:`REQUIREMENTS` §0.3(或等价)已填写本技能状态→角色映射;处理类 Action 确认文案写清仅可操作态 +- [ ] A6-10 **P1** 有 HTML 侧栏预览时(S0-12):预览区横向铺满、无横向滚动条;重新生成后内容与页头时间更新;布局符合 `references/ACTIONS.md`「宿主预览布局」。无 HTML 报告 → **N/A** --- diff --git a/development/DEVELOPMENT.md b/development/DEVELOPMENT.md index f898952..9df5ae5 100644 --- a/development/DEVELOPMENT.md +++ b/development/DEVELOPMENT.md @@ -590,7 +590,7 @@ cmd_stats() # 只读 sync:JSON,无 job_context - 批量数量用 **`pickCount` / `--pick N` 参数**(任意正整数),不写死条数。 - **顺序执行、不并发**同一浏览器 Profile / account lease。 - **同步数据**与**宿主表导出**职责分离:同步不写 CSV/Excel;表导出交给数据管理。 -- **HTML 页面报告**(可选):需要侧栏预览整页时,写入 `html/` + Action `render-html`;契约见 [`../references/ACTIONS.md`](../references/ACTIONS.md)「HTML 页面报告」、[`DATA_PATHS.md`](DATA_PATHS.md);薄写入 helper 见 `scripts/service/html_page_service.py`。 +- **HTML 页面报告**(可选):需要侧栏预览整页时,写入 `html/` + Action `render-html`;契约见 [`../references/ACTIONS.md`](../references/ACTIONS.md)「HTML 页面报告」(含**宿主预览布局**底线)、[`DATA_PATHS.md`](DATA_PATHS.md);薄写入 helper 见 `scripts/service/html_page_service.py`。建议从 `assets/html/example-report.html` 复制壳;`{{BODY}}` 内数据须转义;样式升级后提醒用户重新生成。 - 详情见 [`SKILL_ACTION_RUNTIME.md`](SKILL_ACTION_RUNTIME.md);契约样例见 `tests/samples/test_sync_contract.py.sample`、`tests/samples/test_action_core_contract.py.sample`。 ### 队列 + pick(可选) diff --git a/development/TESTING.md b/development/TESTING.md index 58dcc8c..5d9320c 100644 --- a/development/TESTING.md +++ b/development/TESTING.md @@ -35,6 +35,7 @@ - **发布打包守护**:[`tests/test_release_packaging_constraints.py`](../tests/test_release_packaging_constraints.py) ——`scripts/**/*.py` 单文件 < 1000 行、文本文件 UTF-8 without BOM。 - **开发规范守护(hard policy)**:[`tests/test_development_policy_guard.py`](../tests/test_development_policy_guard.py) ——规则索引见 [`development/POLICY_MATRIX.md`](POLICY_MATRIX.md),只执行可机器检测的 hard 规则。 - **slug 语义**:[`tests/test_slug_naming.py`](../tests/test_slug_naming.py) ——verb-noun-platform 命名规范校验。 +- **HTML 报告壳**:[`tests/test_html_page_service.py`](../tests/test_html_page_service.py) 守护 `assets/html/example-report.html` 的数据管理 iframe 预览布局基线;业务技能若有自定义 `assets/html/*.html`,建议在自有仓库加同类静态断言(见 `references/ACTIONS.md`「宿主预览布局」)。 **原则:`tests/test_*.py` 不允许隐形访问外网、不允许拉起真实浏览器、不允许读写开发者机器的真实数据根**。如果需要仿真服务器,也应仅在 integration(并由档位变量放行)。 diff --git a/references/ACTIONS.md b/references/ACTIONS.md index d47b067..83e22d4 100644 --- a/references/ACTIONS.md +++ b/references/ACTIONS.md @@ -740,7 +740,25 @@ HINT: | `steps` | `afterSuccess` → **`refreshCatalog`**(重扫 `htmlPages`;不要只 `reloadTable`) | | `entrypoint` | CLI 子命令(如 `render-html`)调用同一写入内核 | -完整 JSON 形状见 [`../assets/examples/render-html.action.example.json`](../assets/examples/render-html.action.example.json)。最小页面壳见 [`../assets/html/example-report.html`](../assets/html/example-report.html)。 +完整 JSON 形状见 [`../assets/examples/render-html.action.example.json`](../assets/examples/render-html.action.example.json)。最小页面壳见 [`../assets/html/example-report.html`](../assets/html/example-report.html)(已含数据管理 iframe 预览的布局基线;复制后可按需扩展 `{{BODY}}` 内结构)。 + +### 宿主预览布局 + +数据管理在 **iframe** 内预览 `html/*.html`;宿主 iframe 已占满右侧预览区,**技能页不应再人为收窄正文**(尤其数据管理窗口通常较窄)。 + +| 级别 | 约定 | +|------|------| +| **必须** | 页面横向**铺满** iframe 可用宽度:`main { width: 100%; min-width: 0; }` | +| **必须** | **禁止** `main`(或等价正文容器)使用 `max-width: Npx` 且**无** `margin: 0 auto`(宽屏会左对齐留白;窄宿主窗浪费横向空间) | +| **必须** | `html` / `body` 设 `overflow-x: hidden`;滚动以**纵向**为主,避免横向滚动条 | +| **必须** | 写入 `{{BODY}}` 的业务数据经 `html.escape`(或等价)转义,防 XSS | +| **应当** | `header` 与 `main` 水平内边距一致(如共用 CSS 变量或 `clamp()`) | +| **应当** | 多列表格:`width: 100%` + 单元格 `word-break` / `overflow-wrap`,长文本在格内换行 | +| **应当** | KPI / 卡片网格用 `repeat(auto-fit, minmax(…, 1fr))` 等流体列,勿死写固定列数 | +| **禁止** | 在 `` 上用 `max-width` 限制「说明列」等业务列(易导致列宽异常或横向溢出) | +| **禁止** | 依赖外链 CSS/JS 或 `networkidle` 式加载(iframe `sandbox` 仅 `allow-scripts`;页面应自包含) | + +长文阅读型报告若确需版心,可对整个 `main` 使用 `max-width` **且** `margin: 0 auto`,并令 `header` 与 `main` 同宽;**数据看板类**默认不设 `max-width`。 ### 实现要点 @@ -753,6 +771,7 @@ HINT: ### 验收(复制后自测) - [ ] `html/` 下出现 `.html`,数据管理侧栏能看到报告项,预览正常 +- [ ] 预览区**横向铺满**、**无横向滚动条**;拖窄侧栏后内容自适应(见上节「宿主预览布局」) - [ ] 表顶栏(若声明 toolbar)或报告右键「重新生成」能跑通;成功后预览刷新 - [ ] 未登录/无权限用户被拒绝,且有可读错误 - [ ] 成功路径带 `refreshCatalog`(或等价让侧栏/预览看到更新) diff --git a/scripts/service/html_page_service.py b/scripts/service/html_page_service.py index 7b0455b..4123b6e 100644 --- a/scripts/service/html_page_service.py +++ b/scripts/service/html_page_service.py @@ -4,6 +4,7 @@ - 目录:仅一层 `html/*.html`(非递归) - 重新生成 Action id 必须为 `render-html`(宿主硬编码) +- 页面布局底线见 `references/ACTIONS.md`「宿主预览布局」;模板壳 `assets/html/example-report.html` - 成功后建议 `steps: refreshCatalog` 以重扫侧栏 - 本模块只提供路径/模板/原子写;业务 KPI/表格由各技能自行填充 """ diff --git a/scripts/util/constants.py b/scripts/util/constants.py index 2141baf..a4d0006 100644 --- a/scripts/util/constants.py +++ b/scripts/util/constants.py @@ -1,6 +1,6 @@ """技能标识、版本与平台公共库约束(复制后请修改 slug/version/logger)。""" SKILL_SLUG = "your-skill-slug" -SKILL_VERSION = "1.0.96" +SKILL_VERSION = "1.0.97" LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug" PLATFORM_KIT_MIN_VERSION = "1.2.11" diff --git a/tests/test_html_page_service.py b/tests/test_html_page_service.py index 21b5976..06100d3 100644 --- a/tests/test_html_page_service.py +++ b/tests/test_html_page_service.py @@ -61,6 +61,15 @@ class TestHtmlPageService(unittest.TestCase): with self.assertRaises(ValueError): write_html_page("note.txt", "") + def test_example_report_shell_embedded_preview_layout(self) -> None: + """守护 example-report.html:数据管理 iframe 预览布局基线不退化。""" + template = load_html_template("assets/html/example-report.html") + self.assertIn("overflow-x: hidden", template) + self.assertIn("min-width: 0", template) + self.assertIn("table-layout: fixed", template) + self.assertIn("overflow-wrap: anywhere", template) + self.assertNotIn("max-width:", template) + if __name__ == "__main__": unittest.main()