Files
shanxia2.0/docs/superpowers/specs/2026-11-12-doclib-batch-share-design.md
T
wuzilongandCursor bf89a1f301 docs: 记录文档库多选批量分享设计(#25)。
明确整份覆盖、交集预选、batch-shares 事务与 Web 弹窗扩展范围,供实现对照。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-12 17:36:51 +08:00

4.9 KiB
Raw Blame History

文档库多选批量设置分享(工单 #25)

工单:#25

背景与问题

Web 文档库管理(/#/doclib/enter)工具栏「设置分享」当前仅在恰好选中 1 份且可管理的文档时可用(actionsFor.share),弹窗与接口均为单文档。用户需要多选文档后统一设置分享人员。

已确认决策

项 结论
保存语义 整份覆盖:弹窗所选 userIds 写入每一份所选文档,替换原分享人;空列表表示全部收回
弹窗初始勾选 所选文档现有分享人的交集;无共同人员则为空
修改端 Web 管理端 + 后端批量 API
失败策略 整批事务:全部成功或全部回滚
实现方案 新增 batch-shares + 扩展现有 ShareDialog(方案 A)

范围

包含

  • web-admin:doclib/enter 列表工具栏、ShareDialog、actionsFor、API 封装与单测
  • backend:批量分享路由、schema、服务层事务与单文件写入逻辑复用

不包含

  • 小程序 / 移动 H5
  • 「只追加不收回」、部分成功返回清单
  • 文件夹级分享

后端设计

接口

POST /web/doclib/files/batch-shares

请求体(extra=forbid):

{
  "ids": ["file-id-1", "file-id-2"],
  "userIds": ["user-id-a", "user-id-b"]
}

约束:

  • ids:min_length=1,max_length=100(对齐 DeleteFilesBody)
  • userIds:max_length=500(对齐 ShareBody)
  • 去重后的 ids 均须当前用户可管理;任一份不可管理则 4xx,整批不写
  • 人员须同租户且启用;自动排除各文档上传人(与现 set_shares 一致:requested - {create_by})
  • 非法 / 停用 / 跨租户人员 → 400,整批回滚

响应:成功后返回更新后的文档列表(字段与现有单文档分享成功返回一致的序列化)。

事务与复用

  • 现有 DoclibService.set_shares 在单文件路径末尾 commit。批量路径须在全部文件写入完成前不 commit。
  • 抽取内部方法(名称示例:_apply_shares(file_id, user_ids))完成单文件差量更新(含 lock);set_shares = _apply_shares + commit + 返回序列化;set_shares_batch = 校验全部可管理 → 校验人员 → 对每个 id 调用 _apply_shares → 一次 commit → 返回列表。
  • 任一步抛错依赖会话回滚,不留下部分文档已改的状态。

路由注册位置:与现有 PUT /web/doclib/files/{file_id}/shares、POST .../batch-delete 同模块(backend/app/api/doclib.py)。

前端设计

工具栏与权限

  • actionsFor.share:rows.length > 0 && rows.every((row) => row.canManage)(与删除多选门槛一致,取消「仅 1 条」限制)。
  • 工具栏「设置分享」对 selected 全量打开弹窗,不再只取 selected[0]。
  • 详情抽屉单文档「设置分享」仍传入单元素数组或单文档,行为不变。

ShareDialog

  • Props 改为支持多文档(例如 documents: DoclibDocument[]);打开时:
    • 摘要列出所选文档名称(数量较多时可截断并注明总数)
    • userIds 初始 = 分享人 id 交集
    • 候选人员:交集中的人员 ∪ 远程搜索结果;排除各文档上传人(多文档时排除所有相关 ownerId)
  • 保存:统一调用批量接口 saveDoclibBatchShares(ids, userIds)(单文档也走批量,少分支);成功提示后关闭并刷新列表 / 更新详情。

纯函数(便于单测)

  • shareUserIntersection(documents): string[] — 交集;空文档列表返回 []
  • 可选:canShareSelection(rows) 与 actionsFor 共用语义

API

在 web-admin/src/api/doclib.ts 增加:

saveDoclibBatchShares(ids: string[], userIds: string[]) → POST .../files/batch-shares

单文档 saveDoclibShares 可保留供兼容/测试,页面路径以批量为准。

UI 规范

  • 沿用现有 doclib-dialog dialog-form-layout、Fresh Mint、P12 类弹窗;不新造布局与主色。
  • 按钮图标规则与现页一致(Close / Check 等已有用法)。

验收

  1. 多选可管理文档后可打开「设置分享」;含不可管理项时按钮禁用。
  2. 打开时勾选为交集;无共同分享人时为空。
  3. 保存后所选文档分享人员均等于弹窗所选集合(含清空)。
  4. 故意混入无权限文档(若后端被直接调用)→ 整批不改。
  5. 详情页单文档分享仍可用。
  6. 单测覆盖交集函数与 actionsFor.share;后端/服务层覆盖批量成功与权限失败回滚(按项目既有测试方式)。

风险

  • set_shares 重构时须保证单文档路径回归(commit 时机、上传人排除、软删恢复历史 share 行)。
  • 批量上限 100 与删除一致;超大选区依赖现有表格多选,不另做分片 UI。

状态

设计已获用户确认(会话中「按照推荐」方案 A,「OK,请继续」批准落盘)。待用户审阅本文件后进入实现计划。