Files
im_server/docs/IM-会议笔记前后端对接文档.md
T

19 KiB
Raw Blame History

IM 会议笔记前后端逐图对接协议

版本:v1.0
日期:2026-09-05
需求依据:IM 会议笔记产品原型需求文档
公共协议依据:IM 前后端逐图对接协议
说明:本文档的图片标题和顺序与会议笔记产品原型完全一致。后续合并时建议作为第 9 章的 9.14 会议笔记,原主文档 9.14 接口示例 顺延为 9.15 接口示例。

9.14 会议笔记

会议笔记属于企业工作台模块,复用会议主数据和统一文件能力。服务端负责判断会议是否结束、当前用户是否与会议有关、是否为会议记录员,以及文件查看和操作权限;客户端只根据响应中的状态与 permissions 展示页面,不自行推导权限。

本模块遵循主文档第 0 章的公共约定:产品 HTTP 使用 X-MeetingIM-APIKey、X-IM-Schema: 1、X-Request-ID 和 Authorization: Bearer <token>;写操作额外使用 Idempotency-Key;成功和失败响应均使用统一包裹结构。

会议笔记不产生移动端通知、不写入会议通知未读数,也不增加工作台底部 Tab 红点。客户端进入会议笔记列表或详情页时主动请求最新数据;从上传、预览或下载页面返回后,只刷新当前会议笔记页面。

9.14.1 会议笔记-工作台入口.png

会议笔记-工作台入口

状态:工作台接口需改造。

  • GET /v1/im/workbench 的 modules 增加 code="meeting_notes"、route="/meeting-notes"。服务端按租户功能开关和当前用户权限决定是否返回该入口。
  • 会议笔记模块固定返回 unread_count=0,不参与 GET /v1/im/bootstrap 的 entry_badges.workbench_total_unread 汇总。
  • 当前工作台红点只对应“会议通知”模块的未读通知。日报、月报、打卡、部门框架、举报信箱和会议笔记均不产生工作台通知数。
  • 客户端点击入口后请求 GET /v1/im/meeting-notes。切换企业后必须清空原租户的会议笔记缓存并重新加载。

9.14.2 会议笔记-列表.png

会议笔记-列表

状态:新增。

  • 列表:GET /v1/im/meeting-notes?query=&cursor=&limit=20。接口只返回当前用户作为发起人、会议记录员或参会人的已结束会议,不返回未开始、进行中或已取消会议。
  • query 支持匹配会议主题、发起人、会议记录员、参会人和地点;搜索范围仍受当前用户会议可见权限限制。
  • 列表按 end_at 倒序排列,分页使用不透明 cursor。客户端不得用本地时间过滤会议状态或自行扩大搜索范围。
  • 已结束但尚未上传笔记的会议仍返回,使用 note_status="empty"、file_count=0;客户端展示会议基础信息,进入详情后显示“暂无笔记”。
  • permissions.can_view=true 决定是否允许进入详情;permissions.can_upload 只对当前会议记录员为 true。普通参会人可以进入详情,但不显示上传按钮。
  • state="ended" 是服务端按会议状态及服务端当前时间计算或持久化的有效状态。服务端必须以 end_at 和取消状态为准,不能信任客户端传入的“已结束”条件。

9.14.3 会议笔记-发布页面.png

会议笔记-发布页面

状态:现有会议创建接口需改造。

  • 页面字段顺序为发起人、地点、会议记录员、参会人、开始时间、时长、会议主题。会议记录员默认显示当前会议发起人。
  • 创建仍使用 POST /v1/im/meetings,请求新增 recorder_user_id。客户端未传或传空字符串时,服务端默认使用当前登录用户;客户端不能通过 organizer_id 伪造发起人。
  • 服务端校验会议记录员属于当前租户且账号有效。首版允许会议记录员是发起人或参会人;若选择了非参会人,服务端自动加入参会人列表并在响应中返回最终名单。
  • 服务端保存的会议必须有 recorder_user_id;创建请求可省略该字段以使用发起人默认值。attendee_user_ids、start_at、end_at 和 title 为必填业务数据,location 可为空,且 end_at 必须晚于 start_at。
  • 创建成功后的会议通知仍统一归属“会议通知”模块;会议笔记模块不额外生成通知或未读数。
  • PATCH /v1/im/meetings/{meeting_id} 支持在会议结束前修改 recorder_user_id,并使用 version 做乐观锁。会议结束后返回 MEETING_CLOSED。

9.14.4 会议笔记-详情页.png

会议笔记-详情页

