feat(system): 扩展用户部门权限功能
- 在 AdminUserService 中新增 listEnabledUserIdsByDeptIds 方法获取指定部门集合下启用且未离职的用户 ID 集合 - 在 DeptService 中新增 listDescendantDeptIds 方法获得指定部门集合及其所有子孙部门的 ID 集合 - 在 DeptService 中新增 listCodesByIds 方法按 id 集合批量查询部门 code 集合 - 在 OrgLeaderRelationService 中新增 listEffectiveDeptIdsByUserId 方法查询指定用户当前生效的负责人关系所对应的 dept_id 集合 - 在 PermissionApi 中新增 isSuperAdmin 接口判断用户是否超管 - 在 ObjectPermissionApi 中新增 getObjectRolePermissionDetailMerged 接口按 roleId 列表聚合菜单 + 权限码 - 扩展 ProductContextRoleRespVO 添加多角色场景的附加角色名称列表 - 扩展 ProductCreateWithTeamReqVO 支持创建时添加关心人用户 ID 列表 - 优化 ProductMemberServiceImpl 支持同一用户多角色显示,区分主角色和附加角色 - 新增 MEMBER_ACTION_REACTIVATE 复活动作类型用于处理 INACTIVE 成员行重新激活场景 - 在 ObjectStatusModelDO 中新增 progressExcludedFlag 字段控制是否参与上层进度统计 - 更新 AGENTS.md 和 CLAUDE.md 添加 Git 操作纪律规范 - 在 rdms-project-api 中新增多个错误码常量支持角色转移和内置角色配置验证
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.njcn.rdms.module.system.api.dept;
|
||||
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 组织负责人")
|
||||
public interface OrgLeaderApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/org-leader";
|
||||
|
||||
/**
|
||||
* 反推:当前 user 作为 leader 能"看到"的下属 user_id 集合(含递归子节点)。
|
||||
* 自己默认不在结果里(自己看自己走通道 1)。
|
||||
* 无 leader 关系返回空集。
|
||||
*/
|
||||
@GetMapping(PREFIX + "/get-reachable-user-ids")
|
||||
@Operation(summary = "反推 leader 可见的下属 user 集合")
|
||||
CommonResult<Set<Long>> getReachableUserIds(@RequestParam("currentUserId") Long currentUserId);
|
||||
}
|
||||
@@ -70,6 +70,15 @@ public interface ObjectPermissionApi {
|
||||
@RequestParam("scopeType") String scopeType,
|
||||
@RequestParam("objectType") String objectType);
|
||||
|
||||
@GetMapping(PREFIX + "/role-permission-detail-merged")
|
||||
@Operation(summary = "按 roleId 列表聚合菜单 + 权限码(多角色场景);主角色按 system_role.sort 升序取首个,菜单/权限取并集")
|
||||
@Parameter(name = "roleIds", description = "角色 ID 集合", example = "1,2", required = true)
|
||||
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
|
||||
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
|
||||
CommonResult<ObjectRolePermissionRespDTO> getObjectRolePermissionDetailMerged(@RequestParam("roleIds") Collection<Long> roleIds,
|
||||
@RequestParam("scopeType") String scopeType,
|
||||
@RequestParam("objectType") String objectType);
|
||||
|
||||
/**
|
||||
* 按角色 ID 返回对象作用域角色摘要映射,便于业务模块批量对齐本地成员数据。
|
||||
*
|
||||
|
||||
@@ -24,4 +24,8 @@ public interface PermissionApi extends PermissionCommonApi {
|
||||
@Parameter(name = "roleIds", description = "角色编号集合", example = "1,2", required = true)
|
||||
CommonResult<Set<Long>> getUserRoleIdListByRoleIds(@RequestParam("roleIds") Collection<Long> roleIds);
|
||||
|
||||
@GetMapping(PREFIX + "/is-super-admin")
|
||||
@Operation(summary = "判断用户是否超管")
|
||||
CommonResult<Boolean> isSuperAdmin(@RequestParam("userId") Long userId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.njcn.rdms.module.system.api.permission;
|
||||
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.module.system.api.permission.dto.UserVisibilityConfigRespDTO;
|
||||
import com.njcn.rdms.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 用户可见性配置")
|
||||
public interface UserVisibilityConfigApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/permission/user-visibility-config";
|
||||
|
||||
/**
|
||||
* 拿用户的可见性配置(通道 3)。
|
||||
* 无配置返回 null(不抛异常)。
|
||||
*/
|
||||
@GetMapping(PREFIX + "/get-config")
|
||||
@Operation(summary = "拿用户的可见性配置;无配置返回 null")
|
||||
CommonResult<UserVisibilityConfigRespDTO> getConfig(@RequestParam("userId") Long userId);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -20,4 +21,11 @@ public class ObjectRolePermissionRespDTO {
|
||||
@ArraySchema(schema = @Schema(description = "基于同一批有效菜单资源归一化提取出的权限标识集合,供对象权限校验直接消费", example = "project:product:query"))
|
||||
private Set<String> permissions;
|
||||
|
||||
/**
|
||||
* 非主角色的中文名列表(多角色场景)。单角色或无角色时为空数组。
|
||||
* 前端展示"创建者"等次要角色标签时读这个字段;权限判断仍按 currentRole.code。
|
||||
*/
|
||||
@ArraySchema(schema = @Schema(description = "非主角色的中文名列表,多角色场景使用", example = "创建者"))
|
||||
private List<String> additionalRoleNames = Collections.emptyList();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.rdms.module.system.api.permission.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户可见性配置(通道 3)跨模块响应 DTO。
|
||||
*
|
||||
* directions 类型已由 API 端把 directionId → directionCode 转换好;业务侧不用再 join system_dept。
|
||||
* projects 类型字段保留,当前业务不消费。
|
||||
*/
|
||||
@Schema(description = "RPC 服务 - 用户可见性配置 Response DTO")
|
||||
@Data
|
||||
public class UserVisibilityConfigRespDTO {
|
||||
|
||||
@Schema(description = "\"all\" / \"directions\" / \"projects\"", example = "all")
|
||||
private String type;
|
||||
|
||||
@ArraySchema(schema = @Schema(description = "type=directions 时为方向 code 集合(API 端已转换)", example = "direction_code_1"))
|
||||
private Set<String> directionCodes;
|
||||
|
||||
@ArraySchema(schema = @Schema(description = "type=projects 时为项目 id 集合(保留位,当前业务不消费)", example = "1"))
|
||||
private Set<Long> projectIds;
|
||||
}
|
||||
@@ -152,4 +152,8 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode ORG_LEADER_EFFECTIVE_RANGE_INVALID = new ErrorCode(1_002_004_102, "负责人生效时间区间不合法");
|
||||
ErrorCode ORG_LEADER_RELATION_OVERLAP = new ErrorCode(1_002_004_103, "同一组织下该用户的负责人时间区间存在重叠");
|
||||
|
||||
// ========== 用户可见性配置 1-002-003-200 ==========
|
||||
ErrorCode USER_VISIBILITY_CONFIG_TYPE_FIELD_MISMATCH = new ErrorCode(1_002_003_200,
|
||||
"可见性类型与字段不匹配:type={}, 详情:{}");
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.njcn.rdms.module.system.enums.permission;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 内置对象角色清单。
|
||||
*
|
||||
* 业务代码按 code 查 system_role 拿 role_id(创建者自动落地、关心人、隐式 observer 兜底等都用);
|
||||
* 启动时按本枚举校验 system_role 必须存在;这些 code 同时已加入 {@link RoleCodeEnum#isBuiltIn(String)} 锁住改 code / 删除。
|
||||
*
|
||||
* 不含 product_manager / project_manager / visitor —— 已分别定义在
|
||||
* ProductObjectConstants / ProjectObjectConstants,避免重复维护 code 字面量。
|
||||
*
|
||||
* code / name 直接引用 {@link RoleCodeEnum},两处只有一份字符串。
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ObjectRoleConstants {
|
||||
|
||||
PRODUCT_CREATOR(RoleCodeEnum.PRODUCT_CREATOR, "product"),
|
||||
PRODUCT_WATCHER(RoleCodeEnum.PRODUCT_WATCHER, "product"),
|
||||
IMPLICIT_OBSERVER_PRODUCT(RoleCodeEnum.IMPLICIT_OBSERVER_PRODUCT, "product"),
|
||||
|
||||
PROJECT_CREATOR(RoleCodeEnum.PROJECT_CREATOR, "project"),
|
||||
PROJECT_WATCHER(RoleCodeEnum.PROJECT_WATCHER, "project"),
|
||||
IMPLICIT_OBSERVER_PROJECT(RoleCodeEnum.IMPLICIT_OBSERVER_PROJECT, "project");
|
||||
|
||||
private final RoleCodeEnum roleCode;
|
||||
private final String objectType;
|
||||
|
||||
public String getCode() {
|
||||
return roleCode.getCode();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return roleCode.getName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,18 @@ import lombok.Getter;
|
||||
public enum RoleCodeEnum {
|
||||
|
||||
SUPER_ADMIN("super_admin", "超级管理员"),
|
||||
CRM_ADMIN("crm_admin", "CRM 管理员");
|
||||
CRM_ADMIN("crm_admin", "CRM 管理员"),
|
||||
|
||||
// 对象域内置角色:被业务代码硬编码引用(按 code 查 system_role),改 code 或删除会让对应业务功能炸
|
||||
PRODUCT_MANAGER("product_manager", "产品经理"),
|
||||
PRODUCT_CREATOR("product_creator", "产品创建者"),
|
||||
PRODUCT_WATCHER("product_watcher", "产品关心人"),
|
||||
IMPLICIT_OBSERVER_PRODUCT("implicit_observer_product", "产品隐式观察者"),
|
||||
PROJECT_MANAGER("project_manager", "项目经理"),
|
||||
PROJECT_CREATOR("project_creator", "项目创建者"),
|
||||
PROJECT_WATCHER("project_watcher", "项目关心人"),
|
||||
IMPLICIT_OBSERVER_PROJECT("implicit_observer_project", "项目隐式观察者"),
|
||||
VISITOR("visitor", "游客");
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
@@ -19,7 +30,13 @@ public enum RoleCodeEnum {
|
||||
}
|
||||
|
||||
public static boolean isBuiltIn(String code) {
|
||||
return ObjectUtils.equalsAny(code, SUPER_ADMIN.getCode(), CRM_ADMIN.getCode());
|
||||
return ObjectUtils.equalsAny(code,
|
||||
SUPER_ADMIN.getCode(), CRM_ADMIN.getCode(),
|
||||
PRODUCT_MANAGER.getCode(), PRODUCT_CREATOR.getCode(),
|
||||
PRODUCT_WATCHER.getCode(), IMPLICIT_OBSERVER_PRODUCT.getCode(),
|
||||
PROJECT_MANAGER.getCode(), PROJECT_CREATOR.getCode(),
|
||||
PROJECT_WATCHER.getCode(), IMPLICIT_OBSERVER_PROJECT.getCode(),
|
||||
VISITOR.getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user