关心人功能 — API 接口文档

面向前端开发 · 后端已就绪 · 编写日期 2026-05-14

一句话总结
在产品 / 项目创建向导第 2 步增加"关心人"多选输入框,前端把选中的 userId 列表通过 watcherUserIds 字段一并提交到现有的 create-with-team 接口即可。后端自动给这些用户授予 产品/项目关心人 角色,让他们后续能在列表 / 详情看到这个对象(菜单按 watcher 角色权限渲染)。
目录
  1. 设计意图
  2. 用户旅程 / 前端交互
  3. 接口列表速览
  4. 主接口 — 创建产品(含团队 + 关心人)
  5. 主接口 — 创建项目(含团队 + 关心人)
  6. 辅助接口 — 用户精简列表(用于选关心人)
  7. 业务规则 / 边界 / FAQ

1. 设计意图

1.1 关心人是什么

"关心人"(watcher)是 对产品 / 项目本身长期感兴趣,但不参与交付 的人。典型场景:

1.2 为什么不直接加成员?

身份 角色 code 能看什么 能做什么
产品经理 / 项目负责人 product_manager / project_manager 对象内全部 tab 所有操作(分配任务、改预算、删对象等)
团队成员(开发 / 测试 / 协办等) 各业务角色 对象内执行细节(任务、代码、文档等) 跟自己角色 / 任务挂钩的写操作
关心人 watcher product_watcher / project_watcher 对象主要 tab(概览 / 进度 / 需求) 只读 — 不参与交付
为什么单独做 watcher,不复用现有 member?
数据权限设计里有 三条互不重叠的边界 少量人盯几个对象就是 watcher 的位置 —— 比逐条加成员省事,比配 visibility_config 颗粒细。

1.3 关心人的数据权限路径

关心人记录最终落到 rdms_user_object_role 表(与 member 同表,只是 role_id 指向 watcher 角色)。系统按这个角色让用户进入"数据权限通道 1(自己参与)",跟普通成员路径一致 —— 区别只在 菜单 / 按钮粒度 由 watcher 角色绑定的权限决定。

2. 用户旅程 / 前端交互

2.1 当前两步向导(产品 / 项目都一样)

  1. 第 1 步 :填基础资料 —— 名称 / 编码 / 方向 / 负责人等
  2. 第 2 步 :维护初始团队 —— 必须含负责人本人 + 其他成员(每人一个业务角色)

2.2 本次新增 — 第 2 步追加"关心人"区块

建议 UI:第 2 步页面里在"团队成员"列表下方加一个独立区块" 关心人(选填) ",含一个用户多选控件。

┌─────────────────────────────────────────────────────────┐
│  第 2 步:维护初始团队                                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  团队成员 *                                              │
│  ┌────────────────────────────────────────────────────┐ │
│  │ [+] 添加成员                                       │ │
│  │  · 张三   产品经理      操作 ▾                     │ │
│  │  · 李四   开发          操作 ▾                     │ │
│  └────────────────────────────────────────────────────┘ │
│                                                         │
│  关心人(选填)                                           │
│  ┌────────────────────────────────────────────────────┐ │
│  │ [多选用户] 王五 ╳  赵六 ╳                          │ │
│  └────────────────────────────────────────────────────┘ │
│  提示:关心人将获得"产品/项目关心人"角色,能在列表和概览看到此对象,  │
│       但不开放代码 / 任务 / 文档等执行细节。可与团队成员重叠。      │
│                                                         │
│  [取消]                                  [上一步] [完成] │
└─────────────────────────────────────────────────────────┘

2.3 提交时数据组装

点击"完成"时,按 §4 / §5 的 ReqVO 结构组装:

3. 接口列表速览

