feat(core): 新增项目及相关功能的数据访问层和权限控制切面
- 添加多个Mapper接口及XML文件支持项目、成员、里程碑、任务、风险、资源、 文件附件等模块的数据操作和查询功能,支持复杂查询与统计 - 新增Sa-Token权限配置,集成统一认证管理 - 引入权限常量类,定义系统角色、项目角色及权限编码标准 - 新增项目权限校验切面,实现基于注解的项目权限和角色校验逻辑 - 更新配置文件和依赖,集成MyBatis Plus、MinIO、Spring AI及文档解析相关库 - 调整MyBatis配置的类型别名包路径,统一领域实体引用路径
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
package cn.yinlihupo.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 项目权限校验注解
|
||||
* 用于标注需要校验项目权限的方法
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RequireProjectPermission {
|
||||
|
||||
/**
|
||||
* 项目ID参数名
|
||||
* 默认从方法参数中获取名为"projectId"的参数值
|
||||
*/
|
||||
String projectIdParam() default "projectId";
|
||||
|
||||
/**
|
||||
* 需要的权限编码
|
||||
* 例如: "risk:manage", "task:assign"
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* 错误提示信息
|
||||
*/
|
||||
String message() default "无权访问该项目资源";
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package cn.yinlihupo.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 项目角色校验注解
|
||||
* 用于标注需要校验项目角色的方法
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RequireProjectRole {
|
||||
|
||||
/**
|
||||
* 项目ID参数名
|
||||
* 默认从方法参数中获取名为"projectId"的参数值
|
||||
*/
|
||||
String projectIdParam() default "projectId";
|
||||
|
||||
/**
|
||||
* 需要的项目角色
|
||||
* 可选值: manager, leader, member, observer
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* 是否允许系统管理员绕过角色校验
|
||||
* 默认true,管理员拥有所有权限
|
||||
*/
|
||||
boolean allowAdmin() default true;
|
||||
|
||||
/**
|
||||
* 错误提示信息
|
||||
*/
|
||||
String message() default "无权执行该操作";
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package cn.yinlihupo.common.aspect;
|
||||
|
||||
import cn.yinlihupo.common.annotation.RequireProjectPermission;
|
||||
import cn.yinlihupo.common.annotation.RequireProjectRole;
|
||||
import cn.yinlihupo.common.exception.BusinessException;
|
||||
import cn.yinlihupo.common.util.SecurityUtils;
|
||||
import cn.yinlihupo.service.system.ProjectPermissionService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
/**
|
||||
* 项目权限校验切面
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ProjectPermissionAspect {
|
||||
|
||||
private final ProjectPermissionService projectPermissionService;
|
||||
|
||||
/**
|
||||
* 校验项目权限
|
||||
*/
|
||||
@Before("@annotation(cn.yinlihupo.common.annotation.RequireProjectPermission)")
|
||||
public void checkProjectPermission(JoinPoint joinPoint) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
RequireProjectPermission annotation = method.getAnnotation(RequireProjectPermission.class);
|
||||
|
||||
Long userId = SecurityUtils.getCurrentUserId();
|
||||
if (userId == null) {
|
||||
throw new BusinessException(403, "用户未登录");
|
||||
}
|
||||
|
||||
// 管理员直接放行
|
||||
if (projectPermissionService.isAdmin(userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取项目ID
|
||||
Long projectId = extractProjectId(joinPoint, annotation.projectIdParam());
|
||||
if (projectId == null) {
|
||||
throw new BusinessException(400, "无法获取项目ID");
|
||||
}
|
||||
|
||||
// 校验权限
|
||||
String requiredPermission = annotation.value();
|
||||
boolean hasPermission = projectPermissionService.hasPermission(userId, projectId, requiredPermission);
|
||||
|
||||
if (!hasPermission) {
|
||||
log.warn("用户 [{}] 没有项目 [{}] 的权限 [{}]", userId, projectId, requiredPermission);
|
||||
throw new BusinessException(403, annotation.message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验项目角色
|
||||
*/
|
||||
@Before("@annotation(cn.yinlihupo.common.annotation.RequireProjectRole)")
|
||||
public void checkProjectRole(JoinPoint joinPoint) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
RequireProjectRole annotation = method.getAnnotation(RequireProjectRole.class);
|
||||
|
||||
Long userId = SecurityUtils.getCurrentUserId();
|
||||
if (userId == null) {
|
||||
throw new BusinessException(403, "用户未登录");
|
||||
}
|
||||
|
||||
// 管理员直接放行(如果允许)
|
||||
if (annotation.allowAdmin() && projectPermissionService.isAdmin(userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取项目ID
|
||||
Long projectId = extractProjectId(joinPoint, annotation.projectIdParam());
|
||||
if (projectId == null) {
|
||||
throw new BusinessException(400, "无法获取项目ID");
|
||||
}
|
||||
|
||||
// 获取用户项目角色
|
||||
String userRole = projectPermissionService.getUserProjectRole(userId, projectId);
|
||||
if (userRole == null) {
|
||||
throw new BusinessException(403, "您不是该项目的成员");
|
||||
}
|
||||
|
||||
// 校验角色
|
||||
String[] requiredRoles = annotation.value();
|
||||
boolean hasRole = false;
|
||||
for (String requiredRole : requiredRoles) {
|
||||
if (userRole.equals(requiredRole)) {
|
||||
hasRole = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRole) {
|
||||
log.warn("用户 [{}] 在项目 [{}] 中的角色 [{}] 不符合要求 {}",
|
||||
userId, projectId, userRole, requiredRoles);
|
||||
throw new BusinessException(403, annotation.message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从方法参数中提取项目ID
|
||||
*/
|
||||
private Long extractProjectId(JoinPoint joinPoint, String paramName) {
|
||||
Object[] args = joinPoint.getArgs();
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Parameter[] parameters = signature.getMethod().getParameters();
|
||||
|
||||
// 1. 先从方法参数中查找
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (parameters[i].getName().equals(paramName) && args[i] instanceof Long) {
|
||||
return (Long) args[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 尝试从请求参数中获取
|
||||
try {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
String projectIdStr = request.getParameter(paramName);
|
||||
if (projectIdStr != null && !projectIdStr.isEmpty()) {
|
||||
return Long.valueOf(projectIdStr);
|
||||
}
|
||||
|
||||
// 尝试从路径变量中获取
|
||||
Object pathVar = request.getAttribute(paramName);
|
||||
if (pathVar instanceof Long) {
|
||||
return (Long) pathVar;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("从请求中获取项目ID失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 3. 查找任何名为projectId或包含projectId的参数
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
String paramNameLower = parameters[i].getName().toLowerCase();
|
||||
if ((paramNameLower.contains("projectid") || paramNameLower.contains("project_id"))
|
||||
&& args[i] instanceof Long) {
|
||||
return (Long) args[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
71
src/main/java/cn/yinlihupo/common/config/SaTokenConfig.java
Normal file
71
src/main/java/cn/yinlihupo/common/config/SaTokenConfig.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package cn.yinlihupo.common.config;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.filter.SaServletFilter;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.yinlihupo.common.core.BaseResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Sa-Token 配置类
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class SaTokenConfig implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 注册 Sa-Token 拦截器,打开注解式鉴权功能
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验
|
||||
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(
|
||||
"/auth/login",
|
||||
"/auth/register",
|
||||
"/error",
|
||||
"/swagger-ui/**",
|
||||
"/v3/api-docs/**"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 [Sa-Token 全局过滤器]
|
||||
*/
|
||||
@Bean
|
||||
public SaServletFilter getSaServletFilter() {
|
||||
return new SaServletFilter()
|
||||
// 指定 [拦截路由] 与 [放行路由]
|
||||
.addInclude("/**")
|
||||
.addExclude("/favicon.ico", "/swagger-ui/**", "/v3/api-docs/**")
|
||||
// 认证函数: 每次请求执行
|
||||
.setAuth(obj -> {
|
||||
log.debug("---------- 进入 Sa-Token 全局认证 -----------");
|
||||
})
|
||||
// 异常处理函数:每次认证函数发生异常时执行
|
||||
.setError(e -> {
|
||||
log.error("Sa-Token 认证异常: {}", e.getMessage());
|
||||
return new BaseResponse<>(403, e.getMessage(), null);
|
||||
})
|
||||
// 前置函数:在每次认证函数之前执行
|
||||
.setBeforeAuth(obj -> {
|
||||
// 设置跨域响应头
|
||||
SaHolder.getResponse()
|
||||
.setHeader("Access-Control-Allow-Origin", "*")
|
||||
.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
.setHeader("Access-Control-Allow-Headers", "*")
|
||||
.setHeader("Access-Control-Max-Age", "3600");
|
||||
// 如果是预检请求,则立即返回到前端
|
||||
SaRouter.match("OPTIONS")
|
||||
.free(r -> log.debug("--------OPTIONS预检请求,不做处理"))
|
||||
.back();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.yinlihupo.common.config;
|
||||
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.yinlihupo.mapper.SysPermissionMapper;
|
||||
import cn.yinlihupo.mapper.SysUserMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sa-Token 权限认证接口扩展
|
||||
* 实现 StpInterface 接口,自定义权限和角色获取逻辑
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SaTokenPermissionExtension implements StpInterface {
|
||||
|
||||
private final SysUserMapper sysUserMapper;
|
||||
private final SysPermissionMapper sysPermissionMapper;
|
||||
|
||||
/**
|
||||
* 返回指定账号id所拥有的权限码集合
|
||||
*
|
||||
* @param loginId 账号id
|
||||
* @param loginType 账号类型
|
||||
* @return 权限码集合
|
||||
*/
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
// 项目权限通过 ProjectPermissionService 动态校验
|
||||
// 这里返回系统级别的权限
|
||||
try {
|
||||
Long userId = Long.valueOf(loginId.toString());
|
||||
List<String> roleCodes = sysUserMapper.selectRoleCodesByUserId(userId);
|
||||
if (roleCodes.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 根据角色查询权限
|
||||
return sysPermissionMapper.selectPermissionCodesByRoleCodes(roleCodes);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户权限列表失败: {}", e.getMessage());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回指定账号id所拥有的角色标识集合
|
||||
*
|
||||
* @param loginId 账号id
|
||||
* @param loginType 账号类型
|
||||
* @return 角色标识集合
|
||||
*/
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
try {
|
||||
Long userId = Long.valueOf(loginId.toString());
|
||||
return sysUserMapper.selectRoleCodesByUserId(userId);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户角色列表失败: {}", e.getMessage());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.yinlihupo.common.constant;
|
||||
|
||||
/**
|
||||
* 权限常量类
|
||||
* 定义系统角色、项目角色和权限编码
|
||||
*/
|
||||
public class PermissionConstants {
|
||||
|
||||
// ==================== 系统角色 ====================
|
||||
/** 系统管理员 */
|
||||
public static final String ROLE_ADMIN = "admin";
|
||||
/** 项目经理 */
|
||||
public static final String ROLE_PROJECT_MANAGER = "project_manager";
|
||||
/** 团队负责人 */
|
||||
public static final String ROLE_TEAM_LEADER = "team_leader";
|
||||
/** 普通成员 */
|
||||
public static final String ROLE_MEMBER = "member";
|
||||
|
||||
// ==================== 项目角色 ====================
|
||||
/** 项目经理 - 拥有项目全部权限 */
|
||||
public static final String PROJECT_ROLE_MANAGER = "manager";
|
||||
/** 负责人 - 协助管理项目 */
|
||||
public static final String PROJECT_ROLE_LEADER = "leader";
|
||||
/** 普通成员 */
|
||||
public static final String PROJECT_ROLE_MEMBER = "member";
|
||||
/** 观察者 - 只读权限 */
|
||||
public static final String PROJECT_ROLE_OBSERVER = "observer";
|
||||
|
||||
// ==================== 项目权限编码 ====================
|
||||
// 项目查看权限
|
||||
public static final String PERM_PROJECT_VIEW = "project:view";
|
||||
// 项目管理权限(编辑、删除)
|
||||
public static final String PERM_PROJECT_MANAGE = "project:manage";
|
||||
|
||||
// 风险查看权限
|
||||
public static final String PERM_RISK_VIEW = "risk:view";
|
||||
// 风险管控权限(创建、编辑、删除)
|
||||
public static final String PERM_RISK_MANAGE = "risk:manage";
|
||||
|
||||
// 资源查看权限
|
||||
public static final String PERM_RESOURCE_VIEW = "resource:view";
|
||||
// 资源管控权限(申请、审批、分配)
|
||||
public static final String PERM_RESOURCE_MANAGE = "resource:manage";
|
||||
|
||||
// 里程碑查看权限
|
||||
public static final String PERM_MILESTONE_VIEW = "milestone:view";
|
||||
// 里程碑推进权限
|
||||
public static final String PERM_MILESTONE_PUSH = "milestone:push";
|
||||
|
||||
// 任务工单查看权限
|
||||
public static final String PERM_TASK_VIEW = "task:view";
|
||||
// 任务工单分配权限
|
||||
public static final String PERM_TASK_ASSIGN = "task:assign";
|
||||
// 任务工单处理权限
|
||||
public static final String PERM_TASK_PROCESS = "task:process";
|
||||
|
||||
// 日报查看权限
|
||||
public static final String PERM_REPORT_VIEW = "report:view";
|
||||
// 日报上传权限
|
||||
public static final String PERM_REPORT_CREATE = "report:create";
|
||||
|
||||
// 知识库查看权限
|
||||
public static final String PERM_KB_VIEW = "kb:view";
|
||||
// 知识库上传权限
|
||||
public static final String PERM_KB_CREATE = "kb:create";
|
||||
|
||||
// ==================== 数据权限范围 ====================
|
||||
/** 全部数据 */
|
||||
public static final int DATA_SCOPE_ALL = 1;
|
||||
/** 本部门数据 */
|
||||
public static final int DATA_SCOPE_DEPT = 2;
|
||||
/** 本人数据 */
|
||||
public static final int DATA_SCOPE_SELF = 3;
|
||||
/** 本项目数据 */
|
||||
public static final int DATA_SCOPE_PROJECT = 4;
|
||||
|
||||
private PermissionConstants() {
|
||||
}
|
||||
}
|
||||
125
src/main/java/cn/yinlihupo/common/util/SecurityUtils.java
Normal file
125
src/main/java/cn/yinlihupo/common/util/SecurityUtils.java
Normal file
@@ -0,0 +1,125 @@
|
||||
package cn.yinlihupo.common.util;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.yinlihupo.common.constant.PermissionConstants;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 安全工具类 (Sa-Token 版本)
|
||||
* 提供获取当前用户、权限校验等方法
|
||||
*/
|
||||
public class SecurityUtils {
|
||||
|
||||
/**
|
||||
* 获取当前登录用户ID
|
||||
*/
|
||||
public static Long getCurrentUserId() {
|
||||
try {
|
||||
Object loginId = StpUtil.getLoginIdDefaultNull();
|
||||
if (loginId == null) {
|
||||
return null;
|
||||
}
|
||||
return Long.valueOf(loginId.toString());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户角色列表
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Set<String> getCurrentUserRoles() {
|
||||
try {
|
||||
SaSession session = StpUtil.getSession();
|
||||
Object roles = session.get("roles");
|
||||
if (roles instanceof Set) {
|
||||
return (Set<String>) roles;
|
||||
}
|
||||
if (roles instanceof List) {
|
||||
return Set.copyOf((List<String>) roles);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 未登录或会话不存在
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前用户是否为系统管理员
|
||||
*/
|
||||
public static boolean isAdmin() {
|
||||
return hasRole(PermissionConstants.ROLE_ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前用户是否拥有指定角色
|
||||
*/
|
||||
public static boolean hasRole(String role) {
|
||||
return StpUtil.hasRole(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前用户是否拥有任意一个指定角色
|
||||
*/
|
||||
public static boolean hasAnyRole(String... roles) {
|
||||
for (String role : roles) {
|
||||
if (StpUtil.hasRole(role)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前用户是否拥有指定权限
|
||||
*/
|
||||
public static boolean hasPermission(String permission) {
|
||||
return StpUtil.hasPermission(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前用户是否拥有任意一个指定权限
|
||||
*/
|
||||
public static boolean hasAnyPermission(String... permissions) {
|
||||
for (String permission : permissions) {
|
||||
if (StpUtil.hasPermission(permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录并缓存用户角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param roles 角色列表
|
||||
*/
|
||||
public static void login(Long userId, Set<String> roles) {
|
||||
StpUtil.login(userId);
|
||||
SaSession session = StpUtil.getSession();
|
||||
session.set("roles", roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出
|
||||
*/
|
||||
public static void logout() {
|
||||
StpUtil.logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录Token
|
||||
*/
|
||||
public static String getTokenValue() {
|
||||
return StpUtil.getTokenValue();
|
||||
}
|
||||
|
||||
private SecurityUtils() {
|
||||
}
|
||||
}
|
||||
66
src/main/java/cn/yinlihupo/domain/entity/SysPermission.java
Normal file
66
src/main/java/cn/yinlihupo/domain/entity/SysPermission.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package cn.yinlihupo.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统权限实体类
|
||||
* 对应数据库表: sys_permission
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_permission")
|
||||
public class SysPermission {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/** 父级权限ID */
|
||||
private Long parentId;
|
||||
|
||||
/** 权限编码 */
|
||||
private String permissionCode;
|
||||
|
||||
/** 权限名称 */
|
||||
private String permissionName;
|
||||
|
||||
/** 权限类型: 1-菜单, 2-按钮, 3-接口 */
|
||||
private Integer permissionType;
|
||||
|
||||
/** 路由路径 */
|
||||
private String path;
|
||||
|
||||
/** 组件路径 */
|
||||
private String component;
|
||||
|
||||
/** 图标 */
|
||||
private String icon;
|
||||
|
||||
/** 接口URL */
|
||||
private String apiUrl;
|
||||
|
||||
/** 接口方法 */
|
||||
private String apiMethod;
|
||||
|
||||
/** 排序 */
|
||||
private Integer sortOrder;
|
||||
|
||||
/** 是否可见: 1-是, 0-否 */
|
||||
private Integer visible;
|
||||
|
||||
/** 状态: 1-正常, 0-禁用 */
|
||||
private Integer status;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/** 删除标记 */
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
}
|
||||
57
src/main/java/cn/yinlihupo/domain/entity/SysRole.java
Normal file
57
src/main/java/cn/yinlihupo/domain/entity/SysRole.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package cn.yinlihupo.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统角色实体类
|
||||
* 对应数据库表: sys_role
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_role")
|
||||
public class SysRole {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/** 角色编码 */
|
||||
private String roleCode;
|
||||
|
||||
/** 角色名称 */
|
||||
private String roleName;
|
||||
|
||||
/** 角色类型: system-系统角色, custom-自定义角色 */
|
||||
private String roleType;
|
||||
|
||||
/** 角色描述 */
|
||||
private String description;
|
||||
|
||||
/** 数据权限: 1-全部, 2-本部门, 3-本人 */
|
||||
private Integer dataScope;
|
||||
|
||||
/** 排序 */
|
||||
private Integer sortOrder;
|
||||
|
||||
/** 状态: 1-正常, 0-禁用 */
|
||||
private Integer status;
|
||||
|
||||
/** 创建人 */
|
||||
private Long createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新人 */
|
||||
private Long updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/** 删除标记 */
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.yinlihupo.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 角色权限关联实体类
|
||||
* 对应数据库表: sys_role_permission
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_role_permission")
|
||||
public class SysRolePermission {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/** 角色ID */
|
||||
private Long roleId;
|
||||
|
||||
/** 权限ID */
|
||||
private Long permissionId;
|
||||
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
82
src/main/java/cn/yinlihupo/domain/entity/SysUser.java
Normal file
82
src/main/java/cn/yinlihupo/domain/entity/SysUser.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package cn.yinlihupo.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统用户实体类
|
||||
* 对应数据库表: sys_user
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_user")
|
||||
public class SysUser {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/** 用户名 */
|
||||
private String username;
|
||||
|
||||
/** 密码(加密) */
|
||||
private String password;
|
||||
|
||||
/** 真实姓名 */
|
||||
private String realName;
|
||||
|
||||
/** 昵称 */
|
||||
private String nickname;
|
||||
|
||||
/** 头像URL */
|
||||
private String avatar;
|
||||
|
||||
/** 性别: 0-未知, 1-男, 2-女 */
|
||||
private Integer gender;
|
||||
|
||||
/** 手机号 */
|
||||
private String phone;
|
||||
|
||||
/** 邮箱 */
|
||||
private String email;
|
||||
|
||||
/** 所属部门ID */
|
||||
private Long deptId;
|
||||
|
||||
/** 职位 */
|
||||
private String position;
|
||||
|
||||
/** 工号 */
|
||||
private String employeeNo;
|
||||
|
||||
/** 入职日期 */
|
||||
private LocalDate entryDate;
|
||||
|
||||
/** 状态: 1-正常, 0-禁用, 2-锁定 */
|
||||
private Integer status;
|
||||
|
||||
/** 最后登录时间 */
|
||||
private LocalDateTime lastLoginTime;
|
||||
|
||||
/** 最后登录IP */
|
||||
private String lastLoginIp;
|
||||
|
||||
/** 创建人 */
|
||||
private Long createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新人 */
|
||||
private Long updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/** 删除标记 */
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
}
|
||||
29
src/main/java/cn/yinlihupo/domain/entity/SysUserRole.java
Normal file
29
src/main/java/cn/yinlihupo/domain/entity/SysUserRole.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package cn.yinlihupo.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户角色关联实体类
|
||||
* 对应数据库表: sys_user_role
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_user_role")
|
||||
public class SysUserRole {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/** 用户ID */
|
||||
private Long userId;
|
||||
|
||||
/** 角色ID */
|
||||
private Long roleId;
|
||||
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -3,10 +3,31 @@ package cn.yinlihupo.mapper;
|
||||
import cn.yinlihupo.domain.entity.FileAttachment;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件附件Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface FileAttachmentMapper extends BaseMapper<FileAttachment> {
|
||||
|
||||
/**
|
||||
* 查询某业务实体的附件列表(含上传者信息)
|
||||
*/
|
||||
List<Map<String, Object>> selectAttachmentsByRelated(@Param("relatedType") String relatedType,
|
||||
@Param("relatedId") Long relatedId);
|
||||
|
||||
/**
|
||||
* 分页查询项目下所有附件(支持文件类型筛选)
|
||||
*/
|
||||
List<Map<String, Object>> selectAttachmentsByProject(@Param("projectId") Long projectId,
|
||||
@Param("fileType") String fileType);
|
||||
|
||||
/**
|
||||
* 统计用户上传文件数量和总大小
|
||||
*/
|
||||
List<Map<String, Object>> selectUploaderStats(@Param("projectId") Long projectId);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,46 @@ package cn.yinlihupo.mapper;
|
||||
import cn.yinlihupo.domain.entity.Project;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 项目Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface ProjectMapper extends BaseMapper<Project> {
|
||||
|
||||
/**
|
||||
* 分页查询项目列表(支持多条件筛选)
|
||||
*/
|
||||
List<Project> selectPageList(@Param("status") String status,
|
||||
@Param("priority") String priority,
|
||||
@Param("riskLevel") String riskLevel,
|
||||
@Param("managerId") Long managerId,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("planStartDateFrom") LocalDate planStartDateFrom,
|
||||
@Param("planStartDateTo") LocalDate planStartDateTo);
|
||||
|
||||
/**
|
||||
* 查询指定用户有权限的项目列表(仅自己管理或参与的)
|
||||
*/
|
||||
List<Project> selectProjectsByUserId(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 查询项目详情
|
||||
*/
|
||||
Project selectDetailById(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 统计各状态项目数量
|
||||
*/
|
||||
List<Map<String, Object>> countByStatus();
|
||||
|
||||
/**
|
||||
* 查询即将超期的项目(N天内)
|
||||
*/
|
||||
List<Project> selectAboutToExpire(@Param("days") int days);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,30 @@ package cn.yinlihupo.mapper;
|
||||
import cn.yinlihupo.domain.entity.ProjectMember;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 项目成员Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface ProjectMemberMapper extends BaseMapper<ProjectMember> {
|
||||
|
||||
/**
|
||||
* 查询项目成员列表(含用户详情)
|
||||
*/
|
||||
List<Map<String, Object>> selectMembersWithUser(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 查询用户在某项目中的角色
|
||||
*/
|
||||
String selectRoleByUserAndProject(@Param("projectId") Long projectId,
|
||||
@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 统计某用户参与的项目数量(按角色分组)
|
||||
*/
|
||||
List<Map<String, Object>> countUserProjects(@Param("userId") Long userId);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,36 @@ package cn.yinlihupo.mapper;
|
||||
import cn.yinlihupo.domain.entity.ProjectMilestone;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 项目里程碑Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface ProjectMilestoneMapper extends BaseMapper<ProjectMilestone> {
|
||||
|
||||
/**
|
||||
* 查询项目里程碑列表(含任务统计)
|
||||
*/
|
||||
List<Map<String, Object>> selectMilestoneListWithStats(@Param("projectId") Long projectId,
|
||||
@Param("status") String status);
|
||||
|
||||
/**
|
||||
* 查询已延期的关键里程碑
|
||||
*/
|
||||
List<ProjectMilestone> selectDelayedKeyMilestones(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 查询即将到期的里程碑(N天内)
|
||||
*/
|
||||
List<ProjectMilestone> selectUpcomingMilestones(@Param("projectId") Long projectId,
|
||||
@Param("days") int days);
|
||||
|
||||
/**
|
||||
* 查询里程碑完成进度统计
|
||||
*/
|
||||
Map<String, Object> selectMilestoneProgressSummary(@Param("projectId") Long projectId);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,38 @@ package cn.yinlihupo.mapper;
|
||||
import cn.yinlihupo.domain.entity.Resource;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 资源Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface ResourceMapper extends BaseMapper<Resource> {
|
||||
|
||||
/**
|
||||
* 分页查询资源列表(含负责人信息,支持多条件筛选)
|
||||
*/
|
||||
List<Map<String, Object>> selectResourcePageWithResponsible(@Param("projectId") Long projectId,
|
||||
@Param("resourceType") String resourceType,
|
||||
@Param("status") String status,
|
||||
@Param("keyword") String keyword);
|
||||
|
||||
/**
|
||||
* 查询资源预算汇总(按类型统计)
|
||||
*/
|
||||
List<Map<String, Object>> selectResourceBudgetSummary(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 查询即将到位但尚未到位的资源(N天内)
|
||||
*/
|
||||
List<Resource> selectPendingArrivalResources(@Param("projectId") Long projectId,
|
||||
@Param("days") int days);
|
||||
|
||||
/**
|
||||
* 查询待审批的资源申请
|
||||
*/
|
||||
List<Map<String, Object>> selectPendingApprovalResources(@Param("projectId") Long projectId);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,38 @@ package cn.yinlihupo.mapper;
|
||||
import cn.yinlihupo.domain.entity.Risk;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 风险Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface RiskMapper extends BaseMapper<Risk> {
|
||||
|
||||
/**
|
||||
* 分页查询风险列表(含负责人信息,支持多条件筛选)
|
||||
*/
|
||||
List<Map<String, Object>> selectRiskPageWithOwner(@Param("projectId") Long projectId,
|
||||
@Param("category") String category,
|
||||
@Param("riskLevel") String riskLevel,
|
||||
@Param("status") String status,
|
||||
@Param("keyword") String keyword);
|
||||
|
||||
/**
|
||||
* 查询未解决的高/严重风险(用于预警)
|
||||
*/
|
||||
List<Map<String, Object>> selectHighRisksUnresolved(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 按风险等级统计各分类数量
|
||||
*/
|
||||
List<Map<String, Object>> countRiskByCategoryAndLevel(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 查询风险处理趋势(近6个月)
|
||||
*/
|
||||
List<Map<String, Object>> selectRiskTrend(@Param("projectId") Long projectId);
|
||||
}
|
||||
|
||||
30
src/main/java/cn/yinlihupo/mapper/SysPermissionMapper.java
Normal file
30
src/main/java/cn/yinlihupo/mapper/SysPermissionMapper.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package cn.yinlihupo.mapper;
|
||||
|
||||
import cn.yinlihupo.domain.entity.SysPermission;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统权限Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysPermissionMapper extends BaseMapper<SysPermission> {
|
||||
|
||||
/**
|
||||
* 根据角色编码列表查询权限编码列表
|
||||
*/
|
||||
List<String> selectPermissionCodesByRoleCodes(@Param("roleCodes") List<String> roleCodes);
|
||||
|
||||
/**
|
||||
* 查询菜单树(含按钮权限)
|
||||
*/
|
||||
List<SysPermission> selectMenuTree();
|
||||
|
||||
/**
|
||||
* 根据角色ID查询权限列表
|
||||
*/
|
||||
List<SysPermission> selectPermsByRoleId(@Param("roleId") Long roleId);
|
||||
}
|
||||
12
src/main/java/cn/yinlihupo/mapper/SysRoleMapper.java
Normal file
12
src/main/java/cn/yinlihupo/mapper/SysRoleMapper.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package cn.yinlihupo.mapper;
|
||||
|
||||
import cn.yinlihupo.domain.entity.SysRole;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 系统角色Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysRoleMapper extends BaseMapper<SysRole> {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.yinlihupo.mapper;
|
||||
|
||||
import cn.yinlihupo.domain.entity.SysRolePermission;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 角色权限关联Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysRolePermissionMapper extends BaseMapper<SysRolePermission> {
|
||||
}
|
||||
37
src/main/java/cn/yinlihupo/mapper/SysUserMapper.java
Normal file
37
src/main/java/cn/yinlihupo/mapper/SysUserMapper.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package cn.yinlihupo.mapper;
|
||||
|
||||
import cn.yinlihupo.domain.entity.SysUser;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统用户Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysUserMapper extends BaseMapper<SysUser> {
|
||||
|
||||
/**
|
||||
* 根据用户ID查询角色编码列表
|
||||
*/
|
||||
List<String> selectRoleCodesByUserId(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户名查询用户
|
||||
*/
|
||||
SysUser selectByUsername(@Param("username") String username);
|
||||
|
||||
/**
|
||||
* 分页查询用户列表(支持按部门、状态、关键字筛选)
|
||||
*/
|
||||
List<SysUser> selectPageList(@Param("deptId") Long deptId,
|
||||
@Param("status") Integer status,
|
||||
@Param("keyword") String keyword);
|
||||
|
||||
/**
|
||||
* 查询项目成员用户详情列表
|
||||
*/
|
||||
List<SysUser> selectUsersByProjectId(@Param("projectId") Long projectId);
|
||||
}
|
||||
12
src/main/java/cn/yinlihupo/mapper/SysUserRoleMapper.java
Normal file
12
src/main/java/cn/yinlihupo/mapper/SysUserRoleMapper.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package cn.yinlihupo.mapper;
|
||||
|
||||
import cn.yinlihupo.domain.entity.SysUserRole;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户角色关联Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysUserRoleMapper extends BaseMapper<SysUserRole> {
|
||||
}
|
||||
@@ -3,10 +3,45 @@ package cn.yinlihupo.mapper;
|
||||
import cn.yinlihupo.domain.entity.Task;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 任务Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface TaskMapper extends BaseMapper<Task> {
|
||||
|
||||
/**
|
||||
* 分页查询任务列表(含负责人信息,支持多条件筛选)
|
||||
*/
|
||||
List<Map<String, Object>> selectTaskPageWithAssignee(@Param("projectId") Long projectId,
|
||||
@Param("milestoneId") Long milestoneId,
|
||||
@Param("assigneeId") Long assigneeId,
|
||||
@Param("status") String status,
|
||||
@Param("priority") String priority,
|
||||
@Param("keyword") String keyword);
|
||||
|
||||
/**
|
||||
* 查询我的待办任务(按用户ID)
|
||||
*/
|
||||
List<Task> selectMyTasks(@Param("userId") Long userId,
|
||||
@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 查询超期未完成的任务
|
||||
*/
|
||||
List<Map<String, Object>> selectOverdueTasks(@Param("projectId") Long projectId);
|
||||
|
||||
/**
|
||||
* 查询任务的前置依赖关系
|
||||
*/
|
||||
List<Map<String, Object>> selectDependencies(@Param("taskId") Long taskId);
|
||||
|
||||
/**
|
||||
* 统计项目任务状态分布
|
||||
*/
|
||||
List<Map<String, Object>> countTasksByStatus(@Param("projectId") Long projectId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
package cn.yinlihupo.service.system;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 项目权限服务接口
|
||||
* 提供项目级别的权限校验功能
|
||||
*/
|
||||
public interface ProjectPermissionService {
|
||||
|
||||
/**
|
||||
* 判断用户是否为系统管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return true-是管理员
|
||||
*/
|
||||
boolean isAdmin(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户在项目中的角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param projectId 项目ID
|
||||
* @return 项目角色编码(manager/leader/member/observer),未参与项目返回null
|
||||
*/
|
||||
String getUserProjectRole(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 判断用户是否参与项目
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param projectId 项目ID
|
||||
* @return true-是项目成员
|
||||
*/
|
||||
boolean isProjectMember(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 判断用户是否为项目经理
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param projectId 项目ID
|
||||
* @return true-是项目经理
|
||||
*/
|
||||
boolean isProjectManager(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 判断用户是否为项目负责人或经理
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param projectId 项目ID
|
||||
* @return true-是负责人或经理
|
||||
*/
|
||||
boolean isProjectManagerOrLeader(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 获取用户在项目中拥有的所有权限编码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param projectId 项目ID
|
||||
* @return 权限编码集合
|
||||
*/
|
||||
Set<String> getUserProjectPermissions(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 校验用户是否拥有指定项目权限
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param projectId 项目ID
|
||||
* @param permission 权限编码
|
||||
* @return true-有权限
|
||||
*/
|
||||
boolean hasPermission(Long userId, Long projectId, String permission);
|
||||
|
||||
/**
|
||||
* 校验用户是否拥有任意一个指定权限
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param projectId 项目ID
|
||||
* @param permissions 权限编码数组
|
||||
* @return true-有权限
|
||||
*/
|
||||
boolean hasAnyPermission(Long userId, Long projectId, String... permissions);
|
||||
|
||||
// ==================== 便捷权限校验方法 ====================
|
||||
|
||||
/**
|
||||
* 是否有查看项目的权限
|
||||
*/
|
||||
boolean canViewProject(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有管理项目的权限(编辑、删除)
|
||||
*/
|
||||
boolean canManageProject(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有查看风险的权限
|
||||
*/
|
||||
boolean canViewRisk(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有管控风险的权限(创建、编辑、删除)
|
||||
*/
|
||||
boolean canManageRisk(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有查看资源的权限
|
||||
*/
|
||||
boolean canViewResource(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有管控资源的权限(申请、审批、分配)
|
||||
*/
|
||||
boolean canManageResource(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有查看里程碑的权限
|
||||
*/
|
||||
boolean canViewMilestone(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有推进里程碑的权限
|
||||
*/
|
||||
boolean canPushMilestone(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有查看任务工单的权限
|
||||
*/
|
||||
boolean canViewTask(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有分配任务工单的权限
|
||||
*/
|
||||
boolean canAssignTask(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有处理任务工单的权限
|
||||
*/
|
||||
boolean canProcessTask(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有查看日报的权限
|
||||
*/
|
||||
boolean canViewReport(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有上传日报的权限
|
||||
*/
|
||||
boolean canCreateReport(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有查看知识库的权限
|
||||
*/
|
||||
boolean canViewKnowledgeBase(Long userId, Long projectId);
|
||||
|
||||
/**
|
||||
* 是否有上传知识库的权限
|
||||
*/
|
||||
boolean canCreateKnowledgeBase(Long userId, Long projectId);
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
package cn.yinlihupo.service.system.impl;
|
||||
|
||||
import cn.yinlihupo.common.constant.PermissionConstants;
|
||||
import cn.yinlihupo.domain.entity.Project;
|
||||
import cn.yinlihupo.domain.entity.ProjectMember;
|
||||
import cn.yinlihupo.mapper.ProjectMapper;
|
||||
import cn.yinlihupo.mapper.ProjectMemberMapper;
|
||||
import cn.yinlihupo.mapper.SysUserMapper;
|
||||
import cn.yinlihupo.service.system.ProjectPermissionService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 项目权限服务实现类
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ProjectPermissionServiceImpl implements ProjectPermissionService {
|
||||
|
||||
private final SysUserMapper sysUserMapper;
|
||||
private final ProjectMemberMapper projectMemberMapper;
|
||||
private final ProjectMapper projectMapper;
|
||||
|
||||
@Override
|
||||
public boolean isAdmin(Long userId) {
|
||||
if (userId == null) {
|
||||
return false;
|
||||
}
|
||||
List<String> roleCodes = sysUserMapper.selectRoleCodesByUserId(userId);
|
||||
return roleCodes.contains(PermissionConstants.ROLE_ADMIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserProjectRole(Long userId, Long projectId) {
|
||||
if (userId == null || projectId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 先检查是否为项目经理(project.manager_id)
|
||||
Project project = projectMapper.selectById(projectId);
|
||||
if (project != null && userId.equals(project.getManagerId())) {
|
||||
return PermissionConstants.PROJECT_ROLE_MANAGER;
|
||||
}
|
||||
|
||||
// 查询项目成员表
|
||||
LambdaQueryWrapper<ProjectMember> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ProjectMember::getProjectId, projectId)
|
||||
.eq(ProjectMember::getUserId, userId)
|
||||
.eq(ProjectMember::getStatus, 1)
|
||||
.eq(ProjectMember::getDeleted, 0);
|
||||
ProjectMember member = projectMemberMapper.selectOne(wrapper);
|
||||
|
||||
return member != null ? member.getRoleCode() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProjectMember(Long userId, Long projectId) {
|
||||
return getUserProjectRole(userId, projectId) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProjectManager(Long userId, Long projectId) {
|
||||
String role = getUserProjectRole(userId, projectId);
|
||||
return PermissionConstants.PROJECT_ROLE_MANAGER.equals(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProjectManagerOrLeader(Long userId, Long projectId) {
|
||||
String role = getUserProjectRole(userId, projectId);
|
||||
return PermissionConstants.PROJECT_ROLE_MANAGER.equals(role)
|
||||
|| PermissionConstants.PROJECT_ROLE_LEADER.equals(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getUserProjectPermissions(Long userId, Long projectId) {
|
||||
Set<String> permissions = new HashSet<>();
|
||||
|
||||
if (userId == null || projectId == null) {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
// 系统管理员拥有所有权限
|
||||
if (isAdmin(userId)) {
|
||||
permissions.add(PermissionConstants.PERM_PROJECT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_PROJECT_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_RISK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RISK_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_PUSH);
|
||||
permissions.add(PermissionConstants.PERM_TASK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_TASK_ASSIGN);
|
||||
permissions.add(PermissionConstants.PERM_TASK_PROCESS);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_CREATE);
|
||||
permissions.add(PermissionConstants.PERM_KB_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_KB_CREATE);
|
||||
return permissions;
|
||||
}
|
||||
|
||||
String projectRole = getUserProjectRole(userId, projectId);
|
||||
if (projectRole == null) {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
// 根据项目角色分配权限
|
||||
switch (projectRole) {
|
||||
case PermissionConstants.PROJECT_ROLE_MANAGER:
|
||||
// 项目经理拥有项目全部管理权限
|
||||
permissions.add(PermissionConstants.PERM_PROJECT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_PROJECT_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_RISK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RISK_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_PUSH);
|
||||
permissions.add(PermissionConstants.PERM_TASK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_TASK_ASSIGN);
|
||||
permissions.add(PermissionConstants.PERM_TASK_PROCESS);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_CREATE);
|
||||
permissions.add(PermissionConstants.PERM_KB_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_KB_CREATE);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PROJECT_ROLE_LEADER:
|
||||
// 负责人拥有大部分管理权限,但不能删除项目
|
||||
permissions.add(PermissionConstants.PERM_PROJECT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RISK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RISK_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_MANAGE);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_PUSH);
|
||||
permissions.add(PermissionConstants.PERM_TASK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_TASK_ASSIGN);
|
||||
permissions.add(PermissionConstants.PERM_TASK_PROCESS);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_CREATE);
|
||||
permissions.add(PermissionConstants.PERM_KB_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_KB_CREATE);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PROJECT_ROLE_MEMBER:
|
||||
// 成员拥有基本操作权限
|
||||
permissions.add(PermissionConstants.PERM_PROJECT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RISK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_TASK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_TASK_PROCESS);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_CREATE);
|
||||
permissions.add(PermissionConstants.PERM_KB_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_KB_CREATE);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PROJECT_ROLE_OBSERVER:
|
||||
// 观察者只有查看权限
|
||||
permissions.add(PermissionConstants.PERM_PROJECT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RISK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_RESOURCE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_MILESTONE_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_TASK_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_REPORT_VIEW);
|
||||
permissions.add(PermissionConstants.PERM_KB_VIEW);
|
||||
break;
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Long userId, Long projectId, String permission) {
|
||||
if (permission == null) {
|
||||
return false;
|
||||
}
|
||||
return getUserProjectPermissions(userId, projectId).contains(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyPermission(Long userId, Long projectId, String... permissions) {
|
||||
if (permissions == null || permissions.length == 0) {
|
||||
return false;
|
||||
}
|
||||
Set<String> userPermissions = getUserProjectPermissions(userId, projectId);
|
||||
for (String permission : permissions) {
|
||||
if (userPermissions.contains(permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ==================== 便捷权限校验方法实现 ====================
|
||||
|
||||
@Override
|
||||
public boolean canViewProject(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_PROJECT_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canManageProject(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_PROJECT_MANAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canViewRisk(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_RISK_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canManageRisk(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_RISK_MANAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canViewResource(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_RESOURCE_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canManageResource(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_RESOURCE_MANAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canViewMilestone(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_MILESTONE_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPushMilestone(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_MILESTONE_PUSH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canViewTask(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_TASK_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAssignTask(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_TASK_ASSIGN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProcessTask(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_TASK_PROCESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canViewReport(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_REPORT_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateReport(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_REPORT_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canViewKnowledgeBase(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_KB_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateKnowledgeBase(Long userId, Long projectId) {
|
||||
return hasPermission(userId, projectId, PermissionConstants.PERM_KB_CREATE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user