状态:新增。

  • 详情:GET /v1/im/meetings/{meeting_id}/notes,一次返回会议基础信息、发起人、会议记录员、参会人、文件列表、笔记状态和当前用户权限。
  • 会议基础信息与会议通知页面共用 im_meetings 和 im_meeting_participants 数据,不复制会议标题、时间和成员快照作为另一份可编辑主数据。
  • 当前用户为会议记录员且会议已结束时,permissions.can_upload=true,客户端展示“上传文件”;其他用户不展示该按钮。
  • 上传文件先调用 POST /v0/file/u/,Multipart 携带 purpose=meeting_note 和 meeting_id;上传成功取得 file_id 后,再调用 POST /v1/im/meetings/{meeting_id}/notes/files 建立会议笔记文件记录。
  • 文件登记成功后才进入详情列表。上传成功但登记失败的临时文件不得展示,并由服务端按临时文件 TTL 回收。
  • 当前会议记录员可替换或删除自己登记的文件;所有写操作均需 Idempotency-Key,服务端记录操作审计。

9.14.5 会议笔记-详情页(普通成员).png

会议笔记-详情页(普通成员)

状态:新增权限响应。

  • 普通参会人调用与 9.14.4 相同的详情接口。响应中 permissions.can_view=true、can_upload=false、can_replace=false、can_delete=false。
  • 没有已上传文件时返回 note_status="empty" 和空数组 files=[],客户端展示“暂无笔记”,不把空状态当作请求失败。
  • 有文件时普通参会人只展示文件名、大小、类型、上传人、上传时间和预览入口,不展示上传、替换、删除按钮。
  • 服务端必须在文件登记、替换、删除、预览和下载接口逐次校验会议关系及角色。隐藏客户端按钮不能代替服务端鉴权。
  • 与会议无关、已离开可见范围或跨租户的用户统一返回 RESOURCE_NOT_FOUND 或 FORBIDDEN,不得通过 meeting_id、note_file_id 或 file_id 探测资源。

9.14.6 会议笔记-详情页-在线预览.png

会议笔记-详情页-在线预览

状态:基础文件读取已实现;会议笔记 ACL 和预览转换新增。

  • 文件项返回 preview.status=ready|processing|unsupported|failed、preview.mode=native|converted|download_only 和可选 preview_file_id,客户端根据状态选择直接预览、轮询转换状态或提示暂不支持。
  • 原生可预览文件使用受认证的 GET /v0/file/s/{file_id};转换预览使用 GET /v0/file/s/{preview_file_id}。两个接口都必须校验当前用户仍有会议笔记查看权限。
  • 服务端不得返回长期有效的公共下载 URL。客户端缓存键至少包含 tenant_code + user_id + file_id + etag,退出登录或切换企业时清理受控缓存。
  • preview.status="processing" 时客户端可在当前详情页低频刷新,建议 2 秒后开始、最长 30 秒;离开页面立即停止轮询。

9.14.7 会议笔记-详情页-文件下载中.png

会议笔记-详情页-文件下载中

状态:复用统一下载任务;会议笔记 ACL 新增。

  • 下载使用 GET /v0/file/s/{file_id},Header 传 API Key 与 X-MeetingIM-Auth: token <base64_token>,并支持 Range 和 If-Range 断点续传。
  • 下载任务保存 file_id,etag,total_bytes,downloaded_bytes,temp_path,state。Token 更新后使用新 Token 续传,禁止把 Token 写入任务文件或日志。
  • 服务端在每次下载及续传时重新校验会议可见权限。返回 FILE_FORBIDDEN 时客户端停止重试;返回 FILE_UNAVAILABLE 时标记文件失效并刷新详情。
  • 下载进度属于客户端本地状态,不更新会议笔记业务状态、不产生工作台通知,也不写入未读数。

9.14.8 会议笔记-文件预览.png

会议笔记-文件预览

状态:客户端预览页;服务端复用 9.14.6 文件读取协议。

  • 预览页展示服务端返回的安全文件名和实际内容;标题不得直接信任未经清理的上传文件名。
  • 图片、PDF、文本等受支持类型在应用内预览;Office 等类型优先使用受控转换文件,无法转换时按 preview.mode="download_only" 提示下载后打开。
  • 文件被删除、审核拒绝、转换失败或权限撤销时,服务端返回稳定 reason,客户端关闭预览并刷新详情,不能继续显示旧的授权链接。
  • 从预览页返回详情后调用 GET /v1/im/meetings/{meeting_id}/notes 获取最新文件状态。

9.14.9 接口示例

以下示例用于会议笔记 HTTP 联调快速查阅。成功响应统一包裹为 {"code":0,"data":示例,"request_id":"...","server_time":"..."},下表只展示 data。

9.14.9.1 工作台、会议记录员与会议笔记

