additionalRoleNames: string[]
字段返回。前端只需要把这个数组拼到角色名旁边显示即可。
多角色改造后,
产品/项目的"创建者"角色会自动落一条
rdms_user_object_role
行
。当
创建者本人就是负责人
时,同一用户在同一对象内会出现两条 ACTIVE 记录:
product_manager
/
project_manager
product_creator
/
project_creator
如果后端原样返回,前端列表会出现"同一个人重复两行"。讨论后约定:后端在 列表接口 层做合并展示, 不影响 底层数据(每个角色行仍独立存在,便于后续可能的"按角色单独操作")。
creator + manager
这一种组合
会让同人多角色出现。其他角色(产品专员、开发等)仍是一人一角色。所以前端可以放心按"主角色 + 附加角色名"
的方式渲染,附加列表通常是 0 或 1 个元素。
/admin-api/project/product/{productId}/members
产品团队成员列表
/admin-api/project/project/{projectId}/members
项目团队成员列表
响应结构两个接口对称,本文档下文统一用
RespVO
表示,字段路径一致。
假设:产品 P 里
用户A
是产品经理(同时创建了该产品,所以也有
product_creator
角色),
用户B
是产品专员,
用户C
是已退场的历史成员。
[
{ id: "100", userId: "A", roleCode: "product_manager",
roleName: "产品经理", status: 0, ... },
{ id: "101", userId: "A", roleCode: "product_creator",
roleName: "产品创建者", status: 0, ... },
{ id: "102", userId: "B", roleCode: "product_specialist",
roleName: "产品专员", status: 0, ... },
{ id: "103", userId: "C", roleCode: "product_specialist",
roleName: "产品专员", status: 1, leftTime: "..." }
]
用户 A 出现 2 次 — 前端要么重复显示,要么自己去重。
[
{ id: "100", userId: "A", roleCode: "product_manager",
roleName: "产品经理",
additionalRoleNames: ["产品创建者"], // ← 新增字段
status: 0, ... },
{ id: "102", userId: "B", roleCode: "product_specialist",
roleName: "产品专员",
additionalRoleNames: [],
status: 0, ... },
{ id: "103", userId: "C", roleCode: "product_specialist",
roleName: "产品专员",
additionalRoleNames: [],
status: 1, leftTime: "..." }
]
用户 A 1 行 — 主行 manager,creator 名字进
additionalRoleNames
。
| 规则 | 说明 |
|---|---|
| 仅合并 ACTIVE 行 |
status = 0
的多角色行才聚合;
status = 1
的历史 INACTIVE 行
保持每条独立成行
(历史角色留痕,便于审计)
|
| 主角色选择 |
同人多角色时,
product_manager
/
project_manager
角色行优先做主;不在则按
roleId
升序选第一条(理论不该走到这条兜底)
|
| 主行字段 |
id
/
roleId
/
roleCode
/
roleName
/
joinedTime
/
leftTime
/
remark
等都按主角色行的值返回
|
| 非主角色名顺序 |
additionalRoleNames
按角色中文名字典序升序,前端可以直接顺序渲染
|
additionalRoleNames
| 字段名 | 类型 | 状态 | 说明 |
|---|---|---|---|
additionalRoleNames |
string[] |
本次新增 |
非主角色的中文名列表,多角色场景使用;
单角色时为空数组
[]
,前端可以放心
length
判空
|
所有
原有字段保持不变
(
id
、
userId
、
userNickname
、
roleId
、
roleName
、
roleCode
、
managerFlag
、
status
、
joinedTime
、
leftTime
、
remark
),前端原有代码不会因为字段消失而报错。
const displayRoleName = additionalRoleNames?.length
? `${roleName} + ${additionalRoleNames.join(', ')}`
: roleName;
//
// 例:roleName="产品经理", additionalRoleNames=["产品创建者"]
// → "产品经理 + 产品创建者"
//
// 例:roleName="产品专员", additionalRoleNames=[]
// → "产品专员"
<span class="role-main">{{ roleName }}</span>
<span v-for="extra in additionalRoleNames" :key="extra" class="role-tag">
{{ extra }}
</span>
//
// CSS:role-tag 设计成浅色 background + 小圆角,跟主角色拉开视觉层级
| 用户 | 角色 | 状态 |
|-----------|---------------------------|------|
| 灿能管理 | 产品经理 [产品创建者] | 有效 |
| 洪圣文 | 产品专员 | 有效 |
| 李凡 | 游客 | 历史 |
| 场景 | 预期返回 | 前端展示 |
|---|---|---|
| 用户 A 仅是产品经理(不是创建者) |
1 行,
additionalRoleNames=[]
|
"产品经理" |
| 用户 A 同时是产品经理 + 创建者 |
1 行(主行 manager),
additionalRoleNames=["产品创建者"]
|
"产品经理 + 产品创建者" |
| 用户 A 仅是创建者(罕见,理论上创建后立即把 manager 转给别人才会出现) |
1 行,主行就是 creator,
additionalRoleNames=[]
|
"产品创建者" |
| 用户 A 是产品专员(单角色非 manager) |
1 行,
additionalRoleNames=[]
|
"产品专员" |
| 用户 A 退场(status=1 INACTIVE 历史行) |
每条 INACTIVE 行独立 1 行,
additionalRoleNames=[]
|
"产品专员(已退场)"等灰显 |
| 用户 A 同时有 历史失效 的角色行 + 当前生效 的角色行 | ACTIVE 行合并 1 行 + 每条 INACTIVE 行各占 1 行;同用户在列表里会出现多次(不同 status) | 分别用"有效 / 历史"区分;不要再二次合并 |
以下接口 不变 ,前端原有调用方式保持:
| 接口 | 说明 |
|---|---|
POST /admin-api/project/product/{productId}/members
POST /admin-api/project/project/{projectId}/members
|
新增成员 — 仍按"一个角色一条记录"操作,传
userId + roleId
|
PUT /admin-api/project/.../members/{memberId} |
更新成员 — 按
memberId
(即
rdms_user_object_role.id
)定位具体角色行操作
|
PUT /admin-api/project/.../members/{memberId}/inactive |
失效成员 — 同上,按
memberId
操作
|
GET /admin-api/project/product/{productId}/context
GET /admin-api/project/project/{projectId}/context
|
对象上下文 —
currentRole.additionalRoleNames
字段早已存在,
不在本次变更范围
|
memberId
是
主角色行的
id
(也就是 manager 那条)。
不会影响
同人的 creator 角色行 — creator 角色仍保留。
id
),后续
是否要单独提供"列出某 user 所有角色行"接口
取决于业务实际诉求,目前没有这个接口。
additionalRoleNames
数组加到 TypeScript 类型定义(ProductMemberRespVO / ProjectMemberRespVO 两处)
additionalRoleNames
拼到
roleName
旁边显示(字符串或 chip 标签均可)
additionalRoleNames
应该是
[]
,不影响展示
status=1
),仍按原方式各占一行
memberId
操作主角色行;若业务需要"踢人整体",后端再补接口
本次后端改动仅在
ProductMemberServiceImpl.getProductMemberList
和
ProjectMemberServiceImpl.getProjectMemberList
两个方法中实现,
不修改底层数据
(
rdms_user_object_role
仍按一行一角色存储)。即使前端暂时不读
additionalRoleNames
字段,也只是看不到"+ 产品创建者"字样,不会出现数据错误或重复行问题。