From 7d5d446a8be3d2109763a1a2c5a6846f066bb4f2 Mon Sep 17 00:00:00 2001 From: WuYongJie Date: Mon, 31 Aug 2026 09:42:28 +0800 Subject: [PATCH] docs: document notification card styling and integration --- README.md | 4 +- docs/接入指南.md | 14 ++++-- docs/新项目接入清单.md | 9 ++-- docs/消息规范.md | 80 ++++++++++++++++++++++++------ docs/统一通知中心接入交接说明.md | 27 ++++++++-- docs/通知中心新项目开通操作手册.md | 6 +-- 6 files changed, 107 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 7f7c5e3..d43993a 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - [统一通知中心接入操作手册](docs/统一通知中心接入交接说明.md):可直接交给其他项目负责人的完整接入流程、代码入口与验收标准。 - [通知中心新项目开通操作手册](docs/通知中心新项目开通操作手册.md):仅供通知中心维护人登记项目、生成密钥、安全交付和验收使用。 - [接入指南](docs/接入指南.md):项目登记、环境变量、签名、发送、多人通知和上线验证。 -- [消息规范](docs/消息规范.md):标题、正文、状态和按钮的统一写法。 +- [消息规范](docs/消息规范.md):固定项目抬头、ActionCard / Markdown 模板选择、正文排版、按钮跳转及完整请求示例。 - [错误与状态规范](docs/错误与状态规范.md):HTTP 返回、投递状态、错误码和重试边界。 - [新项目接入清单](docs/新项目接入清单.md):从申请到生产验证的逐项门禁。 - [Node.js 客户端示例](examples/node/README.md):可以直接复制到业务后端的无依赖实现。 @@ -90,7 +90,7 @@ - 业务 `/v1/*`:64 KB - 管理 `/admin/*`:256 KB -普通业务接入接口 `POST /v1/notifications`、`GET /v1/notifications/:id`、`GET /v1/notifications` 与原签名协议保持兼容。消息字段仍是 `title / content / actionTitle / actionUrl` 四件套:通知中心只统一给标题加上 `【项目名称】` 来源前缀,正文、按钮文案和跳转地址都保持业务项目提交值。 +普通业务接入接口 `POST /v1/notifications`、`GET /v1/notifications/:id`、`GET /v1/notifications` 与原签名协议保持兼容。消息字段仍是 `title / content / actionTitle / actionUrl` 四件套:通知中心生成 `【项目名称】业务标题`,并将其作为 Markdown 标题固定显示在钉钉可见正文顶部;业务项目决定其后的正文排版、按钮文案和跳转目标。有 `actionUrl` 时使用原生 ActionCard,无地址时使用无按钮的普通 Markdown 消息。样式示例和总显示长度说明见[消息规范](docs/消息规范.md)。 生产环境建议只把容器端口绑定到 `127.0.0.1`,再由 Nginx 提供独立 HTTPS 域名。素材库和固定资产可能位于不同主机,因此不能把业务项目配置成通知中心的容器内网地址。 diff --git a/docs/接入指南.md b/docs/接入指南.md index 5437cb3..e3c357b 100644 --- a/docs/接入指南.md +++ b/docs/接入指南.md @@ -65,7 +65,7 @@ YYD_NOTIFICATION_PROJECT_SECRET=由通知中心单独分配的项目密钥 | `recipientUserId` | 与 `recipientAlias` 二选一;企业通讯录中的钉钉 `userId` | | `recipientAlias` | 与 `recipientUserId` 二选一;通知中心会调用素材平台内部目录精确解析,最长 50 字符 | | `title` | 必填,最长 100 字符;只写业务主题,不要添加 `【项目名】`,拼接项目名后的最终标题不能超过 120 字符 | -| `content` | 必填,Markdown 或纯文本都可以;正文最长 4800 字符,通知中心不会再自动插入标题或固定说明 | +| `content` | 必填,Markdown 或纯文本都可以;输入最长 4800 字符,发送时在前面加上固定项目抬头;总显示长度见下文 | | `actionTitle` | 可选,最长 20 字符;有 `actionUrl` 但未传时默认“查看详情” | | `actionUrl` | 可选;非空时按业务项目提交值使用,通知中心不限制协议、公网/内网地址或项目域名白名单 | @@ -81,7 +81,13 @@ YYD_NOTIFICATION_PROJECT_SECRET=由通知中心单独分配的项目密钥 【固定资产】资产报废待审批 ``` -通知中心不会再改写正文首行。业务项目提交什么正文,钉钉卡片就发送什么正文。 +发送给钉钉的可见正文固定为 `### 【项目名称】业务标题`、两个换行,再接业务项目的 `content`。业务项目不需要在正文重复抬头,也不要把抬头加入待签名的请求正文;固定抬头由通知中心在发送时生成。 + +有非空 `actionUrl` 时使用钉钉原生 `sampleActionCard`,底部显示 `actionTitle` 按钮;不传或留空时使用 `sampleMarkdown`,没有按钮,卡片外框和宽度可能不同。仅填写 `actionTitle` 不会生成按钮。 + +要复现“固定资产待审批”那种完整卡片,按上面的请求提供 Markdown 正文和跳转地址;正文可用 `**字段名:**` 加粗、空行分段、`>` 显示处理提示。业务方不需要提交钉钉的 `msgKey` 或 `msgParam`。 + +当前发送实现将抬头与正文合并后的钉钉 `text` 截取前 4800 字符,超长正文尾部可能被截断。完整格式、可复制示例和按钮行为见[消息规范](./消息规范.md)。 ## 5. 请求签名 @@ -155,8 +161,8 @@ GET /v1/notifications/{id} 1. 本人收到单聊通知。 2. 另一名真实员工收到单聊通知。 -3. 最终标题包含正确的项目来源。 -4. 标题包含正确的项目来源,正文保持业务项目提交内容。 +3. 钉钉聊天中的可见正文顶部显示正确的项目名称和业务标题,且没有重复抬头。 +4. 有跳转地址时收到 ActionCard,正文排版、按钮文字和点击目标正确;无跳转地址时收到无按钮的 Markdown 消息。 5. 使用相同幂等键重复请求不会重复发送。 6. 无效 `userId` 能得到明确失败状态。 7. 创建接口返回 `202` 后,最终状态能进入 `sent`、`unread` 或 `read`。 diff --git a/docs/新项目接入清单.md b/docs/新项目接入清单.md index 4fdb770..b063f7e 100644 --- a/docs/新项目接入清单.md +++ b/docs/新项目接入清单.md @@ -24,18 +24,19 @@ YYD_NOTIFICATION_PROJECT_SECRET=通知中心生成的项目密钥 - [ ] `recipientUserId` 与 `recipientAlias` 二选一。 - [ ] 花名由通知中心从 `gongxiangp2` 花名册解析;找不到对应钉钉 `userId` 时不会推送。 -- [ ] 业务项目提交标题和正文;通知中心只给标题增加 `【项目名称】` 前缀。 -- [ ] 按钮文字和跳转地址均为可选,由业务项目决定。 +- [ ] 业务项目只提交业务标题和正文,不重复抬头;通知中心在可见正文顶部固定显示 `【项目名称】业务标题`。 +- [ ] 按钮文字和跳转地址均为可选,由业务项目决定;需要 ActionCard 时提供非空 `actionUrl`,无地址时发送无按钮的普通 Markdown 消息。 +- [ ] 需要加粗、分段、引用等样式时,在 `content` 中使用 Markdown,参照[消息规范](./消息规范.md)的完整示例。 - [ ] 跳转地址按业务项目提交值使用,不限制 HTTPS、公网域名或项目域名白名单。 - [ ] 保存通知中心返回的投递 ID;`202` 只表示已接收,不表示已经送达。 ## 4. 上线验证 -- [ ] 正常收件人能够收到通知,标题中的项目名称正确。 +- [ ] 正常收件人能够收到通知,聊天卡片可见抬头中的项目名称正确,正文格式和所选消息模板一致。 - [ ] 花名不存在时返回明确错误,且没有产生投递记录。 - [ ] 相同项目和幂等键不会产生重复通知。 - [ ] 一个项目不能查询另一个项目的投递记录。 -- [ ] HTTP、HTTPS 或内网跳转地址按业务项目提交内容进入通知。 +- [ ] 需要跳转时,ActionCard 的按钮文字正确,点击能进入业务项目指定的 HTTP、HTTPS 或内网页面。 - [ ] 发送失败时能查询到明确状态和错误原因。 以上通过即可完成接入,不增加其它前置表单或审批门槛。 diff --git a/docs/消息规范.md b/docs/消息规范.md index ff36e59..2fdcb19 100644 --- a/docs/消息规范.md +++ b/docs/消息规范.md @@ -1,37 +1,87 @@ # 消息规范 -通知中心只统一一件可见样式:在业务标题前增加项目名称,让收件人知道通知来源。 +本文面向外部业务项目负责人和开发人员。通知使用钉钉原生消息模板,不是 HTML/CSS 网页;卡片外框、宽度、颜色和按钮外观由钉钉客户端渲染。 + +通知中心固定展示项目来源和业务标题;业务项目决定正文排版、按钮文字及跳转目标。 + +## 1. 卡片类型和跳转 + +| 外部项目提交内容 | 通知中心使用的模板 | 收件人看到的效果 | +| --- | --- | --- | +| `actionUrl` 非空 | `sampleActionCard` | 原生 ActionCard,底部显示一个跳转按钮 | +| `actionUrl` 未传或为空 | `sampleMarkdown` | 普通 Markdown 消息,没有底部按钮,外框和宽度可能与 ActionCard 不同 | + +要实现“固定资产待审批”那种带按钮的卡片,提供 Markdown 正文和非空 `actionUrl` 即可;`actionTitle` 建议写明确动作,例如“立即审批”,未填写时默认“查看详情”。只填按钮文字但不填地址,不会生成按钮。 + +业务项目仍调用通知中心的 `POST /v1/notifications`,无需提交 `msgKey`、`msgParam`、`singleTitle` 或 `singleURL`,也无需直接调用钉钉 API。通知中心会把 `actionTitle` 映射为钉钉的 `singleTitle`,把实际发送的跳转地址映射为 `singleURL`。 + +按钮目标由业务项目的 `actionUrl` 决定。HTTP、HTTPS、内网 IP/域名和端口均可使用,无需为普通通知登记域名白名单;接收人的设备仍须能够访问该业务地址。只有启用钉钉 H5 免登且目标满足既有 HTTPS 登录规则时,通知中心才会包装到免登入口,最终仍回到指定业务页面。 + +## 2. 固定项目抬头 + +业务项目的 `title` 只填写业务主题,不要自行拼接项目名称。通知中心从当前鉴权项目的配置中取得名称,生成: ```text 【项目名称】业务标题 ``` -例如外部项目提交: +发送给钉钉时,不只设置独立的 `title` 字段,还会在可见正文顶部加入 Markdown 标题,两种消息模板都如此: + +```markdown +### 【项目名称】业务标题 + +业务项目提交的 content +``` + +请勿在 `content` 中再重复同一条项目抬头或业务标题,以免出现双标题。除此之外,通知中心不添加固定时间、业务字段顺序或其它正文模板。 + +## 3. 完整 ActionCard 请求示例 + +以下为发送接口的 JSON 正文示例。花名、业务记录和地址均为示例值,接入时替换为本项目实际内容;接口鉴权与签名见[接入指南](./接入指南.md#5-请求签名)。 ```json { - "title": "脚本执行失败", - "content": "数据同步任务执行失败,请查看日志。", - "actionTitle": "查看详情", - "actionUrl": "http://192.168.58.20:8080/jobs/123" + "idempotencyKey": "asset_disposal:53:海棠:v1", + "recipientAlias": "海棠", + "title": "资产报废待审批", + "content": "**申请时间:** 2026年8月31日 15:58\n\n**资产:** 电脑桌(JS-CPU-0704)\n\n**申请人:** 示例员工\n\n**报废原因:** 资产损坏,申请报废。\n\n> 请核对资产及配件明细后处理。", + "actionTitle": "立即审批", + "actionUrl": "http://asset.example.com/workflows/disposals/53" } ``` -最终标题为: +假设管理面板中的项目名称是“固定资产”,卡片正文为: -```text -【脚本监控】脚本执行失败 +```markdown +### 【固定资产】资产报废待审批 + +**申请时间:** 2026年8月31日 15:58 + +**资产:** 电脑桌(JS-CPU-0704) + +**申请人:** 示例员工 + +**报废原因:** 资产损坏,申请报废。 + +> 请核对资产及配件明细后处理。 ``` -正文、按钮文字和跳转地址均由业务项目决定,通知中心不再插入固定标题、时间、字段顺序或排版模板。 +底部按钮显示“立即审批”,点击进入 `http://asset.example.com/workflows/disposals/53`。`**字段名:**` 表示加粗,空行用于分段,`>` 用于引用提示;这些只是可复用的示例排版,不要求所有业务项目都使用相同字段。 -字段规则: +## 4. 字段与长度 | 字段 | 规则 | | --- | --- | -| `title` | 必填,业务项目只写业务标题;通知中心自动增加项目名称前缀 | -| `content` | 必填,纯文本或 Markdown 均可;按业务项目内容发送 | -| `actionTitle` | 可选;有跳转地址但未填写时默认“查看详情” | +| `title` | 必填,最长 100 字符;拼接项目名称后的最终标题最长 120 字符 | +| `content` | 必填,输入最长 4800 字符;纯文本或 Markdown 均可,显示在固定项目抬头之后 | +| `actionTitle` | 可选,最长 20 字符;有跳转地址但未填写时默认“查看详情” | | `actionUrl` | 可选;按业务项目提交值使用,不限制协议、公网/内网地址或项目域名白名单 | -业务项目应自行保证内容清楚、按钮可理解、跳转地址适合自己的使用环境。通知中心只负责可靠接收、项目隔离、分发和错误返回。 +当前发送实现会将“`### ` + 最终标题 + 两个换行 + `content`”组成的钉钉 `text` 截取前 4800 字符。因此抬头也占显示额度,超长正文尾部可能被截断;业务详情宜放在跳转页面。业务项目仍对自己提交的原始 JSON 签名,无需预先插入抬头,保存的业务正文也不会因此改写。 + +## 5. 样式验收 + +- 确认钉钉聊天中的可见正文顶部有正确的 `【项目名称】业务标题`,不是只看消息摘要或接口返回值。 +- 如需 ActionCard,使用非空 `actionUrl` 发送,确认正文格式、底部按钮和实际点击目标。 +- 如果选择不提供跳转地址,应预期收到没有按钮的普通 Markdown 消息,而非相同外框的 ActionCard。 +- 已发出的旧消息不会随代码、项目配置或测试页变化而自动更新。测试新的样式时创建一条新的测试事件并使用新幂等键;重试同一业务事件时仍复用原幂等键,不能借此绕过防重。 diff --git a/docs/统一通知中心接入交接说明.md b/docs/统一通知中心接入交接说明.md index 8110dfa..ae27428 100644 --- a/docs/统一通知中心接入交接说明.md +++ b/docs/统一通知中心接入交接说明.md @@ -339,8 +339,8 @@ signature = HMAC_SHA256_HEX(projectSecret, canonical) | `recipientUserId` | 二选一 | 企业通讯录中的钉钉 `userId`;与 `recipientAlias` 只能传一个 | | `recipientAlias` | 二选一 | 通知中心会通过素材平台内部目录精确解析的准确花名,最长 50 字符;与 `recipientUserId` 只能传一个 | | `title` | 是 | 只写业务主题,最长 100 字符;不要自己添加项目名或“由壹点”前缀 | -| `content` | 是 | Markdown 或纯文本业务正文;通知中心不会再自动插入标题或固定说明 | -| `actionTitle` | 否 | 最长 20 字符,建议写明确动作,例如“立即审批” | +| `content` | 是 | Markdown 或纯文本业务正文,输入最长 4800 字符;通知中心在前面加固定项目抬头,总显示长度见下文 | +| `actionTitle` | 否 | 最长 20 字符,建议写明确动作,例如“立即审批”;有跳转地址但未传时默认“查看详情” | | `actionUrl` | 否 | 可为空;非空时按原样透传,支持 HTTP、HTTPS、内网 IP/域名和端口 | 通知中心会根据项目配置统一生成: @@ -349,7 +349,19 @@ signature = HMAC_SHA256_HEX(projectSecret, canonical) 【项目名称】业务标题 ``` -例如业务项目提交“资产报废待审批”,用户最终看到的是“【固定资产】资产报废待审批”。完整文案规则见[消息规范](./消息规范.md)。 +例如业务项目提交“资产报废待审批”,用户最终看到的是“【固定资产】资产报废待审批”。 + +### 9.1 如何实现带样式和按钮的 ActionCard + +- `actionUrl` 非空:通知中心使用钉钉原生 `sampleActionCard`,底部按钮文字为 `actionTitle`,点击进入指定业务页面。 +- `actionUrl` 未传或为空:使用 `sampleMarkdown`,没有底部按钮,外观与 ActionCard 不同;仅填写按钮文字不能生成按钮。 +- `content` 由业务项目用 Markdown 编排,例如 `**资产:** 电脑桌`、空行分段、`> 请核对明细后处理。`。这不是 HTML/CSS,卡片外框、宽度、颜色和按钮外观由钉钉客户端决定。 +- 通知中心会在两种模板的可见正文顶部固定加入 `### 【项目名称】业务标题`,再用两个换行拼接 `content`;业务项目不要在 `title` 或 `content` 中重复项目抬头。 +- 普通通知的跳转地址支持 HTTP、HTTPS 和内网地址;只有明确启用免登且目标满足既有 HTTPS 登录规则时,才会包装到免登入口,最终仍回到业务方指定页面。 + +上面的发送接口 JSON 示例已经具备完整 ActionCard 所需的正文、按钮文字和跳转地址。业务方只需使用本项目的真实值,不需要直接传 `msgKey`、`msgParam`、`singleTitle` 或 `singleURL`,这些由通知中心适配。 + +当前钉钉 `text` 是“固定抬头 + 两个换行 + 业务正文”,合计截取前 4800 字符,超长正文尾部可能被截断。签名仍使用业务方提交的原始 JSON。完整样式规范和可复制的待审批卡片示例见[消息规范](./消息规范.md)。 ## 十、幂等防重和多人通知 @@ -470,8 +482,9 @@ GET /v1/notifications/{deliveryId} - [ ] 使用本人真实钉钉 `userId` 能创建通知并取得投递 `id`。 - [ ] 如使用花名,准确花名能解析并发送,找不到对应 `userId` 时会被明确拒绝。 - [ ] 能使用投递 `id` 查询状态。 -- [ ] 通知标题自动包含正确项目名称,没有重复前缀或双标题。 -- [ ] 按钮进入正确业务记录;如启用免登且目标满足现有 HTTPS 登录流程,会自动包装到统一入口。 +- [ ] 钉钉聊天中的可见正文顶部自动包含正确项目名称和业务标题,没有重复前缀或双标题。 +- [ ] 提供 `actionUrl` 时收到 ActionCard,Markdown 正文和按钮文字正确,点击进入正确业务记录;如启用免登且目标满足现有 HTTPS 登录流程,会自动包装到统一入口。 +- [ ] 若选择不提供 `actionUrl`,收到普通 Markdown 消息且没有底部按钮。 - [ ] 重复执行同一业务事件不会产生第二条通知。 - [ ] 无效钉钉 `userId` 最终进入明确失败状态。 @@ -513,6 +526,10 @@ projectCode: | 把任意姓名直接当花名发送 | 只使用素材平台内部目录能够精确解析的准确花名 | | 同时发送 `recipientUserId` 和 `recipientAlias` | 两种收件人方式只能选择一种 | | 标题自己添加“【项目名】” | 只提交业务标题,由通知中心统一拼接 | +| 正文再手写同一条项目抬头 | `content` 只提供业务正文,通知中心会在可见正文顶部加入抬头 | +| 只传纯文本却希望出现加粗字段和引用 | 在 `content` 中使用 Markdown,按[消息规范](./消息规范.md)的示例编排 | +| 不传 `actionUrl` 却希望出现 ActionCard 按钮 | 提供实际业务页面地址,按钮文字用 `actionTitle`;无地址则是无按钮的 Markdown 消息 | +| 修改样式后沿用旧测试事件并期待旧消息改变 | 新的样式测试使用新测试事件和新幂等键;同一业务事件的重试仍保持原幂等键 | | 签名路径包含公网 `/notification-center` 前缀 | 签名内部路径 `/v1/notifications` | | 先序列化签名,发送时再次序列化成不同正文 | 对实际发送的同一份 raw body 签名 | | 每次重试随机生成新的幂等键 | 重试沿用原幂等键,只更换 nonce | diff --git a/docs/通知中心新项目开通操作手册.md b/docs/通知中心新项目开通操作手册.md index 1c4a214..cfff3ae 100644 --- a/docs/通知中心新项目开通操作手册.md +++ b/docs/通知中心新项目开通操作手册.md @@ -29,7 +29,7 @@ 创建完成后只需确认: -1. 项目名称正确,最终通知标题会显示 `【项目名称】业务标题`。 +1. 项目名称正确,最终通知的可见正文顶部会显示 `【项目名称】业务标题`。 2. 项目代码没有与现有项目冲突。 3. 项目密钥只展示给需要接入的业务后端。 4. 现有项目的代码和密钥没有改变。 @@ -164,8 +164,8 @@ YYD_NOTIFICATION_PROJECT_SECRET=实际项目独立密钥 3. 查询接口只能由当前项目查询该投递记录。 4. 最终状态进入 `sent`、`unread`、`read` 或给出明确 `failed` 原因。 5. 测试员工实际收到“由壹点”机器人单聊。 -6. 标题包含正确项目名称。 -7. 按钮进入业务项目提交的正确页面。 +6. 钉钉聊天中的可见抬头包含正确项目名称和业务标题,业务正文没有重复抬头。 +7. 提供跳转地址时收到 ActionCard,Markdown 正文格式和底部按钮正确,点击进入业务项目提交的页面;无地址时为无按钮的普通 Markdown 消息。样例见[消息规范](./消息规范.md)。 8. 相同幂等键重复请求不产生第二条消息。 9. 如使用花名,花名册中存在对应 userId 时能发送,找不到时明确返回 `RECIPIENT_ALIAS_NOT_FOUND`。