接口 输入示例 成功 data 示例
GET /v1/im/workbench 需改造 Query only {"layout_version":2,"modules":[{"code":"meeting_notifications","name":"会议通知","route":"/meetings","unread_count":3,"enabled":true,"permission":"enabled"},{"code":"meeting_notes","name":"会议笔记","route":"/meeting-notes","unread_count":0,"enabled":true,"permission":"enabled"}]}
POST /v1/im/meetings 需改造 Header Idempotency-Key;Body {"title":"项目周会","start_at":"2026-09-05T10:00:00+08:00","end_at":"2026-09-05T10:30:00+08:00","location":"会议室 A","recorder_user_id":"usr_me","attendee_user_ids":["usr_2"],"reminder_minutes":[10]} {"meeting_id":"mtg_1","title":"项目周会","organizer":{"user_id":"usr_me","display_name":"张三"},"recorder":{"user_id":"usr_me","display_name":"张三"},"start_at":"2026-09-05T02:00:00Z","end_at":"2026-09-05T02:30:00Z","state":"scheduled","participants":[{"user_id":"usr_me","response":"accepted"},{"user_id":"usr_2","response":"pending"}],"permissions":{"can_update":true,"can_cancel":true},"version":1}
PATCH /v1/im/meetings/{meeting_id} 需改造 Header Idempotency-Key;Body {"recorder_user_id":"usr_2","version":1} {"meeting_id":"mtg_1","recorder":{"user_id":"usr_2","display_name":"李四"},"version":2,"updated_at":"2026-09-05T01:30:00Z"}
GET /v1/im/meeting-notes?query=&cursor=&limit=20 新增 Query only {"items":[{"meeting_id":"mtg_1","title":"项目周会","organizer":{"user_id":"usr_me","display_name":"张三"},"recorder":{"user_id":"usr_me","display_name":"张三"},"start_at":"2026-09-05T02:00:00Z","end_at":"2026-09-05T02:30:00Z","location":"会议室 A","state":"ended","participant_count":2,"participant_names":["张三","李四"],"note_status":"empty","file_count":0,"permissions":{"can_view":true,"can_upload":true}}],"next_cursor":"","has_more":false}
GET /v1/im/meetings/{meeting_id}/notes 新增 Path meeting ID {"meeting":{"meeting_id":"mtg_1","title":"项目周会","organizer":{"user_id":"usr_me","display_name":"张三"},"recorder":{"user_id":"usr_me","display_name":"张三"},"start_at":"2026-09-05T02:00:00Z","end_at":"2026-09-05T02:30:00Z","location":"会议室 A","state":"ended","participants":[{"user_id":"usr_me","display_name":"张三"},{"user_id":"usr_2","display_name":"李四"}]},"note_status":"available","files":[{"note_file_id":"mnote_1","file_id":"file_1","name":"会议纪要.pdf","size":204800,"mime":"application/pdf","uploader":{"user_id":"usr_me","display_name":"张三"},"created_at":"2026-09-05T03:00:00Z","version":1,"preview":{"status":"ready","mode":"native","preview_file_id":"file_1"},"permissions":{"can_preview":true,"can_download":true,"can_replace":true,"can_delete":true}}],"permissions":{"can_view":true,"can_upload":true},"version":1}
POST /v0/file/u/ Multipart 文件;字段 purpose=meeting_note、meeting_id=mtg_1;Header X-MeetingIM-Auth {"ctrl":{"code":200,"params":{"file_id":"file_1","url":"/v0/file/s/file_1","name":"会议纪要.pdf","size":204800,"mime":"application/pdf"}}}
POST /v1/im/meetings/{meeting_id}/notes/files 新增 Header Idempotency-Key;Body {"file_id":"file_1"} {"note_file_id":"mnote_1","meeting_id":"mtg_1","file_id":"file_1","name":"会议纪要.pdf","size":204800,"mime":"application/pdf","created_at":"2026-09-05T03:00:00Z","version":1,"preview":{"status":"processing","mode":"converted"}}
PUT /v1/im/meetings/{meeting_id}/notes/files/{note_file_id} 新增 Header Idempotency-Key;Body {"file_id":"file_2","version":1} {"note_file_id":"mnote_1","meeting_id":"mtg_1","file_id":"file_2","name":"会议纪要-v2.pdf","version":2,"updated_at":"2026-09-05T03:10:00Z"}
DELETE /v1/im/meetings/{meeting_id}/notes/files/{note_file_id} 新增 Header Idempotency-Key;Query version=2 {"note_file_id":"mnote_1","deleted":true,"deleted_at":"2026-09-05T03:20:00Z"}
GET /v0/file/s/{file_id} Header X-MeetingIM-Auth;可带 Range: bytes=0- 返回文件字节流及 Content-Type、Content-Length、ETag、Accept-Ranges;失败返回 FILE_FORBIDDEN 或 FILE_UNAVAILABLE