方法 路径 用途 本次是否新接口
POST /project/product/create-with-team 创建产品(含初始团队 + 关心人) 已有接口;本次只是 ReqVO 多了 watcherUserIds 字段
POST /project/project/create-with-team 创建项目(含初始团队 + 关心人) 已有接口;本次只是 ReqVO 多了 watcherUserIds 字段
GET /system/user/list-all-simple
(别名 /system/user/simple-list
获取启用用户精简列表(前端选关心人下拉用) 已有接口,无需任何改动

4. 主接口 — 创建产品(含团队 + 关心人)

POST /project/product/create-with-team

事务性原子接口:产品基础资料 + 初始团队 + 关心人在同一事务内完成,任一步失败整体回滚。

权限

@PreAuthorize("@ss.hasPermission('project:product:create')") — 创建产品权限码

请求体( ProductCreateWithTeamReqVO

{
  "product": {
    "code": "CNPD2026001",
    "directionCode": "system",
    "name": "RDMS 产品平台",
    "managerUserId": 1024,
    "description": "面向研发管理的一体化产品"
  },
  "members": [
    { "userId": 1024, "roleId": 3100000002001, "remark": "产品经理本人" },
    { "userId": 1025, "roleId": 3100000002002, "remark": "开发" }
  ],
  "watcherUserIds": [2001, 2002]
}

字段说明

路径 类型 必填 说明
product object 必填 产品基础资料,结构见下
product.code string ≤ 64 选填 产品编码;为空时由后端按规则生成
product.directionCode string ≤ 32 必填 产品方向字典值(字典类型 object_direction
product.name string ≤ 128 必填 产品名称
product.managerUserId Long 必填 产品经理 user_id;必须在 members 列表里有对应的产品经理角色记录
product.description string 选填 产品描述
members array<object> 必填 初始团队, 必须包含 userId == product.managerUserId 且 roleId 是 product_manager 的记录 ;后端不会自动追加经理
members[].userId Long 必填 成员 user_id
members[].roleId Long 必填 对象域角色 ID( scope_type='object' , object_type='product' );前端用 role code 反查得到(如 product_manager
members[].remark string ≤ 500 选填 成员备注
watcherUserIds array<Long> 选填 关心人 user_id 数组 。允许为空 / 省略字段 / 与 members 重叠;后端按 (user, object, role) 三元组写入,重复跳过 / INACTIVE 复活;后端会自动去 null 去重

响应

{
  "code": 0,
  "data": 30001,   // 新创建的 productId
  "msg": ""
}

典型错误

错误码 / 信息 触发条件
产品基础资料不能为空 product 字段缺失
初始团队成员不能为空 members 空数组或缺失
产品经理不能为空 product.managerUserId 缺失
产品方向不能为空 product.directionCode 缺失
PRODUCT_MEMBER_ALREADY_EXISTS members 里同 user 同 role 重复(multi-role 唯一索引拦截)
PRODUCT_INTERNAL_ROLE_NOT_CONFIGURED 后端启动校验通过但运行时找不到 product_watcher 角色(理论上不会发生 — 启动校验会拦)

5. 主接口 — 创建项目(含团队 + 关心人)

POST /project/project/create-with-team

事务性原子接口:项目基础资料 + 初始团队 + 关心人在同一事务内完成,任一步失败整体回滚。

权限

@PreAuthorize("@ss.hasPermission('project:project:create')") — 创建项目权限码

请求体( ProjectCreateWithTeamReqVO

{
  "project": {
    "projectCode": "CNPJ2026001",
    "projectName": "客户交付项目 A",
    "projectType": "delivery",
    "directionCode": "system",
    "productId": 30001,
    "managerUserId": 1024,
    "plannedStartDate": "2026-06-01",
    "plannedEndDate":   "2026-09-30",
    "projectDesc": "为客户 XX 定制交付"
  },
  "members": [
    { "userId": 1024, "roleId": 3100000003001, "remark": "项目负责人本人" },
    { "userId": 1030, "roleId": 3100000003002, "remark": "前端开发" }
  ],
  "watcherUserIds": [2001, 2002]
}

字段说明

路径 类型 必填 说明
project object 必填 项目基础资料;新建场景不传 actualStartDate / actualEndDate (实际日期由执行阶段才有值)
project.projectCode string ≤ 64 选填 项目编码;为空时由后端按规则生成
project.projectName string ≤ 200 必填 项目名称
project.projectType string ≤ 32 必填 项目类型字典值
project.directionCode string 条件必填 项目方向; 未选产品时必填;选了产品则后端按产品方向覆盖 ,前端可不传
project.productId Long 选填 所属产品 ID;不选表示无产品归属
project.managerUserId Long 必填 项目负责人 user_id;同产品规则,必须在 members 里出现且对应负责人角色
project.plannedStartDate / plannedEndDate date YYYY-MM-DD 选填 计划日期
project.projectDesc string ≤ 4000 选填 项目说明
members array<object> 必填 结构同 ProjectMemberSaveReqVO ,与产品对称。必须包含 userId == project.managerUserId 且 roleId 为 project_manager 的记录
members[].userId Long 必填 成员 user_id
members[].roleId Long 必填 对象域角色 ID( scope_type='object' , object_type='project'
members[].remark string ≤ 500 选填 成员备注
watcherUserIds array<Long> 选填 关心人 user_id 数组 。规则与产品端一致:允许空 / 省略 / 与 members 重叠;后端去 null 去重,按三元组幂等写入

响应

{
  "code": 0,
  "data": 40001,   // 新创建的 projectId
  "msg": ""
}

典型错误

错误码 / 信息 触发条件
项目基础资料不能为空 project 字段缺失
项目名称不能为空 project.projectName 缺失
项目负责人不能为空 project.managerUserId 缺失
初始团队成员不能为空 members
PROJECT_MEMBER_ALREADY_EXISTS members 里同 user 同 role 重复
PROJECT_INTERNAL_ROLE_NOT_CONFIGURED 后端运行时找不到 project_watcher 角色(理论上不会发生)

6. 辅助接口 — 用户精简列表

GET /system/user/list-all-simple

获取所有 已启用 用户的精简信息,用于前端下拉 / 多选控件。也可访问别名 /system/user/simple-list

权限

登录态即可(无显式权限码限制)。

请求

无参数。

响应( List<UserSimpleRespVO>

{
  "code": 0,
  "data": [
    { "id": 1024, "nickname": "张三" },
    { "id": 1025, "nickname": "李四" },
    { "id": 2001, "nickname": "王五" }
  ],
  "msg": ""
}
前端使用建议
这个接口返回的字段比较精简(一般是 id + 昵称)。如果需要按部门 / 工号 / 状态筛选,可以叠加用 GET /system/user/page 走分页查询;或者拉一次全量后在前端做 search filter。

7. 业务规则 / 边界 / FAQ

7.1 watcher 与 member 可不可以是同一人?

可以。多角色合法,会落两条 rdms_user_object_role 记录(一条 member 角色 + 一条 watcher 角色),数据权限 取并集 。这种情况通常不会出现 —— 已经在团队里的人不需要再设为 watcher —— 但允许重叠不报错,前端不需要做"过滤已在 members 里的 user"的校验,让后端兜底。

7.2 创建之后能不能再加 / 删关心人?

当前 create-with-team 是唯一的批量入口 。创建后维护 watcher 的接口暂未单独提供 —— 如果业务后续需要"在产品 / 项目编辑页面再加关心人",需要再拉一条接口(沿用现有的 add member / remove member 模式即可,roleId 传 watcher 角色 ID)。

7.3 watcher 进入对象后能看到什么、能做什么?

取决于业务侧给 product_watcher / project_watcher 角色在权限管理界面绑了哪些菜单(对象域菜单 system_menu.scope_type='object' )。建议粒度:

前端可能用到的角色 code 常量

7.4 watcher 字段不传会怎样?

完全等价于传空数组。 watcherUserIds 是可选字段 —— 不写 / 写 null / 写 [] 都不会落任何 watcher 记录,接口正常完成。

7.5 watcher 列表能放多少人?

当前没有上限校验。从产品语义看,关心人本来就是"少量长期看的人",前端可以加个软性提示(如超过 20 人时提示考虑用方向级 visibility_config 配置),但不阻塞提交。

7.6 关心人能看到对象里的"工时"吗?

看不到。工时是敏感数据,按对象内身份控制:协办人只看自己填报的工时;任务/项目负责人可看团队成员工时。 watcher 既不是协办人也不是负责人,工时列表对其不可见

7.7 watcher 和"用户可见性配置(visibility_config)"什么区别?

维度 关心人 watcher 用户可见性配置 visibility_config
粒度 单个产品 / 项目 整个方向 or 全局(all / directions)
谁来加 产品 / 项目创建人在新建表单里加 系统管理员在用户管理 / 可见性配置页加
典型场景 外部顾问盯几个产品 / 长期评审人 跨方向工程师看一片方向的所有产品 / 技术支持组协调全部
底层存储 rdms_user_object_role (一条对象成员记录) system_user_visibility_config (一条用户级配置)
前端落地 checklist