初始化提交

This commit is contained in:
YangJ
2024-03-20 09:42:17 +08:00
commit 72f30209cf
3705 changed files with 285827 additions and 0 deletions

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>yudao-module-system-api</module>
<module>yudao-module-system-biz</module>
</modules>
<artifactId>yudao-module-system</artifactId>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
<description>
system 模块下,我们放通用业务,支撑上层的核心业务。
例如说:用户、部门、权限、数据字典等等
</description>
</project>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-system</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-system-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
system 模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,61 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 部门 API 接口
*
* @author 芋道源码
*/
public interface DeptApi {
/**
* 获得部门信息
*
* @param id 部门编号
* @return 部门信息
*/
DeptRespDTO getDept(Long id);
/**
* 获得部门信息数组
*
* @param ids 部门编号数组
* @return 部门信息数组
*/
List<DeptRespDTO> getDeptList(Collection<Long> ids);
/**
* 校验部门们是否有效。如下情况,视为无效:
* 1. 部门编号不存在
* 2. 部门被禁用
*
* @param ids 角色编号数组
*/
void validateDeptList(Collection<Long> ids);
/**
* 获得指定编号的部门 Map
*
* @param ids 部门编号数组
* @return 部门 Map
*/
default Map<Long, DeptRespDTO> getDeptMap(Collection<Long> ids) {
List<DeptRespDTO> list = getDeptList(ids);
return CollectionUtils.convertMap(list, DeptRespDTO::getId);
}
/**
* 获得指定部门的所有子部门
*
* @param id 部门编号
* @return 子部门列表
*/
List<DeptRespDTO> getChildDeptList(Long id);
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 岗位 API 接口
*
* @author 芋道源码
*/
public interface PostApi {
/**
* 校验岗位们是否有效。如下情况,视为无效:
* 1. 岗位编号不存在
* 2. 岗位被禁用
*
* @param ids 岗位编号数组
*/
void validPostList(Collection<Long> ids);
List<PostRespDTO> getPostList(Collection<Long> ids);
default Map<Long, PostRespDTO> getPostMap(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return MapUtil.empty();
}
List<PostRespDTO> list = getPostList(ids);
return CollectionUtils.convertMap(list, PostRespDTO::getId);
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.api.dept.dto;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import lombok.Data;
/**
* 部门 Response DTO
*
* @author 芋道源码
*/
@Data
public class DeptRespDTO {
/**
* 部门编号
*/
private Long id;
/**
* 部门名称
*/
private String name;
/**
* 父部门编号
*/
private Long parentId;
/**
* 负责人的用户编号
*/
private Long leaderUserId;
/**
* 部门状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.api.dept.dto;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import lombok.Data;
/**
* 岗位 Response DTO
*
* @author 芋道源码
*/
@Data
public class PostRespDTO {
/**
* 岗位序号
*/
private Long id;
/**
* 岗位名称
*/
private String name;
/**
* 岗位编码
*/
private String code;
/**
* 岗位排序
*/
private Integer sort;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
}

View File

@ -0,0 +1,64 @@
package cn.iocoder.yudao.module.system.api.dict;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
/**
* 字典数据 API 接口
*
* @author 芋道源码
*/
public interface DictDataApi {
/**
* 校验字典数据们是否有效。如下情况,视为无效:
* 1. 字典数据不存在
* 2. 字典数据被禁用
*
* @param dictType 字典类型
* @param values 字典数据值的数组
*/
void validateDictDataList(String dictType, Collection<String> values);
/**
* 获得指定的字典数据,从缓存中
*
* @param type 字典类型
* @param value 字典数据值
* @return 字典数据
*/
DictDataRespDTO getDictData(String type, String value);
/**
* 解析获得指定的字典数据,从缓存中
*
* @param type 字典类型
* @param label 字典数据标签
* @return 字典数据
*/
DictDataRespDTO parseDictData(String type, String label);
/**
* 获得指定字典类型的字典数据列表
*
* @param dictType 字典类型
* @return 字典数据列表
*/
List<DictDataRespDTO> getDictDataList(String dictType);
/**
* 获得字典数据标签列表
*
* @param dictType 字典类型
* @return 字典数据标签列表
*/
default List<String> getDictDataLabelList(String dictType) {
List<DictDataRespDTO> list = getDictDataList(dictType);
return convertList(list, DictDataRespDTO::getLabel);
}
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.api.dict.dto;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import lombok.Data;
/**
* 字典数据 Response DTO
*
* @author 芋道源码
*/
@Data
public class DictDataRespDTO {
/**
* 字典标签
*/
private String label;
/**
* 字典值
*/
private String value;
/**
* 字典类型
*/
private String dictType;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.api.errorcode;
import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
/**
* 错误码 Api 接口
*
* @author 芋道源码
*/
public interface ErrorCodeApi {
/**
* 自动创建错误码
*
* @param autoGenerateDTOs 错误码信息
*/
void autoGenerateErrorCodeList(@Valid List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs);
/**
* 增量获得错误码数组
*
* 如果 minUpdateTime 为空时,则获取所有错误码
*
* @param applicationName 应用名
* @param minUpdateTime 最小更新时间
* @return 错误码数组
*/
List<ErrorCodeRespDTO> getErrorCodeList(String applicationName, LocalDateTime minUpdateTime);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.errorcode.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 错误码自动生成 DTO
*
* @author dylan
*/
@Data
@Accessors(chain = true)
public class ErrorCodeAutoGenerateReqDTO {
/**
* 应用名
*/
@NotNull(message = "应用名不能为空")
private String applicationName;
/**
* 错误码编码
*/
@NotNull(message = "错误码编码不能为空")
private Integer code;
/**
* 错误码错误提示
*/
@NotEmpty(message = "错误码错误提示不能为空")
private String message;
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.api.errorcode.dto;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 错误码的 Response DTO
*
* @author 芋道源码
*/
@Data
public class ErrorCodeRespDTO {
/**
* 错误码编码
*/
private Integer code;
/**
* 错误码错误提示
*/
private String message;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import javax.validation.Valid;
/**
* 登录日志的 API 接口
*
* @author 芋道源码
*/
public interface LoginLogApi {
/**
* 创建登录日志
*
* @param reqDTO 日志信息
*/
void createLoginLog(@Valid LoginLogCreateReqDTO reqDTO);
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO;
import javax.validation.Valid;
/**
* 操作日志 API 接口
*
* @author 芋道源码
*/
public interface OperateLogApi {
/**
* 创建操作日志
*
* @param createReqDTO 请求
*/
void createOperateLog(@Valid OperateLogCreateReqDTO createReqDTO);
/**
* 创建操作日志
*
* @param createReqDTO 请求
*/
void createOperateLogV2(@Valid OperateLogV2CreateReqDTO createReqDTO);
/**
* 获取指定模块的指定数据的操作日志分页
*
* @param pageReqVO 请求
* @return 操作日志分页
*/
PageResult<OperateLogV2RespDTO> getOperateLogPage(OperateLogV2PageReqDTO pageReqVO);
}

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 登录日志创建 Request DTO
*
* @author 芋道源码
*/
@Data
public class LoginLogCreateReqDTO {
/**
* 日志类型
*/
@NotNull(message = "日志类型不能为空")
private Integer logType;
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 用户账号
*
* 不再强制校验 username 非空,因为 Member 社交登录时,此时暂时没有 username(mobile
*/
private String username;
/**
* 登录结果
*/
@NotNull(message = "登录结果不能为空")
private Integer result;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 浏览器 UserAgent
*
* 允许空原因Job 过期登出时,是无法传递 UserAgent 的
*/
private String userAgent;
}

View File

@ -0,0 +1,123 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 操作日志创建 Request DTO
*/
@Data
public class OperateLogCreateReqDTO {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 操作模块
*/
@NotEmpty(message = "操作模块不能为空")
private String module;
/**
* 操作名
*/
@NotEmpty(message = "操作名")
private String name;
/**
* 操作分类
*/
@NotNull(message = "操作分类不能为空")
private Integer type;
/**
* 操作明细
*/
private String content;
/**
* 拓展字段
*/
private Map<String, Object> exts;
/**
* 请求方法名
*/
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
/**
* 请求地址
*/
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 浏览器 UserAgent
*/
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
/**
* Java 方法名
*/
@NotEmpty(message = "Java 方法名不能为空")
private String javaMethod;
/**
* Java 方法的参数
*/
private String javaMethodArgs;
/**
* 开始时间
*/
@NotNull(message = "开始时间不能为空")
private LocalDateTime startTime;
/**
* 执行时长,单位:毫秒
*/
@NotNull(message = "执行时长不能为空")
private Integer duration;
/**
* 结果码
*/
@NotNull(message = "结果码不能为空")
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
/**
* 结果数据
*/
private String resultData;
}

View File

@ -0,0 +1,85 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 系统操作日志 Create Request DTO
*
* @author HUIHUI
*/
@Data
public class OperateLogV2CreateReqDTO {
/**
* 链路追踪编号
*
* 一般来说通过链路追踪编号可以将访问日志错误日志链路追踪日志logger 打印日志等,结合在一起,从而进行排错。
*/
private String traceId;
/**
* 用户编号
*
* 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*
* 关联 {@link UserTypeEnum}
*/
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 操作模块类型
*/
@NotEmpty(message = "操作模块类型不能为空")
private String type;
/**
* 操作名
*/
@NotEmpty(message = "操作名不能为空")
private String subType;
/**
* 操作模块业务编号
*/
@NotNull(message = "操作模块业务编号不能为空")
private Long bizId;
/**
* 操作内容,记录整个操作的明细
* 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
*/
@NotEmpty(message = "操作内容不能为空")
private String action;
/**
* 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 )
* 例如说,记录订单编号,{ orderId: "1"}
*/
private String extra;
/**
* 请求方法名
*/
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
/**
* 请求地址
*/
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 浏览器 UA
*/
@NotEmpty(message = "浏览器 UA 不能为空")
private String userAgent;
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import lombok.Data;
/**
* 操作日志分页 Request DTO
*
* @author HUIHUI
*/
@Data
public class OperateLogV2PageReqDTO extends PageParam {
/**
* 模块类型
*/
private String bizType;
/**
* 模块数据编号
*/
private Long bizId;
/**
* 用户编号
*/
private Long userId;
}

View File

@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 系统操作日志 Resp DTO
*
* @author HUIHUI
*/
@Data
public class OperateLogV2RespDTO {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户名称
*/
private String userName;
/**
* 用户类型
*/
private Integer userType;
/**
* 操作模块类型
*/
private String type;
/**
* 操作名
*/
private String subType;
/**
* 操作模块业务编号
*/
private Long bizId;
/**
* 操作内容
*/
private String action;
/**
* 拓展字段
*/
private String extra;
/**
* 请求方法名
*/
private String requestMethod;
/**
* 请求地址
*/
private String requestUrl;
/**
* 用户 IP
*/
private String userIp;
/**
* 浏览器 UA
*/
private String userAgent;
/**
* 创建时间
*/
private LocalDateTime createTime;
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.mail;
import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
import javax.validation.Valid;
/**
* 邮箱发送 API 接口
*
* @author 芋道源码
*/
public interface MailSendApi {
/**
* 发送单条邮箱给 Admin 用户
*
* 在 mail 为空时,使用 userId 加载对应 Admin 的邮箱
*
* @param reqDTO 发送请求
* @return 发送日志编号
*/
Long sendSingleMailToAdmin(@Valid MailSendSingleToUserReqDTO reqDTO);
/**
* 发送单条邮箱给 Member 用户
*
* 在 mail 为空时,使用 userId 加载对应 Member 的邮箱
*
* @param reqDTO 发送请求
* @return 发送日志编号
*/
Long sendSingleMailToMember(@Valid MailSendSingleToUserReqDTO reqDTO);
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.api.mail.dto;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* 邮件发送 Request DTO
*
* @author wangjingqi
*/
@Data
public class MailSendSingleToUserReqDTO {
/**
* 用户编号
*/
private Long userId;
/**
* 邮箱
*/
@Email
private String mail;
/**
* 邮件模板编号
*/
@NotNull(message = "邮件模板编号不能为空")
private String templateCode;
/**
* 邮件模板参数
*/
private Map<String, Object> templateParams;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.api.notify;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import javax.validation.Valid;
/**
* 站内信发送 API 接口
*
* @author xrcoder
*/
public interface NotifyMessageSendApi {
/**
* 发送单条站内信给 Admin 用户
*
* @param reqDTO 发送请求
* @return 发送消息 ID
*/
Long sendSingleMessageToAdmin(@Valid NotifySendSingleToUserReqDTO reqDTO);
/**
* 发送单条站内信给 Member 用户
*
* @param reqDTO 发送请求
* @return 发送消息 ID
*/
Long sendSingleMessageToMember(@Valid NotifySendSingleToUserReqDTO reqDTO);
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.api.notify.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* 站内信发送给 Admin 或者 Member 用户
*
* @author xrcoder
*/
@Data
public class NotifySendSingleToUserReqDTO {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 站内信模板编号
*/
@NotEmpty(message = "站内信模板编号不能为空")
private String templateCode;
/**
* 站内信模板参数
*/
private Map<String, Object> templateParams;
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.notify.dto;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Data
public class NotifyTemplateReqDTO {
@NotEmpty(message = "模版名称不能为空")
private String name;
@NotNull(message = "模版编码不能为空")
private String code;
@NotNull(message = "模版类型不能为空")
private Integer type;
@NotEmpty(message = "发送人名称不能为空")
private String nickname;
@NotEmpty(message = "模版内容不能为空")
private String content;
@NotNull(message = "状态不能为空")
@InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
private Integer status;
private String remark;
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.api.oauth2;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO;
import javax.validation.Valid;
/**
* OAuth2.0 Token API 接口
*
* @author 芋道源码
*/
public interface OAuth2TokenApi {
/**
* 创建访问令牌
*
* @param reqDTO 访问令牌的创建信息
* @return 访问令牌的信息
*/
OAuth2AccessTokenRespDTO createAccessToken(@Valid OAuth2AccessTokenCreateReqDTO reqDTO);
/**
* 校验访问令牌
*
* @param accessToken 访问令牌
* @return 访问令牌的信息
*/
OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken);
/**
* 移除访问令牌
*
* @param accessToken 访问令牌
* @return 访问令牌的信息
*/
OAuth2AccessTokenRespDTO removeAccessToken(String accessToken);
/**
* 刷新访问令牌
*
* @param refreshToken 刷新令牌
* @param clientId 客户端编号
* @return 访问令牌的信息
*/
OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId);
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.api.oauth2.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* OAuth2.0 访问令牌的校验 Response DTO
*
* @author 芋道源码
*/
@Data
public class OAuth2AccessTokenCheckRespDTO implements Serializable {
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 租户编号
*/
private Long tenantId;
/**
* 授权范围的数组
*/
private List<String> scopes;
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.api.oauth2.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
/**
* OAuth2.0 访问令牌创建 Request DTO
*
* @author 芋道源码
*/
@Data
public class OAuth2AccessTokenCreateReqDTO implements Serializable {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
@InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}")
private Integer userType;
/**
* 客户端编号
*/
@NotNull(message = "客户端编号不能为空")
private String clientId;
/**
* 授权范围
*/
private List<String> scopes;
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.api.oauth2.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* OAuth2.0 访问令牌的信息 Response DTO
*
* @author 芋道源码
*/
@Data
@Accessors(chain = true)
public class OAuth2AccessTokenRespDTO implements Serializable {
/**
* 访问令牌
*/
private String accessToken;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 过期时间
*/
private LocalDateTime expiresTime;
}

View File

@ -0,0 +1,4 @@
/**
* System API 包,定义暴露给其它模块的 API
*/
package cn.iocoder.yudao.module.system.api;

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import java.util.Collection;
import java.util.Set;
/**
* 权限 API 接口
*
* @author 芋道源码
*/
public interface PermissionApi {
/**
* 获得拥有多个角色的用户编号集合
*
* @param roleIds 角色编号集合
* @return 用户编号集合
*/
Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds);
/**
* 判断是否有权限,任一一个即可
*
* @param userId 用户编号
* @param permissions 权限
* @return 是否
*/
boolean hasAnyPermissions(Long userId, String... permissions);
/**
* 判断是否有角色,任一一个即可
*
* @param userId 用户编号
* @param roles 角色数组
* @return 是否
*/
boolean hasAnyRoles(Long userId, String... roles);
/**
* 获得登陆用户的部门数据权限
*
* @param userId 用户编号
* @return 部门数据权限
*/
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.api.permission;
import java.util.Collection;
/**
* 角色 API 接口
*
* @author 芋道源码
*/
public interface RoleApi {
/**
* 校验角色们是否有效。如下情况,视为无效:
* 1. 角色编号不存在
* 2. 角色被禁用
*
* @param ids 角色编号数组
*/
void validRoleList(Collection<Long> ids);
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.api.permission.dto;
import lombok.Data;
import java.util.HashSet;
import java.util.Set;
/**
* 部门的数据权限 Response DTO
*
* @author 芋道源码
*/
@Data
public class DeptDataPermissionRespDTO {
/**
* 是否可查看全部数据
*/
private Boolean all;
/**
* 是否可查看自己的数据
*/
private Boolean self;
/**
* 可查看的部门编号数组
*/
private Set<Long> deptIds;
public DeptDataPermissionRespDTO() {
this.all = false;
this.self = false;
this.deptIds = new HashSet<>();
}
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.api.sensitiveword;
import java.util.List;
/**
* 敏感词 API 接口
*
* @author 永不言败
*/
public interface SensitiveWordApi {
/**
* 获得文本所包含的不合法的敏感词数组
*
* @param text 文本
* @param tags 标签数组
* @return 不合法的敏感词数组
*/
List<String> validateText(String text, List<String> tags);
/**
* 判断文本是否包含敏感词
*
* @param text 文本
* @param tags 表述数组
* @return 是否包含
*/
boolean isTextValid(String text, List<String> tags);
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import javax.validation.Valid;
/**
* 短信验证码 API 接口
*
* @author 芋道源码
*/
public interface SmsCodeApi {
/**
* 创建短信验证码,并进行发送
*
* @param reqDTO 发送请求
*/
void sendSmsCode(@Valid SmsCodeSendReqDTO reqDTO);
/**
* 验证短信验证码,并进行使用
* 如果正确,则将验证码标记成已使用
* 如果错误,则抛出 {@link ServiceException} 异常
*
* @param reqDTO 使用请求
*/
void useSmsCode(@Valid SmsCodeUseReqDTO reqDTO);
/**
* 检查验证码是否有效
*
* @param reqDTO 校验请求
*/
void validateSmsCode(@Valid SmsCodeValidateReqDTO reqDTO);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import javax.validation.Valid;
/**
* 短信发送 API 接口
*
* @author 芋道源码
*/
public interface SmsSendApi {
/**
* 发送单条短信给 Admin 用户
*
* 在 mobile 为空时,使用 userId 加载对应 Admin 的手机号
*
* @param reqDTO 发送请求
* @return 发送日志编号
*/
Long sendSingleSmsToAdmin(@Valid SmsSendSingleToUserReqDTO reqDTO);
/**
* 发送单条短信给 Member 用户
*
* 在 mobile 为空时,使用 userId 加载对应 Member 的手机号
*
* @param reqDTO 发送请求
* @return 发送日志编号
*/
Long sendSingleSmsToMember(@Valid SmsSendSingleToUserReqDTO reqDTO);
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.api.sms.dto.code;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 短信验证码的发送 Request DTO
*
* @author 芋道源码
*/
@Data
public class SmsCodeSendReqDTO {
/**
* 手机号
*/
@Mobile
@NotEmpty(message = "手机号不能为空")
private String mobile;
/**
* 发送场景
*/
@NotNull(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
/**
* 发送 IP
*/
@NotEmpty(message = "发送 IP 不能为空")
private String createIp;
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.system.api.sms.dto.code;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 短信验证码的使用 Request DTO
*
* @author 芋道源码
*/
@Data
public class SmsCodeUseReqDTO {
/**
* 手机号
*/
@Mobile
@NotEmpty(message = "手机号不能为空")
private String mobile;
/**
* 发送场景
*/
@NotNull(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
/**
* 验证码
*/
@NotEmpty(message = "验证码")
private String code;
/**
* 使用 IP
*/
@NotEmpty(message = "使用 IP 不能为空")
private String usedIp;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.api.sms.dto.code;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 短信验证码的校验 Request DTO
*
* @author 芋道源码
*/
@Data
public class SmsCodeValidateReqDTO {
/**
* 手机号
*/
@Mobile
@NotEmpty(message = "手机号不能为空")
private String mobile;
/**
* 发送场景
*/
@NotNull(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
/**
* 验证码
*/
@NotEmpty(message = "验证码")
private String code;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.system.api.sms.dto.send;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.Map;
/**
* 短信发送给 Admin 或者 Member 用户
*
* @author 芋道源码
*/
@Data
public class SmsSendSingleToUserReqDTO {
/**
* 用户编号
*/
private Long userId;
/**
* 手机号
*/
@Mobile
private String mobile;
/**
* 短信模板编号
*/
@NotEmpty(message = "短信模板编号不能为空")
private String templateCode;
/**
* 短信模板参数
*/
private Map<String, Object> templateParams;
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.system.api.social;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
/**
* 社交应用的 API 接口
*
* @author 芋道源码
*/
public interface SocialClientApi {
/**
* 获得社交平台的授权 URL
*
* @param socialType 社交平台的类型 {@link SocialTypeEnum}
* @param userType 用户类型
* @param redirectUri 重定向 URL
* @return 社交平台的授权 URL
*/
String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri);
/**
* 创建微信公众号 JS SDK 初始化所需的签名
*
* @param userType 用户类型
* @param url 访问的 URL 地址
* @return 签名
*/
SocialWxJsapiSignatureRespDTO createWxMpJsapiSignature(Integer userType, String url);
/**
* 获得微信小程序的手机信息
*
* @param userType 用户类型
* @param phoneCode 手机授权码
* @return 手机信息
*/
SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode);
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.system.api.social;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import javax.validation.Valid;
/**
* 社交用户的 API 接口
*
* @author 芋道源码
*/
public interface SocialUserApi {
/**
* 绑定社交用户
*
* @param reqDTO 绑定信息
* @return 社交用户 openid
*/
String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
/**
* 取消绑定社交用户
*
* @param reqDTO 解绑
*/
void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO);
/**
* 获得社交用户,基于 userId
*
* @param userType 用户类型
* @param userId 用户编号
* @param socialType 社交平台的类型
* @return 社交用户
*/
SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType);
/**
* 获得社交用户
*
* 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
*
* @param userType 用户类型
* @param socialType 社交平台的类型
* @param code 授权码
* @param state state
* @return 社交用户
*/
SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state);
}

View File

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.system.api.social.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 取消绑定社交用户 Request DTO
*
* @author 芋道源码
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SocialUserBindReqDTO {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@InEnum(UserTypeEnum.class)
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 社交平台的类型
*/
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer socialType;
/**
* 授权码
*/
@NotEmpty(message = "授权码不能为空")
private String code;
/**
* state
*/
@NotNull(message = "state 不能为空")
private String state;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.api.social.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 社交用户 Response DTO
*
* @author 芋道源码
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SocialUserRespDTO {
/**
* 社交用户的 openid
*/
private String openid;
/**
* 社交用户的昵称
*/
private String nickname;
/**
* 社交用户的头像
*/
private String avatar;
/**
* 关联的用户编号
*/
private Long userId;
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.system.api.social.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 社交绑定 Request DTO使用 code 授权码
*
* @author 芋道源码
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SocialUserUnbindReqDTO {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@InEnum(UserTypeEnum.class)
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 社交平台的类型
*/
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer socialType;
/**
* 社交平台的 openid
*/
@NotEmpty(message = "社交平台的 openid 不能为空")
private String openid;
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.social.dto;
import lombok.Data;
/**
* 微信公众号 JSAPI 签名 Response DTO
*
* @author 芋道源码
*/
@Data
public class SocialWxJsapiSignatureRespDTO {
/**
* 微信公众号的 appId
*/
private String appId;
/**
* 匿名串
*/
private String nonceStr;
/**
* 时间戳
*/
private Long timestamp;
/**
* URL
*/
private String url;
/**
* 签名
*/
private String signature;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.api.social.dto;
import lombok.Data;
/**
* 微信小程序的手机信息 Response DTO
*
* @author 芋道源码
*/
@Data
public class SocialWxPhoneNumberInfoRespDTO {
/**
* 用户绑定的手机号(国外手机号会有区号)
*/
private String phoneNumber;
/**
* 没有区号的手机号
*/
private String purePhoneNumber;
/**
* 区号
*/
private String countryCode;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.api.tenant;
import java.util.List;
/**
* 多租户的 API 接口
*
* @author 芋道源码
*/
public interface TenantApi {
/**
* 获得所有租户
*
* @return 租户编号数组
*/
List<Long> getTenantIdList();
/**
* 校验租户是否合法
*
* @param id 租户编号
*/
void validateTenant(Long id);
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.system.api.user;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Admin 用户 API 接口
*
* @author 芋道源码
*/
public interface AdminUserApi {
/**
* 通过用户 ID 查询用户
*
* @param id 用户ID
* @return 用户对象信息
*/
AdminUserRespDTO getUser(Long id);
/**
* 通过用户 ID 查询用户下属
*
* @param id 用户编号
* @return 用户下属用户列表
*/
List<AdminUserRespDTO> getUserListBySubordinate(Long id);
/**
* 通过用户 ID 查询用户们
*
* @param ids 用户 ID 们
* @return 用户对象信息
*/
List<AdminUserRespDTO> getUserList(Collection<Long> ids);
/**
* 获得指定部门的用户数组
*
* @param deptIds 部门数组
* @return 用户数组
*/
List<AdminUserRespDTO> getUserListByDeptIds(Collection<Long> deptIds);
/**
* 获得指定岗位的用户数组
*
* @param postIds 岗位数组
* @return 用户数组
*/
List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds);
/**
* 获得用户 Map
*
* @param ids 用户编号数组
* @return 用户 Map
*/
default Map<Long, AdminUserRespDTO> getUserMap(Collection<Long> ids) {
List<AdminUserRespDTO> users = getUserList(ids);
return CollectionUtils.convertMap(users, AdminUserRespDTO::getId);
}
/**
* 校验用户是否有效。如下情况,视为无效:
* 1. 用户编号不存在
* 2. 用户被禁用
*
* @param id 用户编号
*/
default void validateUser(Long id) {
validateUserList(Collections.singleton(id));
}
/**
* 校验用户们是否有效。如下情况,视为无效:
* 1. 用户编号不存在
* 2. 用户被禁用
*
* @param ids 用户编号数组
*/
void validateUserList(Collection<Long> ids);
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.system.api.user.dto;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import lombok.Data;
import java.util.Set;
/**
* Admin 用户 Response DTO
*
* @author 芋道源码
*/
@Data
public class AdminUserRespDTO {
/**
* 用户ID
*/
private Long id;
/**
* 用户昵称
*/
private String nickname;
/**
* 帐号状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 部门ID
*/
private Long deptId;
/**
* 岗位编号数组
*/
private Set<Long> postIds;
/**
* 手机号码
*/
private String mobile;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.enums;
/**
* System 字典类型的枚举类
*
* @author 芋道源码
*/
public interface DictTypeConstants {
String USER_TYPE = "user_type"; // 用户类型
String COMMON_STATUS = "common_status"; // 系统状态
// ========== SYSTEM 模块 ==========
String USER_SEX = "system_user_sex"; // 用户性别
String OPERATE_TYPE = "system_operate_type"; // 操作类型
String LOGIN_TYPE = "system_login_type"; // 登录日志的类型
String LOGIN_RESULT = "system_login_result"; // 登录结果
String ERROR_CODE_TYPE = "system_error_code_type"; // 错误码的类型枚举
String SMS_CHANNEL_CODE = "system_sms_channel_code"; // 短信渠道编码
String SMS_TEMPLATE_TYPE = "system_sms_template_type"; // 短信模板类型
String SMS_SEND_STATUS = "system_sms_send_status"; // 短信发送状态
String SMS_RECEIVE_STATUS = "system_sms_receive_status"; // 短信接收状态
}

View File

@ -0,0 +1,174 @@
package cn.iocoder.yudao.module.system.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* System 错误码枚举类
*
* system 系统,使用 1-002-000-000 段
*/
public interface ErrorCodeConstants {
// ========== AUTH 模块 1-002-000-000 ==========
ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_002_000_000, "登录失败,账号密码不正确");
ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_002_000_001, "登录失败,账号被禁用");
ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_004, "验证码不正确,原因:{}");
ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "未绑定账号,需要进行绑定");
ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1_002_000_006, "Token 已经过期");
ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在");
// ========== 菜单模块 1-002-001-000 ==========
ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "已经存在该名字的菜单");
ErrorCode MENU_PARENT_NOT_EXISTS = new ErrorCode(1_002_001_001, "父菜单不存在");
ErrorCode MENU_PARENT_ERROR = new ErrorCode(1_002_001_002, "不能设置自己为父菜单");
ErrorCode MENU_NOT_EXISTS = new ErrorCode(1_002_001_003, "菜单不存在");
ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1_002_001_004, "存在子菜单,无法删除");
ErrorCode MENU_PARENT_NOT_DIR_OR_MENU = new ErrorCode(1_002_001_005, "父菜单的类型必须是目录或者菜单");
// ========== 角色模块 1-002-002-000 ==========
ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "角色不存在");
ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1_002_002_001, "已经存在名为【{}】的角色");
ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1_002_002_002, "已经存在编码为【{}】的角色");
ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "不能操作类型为系统内置的角色");
ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用");
ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "编码【{}】不能使用");
// ========== 用户模块 1-002-003-000 ==========
ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "用户账号已经存在");
ErrorCode USER_MOBILE_EXISTS = new ErrorCode(1_002_003_001, "手机号已经存在");
ErrorCode USER_EMAIL_EXISTS = new ErrorCode(1_002_003_002, "邮箱已经存在");
ErrorCode USER_NOT_EXISTS = new ErrorCode(1_002_003_003, "用户不存在");
ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_002_003_004, "导入用户数据不能为空!");
ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1_002_003_005, "用户密码校验失败");
ErrorCode USER_IS_DISABLE = new ErrorCode(1_002_003_006, "名字为【{}】的用户已被禁用");
ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "创建用户失败,原因:超过租户最大租户配额({})");
// ========== 部门模块 1-002-004-000 ==========
ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门");
ErrorCode DEPT_PARENT_NOT_EXITS = new ErrorCode(1_002_004_001,"父级部门不存在");
ErrorCode DEPT_NOT_FOUND = new ErrorCode(1_002_004_002, "当前部门不存在");
ErrorCode DEPT_EXITS_CHILDREN = new ErrorCode(1_002_004_003, "存在子部门,无法删除");
ErrorCode DEPT_PARENT_ERROR = new ErrorCode(1_002_004_004, "不能设置自己为父部门");
ErrorCode DEPT_EXISTS_USER = new ErrorCode(1_002_004_005, "部门中存在员工,无法删除");
ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1_002_004_006, "部门({})不处于开启状态,不允许选择");
ErrorCode DEPT_PARENT_IS_CHILD = new ErrorCode(1_002_004_007, "不能设置自己的子部门为父部门");
// ========== 岗位模块 1-002-005-000 ==========
ErrorCode POST_NOT_FOUND = new ErrorCode(1_002_005_000, "当前岗位不存在");
ErrorCode POST_NOT_ENABLE = new ErrorCode(1_002_005_001, "岗位({}) 不处于开启状态,不允许选择");
ErrorCode POST_NAME_DUPLICATE = new ErrorCode(1_002_005_002, "已经存在该名字的岗位");
ErrorCode POST_CODE_DUPLICATE = new ErrorCode(1_002_005_003, "已经存在该标识的岗位");
// ========== 字典类型 1-002-006-000 ==========
ErrorCode DICT_TYPE_NOT_EXISTS = new ErrorCode(1_002_006_001, "当前字典类型不存在");
ErrorCode DICT_TYPE_NOT_ENABLE = new ErrorCode(1_002_006_002, "字典类型不处于开启状态,不允许选择");
ErrorCode DICT_TYPE_NAME_DUPLICATE = new ErrorCode(1_002_006_003, "已经存在该名字的字典类型");
ErrorCode DICT_TYPE_TYPE_DUPLICATE = new ErrorCode(1_002_006_004, "已经存在该类型的字典类型");
ErrorCode DICT_TYPE_HAS_CHILDREN = new ErrorCode(1_002_006_005, "无法删除,该字典类型还有字典数据");
// ========== 字典数据 1-002-007-000 ==========
ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1_002_007_001, "当前字典数据不存在");
ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1_002_007_002, "字典数据({})不处于开启状态,不允许选择");
ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1_002_007_003, "已经存在该值的字典数据");
// ========== 通知公告 1-002-008-000 ==========
ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1_002_008_001, "当前通知公告不存在");
// ========== 短信渠道 1-002-011-000 ==========
ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_000, "短信渠道不存在");
ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1_002_011_001, "短信渠道不处于开启状态,不允许选择");
ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1_002_011_002, "无法删除,该短信渠道还有短信模板");
// ========== 短信模板 1-002-012-000 ==========
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在");
ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板");
ErrorCode SMS_TEMPLATE_API_ERROR = new ErrorCode(1_002_012_002, "短信 API 模板调用失败,原因是:{}");
ErrorCode SMS_TEMPLATE_API_AUDIT_CHECKING = new ErrorCode(1_002_012_003, "短信 API 模版无法使用,原因:审批中");
ErrorCode SMS_TEMPLATE_API_AUDIT_FAIL = new ErrorCode(1_002_012_004, "短信 API 模版无法使用,原因:审批不通过,{}");
ErrorCode SMS_TEMPLATE_API_NOT_FOUND = new ErrorCode(1_002_012_005, "短信 API 模版无法使用,原因:模版不存在");
// ========== 短信发送 1-002-013-000 ==========
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在");
ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_013_001, "模板参数({})缺失");
ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_013_002, "短信模板不存在");
// ========== 短信验证码 1-002-014-000 ==========
ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1_002_014_000, "验证码不存在");
ErrorCode SMS_CODE_EXPIRED = new ErrorCode(1_002_014_001, "验证码已过期");
ErrorCode SMS_CODE_USED = new ErrorCode(1_002_014_002, "验证码已使用");
ErrorCode SMS_CODE_NOT_CORRECT = new ErrorCode(1_002_014_003, "验证码不正确");
ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "超过每日短信发送数量");
ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "短信发送过于频繁");
ErrorCode SMS_CODE_IS_EXISTS = new ErrorCode(1_002_014_006, "手机号已被使用");
ErrorCode SMS_CODE_IS_UNUSED = new ErrorCode(1_002_014_007, "验证码未被使用");
// ========== 租户信息 1-002-015-000 ==========
ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1_002_015_000, "租户不存在");
ErrorCode TENANT_DISABLE = new ErrorCode(1_002_015_001, "名字为【{}】的租户已被禁用");
ErrorCode TENANT_EXPIRE = new ErrorCode(1_002_015_002, "名字为【{}】的租户已过期");
ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "系统租户不能进行修改、删除等操作!");
ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "名字为【{}】的租户已存在");
ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的租户已存在");
// ========== 租户套餐 1-002-016-000 ==========
ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "租户套餐不存在");
ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "租户正在使用该套餐,请给租户重新设置套餐后再尝试删除");
ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用");
// ========== 错误码模块 1-002-017-000 ==========
ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1_002_017_000, "错误码不存在");
ErrorCode ERROR_CODE_DUPLICATE = new ErrorCode(1_002_017_001, "已经存在编码为【{}】的错误码");
// ========== 社交用户 1-002-018-000 ==========
ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}");
ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败");
ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_201, "社交客户端不存在");
ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_201, "社交客户端已存在配置");
// ========== 系统敏感词 1-002-019-000 =========
ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1_002_019_000, "系统敏感词在所有标签中都不存在");
ErrorCode SENSITIVE_WORD_EXISTS = new ErrorCode(1_002_019_001, "系统敏感词已在标签中存在");
// ========== OAuth2 客户端 1-002-020-000 =========
ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在");
ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在");
ErrorCode OAUTH2_CLIENT_DISABLE = new ErrorCode(1_002_020_002, "OAuth2 客户端已禁用");
ErrorCode OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS = new ErrorCode(1_002_020_003, "不支持该授权类型");
ErrorCode OAUTH2_CLIENT_SCOPE_OVER = new ErrorCode(1_002_020_004, "授权范围过大");
ErrorCode OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH = new ErrorCode(1_002_020_005, "无效 redirect_uri: {}");
ErrorCode OAUTH2_CLIENT_CLIENT_SECRET_ERROR = new ErrorCode(1_002_020_006, "无效 client_secret: {}");
// ========== OAuth2 授权 1-002-021-000 =========
ErrorCode OAUTH2_GRANT_CLIENT_ID_MISMATCH = new ErrorCode(1_002_021_000, "client_id 不匹配");
ErrorCode OAUTH2_GRANT_REDIRECT_URI_MISMATCH = new ErrorCode(1_002_021_001, "redirect_uri 不匹配");
ErrorCode OAUTH2_GRANT_STATE_MISMATCH = new ErrorCode(1_002_021_002, "state 不匹配");
ErrorCode OAUTH2_GRANT_CODE_NOT_EXISTS = new ErrorCode(1_002_021_003, "code 不存在");
// ========== OAuth2 授权 1-002-022-000 =========
ErrorCode OAUTH2_CODE_NOT_EXISTS = new ErrorCode(1_002_022_000, "code 不存在");
ErrorCode OAUTH2_CODE_EXPIRE = new ErrorCode(1_002_022_001, "code 已过期");
// ========== 邮箱账号 1-002-023-000 ==========
ErrorCode MAIL_ACCOUNT_NOT_EXISTS = new ErrorCode(1_002_023_000, "邮箱账号不存在");
ErrorCode MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS = new ErrorCode(1_002_023_001, "无法删除,该邮箱账号还有邮件模板");
// ========== 邮件模版 1-002-024-000 ==========
ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_024_000, "邮件模版不存在");
ErrorCode MAIL_TEMPLATE_CODE_EXISTS = new ErrorCode(1_002_024_001, "邮件模版 code({}) 已存在");
// ========== 邮件发送 1-002-025-000 ==========
ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_025_000, "模板参数({})缺失");
ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1_002_025_001, "邮箱不存在");
// ========== 站内信模版 1-002-026-000 ==========
ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_026_000, "站内信模版不存在");
ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_026_001, "已经存在编码为【{}】的站内信模板");
// ========== 站内信模版 1-002-027-000 ==========
// ========== 站内信发送 1-002-028-000 ==========
ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失");
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.enums.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 性别的枚举值
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum SexEnum {
/** 男 */
MALE(1),
/** 女 */
FEMALE(2),
/* 未知 */
UNKNOWN(3);
/**
* 性别
*/
private final Integer sex;
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.enums.errorcode;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 错误码的类型枚举
*
* @author dylan
*/
@AllArgsConstructor
@Getter
public enum ErrorCodeTypeEnum implements IntArrayValuable {
/**
* 自动生成
*/
AUTO_GENERATION(1),
/**
* 手动编辑
*/
MANUAL_OPERATION(2);
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErrorCodeTypeEnum::getType).toArray();
/**
* 类型
*/
private final Integer type;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.enums.logger;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录日志的类型枚举
*/
@Getter
@AllArgsConstructor
public enum LoginLogTypeEnum {
LOGIN_USERNAME(100), // 使用账号登录
LOGIN_SOCIAL(101), // 使用社交登录
LOGIN_MOBILE(103), // 使用手机登陆
LOGIN_SMS(104), // 使用短信登陆
LOGOUT_SELF(200), // 自己主动登出
LOGOUT_DELETE(202), // 强制退出
;
/**
* 日志类型
*/
private final Integer type;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.enums.logger;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录结果的枚举类
*/
@Getter
@AllArgsConstructor
public enum LoginResultEnum {
SUCCESS(0), // 成功
BAD_CREDENTIALS(10), // 账号或密码不正确
USER_DISABLED(20), // 用户被禁用
CAPTCHA_NOT_FOUND(30), // 图片验证码不存在
CAPTCHA_CODE_ERROR(31), // 图片验证码不正确
;
/**
* 结果
*/
private final Integer result;
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.enums.mail;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 邮件的发送状态枚举
*
* @author wangjingyi
* @since 2022/4/10 13:39
*/
@Getter
@AllArgsConstructor
public enum MailSendStatusEnum {
INIT(0), // 初始化
SUCCESS(10), // 发送成功
FAILURE(20), // 发送失败
IGNORE(30), // 忽略,即不发送
;
private final int status;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.enums.notice;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 通知类型
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum NoticeTypeEnum {
NOTICE(1),
ANNOUNCEMENT(2);
/**
* 类型
*/
private final Integer type;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.enums.notify;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 通知模板类型枚举
*
* @author HUIHUI
*/
@Getter
@AllArgsConstructor
public enum NotifyTemplateTypeEnum {
/**
* 系统消息
*/
SYSTEM_MESSAGE(2),
/**
* 通知消息
*/
NOTIFICATION_MESSAGE(1);
private final Integer type;
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.system.enums.oauth2;
/**
* OAuth2.0 客户端的通用枚举
*
* @author 芋道源码
*/
public interface OAuth2ClientConstants {
String CLIENT_ID_DEFAULT = "default";
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.enums.oauth2;
import cn.hutool.core.util.ArrayUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* OAuth2 授权类型(模式)的枚举
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum OAuth2GrantTypeEnum {
PASSWORD("password"), // 密码模式
AUTHORIZATION_CODE("authorization_code"), // 授权码模式
IMPLICIT("implicit"), // 简化模式
CLIENT_CREDENTIALS("client_credentials"), // 客户端模式
REFRESH_TOKEN("refresh_token"), // 刷新模式
;
private final String grantType;
public static OAuth2GrantTypeEnum getByGranType(String grantType) {
return ArrayUtil.firstMatch(o -> o.getGrantType().equals(grantType), values());
}
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.enums.permission;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 数据范围枚举类
*
* 用于实现数据级别的权限
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum DataScopeEnum implements IntArrayValuable {
ALL(1), // 全部数据权限
DEPT_CUSTOM(2), // 指定部门数据权限
DEPT_ONLY(3), // 部门数据权限
DEPT_AND_CHILD(4), // 部门及以下数据权限
SELF(5); // 仅本人数据权限
/**
* 范围
*/
private final Integer scope;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DataScopeEnum::getScope).toArray();
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.system.enums.permission;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 菜单类型枚举类
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum MenuTypeEnum {
DIR(1), // 目录
MENU(2), // 菜单
BUTTON(3) // 按钮
;
/**
* 类型
*/
private final Integer type;
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.enums.permission;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 角色标识枚举
*/
@Getter
@AllArgsConstructor
public enum RoleCodeEnum {
SUPER_ADMIN("super_admin", "超级管理员"),
TENANT_ADMIN("tenant_admin", "租户管理员"),
CRM_ADMIN("crm_admin", "CRM 管理员"); // CRM 系统专用
;
/**
* 角色编码
*/
private final String code;
/**
* 名字
*/
private final String name;
public static boolean isSuperAdmin(String code) {
return ObjectUtils.equalsAny(code, SUPER_ADMIN.getCode());
}
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.enums.permission;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum RoleTypeEnum {
/**
* 内置角色
*/
SYSTEM(1),
/**
* 自定义角色
*/
CUSTOM(2);
private final Integer type;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.enums.sms;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 短信的接收状态枚举
*
* @author 芋道源码
* @date 2021/2/1 13:39
*/
@Getter
@AllArgsConstructor
public enum SmsReceiveStatusEnum {
INIT(0), // 初始化
SUCCESS(10), // 接收成功
FAILURE(20), // 接收失败
;
private final int status;
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.system.enums.sms;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 用户短信验证码发送场景的枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum SmsSceneEnum implements IntArrayValuable {
MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登陆"),
MEMBER_UPDATE_MOBILE(2, "user-update-mobile", "会员用户 - 修改手机"),
MEMBER_UPDATE_PASSWORD(3, "user-update-password", "会员用户 - 修改密码"),
MEMBER_RESET_PASSWORD(4, "user-reset-password", "会员用户 - 忘记密码"),
ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SmsSceneEnum::getScene).toArray();
/**
* 验证场景的编号
*/
private final Integer scene;
/**
* 模版编码
*/
private final String templateCode;
/**
* 描述
*/
private final String description;
@Override
public int[] array() {
return ARRAYS;
}
public static SmsSceneEnum getCodeByScene(Integer scene) {
return ArrayUtil.firstMatch(sceneEnum -> sceneEnum.getScene().equals(scene),
values());
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.enums.sms;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 短信的发送状态枚举
*
* @author zzf
* @date 2021/2/1 13:39
*/
@Getter
@AllArgsConstructor
public enum SmsSendStatusEnum {
INIT(0), // 初始化
SUCCESS(10), // 发送成功
FAILURE(20), // 发送失败
IGNORE(30), // 忽略,即不发送
;
private final int status;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.system.enums.sms;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 短信的模板类型枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum SmsTemplateTypeEnum {
VERIFICATION_CODE(1), // 验证码
NOTICE(2), // 通知
PROMOTION(3), // 营销
;
/**
* 类型
*/
private final int type;
}

View File

@ -0,0 +1,78 @@
package cn.iocoder.yudao.module.system.enums.social;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 社交平台的类型枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum SocialTypeEnum implements IntArrayValuable {
/**
* Gitee
*
* @see <a href="https://gitee.com/api/v5/oauth_doc#/">接入文档</a>
*/
GITEE(10, "GITEE"),
/**
* 钉钉
*
* @see <a href="https://developers.dingtalk.com/document/app/obtain-identity-credentials">接入文档</a>
*/
DINGTALK(20, "DINGTALK"),
/**
* 企业微信
*
* @see <a href="https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html">接入文档</a>
*/
WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"),
/**
* 微信公众平台 - 移动端 H5
*
* @see <a href="https://www.cnblogs.com/juewuzhe/p/11905461.html">接入文档</a>
*/
WECHAT_MP(31, "WECHAT_MP"),
/**
* 微信开放平台 - 网站应用 PC 端扫码授权登录
*
* @see <a href="https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证">接入文档</a>
*/
WECHAT_OPEN(32, "WECHAT_OPEN"),
/**
* 微信小程序
*
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a>
*/
WECHAT_MINI_APP(34, "WECHAT_MINI_APP"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SocialTypeEnum::getType).toArray();
/**
* 类型
*/
private final Integer type;
/**
* 类型的标识
*/
private final String source;
@Override
public int[] array() {
return ARRAYS;
}
public static SocialTypeEnum valueOfType(Integer type) {
return ArrayUtil.firstMatch(o -> o.getType().equals(type), values());
}
}

View File

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-system</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-system-biz</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
system 模块下,我们放通用业务,支撑上层的核心业务。
例如说:用户、部门、权限、数据字典等等
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-system-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-infra-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-redis</artifactId>
</dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-mq</artifactId>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId> <!-- 微信登录(公众号) -->
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId> <!-- 微信登录(小程序) -->
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId> <!-- 短信(阿里云) -->
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId> <!-- 短信(阿里云) -->
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId> <!-- 短信(腾讯云) -->
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* 部门 API 实现类
*
* @author 芋道源码
*/
@Service
public class DeptApiImpl implements DeptApi {
@Resource
private DeptService deptService;
@Override
public DeptRespDTO getDept(Long id) {
DeptDO dept = deptService.getDept(id);
return BeanUtils.toBean(dept, DeptRespDTO.class);
}
@Override
public List<DeptRespDTO> getDeptList(Collection<Long> ids) {
List<DeptDO> depts = deptService.getDeptList(ids);
return BeanUtils.toBean(depts, DeptRespDTO.class);
}
@Override
public void validateDeptList(Collection<Long> ids) {
deptService.validateDeptList(ids);
}
@Override
public List<DeptRespDTO> getChildDeptList(Long id) {
List<DeptDO> childDeptList = deptService.getChildDeptList(id);
return BeanUtils.toBean(childDeptList, DeptRespDTO.class);
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* 岗位 API 实现类
*
* @author 芋道源码
*/
@Service
public class PostApiImpl implements PostApi {
@Resource
private PostService postService;
@Override
public void validPostList(Collection<Long> ids) {
postService.validatePostList(ids);
}
@Override
public List<PostRespDTO> getPostList(Collection<Long> ids) {
List<PostDO> list = postService.getPostList(ids);
return BeanUtils.toBean(list, PostRespDTO.class);
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.system.api.dict;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/**
* 字典数据 API 实现类
*
* @author 芋道源码
*/
@Service
public class DictDataApiImpl implements DictDataApi {
@Resource
private DictDataService dictDataService;
@Override
public void validateDictDataList(String dictType, Collection<String> values) {
dictDataService.validateDictDataList(dictType, values);
}
@Override
public DictDataRespDTO getDictData(String dictType, String value) {
DictDataDO dictData = dictDataService.getDictData(dictType, value);
return BeanUtils.toBean(dictData, DictDataRespDTO.class);
}
@Override
public DictDataRespDTO parseDictData(String dictType, String label) {
DictDataDO dictData = dictDataService.parseDictData(dictType, label);
return BeanUtils.toBean(dictData, DictDataRespDTO.class);
}
@Override
public List<DictDataRespDTO> getDictDataList(String dictType) {
List<DictDataDO> list = dictDataService.getDictDataListByDictType(dictType);
return BeanUtils.toBean(list, DictDataRespDTO.class);
}
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.system.api.errorcode;
import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO;
import cn.iocoder.yudao.module.system.service.errorcode.ErrorCodeService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
/**
* 错误码 Api 实现类
*
* @author 芋道源码
*/
@Service
public class ErrorCodeApiImpl implements ErrorCodeApi {
@Resource
private ErrorCodeService errorCodeService;
@Override
public void autoGenerateErrorCodeList(List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs) {
errorCodeService.autoGenerateErrorCodes(autoGenerateDTOs);
}
@Override
public List<ErrorCodeRespDTO> getErrorCodeList(String applicationName, LocalDateTime minUpdateTime) {
return errorCodeService.getErrorCodeList(applicationName, minUpdateTime);
}
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 登录日志的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class LoginLogApiImpl implements LoginLogApi {
@Resource
private LoginLogService loginLogService;
@Override
public void createLoginLog(LoginLogCreateReqDTO reqDTO) {
loginLogService.createLoginLog(reqDTO);
}
}

View File

@ -0,0 +1,61 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO;
import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogV2DO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.logger.OperateLogService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
/**
* 操作日志 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class OperateLogApiImpl implements OperateLogApi {
@Resource
private OperateLogService operateLogService;
@Resource
private AdminUserService adminUserService;
@Override
public void createOperateLog(OperateLogCreateReqDTO createReqDTO) {
operateLogService.createOperateLog(createReqDTO);
}
@Override
@Async
public void createOperateLogV2(OperateLogV2CreateReqDTO createReqDTO) {
operateLogService.createOperateLogV2(createReqDTO);
}
@Override
public PageResult<OperateLogV2RespDTO> getOperateLogPage(OperateLogV2PageReqDTO pageReqVO) {
PageResult<OperateLogV2DO> operateLogPage = operateLogService.getOperateLogPage(pageReqVO);
if (CollUtil.isEmpty(operateLogPage.getList())) {
return PageResult.empty();
}
// 获取用户
List<AdminUserDO> userList = adminUserService.getUserList(
convertSet(operateLogPage.getList(), OperateLogV2DO::getUserId));
return OperateLogConvert.INSTANCE.convertPage(operateLogPage, userList);
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.mail;
import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.service.mail.MailSendService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 邮件发送 API 实现类
*
* @author wangjingyi
*/
@Service
@Validated
public class MailSendApiImpl implements MailSendApi {
@Resource
private MailSendService mailSendService;
@Override
public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) {
return mailSendService.sendSingleMailToAdmin(reqDTO.getMail(), reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
@Override
public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) {
return mailSendService.sendSingleMailToMember(reqDTO.getMail(), reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.api.notify;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.service.notify.NotifySendService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 站内信发送 API 实现类
*
* @author xrcoder
*/
@Service
public class NotifyMessageSendApiImpl implements NotifyMessageSendApi {
@Resource
private NotifySendService notifySendService;
@Override
public Long sendSingleMessageToAdmin(NotifySendSingleToUserReqDTO reqDTO) {
return notifySendService.sendSingleNotifyToAdmin(reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
@Override
public Long sendSingleMessageToMember(NotifySendSingleToUserReqDTO reqDTO) {
return notifySendService.sendSingleNotifyToMember(reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.api.oauth2;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* OAuth2.0 Token API 实现类
*
* @author 芋道源码
*/
@Service
public class OAuth2TokenApiImpl implements OAuth2TokenApi {
@Resource
private OAuth2TokenService oauth2TokenService;
@Override
public OAuth2AccessTokenRespDTO createAccessToken(OAuth2AccessTokenCreateReqDTO reqDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(
reqDTO.getUserId(), reqDTO.getUserType(), reqDTO.getClientId(), reqDTO.getScopes());
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class);
}
@Override
public OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(accessToken);
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenCheckRespDTO.class);
}
@Override
public OAuth2AccessTokenRespDTO removeAccessToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(accessToken);
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class);
}
@Override
public OAuth2AccessTokenRespDTO refreshAccessToken(String refreshToken, String clientId) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, clientId);
return BeanUtils.toBean(accessTokenDO, OAuth2AccessTokenRespDTO.class);
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Set;
/**
* 权限 API 实现类
*
* @author 芋道源码
*/
@Service
public class PermissionApiImpl implements PermissionApi {
@Resource
private PermissionService permissionService;
@Override
public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
return permissionService.getUserRoleIdListByRoleId(roleIds);
}
@Override
public boolean hasAnyPermissions(Long userId, String... permissions) {
return permissionService.hasAnyPermissions(userId, permissions);
}
@Override
public boolean hasAnyRoles(Long userId, String... roles) {
return permissionService.hasAnyRoles(userId, roles);
}
@Override
public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
return permissionService.getDeptDataPermission(userId);
}
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
/**
* 角色 API 实现类
*
* @author 芋道源码
*/
@Service
public class RoleApiImpl implements RoleApi {
@Resource
private RoleService roleService;
@Override
public void validRoleList(Collection<Long> ids) {
roleService.validateRoleList(ids);
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.api.sensitiveword;
import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 敏感词 API 实现类
*
* @author 永不言败
*/
@Service
public class SensitiveWordApiImpl implements SensitiveWordApi {
@Resource
private SensitiveWordService sensitiveWordService;
@Override
public List<String> validateText(String text, List<String> tags) {
return sensitiveWordService.validateText(text, tags);
}
@Override
public boolean isTextValid(String text, List<String> tags) {
return sensitiveWordService.isTextValid(text, tags);
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.service.sms.SmsCodeService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 短信验证码 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class SmsCodeApiImpl implements SmsCodeApi {
@Resource
private SmsCodeService smsCodeService;
@Override
public void sendSmsCode(SmsCodeSendReqDTO reqDTO) {
smsCodeService.sendSmsCode(reqDTO);
}
@Override
public void useSmsCode(SmsCodeUseReqDTO reqDTO) {
smsCodeService.useSmsCode(reqDTO);
}
@Override
public void validateSmsCode(SmsCodeValidateReqDTO reqDTO) {
smsCodeService.validateSmsCode(reqDTO);
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 短信发送 API 接口
*
* @author 芋道源码
*/
@Service
@Validated
public class SmsSendApiImpl implements SmsSendApi {
@Resource
private SmsSendService smsSendService;
@Override
public Long sendSingleSmsToAdmin(SmsSendSingleToUserReqDTO reqDTO) {
return smsSendService.sendSingleSmsToAdmin(reqDTO.getMobile(), reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
@Override
public Long sendSingleSmsToMember(SmsSendSingleToUserReqDTO reqDTO) {
return smsSendService.sendSingleSmsToMember(reqDTO.getMobile(), reqDTO.getUserId(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.module.system.api.social;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 社交应用的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class SocialClientApiImpl implements SocialClientApi {
@Resource
private SocialClientService socialClientService;
@Override
public String getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) {
return socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
}
@Override
public SocialWxJsapiSignatureRespDTO createWxMpJsapiSignature(Integer userType, String url) {
WxJsapiSignature signature = socialClientService.createWxMpJsapiSignature(userType, url);
return BeanUtils.toBean(signature, SocialWxJsapiSignatureRespDTO.class);
}
@Override
public SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode) {
WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
return BeanUtils.toBean(info, SocialWxPhoneNumberInfoRespDTO.class);
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.system.api.social;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 社交用户的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class SocialUserApiImpl implements SocialUserApi {
@Resource
private SocialUserService socialUserService;
@Override
public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
return socialUserService.bindSocialUser(reqDTO);
}
@Override
public void unbindSocialUser(SocialUserUnbindReqDTO reqDTO) {
socialUserService.unbindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(),
reqDTO.getSocialType(), reqDTO.getOpenid());
}
@Override
public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) {
return socialUserService.getSocialUserByUserId(userType, userId, socialType);
}
@Override
public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) {
return socialUserService.getSocialUserByCode(userType, socialType, code, state);
}
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.api.tenant;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 多租户的 API 实现类
*
* @author 芋道源码
*/
@Service
public class TenantApiImpl implements TenantApi {
@Resource
private TenantService tenantService;
@Override
public List<Long> getTenantIdList() {
return tenantService.getTenantIdList();
}
@Override
public void validateTenant(Long id) {
tenantService.validTenant(id);
}
}

View File

@ -0,0 +1,91 @@
package cn.iocoder.yudao.module.system.api.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
/**
* Admin 用户 API 实现类
*
* @author 芋道源码
*/
@Service
public class AdminUserApiImpl implements AdminUserApi {
@Resource
private AdminUserService userService;
@Resource
private DeptService deptService;
@Override
public AdminUserRespDTO getUser(Long id) {
AdminUserDO user = userService.getUser(id);
return BeanUtils.toBean(user, AdminUserRespDTO.class);
}
@Override
public List<AdminUserRespDTO> getUserListBySubordinate(Long id) {
// 1.1 获取用户负责的部门
AdminUserDO user = userService.getUser(id);
if (user == null) {
return Collections.emptyList();
}
ArrayList<Long> deptIds = new ArrayList<>();
DeptDO dept = deptService.getDept(user.getDeptId());
if (dept == null) {
return Collections.emptyList();
}
if (ObjUtil.notEqual(dept.getLeaderUserId(), id)) { // 校验为负责人
return Collections.emptyList();
}
deptIds.add(dept.getId());
// 1.2 获取所有子部门
List<DeptDO> childDeptList = deptService.getChildDeptList(dept.getId());
if (CollUtil.isNotEmpty(childDeptList)) {
deptIds.addAll(convertSet(childDeptList, DeptDO::getId));
}
// 2. 获取部门对应的用户信息
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public List<AdminUserRespDTO> getUserList(Collection<Long> ids) {
List<AdminUserDO> users = userService.getUserList(ids);
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public List<AdminUserRespDTO> getUserListByDeptIds(Collection<Long> deptIds) {
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds) {
List<AdminUserDO> users = userService.getUserListByPostIds(postIds);
return BeanUtils.toBean(users, AdminUserRespDTO.class);
}
@Override
public void validateUserList(Collection<Long> ids) {
userService.validateUserList(ids);
}
}

View File

@ -0,0 +1,33 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenentId}}
tag: Yunai.local
{
"username": "admin",
"password": "admin123",
"uuid": "3acd87a09a4f48fb9118333780e94883",
"code": "1024"
}
### 请求 /login 接口 => 成功(无验证码)
POST {{baseUrl}}/system/auth/login
Content-Type: application/json
tenant-id: {{adminTenentId}}
{
"username": "admin",
"password": "admin123"
}
### 请求 /get-permission-info 接口 => 成功
GET {{baseUrl}}/system/auth/get-permission-info
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /list-menus 接口 => 成功
GET {{baseUrl}}/system/list-menus
Authorization: Bearer {{token}}
#Authorization: Bearer a6aa7714a2e44c95aaa8a2c5adc2a67a
tenant-id: {{adminTenentId}}

View File

@ -0,0 +1,164 @@
package cn.iocoder.yudao.module.system.controller.admin.auth;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {
@Resource
private AdminAuthService authService;
@Resource
private AdminUserService userService;
@Resource
private RoleService roleService;
@Resource
private MenuService menuService;
@Resource
private PermissionService permissionService;
@Resource
private SocialClientService socialClientService;
@Resource
private SecurityProperties securityProperties;
@PostMapping("/login")
@PermitAll
@Operation(summary = "使用账号密码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
return success(authService.login(reqVO));
}
@PostMapping("/logout")
@PermitAll
@Operation(summary = "登出系统")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> logout(HttpServletRequest request) {
String token = SecurityFrameworkUtils.obtainAuthorization(request,
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
if (StrUtil.isNotBlank(token)) {
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
}
return success(true);
}
@PostMapping("/refresh-token")
@PermitAll
@Operation(summary = "刷新令牌")
@Parameter(name = "refreshToken", description = "刷新令牌", required = true)
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
return success(authService.refreshToken(refreshToken));
}
@GetMapping("/get-permission-info")
@Operation(summary = "获取登录用户的权限信息")
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
// 1.1 获得用户信息
AdminUserDO user = userService.getUser(getLoginUserId());
if (user == null) {
return null;
}
// 1.2 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
if (CollUtil.isEmpty(roleIds)) {
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
}
List<RoleDO> roles = roleService.getRoleList(roleIds);
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
// 1.3 获得菜单列表
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
List<MenuDO> menuList = menuService.getMenuList(menuIds);
menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
// 2. 拼接结果返回
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
}
// ========== 短信登录相关 ==========
@PostMapping("/sms-login")
@PermitAll
@Operation(summary = "使用短信验证码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
return success(authService.smsLogin(reqVO));
}
@PostMapping("/send-sms-code")
@PermitAll
@Operation(summary = "发送手机验证码")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
authService.sendSmsCode(reqVO);
return success(true);
}
// ========== 社交登录相关 ==========
@GetMapping("/social-auth-redirect")
@PermitAll
@Operation(summary = "社交授权的跳转")
@Parameters({
@Parameter(name = "type", description = "社交类型", required = true),
@Parameter(name = "redirectUri", description = "回调路径")
})
public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
@RequestParam("redirectUri") String redirectUri) {
return success(socialClientService.getAuthorizeUrl(
type, UserTypeEnum.ADMIN.getValue(), redirectUri));
}
@PostMapping("/social-login")
@PermitAll
@Operation(summary = "社交快捷登录,使用 code 授权码", description = "适合未登录的用户,但是社交账号已绑定用户")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
return success(authService.socialLogin(reqVO));
}
}

View File

@ -0,0 +1,69 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
@Schema(description = "管理后台 - 账号密码登录 Request VO如果登录并绑定社交用户需要传递 social 开头的参数")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginReqVO {
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma")
@NotEmpty(message = "登录账号不能为空")
@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
// ========== 图片验证码相关 ==========
@Schema(description = "验证码,验证码开启时,需要传递", requiredMode = Schema.RequiredMode.REQUIRED,
example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==")
@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
private String captchaVerification;
// ========== 绑定社交登录时,需要传递如下参数 ==========
@Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@InEnum(SocialTypeEnum.class)
private Integer socialType;
@Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private String socialCode;
@Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
private String socialState;
/**
* 开启验证码的 Group
*/
public interface CodeEnableGroup {}
@AssertTrue(message = "授权码不能为空")
public boolean isSocialCodeValid() {
return socialType == null || StrUtil.isNotEmpty(socialCode);
}
@AssertTrue(message = "授权 state 不能为空")
public boolean isSocialState() {
return socialType == null || StrUtil.isNotEmpty(socialState);
}
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 登录 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginRespVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long userId;
@Schema(description = "访问令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "happy")
private String accessToken;
@Schema(description = "刷新令牌", requiredMode = Schema.RequiredMode.REQUIRED, example = "nice")
private String refreshToken;
@Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime expiresTime;
}

View File

@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthMenuRespVO {
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private Long id;
@Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long parentId;
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private String name;
@Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
private String path;
@Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
private String component;
@Schema(description = "组件名", example = "SystemUser")
private String componentName;
@Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
private String icon;
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean visible;
@Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean keepAlive;
@Schema(description = "是否总是显示", example = "false")
private Boolean alwaysShow;
/**
* 子路由
*/
private List<AuthMenuRespVO> children;
}

View File

@ -0,0 +1,96 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Set;
@Schema(description = "管理后台 - 登录用户的权限信息 Response VO额外包括用户信息和角色列表")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthPermissionInfoRespVO {
@Schema(description = "用户信息", requiredMode = Schema.RequiredMode.REQUIRED)
private UserVO user;
@Schema(description = "角色标识数组", requiredMode = Schema.RequiredMode.REQUIRED)
private Set<String> roles;
@Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED)
private Set<String> permissions;
@Schema(description = "菜单树", requiredMode = Schema.RequiredMode.REQUIRED)
private List<MenuVO> menus;
@Schema(description = "用户信息 VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class UserVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
private String nickname;
@Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg")
private String avatar;
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
private Long deptId;
}
@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class MenuVO {
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private Long id;
@Schema(description = "父菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long parentId;
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private String name;
@Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
private String path;
@Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
private String component;
@Schema(description = "组件名", example = "SystemUser")
private String componentName;
@Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
private String icon;
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean visible;
@Schema(description = "是否缓存", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean keepAlive;
@Schema(description = "是否总是显示", example = "false")
private Boolean alwaysShow;
/**
* 子路由
*/
private List<MenuVO> children;
}
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
@Schema(description = "管理后台 - 短信验证码的登录 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSmsLoginReqVO {
@Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma")
@NotEmpty(message = "手机号不能为空")
@Mobile
private String mobile;
@Schema(description = "短信验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotEmpty(message = "验证码不能为空")
private String code;
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 发送手机验证码 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSmsSendReqVO {
@Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudaoyuanma")
@NotEmpty(message = "手机号不能为空")
@Mobile
private String mobile;
@Schema(description = "短信场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 社交绑定登录 Request VO使用 code 授权码 + 账号密码")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthSocialLoginReqVO {
@Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer type;
@Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotEmpty(message = "授权码不能为空")
private String code;
@Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
@NotEmpty(message = "state 不能为空")
private String state;
}

View File

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.system.controller.admin.captcha;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
@Tag(name = "管理后台 - 验证码")
@RestController("adminCaptchaController")
@RequestMapping("/system/captcha")
public class CaptchaController {
@Resource
private CaptchaService captchaService;
@PostMapping({"/get"})
@Operation(summary = "获得验证码")
@PermitAll
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
assert request.getRemoteHost() != null;
data.setBrowserInfo(getRemoteId(request));
return captchaService.get(data);
}
@PostMapping("/check")
@Operation(summary = "校验验证码")
@PermitAll
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {
data.setBrowserInfo(getRemoteId(request));
return captchaService.check(data);
}
public static String getRemoteId(HttpServletRequest request) {
String ip = ServletUtils.getClientIP(request);
String ua = request.getHeader("user-agent");
if (StrUtil.isNotBlank(ip)) {
return ip + ua;
}
return request.getRemoteAddr() + ua;
}
}

View File

@ -0,0 +1,84 @@
package cn.iocoder.yudao.module.system.controller.admin.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptRespVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 部门")
@RestController
@RequestMapping("/system/dept")
@Validated
public class DeptController {
@Resource
private DeptService deptService;
@PostMapping("create")
@Operation(summary = "创建部门")
@PreAuthorize("@ss.hasPermission('system:dept:create')")
public CommonResult<Long> createDept(@Valid @RequestBody DeptSaveReqVO createReqVO) {
Long deptId = deptService.createDept(createReqVO);
return success(deptId);
}
@PutMapping("update")
@Operation(summary = "更新部门")
@PreAuthorize("@ss.hasPermission('system:dept:update')")
public CommonResult<Boolean> updateDept(@Valid @RequestBody DeptSaveReqVO updateReqVO) {
deptService.updateDept(updateReqVO);
return success(true);
}
@DeleteMapping("delete")
@Operation(summary = "删除部门")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
public CommonResult<Boolean> deleteDept(@RequestParam("id") Long id) {
deptService.deleteDept(id);
return success(true);
}
@GetMapping("/list")
@Operation(summary = "获取部门列表")
@PreAuthorize("@ss.hasPermission('system:dept:query')")
public CommonResult<List<DeptRespVO>> getDeptList(DeptListReqVO reqVO) {
List<DeptDO> list = deptService.getDeptList(reqVO);
return success(BeanUtils.toBean(list, DeptRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "/simple-list"})
@Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项")
public CommonResult<List<DeptSimpleRespVO>> getSimpleDeptList() {
List<DeptDO> list = deptService.getDeptList(
new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
}
@GetMapping("/get")
@Operation(summary = "获得部门信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:dept:query')")
public CommonResult<DeptRespVO> getDept(@RequestParam("id") Long id) {
DeptDO dept = deptService.getDept(id);
return success(BeanUtils.toBean(dept, DeptRespVO.class));
}
}

View File

@ -0,0 +1,106 @@
package cn.iocoder.yudao.module.system.controller.admin.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostRespVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSimpleRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 岗位")
@RestController
@RequestMapping("/system/post")
@Validated
public class PostController {
@Resource
private PostService postService;
@PostMapping("/create")
@Operation(summary = "创建岗位")
@PreAuthorize("@ss.hasPermission('system:post:create')")
public CommonResult<Long> createPost(@Valid @RequestBody PostSaveReqVO createReqVO) {
Long postId = postService.createPost(createReqVO);
return success(postId);
}
@PutMapping("/update")
@Operation(summary = "修改岗位")
@PreAuthorize("@ss.hasPermission('system:post:update')")
public CommonResult<Boolean> updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) {
postService.updatePost(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除岗位")
@PreAuthorize("@ss.hasPermission('system:post:delete')")
public CommonResult<Boolean> deletePost(@RequestParam("id") Long id) {
postService.deletePost(id);
return success(true);
}
@GetMapping(value = "/get")
@Operation(summary = "获得岗位信息")
@Parameter(name = "id", description = "岗位编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PostRespVO> getPost(@RequestParam("id") Long id) {
PostDO post = postService.getPost(id);
return success(BeanUtils.toBean(post, PostRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "simple-list"})
@Operation(summary = "获取岗位全列表", description = "只包含被开启的岗位,主要用于前端的下拉选项")
public CommonResult<List<PostSimpleRespVO>> getSimplePostList() {
// 获得岗位列表,只要开启状态的
List<PostDO> list = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
// 排序后,返回给前端
list.sort(Comparator.comparing(PostDO::getSort));
return success(BeanUtils.toBean(list, PostSimpleRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得岗位分页列表")
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO pageReqVO) {
PageResult<PostDO> pageResult = postService.getPostPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PostRespVO.class));
}
@GetMapping("/export")
@Operation(summary = "岗位管理")
@PreAuthorize("@ss.hasPermission('system:post:export')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Validated PostPageReqVO reqVO) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<PostDO> list = postService.getPostPage(reqVO).getList();
// 输出
ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostRespVO.class,
BeanUtils.toBean(list, PostRespVO.class));
}
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 部门列表 Request VO")
@Data
public class DeptListReqVO {
@Schema(description = "部门名称,模糊匹配", example = "芋道")
private String name;
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
private Integer status;
}

Some files were not shown because too many files have changed in this diff Show More