9.14.10 字段与状态约定

字段 取值 前端处理
meeting.state scheduled、in_progress、ended、canceled 会议笔记列表只展示 ended
note_status empty、available empty 展示“暂无笔记”,available 展示文件列表
preview.status ready、processing、unsupported、failed 分别进入预览、短时刷新、仅下载提示、失败提示
preview.mode native、converted、download_only 使用原文件、转换文件或仅提供下载
permissions.can_view Boolean 是否可以查看当前会议笔记
permissions.can_upload Boolean 是否显示并允许使用上传按钮,仅会议记录员为 true
permissions.can_replace Boolean 是否允许替换当前笔记文件
permissions.can_delete Boolean 是否允许删除当前笔记文件
permissions.can_preview Boolean 是否允许预览当前文件
permissions.can_download Boolean 是否允许下载当前文件;首版普通参会人若产品要求“只能预览”,该值返回 false

客户端必须以服务端返回的 permissions 为准。特别是普通参会人“只能预览”的要求,由文件项 can_preview=true,can_download=false 表达;即使预览底层使用文件读取接口,客户端也不得提供导出、系统分享或保存到相册入口。

9.14.11 错误码与客户端处理

reason 典型 HTTP 状态 场景 客户端处理
MEETING_NOT_ENDED 409 未结束会议上传或登记笔记 提示“会议结束后可上传笔记”,刷新会议详情
MEETING_CLOSED 409 会议结束后修改记录员或会议数据 切换为只读并刷新详情
NOT_MEETING_RECORDER 403 非记录员上传、替换或删除文件 隐藏操作入口并刷新权限
MEETING_NOTE_VERSION_CONFLICT 409 替换或删除时版本过期 拉取最新详情,不自动覆盖
MEETING_NOTE_FILE_INVALID 400 文件未上传完成、用途不符或不属于当前租户 提示重新上传
FILE_PREVIEW_PROCESSING 409 转换预览尚未完成 保持当前页并按退避策略刷新
FILE_PREVIEW_UNSUPPORTED 422 文件类型不支持在线预览 根据 can_download 决定是否提供下载
FILE_FORBIDDEN 403 当前用户无文件访问权限 关闭预览或停止下载并刷新详情
FILE_UNAVAILABLE 404/410 文件被删除、失效或审核拒绝 标记不可用并刷新文件列表
RESOURCE_NOT_FOUND 404 会议或笔记不可见、跨租户访问 返回列表,不提示资源是否真实存在

9.14.12 前后端联调与验收要点

  1. 发起会议时不传 recorder_user_id,响应中的记录员必须默认为当前发起人;指定其他记录员时,响应返回最终记录员和参会人名单。
  2. 会议笔记列表只包含与当前用户有关的已结束会议;已结束但无文件的会议仍展示,详情为空状态。
  3. 记录员进入详情显示上传按钮,普通参会人进入同一会议不显示上传按钮;直接调用写接口仍必须被服务端拒绝。
  4. 普通参会人只允许在线预览时,响应为 can_preview=true,can_download=false,客户端不展示下载、分享或导出入口。
  5. 文件上传成功但会议笔记登记失败时,详情列表不出现该文件;重复登记同一幂等键返回首次结果。
  6. 文件替换和删除必须校验 version;旧版本请求返回冲突,不能覆盖新文件。
  7. 进入列表、进入详情以及从上传/预览/下载页面返回时均主动刷新;断开 WebSocket 不影响会议笔记数据获取。
  8. 会议笔记新增、替换、删除均不产生 Push、会议通知未读或工作台红点;工作台红点只随会议通知模块变化。
  9. 跨租户、无关用户和已撤销权限用户无法通过会议 ID 或文件 ID 查看、预览、下载会议笔记。
  10. 切换企业或退出登录后,会议笔记列表、详情、预览文件和下载临时数据按租户及账号隔离清理。

合并建议

  1. 将本文 9.14 会议笔记 整段插入现有《IM 前后端逐图对接协议》第 9 章的 9.13 总经理信箱-文案提示.png 之后。
  2. 将现有 9.14 接口示例 及其子章节顺延为 9.15,并把本文 9.14.9.1 的接口行合并到新的第 9 章接口示例表中。
  3. 同步扩展会议数据模型:im_meetings 增加会议记录员字段,并新增会议笔记文件关联表;具体表结构在系统设计和数据库变更文档中统一维护。
  4. 主文档第 9 章现有会议创建示例需要补充 recorder_user_id,工作台示例需要增加 meeting_notes 模块并明确其 unread_count=0。