commit:升级到vue3,更新最近工作流技术栈,支持sa-token

This commit is contained in:
Jerry
2024-07-05 22:42:33 +08:00
parent bbcc608584
commit 565ecb6371
1751 changed files with 236790 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
package com.orangeforms.webadmin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 应用服务启动类。
*
* @author Jerry
* @date 2024-07-02
*/
@EnableAsync
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@ComponentScan("com.orangeforms")
public class WebAdminApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminApplication.class, args);
}
}

View File

@@ -0,0 +1,244 @@
package com.orangeforms.webadmin.app.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.orangeforms.common.flow.util.BaseFlowIdentityExtHelper;
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
import com.orangeforms.webadmin.upms.model.SysDept;
import com.orangeforms.webadmin.upms.model.SysUser;
import com.orangeforms.webadmin.upms.model.constant.SysUserStatus;
import com.orangeforms.webadmin.upms.model.SysDeptPost;
import com.orangeforms.webadmin.upms.service.SysDeptService;
import com.orangeforms.webadmin.upms.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
* 为流程提供所需的用户身份相关的等扩展信息的帮助类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Component
public class FlowIdentityExtHelper implements BaseFlowIdentityExtHelper {
@Autowired
private SysDeptService sysDeptService;
@Autowired
private SysUserService sysUserService;
@Autowired
private FlowCustomExtFactory flowCustomExtFactory;
@PostConstruct
public void doRegister() {
flowCustomExtFactory.registerFlowIdentityExtHelper(this);
}
@Override
public Long getLeaderDeptPostId(Long deptId) {
List<Long> deptPostIdList = sysDeptService.getLeaderDeptPostIdList(deptId);
return CollUtil.isEmpty(deptPostIdList) ? null : deptPostIdList.get(0);
}
@Override
public Long getUpLeaderDeptPostId(Long deptId) {
List<Long> deptPostIdList = sysDeptService.getUpLeaderDeptPostIdList(deptId);
return CollUtil.isEmpty(deptPostIdList) ? null : deptPostIdList.get(0);
}
@Override
public Map<String, String> getDeptPostIdMap(Long deptId, Set<String> postIdSet) {
Set<Long> postIdSet2 = postIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
List<SysDeptPost> deptPostList = sysDeptService.getSysDeptPostList(deptId, postIdSet2);
if (CollUtil.isEmpty(deptPostList)) {
return null;
}
Map<String, String> resultMap = new HashMap<>(deptPostList.size());
deptPostList.forEach(sysDeptPost ->
resultMap.put(sysDeptPost.getPostId().toString(), sysDeptPost.getDeptPostId().toString()));
return resultMap;
}
@Override
public Map<String, String> getSiblingDeptPostIdMap(Long deptId, Set<String> postIdSet) {
Set<Long> postIdSet2 = postIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
List<SysDeptPost> deptPostList = sysDeptService.getSiblingSysDeptPostList(deptId, postIdSet2);
if (CollUtil.isEmpty(deptPostList)) {
return null;
}
Map<String, String> resultMap = new HashMap<>(deptPostList.size());
for (SysDeptPost deptPost : deptPostList) {
String deptPostId = resultMap.get(deptPost.getPostId().toString());
if (deptPostId != null) {
deptPostId = deptPostId + "," + deptPost.getDeptPostId();
} else {
deptPostId = deptPost.getDeptPostId().toString();
}
resultMap.put(deptPost.getPostId().toString(), deptPostId);
}
return resultMap;
}
@Override
public Map<String, String> getUpDeptPostIdMap(Long deptId, Set<String> postIdSet) {
SysDept sysDept = sysDeptService.getById(deptId);
if (sysDept == null || sysDept.getParentId() == null) {
return null;
}
return getDeptPostIdMap(sysDept.getParentId(), postIdSet);
}
@Override
public Set<String> getUsernameListByRoleIds(Set<String> roleIdSet) {
Set<String> usernameSet = new HashSet<>();
Set<Long> roleIdSet2 = roleIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
SysUser filter = new SysUser();
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
for (Long roleId : roleIdSet2) {
List<SysUser> userList = sysUserService.getSysUserListByRoleId(roleId, filter, null);
this.extractAndAppendUsernameList(usernameSet, userList);
}
return usernameSet;
}
@Override
public List<FlowUserInfoVo> getUserInfoListByRoleIds(Set<String> roleIdSet) {
List<FlowUserInfoVo> resultList = new LinkedList<>();
Set<Long> roleIdSet2 = roleIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
SysUser filter = new SysUser();
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
for (Long roleId : roleIdSet2) {
List<SysUser> userList = sysUserService.getSysUserListByRoleId(roleId, filter, null);
if (CollUtil.isNotEmpty(userList)) {
resultList.addAll(BeanUtil.copyToList(userList, FlowUserInfoVo.class));
}
}
return resultList;
}
@Override
public Set<String> getUsernameListByDeptIds(Set<String> deptIdSet) {
Set<String> usernameSet = new HashSet<>();
Set<Long> deptIdSet2 = deptIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
for (Long deptId : deptIdSet2) {
SysUser filter = new SysUser();
filter.setDeptId(deptId);
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
List<SysUser> userList = sysUserService.getSysUserList(filter, null);
this.extractAndAppendUsernameList(usernameSet, userList);
}
return usernameSet;
}
@Override
public List<FlowUserInfoVo> getUserInfoListByDeptIds(Set<String> deptIdSet) {
List<FlowUserInfoVo> resultList = new LinkedList<>();
Set<Long> deptIdSet2 = deptIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
for (Long deptId : deptIdSet2) {
SysUser filter = new SysUser();
filter.setDeptId(deptId);
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
List<SysUser> userList = sysUserService.getSysUserList(filter, null);
if (CollUtil.isNotEmpty(userList)) {
resultList.addAll(BeanUtil.copyToList(userList, FlowUserInfoVo.class));
}
}
return resultList;
}
@Override
public Set<String> getUsernameListByPostIds(Set<String> postIdSet) {
Set<String> usernameSet = new HashSet<>();
Set<Long> postIdSet2 = postIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
SysUser filter = new SysUser();
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
for (Long postId : postIdSet2) {
List<SysUser> userList = sysUserService.getSysUserListByPostId(postId, filter, null);
this.extractAndAppendUsernameList(usernameSet, userList);
}
return usernameSet;
}
@Override
public List<FlowUserInfoVo> getUserInfoListByPostIds(Set<String> postIdSet) {
List<FlowUserInfoVo> resultList = new LinkedList<>();
Set<Long> postIdSet2 = postIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
SysUser filter = new SysUser();
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
for (Long postId : postIdSet2) {
List<SysUser> userList = sysUserService.getSysUserListByPostId(postId, filter, null);
if (CollUtil.isNotEmpty(userList)) {
resultList.addAll(BeanUtil.copyToList(userList, FlowUserInfoVo.class));
}
}
return resultList;
}
@Override
public Set<String> getUsernameListByDeptPostIds(Set<String> deptPostIdSet) {
Set<String> usernameSet = new HashSet<>();
Set<Long> deptPostIdSet2 = deptPostIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
SysUser filter = new SysUser();
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
for (Long deptPostId : deptPostIdSet2) {
List<SysUser> userList = sysUserService.getSysUserListByDeptPostId(deptPostId, filter, null);
this.extractAndAppendUsernameList(usernameSet, userList);
}
return usernameSet;
}
@Override
public List<FlowUserInfoVo> getUserInfoListByDeptPostIds(Set<String> deptPostIdSet) {
List<FlowUserInfoVo> resultList = new LinkedList<>();
Set<Long> deptPostIdSet2 = deptPostIdSet.stream().map(Long::valueOf).collect(Collectors.toSet());
SysUser filter = new SysUser();
filter.setUserStatus(SysUserStatus.STATUS_NORMAL);
for (Long deptPostId : deptPostIdSet2) {
List<SysUser> userList = sysUserService.getSysUserListByDeptPostId(deptPostId, filter, null);
if (CollUtil.isNotEmpty(userList)) {
resultList.addAll(BeanUtil.copyToList(userList, FlowUserInfoVo.class));
}
}
return resultList;
}
@Override
public List<FlowUserInfoVo> getUserInfoListByUsernameSet(Set<String> usernameSet) {
List<FlowUserInfoVo> resultList = null;
List<SysUser> userList = sysUserService.getInList("loginName", usernameSet);
if (CollUtil.isNotEmpty(userList)) {
resultList = BeanUtil.copyToList(userList, FlowUserInfoVo.class);
}
return resultList;
}
@Override
public Boolean supprtDataPerm() {
return true;
}
@Override
public Map<String, String> mapUserShowNameByLoginName(Set<String> loginNameSet) {
if (CollUtil.isEmpty(loginNameSet)) {
return new HashMap<>(1);
}
Map<String, String> resultMap = new HashMap<>(loginNameSet.size());
List<SysUser> userList = sysUserService.getInList("loginName", loginNameSet);
userList.forEach(user -> resultMap.put(user.getLoginName(), user.getShowName()));
return resultMap;
}
private void extractAndAppendUsernameList(Set<String> resultUsernameList, List<SysUser> userList) {
List<String> usernameList = userList.stream().map(SysUser::getLoginName).collect(Collectors.toList());
if (CollUtil.isNotEmpty(usernameList)) {
resultUsernameList.addAll(usernameList);
}
}
}

View File

@@ -0,0 +1,38 @@
package com.orangeforms.webadmin.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 应用程序自定义的程序属性配置文件。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "application")
public class ApplicationConfig {
/**
* 用户密码被重置之后的缺省密码
*/
private String defaultUserPassword;
/**
* 上传文件的基础目录
*/
private String uploadFileBaseDir;
/**
* 授信ip列表没有填写表示全部信任。多个ip之间逗号分隔如: http://10.10.10.1:8080,http://10.10.10.2:8080
*/
private String credentialIpList;
/**
* Session的用户权限在Redis中的过期时间(秒)。一定要和sa-token.timeout
* 缺省值是 one day
*/
private int sessionExpiredSeconds = 86400;
/**
* 是否排他登录。
*/
private Boolean excludeLogin = false;
}

View File

@@ -0,0 +1,47 @@
package com.orangeforms.webadmin.config;
import com.orangeforms.common.core.constant.ApplicationConstant;
import java.util.HashMap;
import java.util.Map;
/**
* 表示数据源类型的常量对象。
*
* @author Jerry
* @date 2024-07-02
*/
public final class DataSourceType {
public static final int MAIN = 0;
/**
* 以下所有数据源的类都型是固定值。如果有冲突,请修改上面定义的业务服务的数据源类型值。
*/
public static final int OPERATION_LOG = ApplicationConstant.OPERATION_LOG_DATASOURCE_TYPE;
public static final int GLOBAL_DICT = ApplicationConstant.COMMON_GLOBAL_DICT_TYPE;
public static final int COMMON_FLOW_AND_ONLINE = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE;
private static final Map<String, Integer> TYPE_MAP = new HashMap<>(8);
static {
TYPE_MAP.put("main", MAIN);
TYPE_MAP.put("operation-log", OPERATION_LOG);
TYPE_MAP.put("global-dict", GLOBAL_DICT);
TYPE_MAP.put("common-flow-online", COMMON_FLOW_AND_ONLINE);
}
/**
* 根据名称获取字典类型。
*
* @param name 数据源在配置中的名称。
* @return 返回可用于多数据源切换的数据源类型。
*/
public static Integer getDataSourceTypeByName(String name) {
return TYPE_MAP.get(name);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private DataSourceType() {
}
}

View File

@@ -0,0 +1,60 @@
package com.orangeforms.webadmin.config;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import jakarta.servlet.Filter;
import java.nio.charset.StandardCharsets;
/**
* 这里主要配置Web的各种过滤器和监听器等Servlet容器组件。
*
* @author Jerry
* @date 2024-07-02
*/
@Configuration
public class FilterConfig {
/**
* 配置Ajax跨域过滤器。
*/
@Bean
public CorsFilter corsFilterRegistration(ApplicationConfig applicationConfig) {
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
if (StringUtils.isNotBlank(applicationConfig.getCredentialIpList())) {
if ("*".equals(applicationConfig.getCredentialIpList())) {
corsConfiguration.addAllowedOriginPattern("*");
} else {
String[] credentialIpList = StringUtils.split(applicationConfig.getCredentialIpList(), ",");
if (credentialIpList.length > 0) {
for (String ip : credentialIpList) {
corsConfiguration.addAllowedOrigin(ip);
}
}
}
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
configSource.registerCorsConfiguration("/**", corsConfiguration);
}
return new CorsFilter(configSource);
}
@Bean
public FilterRegistrationBean<Filter> characterEncodingFilterRegistration() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(
new org.springframework.web.filter.CharacterEncodingFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("encoding", StandardCharsets.UTF_8.name());
// forceEncoding强制response也被编码另外即使request中已经设置encodingforceEncoding也会重新设置
filterRegistrationBean.addInitParameter("forceEncoding", "true");
filterRegistrationBean.setAsyncSupported(true);
return filterRegistrationBean;
}
}

View File

@@ -0,0 +1,21 @@
package com.orangeforms.webadmin.config;
import com.orangeforms.webadmin.interceptor.AuthenticationInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 所有的项目拦截器都在这里集中配置
*
* @author Jerry
* @date 2024-07-02
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/admin/**");
}
}

View File

@@ -0,0 +1,77 @@
package com.orangeforms.webadmin.config;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.orangeforms.common.core.config.BaseMultiDataSourceConfig;
import com.orangeforms.common.core.config.DynamicDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.mybatis.spring.annotation.MapperScan;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 多数据源配置对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Configuration
@EnableTransactionManagement
@MapperScan(value = {"com.orangeforms.webadmin.*.dao", "com.orangeforms.common.*.dao"})
public class MultiDataSourceConfig extends BaseMultiDataSourceConfig {
@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties(prefix = "spring.datasource.druid.main")
public DataSource mainDataSource() {
return super.applyCommonProps(DruidDataSourceBuilder.create().build());
}
/**
* 默认生成的用于保存操作日志的数据源,可根据需求修改。
* 这里我们还是非常推荐给操作日志使用独立的数据源,这样便于今后的数据迁移。
*/
@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties(prefix = "spring.datasource.druid.operation-log")
public DataSource operationLogDataSource() {
return super.applyCommonProps(DruidDataSourceBuilder.create().build());
}
/**
* 默认生成的用于全局编码字典的数据源,可根据需求修改。
*/
@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties(prefix = "spring.datasource.druid.global-dict")
public DataSource globalDictDataSource() {
return super.applyCommonProps(DruidDataSourceBuilder.create().build());
}
/**
* 默认生成的用于在线表单内部表的数据源,可根据需求修改。
* 这里我们还是非常推荐使用独立数据源,这样便于今后的服务拆分。
*/
@Bean(initMethod = "init", destroyMethod = "close")
@ConfigurationProperties(prefix = "spring.datasource.druid.common-flow-online")
public DataSource commonFlowAndOnlineDataSource() {
return super.applyCommonProps(DruidDataSourceBuilder.create().build());
}
@Bean
@Primary
public DynamicDataSource dataSource() {
Map<Object, Object> targetDataSources = new HashMap<>(1);
targetDataSources.put(DataSourceType.MAIN, mainDataSource());
targetDataSources.put(DataSourceType.OPERATION_LOG, operationLogDataSource());
targetDataSources.put(DataSourceType.GLOBAL_DICT, globalDictDataSource());
targetDataSources.put(DataSourceType.COMMON_FLOW_AND_ONLINE, commonFlowAndOnlineDataSource());
// 如果当前工程支持在线表单这里请务必保证upms数据表所在数据库为缺省数据源。
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(mainDataSource());
return dynamicDataSource;
}
}

View File

@@ -0,0 +1,66 @@
package com.orangeforms.webadmin.config;
import cn.hutool.core.collection.CollUtil;
import lombok.Data;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 第三方应用鉴权配置。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "third-party")
public class ThirdPartyAuthConfig implements InitializingBean {
private List<AuthProperties> auth;
private Map<String, AuthProperties> applicationMap;
@Override
public void afterPropertiesSet() throws Exception {
if (CollUtil.isEmpty(auth)) {
applicationMap = new HashMap<>(1);
} else {
applicationMap = auth.stream().collect(Collectors.toMap(AuthProperties::getAppCode, c -> c));
}
}
@Data
public static class AuthProperties {
/**
* 应用Id。
*/
private String appCode;
/**
* 身份验证相关url的base地址。
*/
private String baseUrl;
/**
* 是否为橙单框架。
*/
private Boolean orangeFramework = true;
/**
* token的Http Request Header的key
*/
private String tokenHeaderKey;
/**
* 数据权限和用户操作权限缓存过期时间,单位秒。
*/
private Integer permExpiredSeconds = 86400;
/**
* 用户Token缓存过期时间单位秒。
* 如果为0则每次都要去第三方服务进行验证。
*/
private Integer tokenExpiredSeconds = 0;
}
}

View File

@@ -0,0 +1,281 @@
package com.orangeforms.webadmin.interceptor;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.orangeforms.common.core.cache.CacheConfig;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.common.core.constant.DataPermRuleType;
import com.orangeforms.common.core.constant.ErrorCodeEnum;
import com.orangeforms.common.core.exception.MyRuntimeException;
import com.orangeforms.common.core.object.ResponseResult;
import com.orangeforms.common.core.object.TokenData;
import com.orangeforms.common.core.util.ApplicationContextHolder;
import com.orangeforms.common.core.util.RedisKeyUtil;
import com.orangeforms.common.satoken.util.SaTokenUtil;
import com.orangeforms.webadmin.config.ThirdPartyAuthConfig;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 登录用户Token验证、生成和权限验证的拦截器。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
private final ThirdPartyAuthConfig thirdPartyAuthConfig =
ApplicationContextHolder.getBean("thirdPartyAuthConfig");
private final RedissonClient redissonClient = ApplicationContextHolder.getBean(RedissonClient.class);
private final CacheManager cacheManager = ApplicationContextHolder.getBean("caffeineCacheManager");
private final SaTokenUtil saTokenUtil =
ApplicationContextHolder.getBean("saTokenUtil");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String appCode = this.getAppCodeFromRequest(request);
if (StrUtil.isNotBlank(appCode)) {
return this.handleThirdPartyRequest(appCode, request);
}
ResponseResult<Void> result = saTokenUtil.handleAuthIntercept(request, handler);
if (!result.isSuccess()) {
ResponseResult.output(result.getHttpStatus(), result);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 这里需要空注解否则sonar会不happy。
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 这里需要空注解否则sonar会不happy。
}
private String getTokenFromRequest(HttpServletRequest request, String appCode) {
ThirdPartyAuthConfig.AuthProperties prop = thirdPartyAuthConfig.getApplicationMap().get(appCode);
String token = request.getHeader(prop.getTokenHeaderKey());
if (StrUtil.isBlank(token)) {
token = request.getParameter(prop.getTokenHeaderKey());
}
if (StrUtil.isBlank(token)) {
token = request.getHeader(ApplicationConstant.HTTP_HEADER_INTERNAL_TOKEN);
}
return token;
}
private String getAppCodeFromRequest(HttpServletRequest request) {
String appCode = request.getHeader("AppCode");
if (StrUtil.isBlank(appCode)) {
appCode = request.getParameter("AppCode");
}
return appCode;
}
private boolean handleThirdPartyRequest(String appCode, HttpServletRequest request) throws IOException {
String token = this.getTokenFromRequest(request, appCode);
ThirdPartyAuthConfig.AuthProperties authProps = thirdPartyAuthConfig.getApplicationMap().get(appCode);
if (authProps == null) {
String msg = StrFormatter.format("请求的 appCode[{}] 信息,在当前服务中尚未配置!", appCode);
ResponseResult.output(ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, msg));
return false;
}
ResponseResult<TokenData> result = this.getAndCacheThirdPartyTokenData(authProps, token);
if (!result.isSuccess()) {
ResponseResult.output(result.getHttpStatus(),
ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, result.getErrorMessage()));
return false;
}
TokenData tokenData = result.getData();
tokenData.setAppCode(appCode);
tokenData.setSessionId(this.prependAppCode(authProps.getAppCode(), tokenData.getSessionId()));
TokenData.addToRequest(tokenData);
String url = request.getRequestURI();
if (Boolean.FALSE.equals(tokenData.getIsAdmin())
&& !this.hasThirdPartyPermission(authProps, tokenData, url)) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION));
return false;
}
return true;
}
private ResponseResult<TokenData> getAndCacheThirdPartyTokenData(
ThirdPartyAuthConfig.AuthProperties authProps, String token) {
if (authProps.getTokenExpiredSeconds() == 0) {
return this.getThirdPartyTokenData(authProps, token);
}
String tokeKey = this.prependAppCode(authProps.getAppCode(), RedisKeyUtil.makeSessionIdKey(token));
RBucket<String> sessionData = redissonClient.getBucket(tokeKey);
if (sessionData.isExists()) {
return ResponseResult.success(JSON.parseObject(sessionData.get(), TokenData.class));
}
ResponseResult<TokenData> responseResult = this.getThirdPartyTokenData(authProps, token);
if (responseResult.isSuccess()) {
sessionData.set(JSON.toJSONString(responseResult.getData()), authProps.getTokenExpiredSeconds(), TimeUnit.SECONDS);
}
return responseResult;
}
private String prependAppCode(String appCode, String key) {
return appCode.toUpperCase() + ":" + key;
}
private ResponseResult<TokenData> getThirdPartyTokenData(
ThirdPartyAuthConfig.AuthProperties authProps, String token) {
try {
String resultData = this.invokeThirdPartyUrl(authProps.getBaseUrl() + "/getTokenData", token);
return JSON.parseObject(resultData, new TypeReference<ResponseResult<TokenData>>() {});
} catch (MyRuntimeException ex) {
return ResponseResult.error(ErrorCodeEnum.FAILED_TO_INVOKE_THIRDPARTY_URL, ex.getMessage());
}
}
private ResponseResult<ThirdPartyAppPermData> getThirdPartyPermData(
ThirdPartyAuthConfig.AuthProperties authProps, String token) {
try {
String resultData = this.invokeThirdPartyUrl(authProps.getBaseUrl() + "/getPermData", token);
return JSON.parseObject(resultData, new TypeReference<ResponseResult<ThirdPartyAppPermData>>() {});
} catch (MyRuntimeException ex) {
return ResponseResult.error(ErrorCodeEnum.FAILED_TO_INVOKE_THIRDPARTY_URL, ex.getMessage());
}
}
private String invokeThirdPartyUrl(String url, String token) {
Map<String, String> headerMap = new HashMap<>(1);
headerMap.put("Authorization", token);
StringBuilder fullUrl = new StringBuilder(128);
fullUrl.append(url).append("?token=").append(token);
HttpResponse httpResponse = HttpUtil.createGet(fullUrl.toString()).addHeaders(headerMap).execute();
if (!httpResponse.isOk()) {
String msg = StrFormatter.format(
"Failed to call [{}] with ERROR HTTP Status [{}] and [{}].",
url, httpResponse.getStatus(), httpResponse.body());
log.error(msg);
throw new MyRuntimeException(msg);
}
return httpResponse.body();
}
@SuppressWarnings("unchecked")
private boolean hasThirdPartyPermission(
ThirdPartyAuthConfig.AuthProperties authProps, TokenData tokenData, String url) {
// 为了提升效率先检索Caffeine的一级缓存如果不存在再检索Redis的二级缓存并将结果存入一级缓存。
String permKey = RedisKeyUtil.makeSessionPermIdKey(tokenData.getSessionId());
Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.USER_PERMISSION_CACHE.name());
Assert.notNull(cache, "Cache USER_PERMISSION_CACHE can't be NULL");
Cache.ValueWrapper wrapper = cache.get(permKey);
if (wrapper != null) {
Object cachedData = wrapper.get();
if (cachedData != null) {
return ((Set<String>) cachedData).contains(url);
}
}
Set<String> localPermSet;
RSet<String> permSet = redissonClient.getSet(permKey);
if (permSet.isExists()) {
localPermSet = permSet.readAll();
cache.put(permKey, localPermSet);
return localPermSet.contains(url);
}
ResponseResult<ThirdPartyAppPermData> responseResult = this.getThirdPartyPermData(authProps, tokenData.getToken());
this.cacheThirdPartyDataPermData(authProps, tokenData, responseResult.getData().getDataPerms());
if (CollUtil.isEmpty(responseResult.getData().urlPerms)) {
return false;
}
permSet.addAll(responseResult.getData().urlPerms);
permSet.expire(authProps.getPermExpiredSeconds(), TimeUnit.SECONDS);
localPermSet = new HashSet<>(responseResult.getData().urlPerms);
cache.put(permKey, localPermSet);
return localPermSet.contains(url);
}
private void cacheThirdPartyDataPermData(
ThirdPartyAuthConfig.AuthProperties authProps, TokenData tokenData, List<ThirdPartyAppDataPermData> dataPerms) {
if (CollUtil.isEmpty(dataPerms)) {
return;
}
Map<Integer, List<ThirdPartyAppDataPermData>> dataPermMap =
dataPerms.stream().collect(Collectors.groupingBy(ThirdPartyAppDataPermData::getRuleType));
Map<Integer, List<ThirdPartyAppDataPermData>> normalizedDataPermMap = new HashMap<>(dataPermMap.size());
for (Map.Entry<Integer, List<ThirdPartyAppDataPermData>> entry : dataPermMap.entrySet()) {
List<ThirdPartyAppDataPermData> ruleTypeDataPermDataList;
if (entry.getKey().equals(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT)) {
ruleTypeDataPermDataList =
normalizedDataPermMap.computeIfAbsent(DataPermRuleType.TYPE_CUSTOM_DEPT_LIST, k -> new LinkedList<>());
} else {
ruleTypeDataPermDataList =
normalizedDataPermMap.computeIfAbsent(entry.getKey(), k -> new LinkedList<>());
}
ruleTypeDataPermDataList.addAll(entry.getValue());
}
Map<Integer, String> resultDataPermMap = new HashMap<>(normalizedDataPermMap.size());
for (Map.Entry<Integer, List<ThirdPartyAppDataPermData>> entry : normalizedDataPermMap.entrySet()) {
if (entry.getKey().equals(DataPermRuleType.TYPE_CUSTOM_DEPT_LIST)) {
String deptIds = entry.getValue().stream()
.map(ThirdPartyAppDataPermData::getDeptIds).collect(Collectors.joining(","));
resultDataPermMap.put(entry.getKey(), deptIds);
} else {
resultDataPermMap.put(entry.getKey(), "null");
}
}
Map<String, Map<Integer, String>> menuDataPermMap = new HashMap<>(1);
menuDataPermMap.put(ApplicationConstant.DATA_PERM_ALL_MENU_ID, resultDataPermMap);
String dataPermSessionKey = RedisKeyUtil.makeSessionDataPermIdKey(tokenData.getSessionId());
RBucket<String> bucket = redissonClient.getBucket(dataPermSessionKey);
bucket.set(JSON.toJSONString(menuDataPermMap), authProps.getPermExpiredSeconds(), TimeUnit.SECONDS);
}
@Data
public static class ThirdPartyAppPermData {
/**
* 当前用户会话可访问的url接口地址列表。
*/
private List<String> urlPerms;
/**
* 当前用户会话的数据权限列表。
*/
private List<ThirdPartyAppDataPermData> dataPerms;
}
@Data
public static class ThirdPartyAppDataPermData {
/**
* 数据权限的规则类型。需要按照橙单的约定返回。具体值可参考DataPermRuleType常量类。
*/
private Integer ruleType;
/**
* 部门Id集合多个部门Id之间逗号分隔。
* 注意仅当ruleType为3、4、5时需要包含该字段值。
*/
private String deptIds;
}
}

View File

@@ -0,0 +1,55 @@
package com.orangeforms.webadmin.upms.bo;
import lombok.Data;
import java.util.List;
/**
* 菜单扩展数据对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
public class SysMenuExtraData {
/**
* 路由名称。
*/
private String formRouterName;
/**
* 在线表单。
*/
private Long onlineFormId;
/**
* 报表页面。
*/
private Long reportPageId;
/**
* 流程。
*/
private Long onlineFlowEntryId;
/**
* 目标url。
*/
private String targetUrl;
/**
* 绑定类型。
*/
private Integer bindType;
/**
* 前端使用的菜单编码。仅当选择satoken权限框架时使用。
*/
private String menuCode;
/**
* 菜单关联的后台使用的权限字列表。仅当选择satoken权限框架时使用。
*/
private List<String> permCodeList;
}

View File

@@ -0,0 +1,66 @@
package com.orangeforms.webadmin.upms.bo;
import lombok.Data;
import java.util.HashSet;
import java.util.Set;
/**
* 菜单相关的业务对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
public class SysMenuPerm {
/**
* 菜单Id。
*/
private Long menuId;
/**
* 父菜单Id目录菜单的父菜单为null
*/
private Long parentId;
/**
* 菜单显示名称。
*/
private String menuName;
/**
* 菜单类型 (0: 目录 1: 菜单 2: 按钮 3: UI片段)。
*/
private Integer menuType;
/**
* 在线表单主键Id仅用于在线表单绑定的菜单。
*/
private Long onlineFormId;
/**
* 在线表单菜单的权限控制类型具体值可参考SysOnlineMenuPermType常量对象。
*/
private Integer onlineMenuPermType;
/**
* 统计页面主键Id仅用于统计页面绑定的菜单。
*/
private Long reportPageId;
/**
* 仅用于在线表单的流程Id。
*/
private Long onlineFlowEntryId;
/**
* 关联权限URL集合。
*/
Set<String> permUrlSet = new HashSet<>();
/**
* 关联的某一个url。
*/
String url;
}

View File

@@ -0,0 +1,340 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.core.constant.ErrorCodeEnum;
import com.orangeforms.common.core.object.MyOrderParam;
import com.orangeforms.common.core.object.MyPageData;
import com.orangeforms.common.core.object.MyPageParam;
import com.orangeforms.common.core.object.ResponseResult;
import com.orangeforms.common.core.util.MyCommonUtil;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.MyPageUtil;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.common.dict.dto.GlobalDictDto;
import com.orangeforms.common.dict.dto.GlobalDictItemDto;
import com.orangeforms.common.dict.model.GlobalDict;
import com.orangeforms.common.dict.model.GlobalDictItem;
import com.orangeforms.common.dict.service.GlobalDictItemService;
import com.orangeforms.common.dict.service.GlobalDictService;
import com.orangeforms.common.dict.util.GlobalDictOperationHelper;
import com.orangeforms.common.dict.vo.GlobalDictVo;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.groups.Default;
import java.util.*;
import java.util.stream.Collectors;
/**
* 全局通用字典操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "全局字典管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/globalDict")
public class GlobalDictController {
@Autowired
private GlobalDictService globalDictService;
@Autowired
private GlobalDictItemService globalDictItemService;
@Autowired
private GlobalDictOperationHelper globalDictOperationHelper;
/**
* 新增全局字典接口。
*
* @param globalDictDto 新增字典对象。
* @return 保存后的字典对象。
*/
@ApiOperationSupport(ignoreParameters = {"globalDictDto.dictId"})
@SaCheckPermission("globalDict.update")
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody GlobalDictDto globalDictDto) {
String errorMessage = MyCommonUtil.getModelValidationError(globalDictDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
// 这里必须手动校验字典编码是否存在,因为我们缺省的实现是逻辑删除,所以字典编码字段没有设置为唯一索引。
if (globalDictService.existDictCode(globalDictDto.getDictCode())) {
errorMessage = "数据验证失败,字典编码已经存在!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
GlobalDict globalDict = MyModelUtil.copyTo(globalDictDto, GlobalDict.class);
globalDictService.saveNew(globalDict);
return ResponseResult.success(globalDict.getDictId());
}
/**
* 更新全局字典操作。
*
* @param globalDictDto 更新全局字典对象。
* @return 应答结果对象。
*/
@SaCheckPermission("globalDict.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody GlobalDictDto globalDictDto) {
String errorMessage = MyCommonUtil.getModelValidationError(globalDictDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
GlobalDict originalGlobalDict = globalDictService.getById(globalDictDto.getDictId());
if (originalGlobalDict == null) {
errorMessage = "数据验证失败,当前全局字典并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
GlobalDict globalDict = MyModelUtil.copyTo(globalDictDto, GlobalDict.class);
if (ObjectUtil.notEqual(globalDict.getDictCode(), originalGlobalDict.getDictCode())
&& globalDictService.existDictCode(globalDict.getDictCode())) {
errorMessage = "数据验证失败,字典编码已经存在!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!globalDictService.update(globalDict, originalGlobalDict)) {
errorMessage = "更新失败,数据不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 删除指定的全局字典。
*
* @param dictId 指定全局字典主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("globalDict.update")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody(required = true) Long dictId) {
if (!globalDictService.remove(dictId)) {
String errorMessage = "数据操作失败全局字典Id不存在请刷新后重试";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 查看全局字典列表。
*
* @param globalDictDtoFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含角色列表。
*/
@SaCheckPermission("globalDict.view")
@PostMapping("/list")
public ResponseResult<MyPageData<GlobalDictVo>> list(
@MyRequestBody GlobalDictDto globalDictDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
GlobalDict filter = MyModelUtil.copyTo(globalDictDtoFilter, GlobalDict.class);
List<GlobalDict> globalDictList =
globalDictService.getGlobalDictList(filter, MyOrderParam.buildOrderBy(orderParam, GlobalDict.class));
List<GlobalDictVo> globalDictVoList =
MyModelUtil.copyCollectionTo(globalDictList, GlobalDictVo.class);
long totalCount = 0L;
if (globalDictList instanceof Page) {
totalCount = ((Page<GlobalDict>) globalDictList).getTotal();
}
return ResponseResult.success(MyPageUtil.makeResponseData(globalDictVoList, totalCount));
}
/**
* 新增全局字典项目接口。
*
* @param globalDictItemDto 新增字典项目对象。
* @return 保存后的字典对象。
*/
@SaCheckPermission("globalDict.update")
@ApiOperationSupport(ignoreParameters = {"globalDictItemDto.id"})
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/addItem")
public ResponseResult<Long> addItem(@MyRequestBody GlobalDictItemDto globalDictItemDto) {
String errorMessage = MyCommonUtil.getModelValidationError(globalDictItemDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!globalDictService.existDictCode(globalDictItemDto.getDictCode())) {
errorMessage = "数据验证失败,字典编码不存在!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (globalDictItemService.existDictCodeAndItemId(
globalDictItemDto.getDictCode(), globalDictItemDto.getItemId())) {
errorMessage = "数据验证失败该字典编码的项目Id已存在";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
GlobalDictItem globalDictItem = MyModelUtil.copyTo(globalDictItemDto, GlobalDictItem.class);
globalDictItemService.saveNew(globalDictItem);
return ResponseResult.success(globalDictItem.getId());
}
/**
* 更新全局字典项目。
*
* @param globalDictItemDto 更新全局字典项目对象。
* @return 应答结果对象。
*/
@SaCheckPermission("globalDict.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/updateItem")
public ResponseResult<Void> updateItem(@MyRequestBody GlobalDictItemDto globalDictItemDto) {
String errorMessage = MyCommonUtil.getModelValidationError(globalDictItemDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
GlobalDictItem originalGlobalDictItem = globalDictItemService.getById(globalDictItemDto.getId());
if (originalGlobalDictItem == null) {
errorMessage = "数据验证失败,当前全局字典项目并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
GlobalDictItem globalDictItem = MyModelUtil.copyTo(globalDictItemDto, GlobalDictItem.class);
if (ObjectUtil.notEqual(globalDictItem.getDictCode(), originalGlobalDictItem.getDictCode())) {
errorMessage = "数据验证失败,字典项目的字典编码不能修改!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (ObjectUtil.notEqual(globalDictItem.getItemId(), originalGlobalDictItem.getItemId())
&& globalDictItemService.existDictCodeAndItemId(globalDictItem.getDictCode(), globalDictItem.getItemId())) {
errorMessage = "数据验证失败该字典编码已经包含了该项目Id";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!globalDictItemService.update(globalDictItem, originalGlobalDictItem)) {
errorMessage = "更新失败,数据不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 更新全局字典项目的状态。
*
* @param id 更新全局字典项目主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("globalDict.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/updateItemStatus")
public ResponseResult<Void> updateItemStatus(
@MyRequestBody(required = true) Long id, @MyRequestBody(required = true) Integer status) {
String errorMessage;
GlobalDictItem dictItem = globalDictItemService.getById(id);
if (dictItem == null) {
errorMessage = "数据操作失败全局字典项目Id不存在请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (ObjectUtil.notEqual(dictItem.getStatus(), status)) {
globalDictItemService.updateStatus(dictItem, status);
}
return ResponseResult.success();
}
/**
* 删除指定编码的全局字典项目。
*
* @param id 主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("globalDict.update")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/deleteItem")
public ResponseResult<Void> deleteItem(@MyRequestBody(required = true) Long id) {
String errorMessage;
GlobalDictItem dictItem = globalDictItemService.getById(id);
if (dictItem == null) {
errorMessage = "数据操作失败全局字典项目Id不存在请刷新后重试";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!globalDictItemService.remove(dictItem)) {
errorMessage = "数据操作失败全局字典项目Id不存在请刷新后重试";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 将当前字典表的数据重新加载到缓存中。
* 由于缓存的数据更新在add/update/delete等接口均有同步处理。因此该接口仅当同步过程中出现问题时
* 可手工调用,或者每天晚上定时同步一次。
*/
@SaCheckPermission("globalDict.view")
@OperationLog(type = SysOperationLogType.RELOAD_CACHE)
@GetMapping("/reloadCachedData")
public ResponseResult<Boolean> reloadCachedData(@RequestParam String dictCode) {
globalDictService.reloadCachedData(dictCode);
return ResponseResult.success(true);
}
/**
* 获取指定字典编码的全局字典项目。字典的键值为[itemId, itemName]。
* NOTE: 白名单接口。
*
* @param dictCode 字典编码。
* @param itemIdType 字典项目的ItemId值转换到的目标类型。可能值为Integer或Long。
* @return 应答结果对象。
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(
@RequestParam String dictCode, @RequestParam(required = false) String itemIdType) {
List<GlobalDictItem> resultList =
globalDictService.getGlobalDictItemListFromCache(dictCode, null);
resultList = resultList.stream()
.sorted(Comparator.comparing(GlobalDictItem::getStatus))
.sorted(Comparator.comparing(GlobalDictItem::getShowOrder))
.collect(Collectors.toList());
return ResponseResult.success(globalDictOperationHelper.toDictDataList(resultList, itemIdType));
}
/**
* 根据字典Id集合获取查询后的字典数据。
* NOTE: 白名单接口。
*
* @param dictCode 字典编码。
* @param itemIds 字典项目Id集合。
* @param itemIdType 字典项目的ItemId值转换到的目标类型。可能值为Integer或Long。
* @return 应答结果对象,包含字典形式的数据集合。
*/
@GetMapping("/listDictByIds")
public ResponseResult<List<Map<String, Object>>> listDictByIds(
@RequestParam String dictCode,
@RequestParam List<String> itemIds,
@RequestParam(required = false) String itemIdType) {
List<GlobalDictItem> resultList =
globalDictService.getGlobalDictItemListFromCache(dictCode, new HashSet<>(itemIds));
return ResponseResult.success(globalDictOperationHelper.toDictDataList(resultList, itemIdType));
}
/**
* 白名单接口,登录用户均可访问。以字典形式返回全部字典数据集合。
* fullResultList中的字典列表全部取自于数据库而cachedResultList全部取自于缓存前端负责比对。
*
* @return 应答结果对象,包含字典形式的数据集合。
*/
@GetMapping("/listAll")
public ResponseResult<JSONObject> listAll(@RequestParam String dictCode) {
List<GlobalDictItem> fullResultList =
globalDictItemService.getGlobalDictItemListByDictCode(dictCode);
List<GlobalDictItem> cachedList =
globalDictService.getGlobalDictItemListFromCache(dictCode, null);
JSONObject jsonObject = new JSONObject();
jsonObject.put("fullResultList", globalDictOperationHelper.toDictDataList2(fullResultList));
jsonObject.put("cachedResultList", globalDictOperationHelper.toDictDataList2(cachedList));
return ResponseResult.success(jsonObject);
}
}

View File

@@ -0,0 +1,475 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import com.orangeforms.webadmin.config.ApplicationConfig;
import com.orangeforms.webadmin.upms.bo.SysMenuExtraData;
import com.orangeforms.webadmin.upms.service.*;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.webadmin.upms.model.constant.SysUserStatus;
import com.orangeforms.webadmin.upms.model.constant.SysUserType;
import com.orangeforms.webadmin.upms.model.constant.SysMenuType;
import com.orangeforms.webadmin.upms.model.constant.SysOnlineMenuPermType;
import com.orangeforms.common.flow.online.service.FlowOnlineOperationService;
import com.orangeforms.common.online.service.OnlineOperationService;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.core.annotation.DisableDataFilter;
import com.orangeforms.common.core.constant.ErrorCodeEnum;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.*;
import com.orangeforms.common.core.upload.*;
import com.orangeforms.common.redis.cache.SessionCacheHelper;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import com.orangeforms.common.satoken.util.SaTokenUtil;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 登录接口控制器类。
*
* @author Jerry
* @date 2024-07-02
*/
@ApiSupport(order = 1)
@Tag(name = "用户登录接口")
@DisableDataFilter
@Slf4j
@RestController
@RequestMapping("/admin/upms/login")
public class LoginController {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysDeptService sysDeptService;
@Autowired
private SysMenuService sysMenuService;
@Autowired
private SysPostService sysPostService;
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysDataPermService sysDataPermService;
@Autowired
private SysPermWhitelistService sysPermWhitelistService;
@Autowired
private OnlineOperationService onlineOperationService;
@Autowired
private FlowOnlineOperationService flowOnlineOperationService;
@Autowired
private ApplicationConfig appConfig;
@Autowired
private RedissonClient redissonClient;
@Autowired
private SessionCacheHelper cacheHelper;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UpDownloaderFactory upDownloaderFactory;
@Autowired
private SaTokenUtil saTokenUtil;
private static final String IS_ADMIN = "isAdmin";
private static final String SHOW_NAME_FIELD = "showName";
private static final String SHOW_ORDER_FIELD = "showOrder";
private static final String HEAD_IMAGE_URL_FIELD = "headImageUrl";
/**
* 登录接口。
*
* @param loginName 登录名。
* @param password 密码。
* @return 应答结果对象其中包括Token数据以及菜单列表。
*/
@Parameter(name = "loginName", example = "admin")
@Parameter(name = "password", example = "IP3ccke3GhH45iGHB5qP9p7iZw6xUyj28Ju10rnBiPKOI35sc%2BjI7%2FdsjOkHWMfUwGYGfz8ik31HC2Ruk%2Fhkd9f6RPULTHj7VpFdNdde2P9M4mQQnFBAiPM7VT9iW3RyCtPlJexQ3nAiA09OqG%2F0sIf1kcyveSrulxembARDbDo%3D")
@SaIgnore
@OperationLog(type = SysOperationLogType.LOGIN, saveResponse = false)
@PostMapping("/doLogin")
public ResponseResult<JSONObject> doLogin(
@MyRequestBody String loginName,
@MyRequestBody String password) throws UnsupportedEncodingException {
if (MyCommonUtil.existBlankArgument(loginName, password)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
ResponseResult<SysUser> verifyResult = this.verifyAndHandleLoginUser(loginName, password);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
JSONObject jsonData = this.buildLoginDataAndLogin(verifyResult.getData());
return ResponseResult.success(jsonData);
}
/**
* 登出操作。同时将Session相关的信息从缓存中删除。
*
* @return 应答结果对象。
*/
@OperationLog(type = SysOperationLogType.LOGOUT)
@PostMapping("/doLogout")
public ResponseResult<Void> doLogout() {
String sessionId = TokenData.takeFromRequest().getSessionId();
redissonClient.getBucket(TokenData.takeFromRequest().getMySessionId()).deleteAsync();
redissonClient.getBucket(RedisKeyUtil.makeSessionPermCodeKey(sessionId)).deleteAsync();
redissonClient.getBucket(RedisKeyUtil.makeSessionPermIdKey(sessionId)).deleteAsync();
sysDataPermService.removeDataPermCache(sessionId);
cacheHelper.removeAllSessionCache(sessionId);
StpUtil.logout();
return ResponseResult.success();
}
/**
* 在登录之后通过token再次获取登录信息。
* 用于在当前浏览器登录系统后在新tab页中可以免密登录。
*
* @return 应答结果对象其中包括JWT的Token数据以及菜单列表。
*/
@GetMapping("/getLoginInfo")
public ResponseResult<JSONObject> getLoginInfo() {
TokenData tokenData = TokenData.takeFromRequest();
JSONObject jsonData = new JSONObject();
jsonData.put(SHOW_NAME_FIELD, tokenData.getShowName());
jsonData.put(IS_ADMIN, tokenData.getIsAdmin());
if (StrUtil.isNotBlank(tokenData.getHeadImageUrl())) {
jsonData.put(HEAD_IMAGE_URL_FIELD, tokenData.getHeadImageUrl());
}
Collection<SysMenu> allMenuList;
if (BooleanUtil.isTrue(tokenData.getIsAdmin())) {
allMenuList = sysMenuService.getAllListByOrder(SHOW_ORDER_FIELD);
} else {
allMenuList = sysMenuService.getMenuListByRoleIds(tokenData.getRoleIds());
}
List<String> menuCodeList = new LinkedList<>();
OnlinePermData onlinePermData = this.getOnlineMenuPermData(allMenuList);
CollUtil.addAll(menuCodeList, onlinePermData.permCodeSet);
OnlinePermData onlineFlowPermData = this.getFlowOnlineMenuPermData(allMenuList);
CollUtil.addAll(menuCodeList, onlineFlowPermData.permCodeSet);
allMenuList.stream().filter(m -> m.getExtraData() != null)
.forEach(m -> m.setExtraObject(JSON.parseObject(m.getExtraData(), SysMenuExtraData.class)));
this.appendResponseMenuAndPermCodeData(jsonData, allMenuList, menuCodeList);
return ResponseResult.success(jsonData);
}
/**
* 返回所有可用的权限字列表。
*
* @return 整个系统所有可用的权限字列表。
*/
@GetMapping("/getAllPermCodes")
public ResponseResult<List<String>> getAllPermCodes() {
List<String> permCodes = saTokenUtil.getAllPermCodes();
return ResponseResult.success(permCodes);
}
/**
* 用户修改自己的密码。
*
* @param oldPass 原有密码。
* @param newPass 新密码。
* @return 应答结果对象。
*/
@PostMapping("/changePassword")
public ResponseResult<Void> changePassword(
@MyRequestBody String oldPass, @MyRequestBody String newPass) throws UnsupportedEncodingException {
if (MyCommonUtil.existBlankArgument(newPass, oldPass)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
TokenData tokenData = TokenData.takeFromRequest();
SysUser user = sysUserService.getById(tokenData.getUserId());
oldPass = URLDecoder.decode(oldPass, StandardCharsets.UTF_8.name());
// NOTE: 第一次使用时请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。
// 执行RsaUtil工具类中的main函数可以生成新的公钥和私钥。
oldPass = RsaUtil.decrypt(oldPass, ApplicationConstant.PRIVATE_KEY);
if (user == null || !passwordEncoder.matches(oldPass, user.getPassword())) {
return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD);
}
newPass = URLDecoder.decode(newPass, StandardCharsets.UTF_8.name());
newPass = RsaUtil.decrypt(newPass, ApplicationConstant.PRIVATE_KEY);
if (!sysUserService.changePassword(tokenData.getUserId(), newPass)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 上传并修改用户头像。
*
* @param uploadFile 上传的头像文件。
*/
@PostMapping("/changeHeadImage")
public void changeHeadImage(@RequestParam("uploadFile") MultipartFile uploadFile) throws IOException {
UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(SysUser.class, HEAD_IMAGE_URL_FIELD);
BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType());
UploadResponseInfo responseInfo = upDownloader.doUpload(null,
appConfig.getUploadFileBaseDir(), SysUser.class.getSimpleName(), HEAD_IMAGE_URL_FIELD, true, uploadFile);
if (BooleanUtil.isTrue(responseInfo.getUploadFailed())) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN,
ResponseResult.error(ErrorCodeEnum.UPLOAD_FAILED, responseInfo.getErrorMessage()));
return;
}
responseInfo.setDownloadUri("/admin/upms/login/downloadHeadImage");
String newHeadImage = JSONArray.toJSONString(CollUtil.newArrayList(responseInfo));
if (!sysUserService.changeHeadImage(TokenData.takeFromRequest().getUserId(), newHeadImage)) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST));
return;
}
ResponseResult.output(ResponseResult.success(responseInfo));
}
/**
* 下载用户头像。
*
* @param filename 文件名。如果没有提供该参数,就从当前记录的指定字段中读取。
* @param response Http 应答对象。
*/
@GetMapping("/downloadHeadImage")
public void downloadHeadImage(String filename, HttpServletResponse response) {
try {
UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(SysUser.class, HEAD_IMAGE_URL_FIELD);
BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType());
upDownloader.doDownload(appConfig.getUploadFileBaseDir(),
SysUser.class.getSimpleName(), HEAD_IMAGE_URL_FIELD, filename, true, response);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
log.error(e.getMessage(), e);
}
}
private ResponseResult<SysUser> verifyAndHandleLoginUser(
String loginName, String password) throws UnsupportedEncodingException {
String errorMessage;
SysUser user = sysUserService.getSysUserByLoginName(loginName);
password = URLDecoder.decode(password, StandardCharsets.UTF_8.name());
// NOTE: 第一次使用时请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。
// 执行RsaUtil工具类中的main函数可以生成新的公钥和私钥。
password = RsaUtil.decrypt(password, ApplicationConstant.PRIVATE_KEY);
if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD);
}
if (user.getUserStatus() == SysUserStatus.STATUS_LOCKED) {
errorMessage = "登录失败,用户账号被锁定!";
return ResponseResult.error(ErrorCodeEnum.INVALID_USER_STATUS, errorMessage);
}
if (BooleanUtil.isTrue(appConfig.getExcludeLogin())) {
String deviceType = MyCommonUtil.getDeviceTypeWithString();
LoginUserInfo userInfo = BeanUtil.copyProperties(user, LoginUserInfo.class);
String loginId = SaTokenUtil.makeLoginId(userInfo);
StpUtil.kickout(loginId, deviceType);
}
return ResponseResult.success(user);
}
private JSONObject buildLoginDataAndLogin(SysUser user) {
TokenData tokenData = this.loginAndCreateToken(user);
// 这里手动将TokenData存入request便于OperationLogAspect统一处理操作日志。
TokenData.addToRequest(tokenData);
JSONObject jsonData = this.createResponseData(user);
Collection<SysMenu> allMenuList;
boolean isAdmin = user.getUserType() == SysUserType.TYPE_ADMIN;
if (isAdmin) {
allMenuList = sysMenuService.getAllListByOrder(SHOW_ORDER_FIELD);
} else {
allMenuList = sysMenuService.getMenuListByRoleIds(tokenData.getRoleIds());
}
allMenuList.stream().filter(m -> m.getExtraData() != null)
.forEach(m -> m.setExtraObject(JSON.parseObject(m.getExtraData(), SysMenuExtraData.class)));
Collection<String> permCodeList = new LinkedList<>();
allMenuList.stream().filter(m -> m.getExtraObject() != null)
.forEach(m -> CollUtil.addAll(permCodeList, m.getExtraObject().getPermCodeList()));
Set<String> permSet = new HashSet<>();
if (!isAdmin) {
// 所有登录用户都有白名单接口的访问权限。
CollUtil.addAll(permSet, sysPermWhitelistService.getWhitelistPermList());
}
List<String> menuCodeList = new LinkedList<>();
OnlinePermData onlinePermData = this.getOnlineMenuPermData(allMenuList);
CollUtil.addAll(menuCodeList, onlinePermData.permCodeSet);
OnlinePermData onlineFlowPermData = this.getFlowOnlineMenuPermData(allMenuList);
CollUtil.addAll(menuCodeList, onlineFlowPermData.permCodeSet);
if (!isAdmin) {
permSet.addAll(onlinePermData.permUrlSet);
permSet.addAll(onlineFlowPermData.permUrlSet);
String sessionId = tokenData.getSessionId();
// 缓存用户的权限资源这里缓存的是基于URL验证的权限资源比如在线表单、工作流和数据表中的白名单资源。
this.putUserSysPermCache(sessionId, permSet);
// 缓存权限字字段StpInterfaceImpl中会从缓存中读取并交给satoken进行接口权限的验证。
this.putUserSysPermCodeCache(sessionId, permCodeList);
sysDataPermService.putDataPermCache(sessionId, user.getUserId(), user.getDeptId());
}
this.appendResponseMenuAndPermCodeData(jsonData, allMenuList, menuCodeList);
return jsonData;
}
private TokenData loginAndCreateToken(SysUser user) {
String deviceType = MyCommonUtil.getDeviceTypeWithString();
LoginUserInfo userInfo = BeanUtil.copyProperties(user, LoginUserInfo.class);
String loginId = SaTokenUtil.makeLoginId(userInfo);
StpUtil.login(loginId, deviceType);
SaSession session = StpUtil.getTokenSession();
TokenData tokenData = this.buildTokenData(user, session.getId(), StpUtil.getLoginDevice());
String mySessionId = RedisKeyUtil.getSessionIdPrefix(tokenData, user.getLoginName()) + MyCommonUtil.generateUuid();
tokenData.setMySessionId(mySessionId);
tokenData.setToken(session.getToken());
redissonClient.getBucket(mySessionId)
.set(JSON.toJSONString(tokenData), appConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS);
session.set(TokenData.REQUEST_ATTRIBUTE_NAME, tokenData);
return tokenData;
}
private JSONObject createResponseData(SysUser user) {
JSONObject jsonData = new JSONObject();
jsonData.put(TokenData.REQUEST_ATTRIBUTE_NAME, StpUtil.getTokenValue());
jsonData.put(SHOW_NAME_FIELD, user.getShowName());
jsonData.put(IS_ADMIN, user.getUserType() == SysUserType.TYPE_ADMIN);
if (user.getDeptId() != null) {
SysDept dept = sysDeptService.getById(user.getDeptId());
jsonData.put("deptName", dept.getDeptName());
}
if (StrUtil.isNotBlank(user.getHeadImageUrl())) {
jsonData.put(HEAD_IMAGE_URL_FIELD, user.getHeadImageUrl());
}
return jsonData;
}
private void appendResponseMenuAndPermCodeData(
JSONObject responseData, Collection<SysMenu> allMenuList, Collection<String> menuCodeList) {
allMenuList.stream()
.filter(m -> m.getExtraObject() != null && StrUtil.isNotBlank(m.getExtraObject().getMenuCode()))
.forEach(m -> CollUtil.addAll(menuCodeList, m.getExtraObject().getMenuCode()));
List<SysMenu> menuList = allMenuList.stream()
.filter(m -> m.getMenuType() <= SysMenuType.TYPE_MENU).collect(Collectors.toList());
responseData.put("menuList", menuList);
responseData.put("permCodeList", menuCodeList);
}
private TokenData buildTokenData(SysUser user, String sessionId, String deviceType) {
TokenData tokenData = new TokenData();
tokenData.setSessionId(sessionId);
tokenData.setUserId(user.getUserId());
tokenData.setDeptId(user.getDeptId());
tokenData.setLoginName(user.getLoginName());
tokenData.setShowName(user.getShowName());
tokenData.setIsAdmin(user.getUserType().equals(SysUserType.TYPE_ADMIN));
tokenData.setLoginIp(IpUtil.getRemoteIpAddress(ContextUtil.getHttpRequest()));
tokenData.setLoginTime(new Date());
tokenData.setDeviceType(deviceType);
tokenData.setHeadImageUrl(user.getHeadImageUrl());
List<SysUserPost> userPostList = sysPostService.getSysUserPostListByUserId(user.getUserId());
if (CollUtil.isNotEmpty(userPostList)) {
Set<Long> deptPostIdSet = userPostList.stream().map(SysUserPost::getDeptPostId).collect(Collectors.toSet());
tokenData.setDeptPostIds(StrUtil.join(",", deptPostIdSet));
Set<Long> postIdSet = userPostList.stream().map(SysUserPost::getPostId).collect(Collectors.toSet());
tokenData.setPostIds(StrUtil.join(",", postIdSet));
}
List<SysUserRole> userRoleList = sysRoleService.getSysUserRoleListByUserId(user.getUserId());
if (CollUtil.isNotEmpty(userRoleList)) {
Set<Long> userRoleIdSet = userRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());
tokenData.setRoleIds(StrUtil.join(",", userRoleIdSet));
}
return tokenData;
}
private void putUserSysPermCache(String sessionId, Collection<String> permUrlSet) {
if (CollUtil.isEmpty(permUrlSet)) {
return;
}
String sessionPermKey = RedisKeyUtil.makeSessionPermIdKey(sessionId);
RSet<String> redisPermSet = redissonClient.getSet(sessionPermKey);
redisPermSet.addAll(permUrlSet);
redisPermSet.expire(appConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS);
}
private void putUserSysPermCodeCache(String sessionId, Collection<String> permCodeSet) {
if (CollUtil.isEmpty(permCodeSet)) {
return;
}
String sessionPermCodeKey = RedisKeyUtil.makeSessionPermCodeKey(sessionId);
RSet<String> redisPermSet = redissonClient.getSet(sessionPermCodeKey);
redisPermSet.addAll(permCodeSet);
redisPermSet.expire(appConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS);
}
private OnlinePermData getOnlineMenuPermData(Collection<SysMenu> allMenuList) {
List<SysMenu> onlineMenuList = allMenuList.stream()
.filter(m -> m.getOnlineFormId() != null && m.getMenuType().equals(SysMenuType.TYPE_BUTTON))
.collect(Collectors.toList());
if (CollUtil.isEmpty(onlineMenuList)) {
return new OnlinePermData();
}
Set<Long> formIds = allMenuList.stream()
.filter(m -> m.getOnlineFormId() != null
&& m.getOnlineFlowEntryId() == null
&& m.getMenuType().equals(SysMenuType.TYPE_MENU))
.map(SysMenu::getOnlineFormId)
.collect(Collectors.toSet());
Set<Long> viewFormIds = onlineMenuList.stream()
.filter(m -> m.getOnlineMenuPermType() == SysOnlineMenuPermType.TYPE_VIEW)
.map(SysMenu::getOnlineFormId)
.collect(Collectors.toSet());
Set<Long> editFormIds = onlineMenuList.stream()
.filter(m -> m.getOnlineMenuPermType() == SysOnlineMenuPermType.TYPE_EDIT)
.map(SysMenu::getOnlineFormId)
.collect(Collectors.toSet());
Map<String, Object> permDataMap =
onlineOperationService.calculatePermData(formIds, viewFormIds, editFormIds);
OnlinePermData permData = BeanUtil.mapToBean(permDataMap, OnlinePermData.class, false, null);
permData.permUrlSet.addAll(permData.onlineWhitelistUrls);
return permData;
}
private OnlinePermData getFlowOnlineMenuPermData(Collection<SysMenu> allMenuList) {
List<SysMenu> flowOnlineMenuList = allMenuList.stream()
.filter(m -> m.getOnlineFlowEntryId() != null).collect(Collectors.toList());
Set<Long> entryIds = flowOnlineMenuList.stream()
.map(SysMenu::getOnlineFlowEntryId).collect(Collectors.toSet());
List<Map<String, Object>> flowPermDataList = flowOnlineOperationService.calculatePermData(entryIds);
List<OnlineFlowPermData> flowOnlinePermDataList =
MyModelUtil.mapToBeanList(flowPermDataList, OnlineFlowPermData.class);
OnlinePermData permData = new OnlinePermData();
flowOnlinePermDataList.forEach(perm -> {
permData.permCodeSet.addAll(perm.getPermCodeList());
permData.permUrlSet.addAll(perm.getPermList());
});
return permData;
}
static class OnlinePermData {
public final Set<String> permCodeSet = new HashSet<>();
public final Set<String> permUrlSet = new HashSet<>();
public final List<String> onlineWhitelistUrls = new LinkedList<>();
}
@Data
static class OnlineFlowPermData {
private List<String> permCodeList;
private List<String> permList;
}
}

View File

@@ -0,0 +1,89 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.RedisKeyUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
/**
* 在线用户控制器对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "在线用户接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/loginUser")
public class LoginUserController {
@Autowired
private RedissonClient redissonClient;
/**
* 显示在线用户列表。
*
* @param loginName 登录名过滤。
* @param pageParam 分页参数。
* @return 登录用户信息列表。
*/
@SaCheckPermission("loginUser.view")
@PostMapping("/list")
public ResponseResult<MyPageData<LoginUserInfo>> list(
@MyRequestBody String loginName, @MyRequestBody MyPageParam pageParam) {
int skipCount = (pageParam.getPageNum() - 1) * pageParam.getPageSize();
String patternKey;
if (StrUtil.isBlank(loginName)) {
patternKey = RedisKeyUtil.getSessionIdPrefix() + "*";
} else {
patternKey = RedisKeyUtil.getSessionIdPrefix(loginName) + "*";
}
List<LoginUserInfo> loginUserInfoList = new LinkedList<>();
Iterable<String> keys = redissonClient.getKeys().getKeysByPattern(patternKey);
for (String key : keys) {
loginUserInfoList.add(this.buildTokenDataByRedisKey(key));
}
loginUserInfoList.sort((o1, o2) -> (int) (o2.getLoginTime().getTime() - o1.getLoginTime().getTime()));
int toIndex = Math.min(skipCount + pageParam.getPageSize(), loginUserInfoList.size());
List<LoginUserInfo> resultList = loginUserInfoList.subList(skipCount, toIndex);
return ResponseResult.success(new MyPageData<>(resultList, (long) loginUserInfoList.size()));
}
/**
* 强制下线指定登录会话。
*
* @param sessionId 待强制下线的SessionId。
* @return 应答结果对象。
*/
@SaCheckPermission("loginUser.delete")
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody String sessionId) {
RBucket<String> sessionData = redissonClient.getBucket(sessionId);
TokenData tokenData = JSON.parseObject(sessionData.get(), TokenData.class);
StpUtil.kickoutByTokenValue(tokenData.getToken());
sessionData.delete();
return ResponseResult.success();
}
private LoginUserInfo buildTokenDataByRedisKey(String key) {
RBucket<String> sessionData = redissonClient.getBucket(key);
TokenData tokenData = JSON.parseObject(sessionData.get(), TokenData.class);
LoginUserInfo userInfo = BeanUtil.copyProperties(tokenData, LoginUserInfo.class);
userInfo.setSessionId(tokenData.getMySessionId());
return userInfo;
}
}

View File

@@ -0,0 +1,337 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.alibaba.fastjson.TypeReference;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import lombok.extern.slf4j.Slf4j;
import com.orangeforms.webadmin.upms.dto.SysDataPermDto;
import com.orangeforms.webadmin.upms.dto.SysUserDto;
import com.orangeforms.webadmin.upms.vo.SysDataPermVo;
import com.orangeforms.webadmin.upms.vo.SysUserVo;
import com.orangeforms.webadmin.upms.model.SysDataPerm;
import com.orangeforms.webadmin.upms.model.SysUser;
import com.orangeforms.webadmin.upms.service.SysDataPermService;
import com.orangeforms.webadmin.upms.service.SysUserService;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.common.core.constant.ErrorCodeEnum;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.*;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.groups.Default;
import java.util.*;
import java.util.stream.Collectors;
/**
* 数据权限接口控制器对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "数据权限管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysDataPerm")
public class SysDataPermController {
@Autowired
private SysDataPermService sysDataPermService;
@Autowired
private SysUserService sysUserService;
/**
* 添加新数据权限操作。
*
* @param sysDataPermDto 新增对象。
* @param deptIdListString 数据权限关联的部门Id列表多个之间逗号分隔。
* @param menuIdListString 数据权限关联的菜单Id列表多个之间逗号分隔。
* @return 应答结果对象。包含新增数据权限对象的主键Id。
*/
@ApiOperationSupport(ignoreParameters = {
"sysDataPermDto.dataPermId",
"sysDataPermDto.createTimeStart",
"sysDataPermDto.createTimeEnd",
"sysDataPermDto.searchString"})
@SaCheckPermission("sysDataPerm.add")
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(
@MyRequestBody SysDataPermDto sysDataPermDto,
@MyRequestBody String deptIdListString,
@MyRequestBody String menuIdListString) {
String errorMessage = MyCommonUtil.getModelValidationError(sysDataPermDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysDataPerm sysDataPerm = MyModelUtil.copyTo(sysDataPermDto, SysDataPerm.class);
CallResult result = sysDataPermService.verifyRelatedData(sysDataPerm, deptIdListString, menuIdListString);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
Set<Long> menuIdSet = null;
if (result.getData() != null) {
menuIdSet = result.getData().getObject("menuIdSet", new TypeReference<Set<Long>>(){});
}
Set<Long> deptIdSet = null;
if (result.getData() != null) {
deptIdSet = result.getData().getObject("deptIdSet", new TypeReference<Set<Long>>(){});
}
sysDataPermService.saveNew(sysDataPerm, deptIdSet, menuIdSet);
return ResponseResult.success(sysDataPerm.getDataPermId());
}
/**
* 更新数据权限操作。
*
* @param sysDataPermDto 更新的数据权限对象。
* @param deptIdListString 数据权限关联的部门Id列表多个之间逗号分隔。
* @param menuIdListString 数据权限关联的菜单Id列表多个之间逗号分隔。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {
"sysDataPermDto.createTimeStart",
"sysDataPermDto.createTimeEnd",
"sysDataPermDto.searchString"})
@SaCheckPermission("sysDataPerm.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(
@MyRequestBody SysDataPermDto sysDataPermDto,
@MyRequestBody String deptIdListString,
@MyRequestBody String menuIdListString) {
String errorMessage = MyCommonUtil.getModelValidationError(sysDataPermDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysDataPerm originalSysDataPerm = sysDataPermService.getById(sysDataPermDto.getDataPermId());
if (originalSysDataPerm == null) {
errorMessage = "数据验证失败,当前数据权限并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
SysDataPerm sysDataPerm = MyModelUtil.copyTo(sysDataPermDto, SysDataPerm.class);
CallResult result = sysDataPermService.verifyRelatedData(sysDataPerm, deptIdListString, menuIdListString);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
Set<Long> deptIdSet = null;
if (result.getData() != null) {
deptIdSet = result.getData().getObject("deptIdSet", new TypeReference<Set<Long>>(){});
}
Set<Long> menuIdSet = null;
if (result.getData() != null) {
menuIdSet = result.getData().getObject("menuIdSet", new TypeReference<Set<Long>>(){});
}
if (!sysDataPermService.update(sysDataPerm, originalSysDataPerm, deptIdSet, menuIdSet)) {
errorMessage = "更新失败,数据不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 删除数据权限操作。
*
* @param dataPermId 待删除数据权限主键Id。
* @return 应答数据结果。
*/
@SaCheckPermission("sysDataPerm.delete")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long dataPermId) {
if (MyCommonUtil.existBlankArgument(dataPermId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysDataPermService.remove(dataPermId)) {
String errorMessage = "数据操作失败,数据权限不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 查看数据权限列表。
*
* @param sysDataPermDtoFilter 数据权限查询过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象。包含数据权限列表。
*/
@SaCheckPermission("sysDataPerm.view")
@PostMapping("/list")
public ResponseResult<MyPageData<SysDataPermVo>> list(
@MyRequestBody SysDataPermDto sysDataPermDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysDataPerm filter = MyModelUtil.copyTo(sysDataPermDtoFilter, SysDataPerm.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysDataPerm.class);
List<SysDataPerm> dataPermList = sysDataPermService.getSysDataPermListWithRelation(filter, orderBy);
List<SysDataPermVo> dataPermVoList = MyModelUtil.copyCollectionTo(dataPermList, SysDataPermVo.class);
long totalCount = 0L;
if (dataPermList instanceof Page) {
totalCount = ((Page<SysDataPerm>) dataPermList).getTotal();
}
return ResponseResult.success(MyPageUtil.makeResponseData(dataPermVoList, totalCount));
}
/**
* 查看单条数据权限详情。
*
* @param dataPermId 数据权限的主键Id。
* @return 应答结果对象,包含数据权限的详情。
*/
@SaCheckPermission("sysDataPerm.view")
@GetMapping("/view")
public ResponseResult<SysDataPermVo> view(@RequestParam Long dataPermId) {
if (MyCommonUtil.existBlankArgument(dataPermId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
SysDataPerm dataPerm = sysDataPermService.getByIdWithRelation(dataPermId, MyRelationParam.full());
if (dataPerm == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysDataPermVo dataPermVo = MyModelUtil.copyTo(dataPerm, SysDataPermVo.class);
return ResponseResult.success(dataPermVo);
}
/**
* 拥有指定数据权限的用户列表。
*
* @param dataPermId 数据权限Id。
* @param sysUserDtoFilter 用户过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含用户列表数据。
*/
@SaCheckPermission("sysDataPerm.view")
@PostMapping("/listDataPermUser")
public ResponseResult<MyPageData<SysUserVo>> listDataPermUser(
@MyRequestBody Long dataPermId,
@MyRequestBody SysUserDto sysUserDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doDataPermUserVerify(dataPermId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class);
List<SysUser> userList = sysUserService.getSysUserListByDataPermId(dataPermId, filter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(userList, SysUserVo.class));
}
/**
* 获取不包含指定数据权限Id的用户列表。
* 用户和数据权限是多对多关系当前接口将返回没有赋值指定DataPermId的用户列表。可用于给数据权限添加新用户。
*
* @param dataPermId 数据权限主键Id。
* @param sysUserDtoFilter 用户数据的过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含用户列表数据。
*/
@SaCheckPermission("sysDataPerm.update")
@PostMapping("/listNotInDataPermUser")
public ResponseResult<MyPageData<SysUserVo>> listNotInDataPermUser(
@MyRequestBody Long dataPermId,
@MyRequestBody SysUserDto sysUserDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doDataPermUserVerify(dataPermId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class);
List<SysUser> userList =
sysUserService.getNotInSysUserListByDataPermId(dataPermId, filter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(userList, SysUserVo.class));
}
/**
* 为指定数据权限添加用户列表。该操作可同时给一批用户赋值数据权限,并在同一事务内完成。
*
* @param dataPermId 数据权限主键Id。
* @param userIdListString 逗号分隔的用户Id列表。
* @return 应答结果对象。
*/
@SaCheckPermission("sysDataPerm.update")
@OperationLog(type = SysOperationLogType.ADD_M2M)
@PostMapping("/addDataPermUser")
public ResponseResult<Void> addDataPermUser(
@MyRequestBody Long dataPermId, @MyRequestBody String userIdListString) {
if (MyCommonUtil.existBlankArgument(dataPermId, userIdListString)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
Set<Long> userIdSet =
Arrays.stream(userIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet());
if (!sysDataPermService.existId(dataPermId)
|| !sysUserService.existUniqueKeyList("userId", userIdSet)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
sysDataPermService.addDataPermUserList(dataPermId, userIdSet);
return ResponseResult.success();
}
/**
* 为指定用户移除指定数据权限。
*
* @param dataPermId 指定数据权限主键Id。
* @param userId 指定用户主键Id。
* @return 应答数据结果。
*/
@SaCheckPermission("sysDataPerm.update")
@OperationLog(type = SysOperationLogType.DELETE_M2M)
@PostMapping("/deleteDataPermUser")
public ResponseResult<Void> deleteDataPermUser(
@MyRequestBody Long dataPermId, @MyRequestBody Long userId) {
if (MyCommonUtil.existBlankArgument(dataPermId, userId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysDataPermService.removeDataPermUser(dataPermId, userId)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 以字典形式返回全部数据权限管理数据集合。字典的键值为[dataPermId, dataPermName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject SysDataPermDto filter) {
List<SysDataPerm> resultList =
sysDataPermService.getListByFilter(MyModelUtil.copyTo(filter, SysDataPerm.class));
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, SysDataPerm::getDataPermId, SysDataPerm::getDataPermName));
}
private ResponseResult<Void> doDataPermUserVerify(Long dataPermId) {
if (MyCommonUtil.existBlankArgument(dataPermId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysDataPermService.existId(dataPermId)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
return ResponseResult.success();
}
}

View File

@@ -0,0 +1,428 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ObjectUtil;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.webadmin.upms.vo.*;
import com.orangeforms.webadmin.upms.dto.*;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.webadmin.upms.service.*;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.*;
import com.orangeforms.common.core.constant.*;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
/**
* 部门管理操作控制器类。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "部门管理管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysDept")
public class SysDeptController {
@Autowired
private SysPostService sysPostService;
@Autowired
private SysDeptService sysDeptService;
/**
* 新增部门管理数据。
*
* @param sysDeptDto 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"sysDeptDto.deptId"})
@SaCheckPermission("sysDept.add")
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody SysDeptDto sysDeptDto) {
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto, false);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysDept sysDept = MyModelUtil.copyTo(sysDeptDto, SysDept.class);
// 验证父Id的数据合法性
SysDept parentSysDept = null;
if (MyCommonUtil.isNotBlankOrNull(sysDept.getParentId())) {
parentSysDept = sysDeptService.getById(sysDept.getParentId());
if (parentSysDept == null) {
errorMessage = "数据验证失败,关联的父节点并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage);
}
}
sysDept = sysDeptService.saveNew(sysDept, parentSysDept);
return ResponseResult.success(sysDept.getDeptId());
}
/**
* 更新部门管理数据。
*
* @param sysDeptDto 更新对象。
* @return 应答结果对象。
*/
@SaCheckPermission("sysDept.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody SysDeptDto sysDeptDto) {
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto, true);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysDept sysDept = MyModelUtil.copyTo(sysDeptDto, SysDept.class);
SysDept originalSysDept = sysDeptService.getById(sysDept.getDeptId());
if (originalSysDept == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
// 验证父Id的数据合法性
if (MyCommonUtil.isNotBlankOrNull(sysDept.getParentId())
&& ObjectUtil.notEqual(sysDept.getParentId(), originalSysDept.getParentId())) {
SysDept parentSysDept = sysDeptService.getById(sysDept.getParentId());
if (parentSysDept == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,关联的 [父节点] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage);
}
}
if (!sysDeptService.update(sysDept, originalSysDept)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除部门管理数据。
*
* @param deptId 删除对象主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("sysDept.delete")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long deptId) {
if (MyCommonUtil.existBlankArgument(deptId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
return this.doDelete(deptId);
}
/**
* 批量删除部门管理数据。
*
* @param deptIdList 待删除对象的主键Id列表。
* @return 应答结果对象。
*/
@SaCheckPermission("sysDept.delete")
@OperationLog(type = SysOperationLogType.DELETE_BATCH)
@PostMapping("/deleteBatch")
public ResponseResult<Void> deleteBatch(@MyRequestBody List<Long> deptIdList) {
if (MyCommonUtil.existBlankArgument(deptIdList)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
for (Long deptId : deptIdList) {
ResponseResult<Void> responseResult = this.doDelete(deptId);
if (!responseResult.isSuccess()) {
return responseResult;
}
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的部门管理列表。
*
* @param sysDeptDtoFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@SaCheckPermission("sysDept.view")
@PostMapping("/list")
public ResponseResult<MyPageData<SysDeptVo>> list(
@MyRequestBody SysDeptDto sysDeptDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
SysDept sysDeptFilter = MyModelUtil.copyTo(sysDeptDtoFilter, SysDept.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysDept.class);
List<SysDept> sysDeptList = sysDeptService.getSysDeptListWithRelation(sysDeptFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(sysDeptList, SysDeptVo.class));
}
/**
* 查看指定部门管理对象详情。
*
* @param deptId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@SaCheckPermission("sysDept.view")
@GetMapping("/view")
public ResponseResult<SysDeptVo> view(@RequestParam Long deptId) {
SysDept sysDept = sysDeptService.getByIdWithRelation(deptId, MyRelationParam.full());
if (sysDept == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysDeptVo sysDeptVo = MyModelUtil.copyTo(sysDept, SysDeptVo.class);
return ResponseResult.success(sysDeptVo);
}
/**
* 列出不与指定部门管理存在多对多关系的 [岗位管理] 列表数据。通常用于查看添加新 [岗位管理] 对象的候选列表。
*
* @param deptId 主表关联字段。
* @param sysPostDtoFilter [岗位管理] 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,返回符合条件的数据列表。
*/
@SaCheckPermission("sysDept.update")
@PostMapping("/listNotInSysDeptPost")
public ResponseResult<MyPageData<SysPostVo>> listNotInSysDeptPost(
@MyRequestBody Long deptId,
@MyRequestBody SysPostDto sysPostDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (MyCommonUtil.isNotBlankOrNull(deptId) && !sysDeptService.existId(deptId)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysPost filter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class);
List<SysPost> sysPostList;
if (MyCommonUtil.isNotBlankOrNull(deptId)) {
sysPostList = sysPostService.getNotInSysPostListByDeptId(deptId, filter, orderBy);
} else {
sysPostList = sysPostService.getSysPostList(filter, orderBy);
sysPostService.buildRelationForDataList(sysPostList, MyRelationParam.dictOnly());
}
return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPostVo.class));
}
/**
* 列出与指定部门管理存在多对多关系的 [岗位管理] 列表数据。
*
* @param deptId 主表关联字段。
* @param sysPostDtoFilter [岗位管理] 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,返回符合条件的数据列表。
*/
@SaCheckPermission("sysDept.view")
@PostMapping("/listSysDeptPost")
public ResponseResult<MyPageData<SysPostVo>> listSysDeptPost(
@MyRequestBody(required = true) Long deptId,
@MyRequestBody SysPostDto sysPostDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (!sysDeptService.existId(deptId)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysPost filter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class);
List<SysPost> sysPostList = sysPostService.getSysPostListByDeptId(deptId, filter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPostVo.class));
}
/**
* 批量添加部门管理和 [岗位管理] 对象的多对多关联关系数据。
*
* @param deptId 主表主键Id。
* @param sysDeptPostDtoList 关联对象列表。
* @return 应答结果对象。
*/
@SaCheckPermission("sysDept.update")
@PostMapping("/addSysDeptPost")
public ResponseResult<Void> addSysDeptPost(
@MyRequestBody Long deptId,
@MyRequestBody List<SysDeptPostDto> sysDeptPostDtoList) {
if (MyCommonUtil.existBlankArgument(deptId, sysDeptPostDtoList)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptPostDtoList);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
Set<Long> postIdSet = sysDeptPostDtoList.stream().map(SysDeptPostDto::getPostId).collect(Collectors.toSet());
if (!sysDeptService.existId(deptId) || !sysPostService.existUniqueKeyList("postId", postIdSet)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
List<SysDeptPost> sysDeptPostList = MyModelUtil.copyCollectionTo(sysDeptPostDtoList, SysDeptPost.class);
sysDeptService.addSysDeptPostList(sysDeptPostList, deptId);
return ResponseResult.success();
}
/**
* 更新指定部门管理和指定 [岗位管理] 的多对多关联数据。
*
* @param sysDeptPostDto 对多对中间表对象。
* @return 应答结果对象。
*/
@SaCheckPermission("sysDept.update")
@PostMapping("/updateSysDeptPost")
public ResponseResult<Void> updateSysDeptPost(@MyRequestBody SysDeptPostDto sysDeptPostDto) {
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptPostDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysDeptPost sysDeptPost = MyModelUtil.copyTo(sysDeptPostDto, SysDeptPost.class);
if (!sysDeptService.updateSysDeptPost(sysDeptPost)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 显示部门管理和指定 [岗位管理] 的多对多关联详情数据。
*
* @param deptId 主表主键Id。
* @param postId 从表主键Id。
* @return 应答结果对象,包括中间表详情。
*/
@SaCheckPermission("sysDept.update")
@GetMapping("/viewSysDeptPost")
public ResponseResult<SysDeptPostVo> viewSysDeptPost(@RequestParam Long deptId, @RequestParam Long postId) {
SysDeptPost sysDeptPost = sysDeptService.getSysDeptPost(deptId, postId);
if (sysDeptPost == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysDeptPostVo sysDeptPostVo = MyModelUtil.copyTo(sysDeptPost, SysDeptPostVo.class);
return ResponseResult.success(sysDeptPostVo);
}
/**
* 移除指定部门管理和指定 [岗位管理] 的多对多关联关系。
*
* @param deptId 主表主键Id。
* @param postId 从表主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("sysDept.update")
@PostMapping("/deleteSysDeptPost")
public ResponseResult<Void> deleteSysDeptPost(@MyRequestBody Long deptId, @MyRequestBody Long postId) {
if (MyCommonUtil.existBlankArgument(deptId, postId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysDeptService.removeSysDeptPost(deptId, postId)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 获取部门岗位多对多关联数据,及其关联的部门和岗位数据。
*
* @param deptId 部门Id如果为空返回全部数据列表。
* @return 部门岗位多对多关联数据,及其关联的部门和岗位数据
*/
@GetMapping("/listSysDeptPostWithRelation")
public ResponseResult<List<Map<String, Object>>> listSysDeptPostWithRelation(
@RequestParam(required = false) Long deptId) {
return ResponseResult.success(sysDeptService.getSysDeptPostListWithRelationByDeptId(deptId));
}
/**
* 以字典形式返回全部部门管理数据集合。字典的键值为[deptId, deptName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject SysDeptDto filter) {
List<SysDept> resultList =
sysDeptService.getListByFilter(MyModelUtil.copyTo(filter, SysDept.class));
return ResponseResult.success(MyCommonUtil.toDictDataList(
resultList, SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId));
}
/**
* 根据字典Id集合获取查询后的字典数据。
*
* @param dictIds 字典Id集合。
* @return 应答结果对象,包含字典形式的数据集合。
*/
@GetMapping("/listDictByIds")
public ResponseResult<List<Map<String, Object>>> listDictByIds(@RequestParam List<Long> dictIds) {
List<SysDept> resultList = sysDeptService.getInList(new HashSet<>(dictIds));
return ResponseResult.success(MyCommonUtil.toDictDataList(
resultList, SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId));
}
/**
* 根据父主键Id以字典的形式返回其下级数据列表。
* 白名单接口,登录用户均可访问。
*
* @param parentId 父主键Id。
* @return 按照字典的形式返回下级数据列表。
*/
@GetMapping("/listDictByParentId")
public ResponseResult<List<Map<String, Object>>> listDictByParentId(@RequestParam(required = false) Long parentId) {
List<SysDept> resultList = sysDeptService.getListByParentId("parentId", parentId);
return ResponseResult.success(MyCommonUtil.toDictDataList(
resultList, SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId));
}
/**
* 根据父主键Id列表获取当前部门Id及其所有下级部门Id列表。
* 白名单接口,登录用户均可访问。
*
* @param parentIds 父主键Id列表多个Id之间逗号分隔。
* @return 获取当前部门Id及其所有下级部门Id列表。
*/
@GetMapping("/listAllChildDeptIdByParentIds")
public ResponseResult<List<Long>> listAllChildDeptIdByParentIds(
@RequestParam(required = false) String parentIds) {
List<Long> parentIdList = StrUtil.split(parentIds, ',')
.stream().map(Long::valueOf).collect(Collectors.toList());
return ResponseResult.success(sysDeptService.getAllChildDeptIdByParentIds(parentIdList));
}
private ResponseResult<Void> doDelete(Long deptId) {
String errorMessage;
// 验证关联Id的数据合法性
SysDept originalSysDept = sysDeptService.getById(deptId);
if (originalSysDept == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (sysDeptService.hasChildren(deptId)) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象存在子对象] ,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage);
}
if (sysDeptService.hasChildrenUser(deptId)) {
errorMessage = "数据验证失败,请先移除部门用户数据后,再删除当前部门!";
return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage);
}
if (!sysDeptService.remove(deptId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
}

View File

@@ -0,0 +1,231 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import com.orangeforms.webadmin.upms.dto.SysMenuDto;
import com.orangeforms.webadmin.upms.vo.SysMenuVo;
import com.orangeforms.webadmin.upms.model.SysMenu;
import com.orangeforms.webadmin.upms.model.SysDataPerm;
import com.orangeforms.webadmin.upms.model.constant.SysMenuType;
import com.orangeforms.webadmin.upms.service.SysMenuService;
import com.orangeforms.webadmin.upms.service.SysDataPermService;
import com.orangeforms.common.core.constant.ErrorCodeEnum;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.*;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.groups.Default;
import java.util.*;
import java.util.stream.Collectors;
/**
* 菜单管理接口控制器类。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "菜单管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysMenu")
public class SysMenuController {
@Autowired
private SysMenuService sysMenuService;
@Autowired
private SysDataPermService sysDataPermService;
/**
* 添加新菜单操作。
*
* @param sysMenuDto 新菜单对象。
* @return 应答结果对象包含新增菜单的主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"sysMenuDto.menuId"})
@SaCheckPermission("sysMenu.add")
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody SysMenuDto sysMenuDto) {
String errorMessage = MyCommonUtil.getModelValidationError(sysMenuDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysMenu sysMenu = MyModelUtil.copyTo(sysMenuDto, SysMenu.class);
if (sysMenu.getParentId() != null) {
SysMenu parentSysMenu = sysMenuService.getById(sysMenu.getParentId());
if (parentSysMenu == null) {
errorMessage = "数据验证失败,关联的父菜单不存在!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (parentSysMenu.getOnlineFormId() != null) {
errorMessage = "数据验证失败,不能为动态表单菜单添加子菜单!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
}
CallResult result = sysMenuService.verifyRelatedData(sysMenu, null);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
sysMenuService.saveNew(sysMenu);
return ResponseResult.success(sysMenu.getMenuId());
}
/**
* 更新菜单数据操作。
*
* @param sysMenuDto 新菜单对象。
* @return 应答结果对象。
*/
@SaCheckPermission("sysMenu.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody SysMenuDto sysMenuDto) {
String errorMessage = MyCommonUtil.getModelValidationError(sysMenuDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysMenu originalSysMenu = sysMenuService.getById(sysMenuDto.getMenuId());
if (originalSysMenu == null) {
errorMessage = "数据验证失败,当前菜单并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
SysMenu sysMenu = MyModelUtil.copyTo(sysMenuDto, SysMenu.class);
if (ObjectUtil.notEqual(originalSysMenu.getOnlineFormId(), sysMenu.getOnlineFormId())) {
if (originalSysMenu.getOnlineFormId() == null) {
errorMessage = "数据验证失败不能为当前菜单添加在线表单Id属性";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (sysMenu.getOnlineFormId() == null) {
errorMessage = "数据验证失败不能去掉当前菜单的在线表单Id属性";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
}
if (originalSysMenu.getOnlineFormId() != null
&& originalSysMenu.getMenuType().equals(SysMenuType.TYPE_BUTTON)) {
errorMessage = "数据验证失败,在线表单的内置菜单不能编辑!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
CallResult result = sysMenuService.verifyRelatedData(sysMenu, originalSysMenu);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
if (!sysMenuService.update(sysMenu, originalSysMenu)) {
errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 删除指定菜单操作。
*
* @param menuId 指定菜单主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("sysMenu.delete")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long menuId) {
if (MyCommonUtil.existBlankArgument(menuId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
String errorMessage;
SysMenu menu = sysMenuService.getById(menuId);
if (menu == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
if (menu.getOnlineFormId() != null && menu.getMenuType().equals(SysMenuType.TYPE_BUTTON)) {
errorMessage = "数据验证失败,在线表单的内置菜单不能删除!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
// 对于在线表单,无需进行子菜单的验证,而是在删除的时候,连同子菜单一起删除。
if (menu.getOnlineFormId() == null && sysMenuService.hasChildren(menuId)) {
errorMessage = "数据验证失败,当前菜单存在下级菜单!";
return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage);
}
List<SysDataPerm> dataPermList = sysDataPermService.getSysDataPermListByMenuId(menuId);
if (CollUtil.isNotEmpty(dataPermList)) {
SysDataPerm dataPerm = dataPermList.get(0);
errorMessage = "数据验证失败,当前菜单正在被数据权限 [" + dataPerm.getDataPermName() + "] 引用,不能直接删除!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!sysMenuService.remove(menu)) {
errorMessage = "数据操作失败,菜单不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 获取全部菜单列表。
*
* @return 应答结果对象,包含全部菜单数据列表。
*/
@SaCheckPermission("sysMenu.view")
@PostMapping("/list")
public ResponseResult<List<SysMenuVo>> list() {
List<SysMenu> resultList = this.getAllMenuListByShowOrder();
return ResponseResult.success(MyModelUtil.copyCollectionTo(resultList, SysMenuVo.class));
}
/**
* 查看指定菜单数据详情。
*
* @param menuId 指定菜单主键Id。
* @return 应答结果对象,包含菜单详情。
*/
@SaCheckPermission("sysMenu.view")
@GetMapping("/view")
public ResponseResult<SysMenuVo> view(@RequestParam Long menuId) {
if (MyCommonUtil.existBlankArgument(menuId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
SysMenu sysMenu = sysMenuService.getByIdWithRelation(menuId, MyRelationParam.full());
if (sysMenu == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysMenuVo sysMenuVo = MyModelUtil.copyTo(sysMenu, SysMenuVo.class);
return ResponseResult.success(sysMenuVo);
}
/**
* 以字典形式返回目录和菜单类型的菜单管理数据集合。字典的键值为[menuId, menuName]。
* 白名单接口,登录用户均可访问。
*
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listMenuDict")
public ResponseResult<List<Map<String, Object>>> listMenuDict() {
List<SysMenu> resultList = this.getAllMenuListByShowOrder();
resultList = resultList.stream()
.filter(m -> m.getMenuType() <= SysMenuType.TYPE_MENU).collect(Collectors.toList());
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, SysMenu::getMenuId, SysMenu::getMenuName, SysMenu::getParentId));
}
/**
* 以字典形式返回全部的菜单管理数据集合。字典的键值为[menuId, menuName]。
* 白名单接口,登录用户均可访问。
*
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict() {
List<SysMenu> resultList = this.getAllMenuListByShowOrder();
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, SysMenu::getMenuId, SysMenu::getMenuName, SysMenu::getParentId));
}
private List<SysMenu> getAllMenuListByShowOrder() {
return sysMenuService.getAllListByOrder("showOrder");
}
}

View File

@@ -0,0 +1,63 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.MyPageUtil;
import com.orangeforms.common.log.model.SysOperationLog;
import com.orangeforms.common.log.service.SysOperationLogService;
import com.orangeforms.common.log.dto.SysOperationLogDto;
import com.orangeforms.common.log.vo.SysOperationLogVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 操作日志接口控制器对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "操作日志接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysOperationLog")
public class SysOperationLogController {
@Autowired
private SysOperationLogService operationLogService;
/**
* 数据权限列表。
*
* @param sysOperationLogDtoFilter 操作日志查询过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象。包含操作日志列表。
*/
@SaCheckPermission("sysOperationLog.view")
@PostMapping("/list")
public ResponseResult<MyPageData<SysOperationLogVo>> list(
@MyRequestBody SysOperationLogDto sysOperationLogDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysOperationLog filter = MyModelUtil.copyTo(sysOperationLogDtoFilter, SysOperationLog.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysOperationLog.class);
List<SysOperationLog> operationLogList = operationLogService.getSysOperationLogList(filter, orderBy);
List<SysOperationLogVo> operationLogVoList = MyModelUtil.copyCollectionTo(operationLogList, SysOperationLogVo.class);
long totalCount = 0L;
if (operationLogList instanceof Page) {
totalCount = ((Page<SysOperationLog>) operationLogList).getTotal();
}
return ResponseResult.success(MyPageUtil.makeResponseData(operationLogVoList, totalCount));
}
}

View File

@@ -0,0 +1,183 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.*;
import com.orangeforms.common.core.constant.*;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.webadmin.upms.dto.SysPostDto;
import com.orangeforms.webadmin.upms.model.SysPost;
import com.orangeforms.webadmin.upms.service.SysPostService;
import com.orangeforms.webadmin.upms.vo.SysPostVo;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import jakarta.validation.groups.Default;
/**
* 岗位管理操作控制器类。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "岗位管理操作管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysPost")
public class SysPostController {
@Autowired
private SysPostService sysPostService;
/**
* 新增岗位管理数据。
*
* @param sysPostDto 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"sysPostDto.postId"})
@SaCheckPermission("sysPost.add")
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody SysPostDto sysPostDto) {
String errorMessage = MyCommonUtil.getModelValidationError(sysPostDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysPost sysPost = MyModelUtil.copyTo(sysPostDto, SysPost.class);
sysPost = sysPostService.saveNew(sysPost);
return ResponseResult.success(sysPost.getPostId());
}
/**
* 更新岗位管理数据。
*
* @param sysPostDto 更新对象。
* @return 应答结果对象。
*/
@SaCheckPermission("sysPost.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody SysPostDto sysPostDto) {
String errorMessage = MyCommonUtil.getModelValidationError(sysPostDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysPost sysPost = MyModelUtil.copyTo(sysPostDto, SysPost.class);
SysPost originalSysPost = sysPostService.getById(sysPost.getPostId());
if (originalSysPost == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!sysPostService.update(sysPost, originalSysPost)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除岗位管理数据。
*
* @param postId 删除对象主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("sysPost.delete")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long postId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(postId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
SysPost originalSysPost = sysPostService.getById(postId);
if (originalSysPost == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!sysPostService.remove(postId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的岗位管理列表。
*
* @param sysPostDtoFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@SaCheckPermission("sysPost.view")
@PostMapping("/list")
public ResponseResult<MyPageData<SysPostVo>> list(
@MyRequestBody SysPostDto sysPostDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysPost sysPostFilter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class);
List<SysPost> sysPostList = sysPostService.getSysPostListWithRelation(sysPostFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPostVo.class));
}
/**
* 查看指定岗位管理对象详情。
*
* @param postId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@SaCheckPermission("sysPost.view")
@GetMapping("/view")
public ResponseResult<SysPostVo> view(@RequestParam Long postId) {
if (MyCommonUtil.existBlankArgument(postId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
SysPost sysPost = sysPostService.getByIdWithRelation(postId, MyRelationParam.full());
if (sysPost == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysPostVo sysPostVo = MyModelUtil.copyTo(sysPost, SysPostVo.class);
return ResponseResult.success(sysPostVo);
}
/**
* 以字典形式返回全部岗位管理数据集合。字典的键值为[postId, postName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject SysPostDto filter) {
List<SysPost> resultList = sysPostService.getListByFilter(MyModelUtil.copyTo(filter, SysPost.class));
return ResponseResult.success(MyCommonUtil.toDictDataList(resultList, SysPost::getPostId, SysPost::getPostName));
}
/**
* 根据字典Id集合获取查询后的字典数据。
*
* @param postIds 字典Id集合。
* @return 应答结果对象,包含字典形式的数据集合。
*/
@GetMapping("/listDictByIds")
public ResponseResult<List<Map<String, Object>>> listDictByIds(@RequestParam List<Long> postIds) {
List<SysPost> resultList = sysPostService.getInList(new HashSet<>(postIds));
return ResponseResult.success(MyCommonUtil.toDictDataList(resultList, SysPost::getPostId, SysPost::getPostName));
}
}

View File

@@ -0,0 +1,331 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.alibaba.fastjson.TypeReference;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import lombok.extern.slf4j.Slf4j;
import com.orangeforms.webadmin.upms.dto.SysRoleDto;
import com.orangeforms.webadmin.upms.dto.SysUserDto;
import com.orangeforms.webadmin.upms.vo.SysRoleVo;
import com.orangeforms.webadmin.upms.vo.SysUserVo;
import com.orangeforms.webadmin.upms.model.SysRole;
import com.orangeforms.webadmin.upms.model.SysUser;
import com.orangeforms.webadmin.upms.model.SysUserRole;
import com.orangeforms.webadmin.upms.service.SysRoleService;
import com.orangeforms.webadmin.upms.service.SysUserService;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.common.core.constant.ErrorCodeEnum;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.*;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.groups.Default;
import java.util.*;
import java.util.stream.Collectors;
/**
* 角色管理接口控制器类。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "角色管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysRole")
public class SysRoleController {
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysUserService sysUserService;
/**
* 新增角色操作。
*
* @param sysRoleDto 新增角色对象。
* @param menuIdListString 与当前角色Id绑定的menuId列表多个menuId之间逗号分隔。
* @return 应答结果对象包含新增角色的主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"sysRoleDto.roleId", "sysRoleDto.createTimeStart", "sysRoleDto.createTimeEnd"})
@SaCheckPermission("sysRole.add")
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(
@MyRequestBody SysRoleDto sysRoleDto, @MyRequestBody String menuIdListString) {
String errorMessage = MyCommonUtil.getModelValidationError(sysRoleDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysRole sysRole = MyModelUtil.copyTo(sysRoleDto, SysRole.class);
CallResult result = sysRoleService.verifyRelatedData(sysRole, null, menuIdListString);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
Set<Long> menuIdSet = null;
if (result.getData() != null) {
menuIdSet = result.getData().getObject("menuIdSet", new TypeReference<Set<Long>>(){});
}
sysRoleService.saveNew(sysRole, menuIdSet);
return ResponseResult.success(sysRole.getRoleId());
}
/**
* 更新角色操作。
*
* @param sysRoleDto 更新角色对象。
* @param menuIdListString 与当前角色Id绑定的menuId列表多个menuId之间逗号分隔。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {"sysRoleDto.createTimeStart", "sysRoleDto.createTimeEnd"})
@SaCheckPermission("sysRole.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(
@MyRequestBody SysRoleDto sysRoleDto, @MyRequestBody String menuIdListString) {
String errorMessage = MyCommonUtil.getModelValidationError(sysRoleDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysRole originalSysRole = sysRoleService.getById(sysRoleDto.getRoleId());
if (originalSysRole == null) {
errorMessage = "数据验证失败,当前角色并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
SysRole sysRole = MyModelUtil.copyTo(sysRoleDto, SysRole.class);
CallResult result = sysRoleService.verifyRelatedData(sysRole, originalSysRole, menuIdListString);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
Set<Long> menuIdSet = null;
if (result.getData() != null) {
menuIdSet = result.getData().getObject("menuIdSet", new TypeReference<Set<Long>>(){});
}
if (!sysRoleService.update(sysRole, originalSysRole, menuIdSet)) {
errorMessage = "更新失败,数据不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 删除指定角色操作。
*
* @param roleId 指定角色主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("sysRole.delete")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long roleId) {
if (MyCommonUtil.existBlankArgument(roleId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysRoleService.remove(roleId)) {
String errorMessage = "数据操作失败,角色不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 查看角色列表。
*
* @param sysRoleDtoFilter 角色过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含角色列表。
*/
@SaCheckPermission("sysRole.view")
@PostMapping("/list")
public ResponseResult<MyPageData<SysRoleVo>> list(
@MyRequestBody SysRoleDto sysRoleDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysRole filter = MyModelUtil.copyTo(sysRoleDtoFilter, SysRole.class);
List<SysRole> roleList = sysRoleService.getSysRoleList(
filter, MyOrderParam.buildOrderBy(orderParam, SysRole.class));
List<SysRoleVo> roleVoList = MyModelUtil.copyCollectionTo(roleList, SysRoleVo.class);
long totalCount = 0L;
if (roleList instanceof Page) {
totalCount = ((Page<SysRole>) roleList).getTotal();
}
return ResponseResult.success(MyPageUtil.makeResponseData(roleVoList, totalCount));
}
/**
* 查看角色详情。
*
* @param roleId 指定角色主键Id。
* @return 应答结果对象,包含角色详情对象。
*/
@SaCheckPermission("sysRole.view")
@GetMapping("/view")
public ResponseResult<SysRoleVo> view(@RequestParam Long roleId) {
if (MyCommonUtil.existBlankArgument(roleId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
SysRole sysRole = sysRoleService.getByIdWithRelation(roleId, MyRelationParam.full());
if (sysRole == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysRoleVo sysRoleVo = MyModelUtil.copyTo(sysRole, SysRoleVo.class);
return ResponseResult.success(sysRoleVo);
}
/**
* 拥有指定角色的用户列表。
*
* @param roleId 角色主键Id。
* @param sysUserDtoFilter 用户过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含用户列表数据。
*/
@SaCheckPermission("sysRole.view")
@PostMapping("/listUserRole")
public ResponseResult<MyPageData<SysUserVo>> listUserRole(
@MyRequestBody Long roleId,
@MyRequestBody SysUserDto sysUserDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doRoleUserVerify(roleId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class);
List<SysUser> userList = sysUserService.getSysUserListByRoleId(roleId, filter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(userList, SysUserVo.class));
}
/**
* 获取不包含指定角色Id的用户列表。
* 用户和角色是多对多关系当前接口将返回没有赋值指定RoleId的用户列表。可用于给角色添加新用户。
*
* @param roleId 角色主键Id。
* @param sysUserDtoFilter 用户过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含用户列表数据。
*/
@SaCheckPermission("sysRole.update")
@PostMapping("/listNotInUserRole")
public ResponseResult<MyPageData<SysUserVo>> listNotInUserRole(
@MyRequestBody Long roleId,
@MyRequestBody SysUserDto sysUserDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doRoleUserVerify(roleId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class);
List<SysUser> userList = sysUserService.getNotInSysUserListByRoleId(roleId, filter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(userList, SysUserVo.class));
}
/**
* 为指定角色添加用户列表。该操作可同时给一批用户赋值角色,并在同一事务内完成。
*
* @param roleId 角色主键Id。
* @param userIdListString 逗号分隔的用户Id列表。
* @return 应答结果对象。
*/
@SaCheckPermission("sysRole.update")
@OperationLog(type = SysOperationLogType.ADD_M2M)
@PostMapping("/addUserRole")
public ResponseResult<Void> addUserRole(@MyRequestBody Long roleId, @MyRequestBody String userIdListString) {
if (MyCommonUtil.existBlankArgument(roleId, userIdListString)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
Set<Long> userIdSet = Arrays.stream(
userIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet());
if (!sysRoleService.existId(roleId)
|| !sysUserService.existUniqueKeyList("userId", userIdSet)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
List<SysUserRole> userRoleList = new LinkedList<>();
for (Long userId : userIdSet) {
SysUserRole userRole = new SysUserRole();
userRole.setRoleId(roleId);
userRole.setUserId(userId);
userRoleList.add(userRole);
}
sysRoleService.addUserRoleList(userRoleList);
return ResponseResult.success();
}
/**
* 为指定用户移除指定角色。
*
* @param roleId 指定角色主键Id。
* @param userId 指定用户主键Id。
* @return 应答数据结果。
*/
@SaCheckPermission("sysRole.update")
@OperationLog(type = SysOperationLogType.DELETE_M2M)
@PostMapping("/deleteUserRole")
public ResponseResult<Void> deleteUserRole(@MyRequestBody Long roleId, @MyRequestBody Long userId) {
if (MyCommonUtil.existBlankArgument(roleId, userId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysRoleService.removeUserRole(roleId, userId)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 以字典形式返回全部角色管理数据集合。字典的键值为[roleId, roleName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject SysRoleDto filter) {
List<SysRole> resultList = sysRoleService.getListByFilter(MyModelUtil.copyTo(filter, SysRole.class));
return ResponseResult.success(MyCommonUtil.toDictDataList(resultList, SysRole::getRoleId, SysRole::getRoleName));
}
/**
* 根据字典Id集合获取查询后的字典数据。
*
* @param dictIds 字典Id集合。
* @return 应答结果对象,包含字典形式的数据集合。
*/
@GetMapping("/listDictByIds")
public ResponseResult<List<Map<String, Object>>> listDictByIds(@RequestParam List<Long> dictIds) {
List<SysRole> resultList = sysRoleService.getInList(new HashSet<>(dictIds));
return ResponseResult.success(MyCommonUtil.toDictDataList(resultList, SysRole::getRoleId, SysRole::getRoleName));
}
private ResponseResult<Void> doRoleUserVerify(Long roleId) {
if (MyCommonUtil.existBlankArgument(roleId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysRoleService.existId(roleId)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
return ResponseResult.success();
}
}

View File

@@ -0,0 +1,378 @@
package com.orangeforms.webadmin.upms.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.alibaba.fastjson.TypeReference;
import cn.hutool.core.util.ReflectUtil;
import com.orangeforms.common.core.upload.BaseUpDownloader;
import com.orangeforms.common.core.upload.UpDownloaderFactory;
import com.orangeforms.common.core.upload.UploadResponseInfo;
import com.orangeforms.common.core.upload.UploadStoreInfo;
import com.orangeforms.common.log.annotation.OperationLog;
import com.orangeforms.common.log.model.constant.SysOperationLogType;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.webadmin.upms.vo.*;
import com.orangeforms.webadmin.upms.dto.*;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.webadmin.upms.service.*;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.*;
import com.orangeforms.common.core.constant.*;
import com.orangeforms.common.core.annotation.MyRequestBody;
import com.orangeforms.common.redis.cache.SessionCacheHelper;
import com.orangeforms.webadmin.config.ApplicationConfig;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
* 用户管理操作控制器类。
*
* @author Jerry
* @date 2024-07-02
*/
@Tag(name = "用户管理管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysUser")
public class SysUserController {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private ApplicationConfig appConfig;
@Autowired
private SessionCacheHelper cacheHelper;
@Autowired
private UpDownloaderFactory upDownloaderFactory;
@Autowired
private SysUserService sysUserService;
/**
* 新增用户操作。
*
* @param sysUserDto 新增用户对象。
* @param deptPostIdListString 逗号分隔的部门岗位Id列表。
* @param dataPermIdListString 逗号分隔的数据权限Id列表。
* @param roleIdListString 逗号分隔的角色Id列表。
* @return 应答结果对象包含新增用户的主键Id。
*/
@ApiOperationSupport(ignoreParameters = {
"sysUserDto.userId",
"sysUserDto.createTimeStart",
"sysUserDto.createTimeEnd"})
@SaCheckPermission("sysUser.add")
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(
@MyRequestBody SysUserDto sysUserDto,
@MyRequestBody String deptPostIdListString,
@MyRequestBody String dataPermIdListString,
@MyRequestBody String roleIdListString) {
String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, false);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysUser sysUser = MyModelUtil.copyTo(sysUserDto, SysUser.class);
CallResult result = sysUserService.verifyRelatedData(
sysUser, null, roleIdListString, deptPostIdListString, dataPermIdListString);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
Set<Long> deptPostIdSet = result.getData().getObject("deptPostIdSet", new TypeReference<Set<Long>>() {});
Set<Long> roleIdSet = result.getData().getObject("roleIdSet", new TypeReference<Set<Long>>() {});
Set<Long> dataPermIdSet = result.getData().getObject("dataPermIdSet", new TypeReference<Set<Long>>() {});
sysUserService.saveNew(sysUser, roleIdSet, deptPostIdSet, dataPermIdSet);
return ResponseResult.success(sysUser.getUserId());
}
/**
* 更新用户操作。
*
* @param sysUserDto 更新用户对象。
* @param deptPostIdListString 逗号分隔的部门岗位Id列表。
* @param dataPermIdListString 逗号分隔的数据权限Id列表。
* @param roleIdListString 逗号分隔的角色Id列表。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {
"sysUserDto.createTimeStart",
"sysUserDto.createTimeEnd"})
@SaCheckPermission("sysUser.update")
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(
@MyRequestBody SysUserDto sysUserDto,
@MyRequestBody String deptPostIdListString,
@MyRequestBody String dataPermIdListString,
@MyRequestBody String roleIdListString) {
String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, true);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
SysUser originalUser = sysUserService.getById(sysUserDto.getUserId());
if (originalUser == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysUser sysUser = MyModelUtil.copyTo(sysUserDto, SysUser.class);
CallResult result = sysUserService.verifyRelatedData(
sysUser, originalUser, roleIdListString, deptPostIdListString, dataPermIdListString);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage());
}
Set<Long> roleIdSet = result.getData().getObject("roleIdSet", new TypeReference<Set<Long>>() {});
Set<Long> deptPostIdSet = result.getData().getObject("deptPostIdSet", new TypeReference<Set<Long>>() {});
Set<Long> dataPermIdSet = result.getData().getObject("dataPermIdSet", new TypeReference<Set<Long>>() {});
if (!sysUserService.update(sysUser, originalUser, roleIdSet, deptPostIdSet, dataPermIdSet)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 重置密码操作。
*
* @param userId 指定用户主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("sysUser.resetPassword")
@PostMapping("/resetPassword")
public ResponseResult<Void> resetPassword(@MyRequestBody Long userId) {
if (MyCommonUtil.existBlankArgument(userId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysUserService.changePassword(userId, appConfig.getDefaultUserPassword())) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除用户管理数据。
*
* @param userId 删除对象主键Id。
* @return 应答结果对象。
*/
@SaCheckPermission("sysUser.delete")
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long userId) {
if (MyCommonUtil.existBlankArgument(userId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
return this.doDelete(userId);
}
/**
* 批量删除用户管理数据。
*
* @param userIdList 待删除对象的主键Id列表。
* @return 应答结果对象。
*/
@SaCheckPermission("sysUser.delete")
@OperationLog(type = SysOperationLogType.DELETE_BATCH)
@PostMapping("/deleteBatch")
public ResponseResult<Void> deleteBatch(@MyRequestBody List<Long> userIdList) {
if (MyCommonUtil.existBlankArgument(userIdList)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
for (Long userId : userIdList) {
ResponseResult<Void> responseResult = this.doDelete(userId);
if (!responseResult.isSuccess()) {
return responseResult;
}
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的用户管理列表。
*
* @param sysUserDtoFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@SaCheckPermission("sysUser.view")
@PostMapping("/list")
public ResponseResult<MyPageData<SysUserVo>> list(
@MyRequestBody SysUserDto sysUserDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
SysUser sysUserFilter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class);
List<SysUser> sysUserList = sysUserService.getSysUserListWithRelation(sysUserFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(sysUserList, SysUserVo.class));
}
/**
* 查看指定用户管理对象详情。
*
* @param userId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@SaCheckPermission("sysUser.view")
@GetMapping("/view")
public ResponseResult<SysUserVo> view(@RequestParam Long userId) {
// 这里查看用户数据时候需要把用户多对多关联的角色和数据权限Id一并查出。
SysUser sysUser = sysUserService.getByIdWithRelation(userId, MyRelationParam.full());
if (sysUser == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
SysUserVo sysUserVo = MyModelUtil.copyTo(sysUser, SysUserVo.class);
return ResponseResult.success(sysUserVo);
}
/**
* 附件文件下载。
* 这里将图片和其他类型的附件文件放到不同的父目录下,主要为了便于今后图片文件的迁移。
*
* @param userId 附件所在记录的主键Id。
* @param fieldName 附件所属的字段名。
* @param filename 文件名。如果没有提供该参数,就从当前记录的指定字段中读取。
* @param asImage 下载文件是否为图片。
* @param response Http 应答对象。
*/
@SaCheckPermission("sysUser.view")
@OperationLog(type = SysOperationLogType.DOWNLOAD, saveResponse = false)
@GetMapping("/download")
public void download(
@RequestParam(required = false) Long userId,
@RequestParam String fieldName,
@RequestParam String filename,
@RequestParam Boolean asImage,
HttpServletResponse response) {
if (MyCommonUtil.existBlankArgument(fieldName, filename, asImage)) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// 使用try来捕获异常是为了保证一旦出现异常可以返回500的错误状态便于调试。
// 否则有可能给前端返回的是200的错误码。
try {
// 如果请求参数中没有包含主键Id就判断该文件是否为当前session上传的。
if (userId == null) {
if (!cacheHelper.existSessionUploadFile(filename)) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN);
return;
}
} else {
SysUser sysUser = sysUserService.getById(userId);
if (sysUser == null) {
ResponseResult.output(HttpServletResponse.SC_NOT_FOUND);
return;
}
String fieldJsonData = (String) ReflectUtil.getFieldValue(sysUser, fieldName);
if (fieldJsonData == null && !cacheHelper.existSessionUploadFile(filename)) {
ResponseResult.output(HttpServletResponse.SC_BAD_REQUEST);
return;
}
if (!BaseUpDownloader.containFile(fieldJsonData, filename)
&& !cacheHelper.existSessionUploadFile(filename)) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(SysUser.class, fieldName);
if (!storeInfo.isSupportUpload()) {
ResponseResult.output(HttpServletResponse.SC_NOT_IMPLEMENTED,
ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD));
return;
}
BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType());
upDownloader.doDownload(appConfig.getUploadFileBaseDir(),
SysUser.class.getSimpleName(), fieldName, filename, asImage, response);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
log.error(e.getMessage(), e);
}
}
/**
* 文件上传操作。
*
* @param fieldName 上传文件名。
* @param asImage 是否作为图片上传。如果是图片,今后下载的时候无需权限验证。否则就是附件上传,下载时需要权限验证。
* @param uploadFile 上传文件对象。
*/
@SaCheckPermission("sysUser.view")
@OperationLog(type = SysOperationLogType.UPLOAD, saveResponse = false)
@PostMapping("/upload")
public void upload(
@RequestParam String fieldName,
@RequestParam Boolean asImage,
@RequestParam("uploadFile") MultipartFile uploadFile) throws IOException {
UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(SysUser.class, fieldName);
// 这里就会判断参数中指定的字段,是否支持上传操作。
if (!storeInfo.isSupportUpload()) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN,
ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD));
return;
}
// 根据字段注解中的存储类型,通过工厂方法获取匹配的上传下载实现类,从而解耦。
BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType());
UploadResponseInfo responseInfo = upDownloader.doUpload(null,
appConfig.getUploadFileBaseDir(), SysUser.class.getSimpleName(), fieldName, asImage, uploadFile);
if (Boolean.TRUE.equals(responseInfo.getUploadFailed())) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN,
ResponseResult.error(ErrorCodeEnum.UPLOAD_FAILED, responseInfo.getErrorMessage()));
return;
}
cacheHelper.putSessionUploadFile(responseInfo.getFilename());
ResponseResult.output(ResponseResult.success(responseInfo));
}
/**
* 以字典形式返回全部用户管理数据集合。字典的键值为[userId, showName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject SysUserDto filter) {
List<SysUser> resultList =
sysUserService.getListByFilter(MyModelUtil.copyTo(filter, SysUser.class));
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, SysUser::getUserId, SysUser::getShowName));
}
/**
* 根据字典Id集合获取查询后的字典数据。
*
* @param dictIds 字典Id集合。
* @return 应答结果对象,包含字典形式的数据集合。
*/
@GetMapping("/listDictByIds")
public ResponseResult<List<Map<String, Object>>> listDictByIds(@RequestParam List<Long> dictIds) {
List<SysUser> resultList = sysUserService.getInList(new HashSet<>(dictIds));
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, SysUser::getUserId, SysUser::getShowName));
}
private ResponseResult<Void> doDelete(Long userId) {
String errorMessage;
// 验证关联Id的数据合法性
SysUser originalSysUser = sysUserService.getById(userId);
if (originalSysUser == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!sysUserService.remove(userId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysDataPermDept;
/**
* 数据权限与部门关系数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDataPermDeptMapper extends BaseDaoMapper<SysDataPermDept> {
}

View File

@@ -0,0 +1,43 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysDataPerm;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 数据权限数据访问操作接口。
* NOTE: 该对象一定不能被 @EnableDataPerm 注解标注,否则会导致无限递归。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDataPermMapper extends BaseDaoMapper<SysDataPerm> {
/**
* 获取数据权限列表。
*
* @param sysDataPermFilter 过滤对象。
* @param orderBy 排序字符串。
* @return 过滤后的数据权限列表。
*/
List<SysDataPerm> getSysDataPermList(
@Param("sysDataPermFilter") SysDataPerm sysDataPermFilter, @Param("orderBy") String orderBy);
/**
* 获取指定用户的数据权限列表。
*
* @param userId 用户Id。
* @return 数据权限列表。
*/
List<SysDataPerm> getSysDataPermListByUserId(@Param("userId") Long userId);
/**
* 查询与指定菜单关联的数据权限列表。
*
* @param menuId 菜单Id。
* @return 与菜单Id关联的数据权限列表。
*/
List<SysDataPerm> getSysDataPermListByMenuId(@Param("menuId") Long menuId);
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysDataPermMenu;
/**
* 数据权限与菜单关系数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDataPermMenuMapper extends BaseDaoMapper<SysDataPermMenu> {
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysDataPermUser;
/**
* 数据权限与用户关系数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDataPermUserMapper extends BaseDaoMapper<SysDataPermUser> {
}

View File

@@ -0,0 +1,33 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysDept;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 部门管理数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDeptMapper extends BaseDaoMapper<SysDept> {
/**
* 批量插入对象列表。
*
* @param sysDeptList 新增对象列表。
*/
void insertList(List<SysDept> sysDeptList);
/**
* 获取过滤后的对象列表。
*
* @param sysDeptFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<SysDept> getSysDeptList(
@Param("sysDeptFilter") SysDept sysDeptFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,33 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysDeptPost;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 部门岗位数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDeptPostMapper extends BaseDaoMapper<SysDeptPost> {
/**
* 获取指定部门Id的部门岗位多对多关联数据列表以及关联的部门和岗位数据。
*
* @param deptId 部门Id。如果参数为空则返回全部数据。
* @return 部门岗位多对多数据列表。
*/
List<Map<String, Object>> getSysDeptPostListWithRelationByDeptId(@Param("deptId") Long deptId);
/**
* 获取指定部门Id的领导部门岗位列表。
*
* @param deptId 部门Id。
* @return 指定部门Id的领导部门岗位列表
*/
List<SysDeptPost> getLeaderDeptPostList(@Param("deptId") Long deptId);
}

View File

@@ -0,0 +1,42 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysDeptRelation;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 部门关系树关联关系表访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDeptRelationMapper extends BaseDaoMapper<SysDeptRelation> {
/**
* 将myDeptId的所有子部门与其父部门parentDeptId解除关联关系。
*
* @param parentDeptIds myDeptId的父部门Id列表。
* @param myDeptId 当前部门。
*/
void removeBetweenChildrenAndParents(
@Param("parentDeptIds") List<Long> parentDeptIds, @Param("myDeptId") Long myDeptId);
/**
* 批量插入部门关联数据。
* 由于目前版本(3.4.1)的Mybatis Plus没有提供真正的批量插入为了保证效率需要自己实现。
* 目前我们仅仅给出MySQL和PostgresSQL的insert list实现作为参考其他数据库需要自行修改。
*
* @param deptRelationList 部门关联关系数据列表。
*/
void insertList(List<SysDeptRelation> deptRelationList);
/**
* 批量插入当前部门的所有父部门列表,包括自己和自己的关系。
*
* @param parentDeptId myDeptId的父部门Id。
* @param myDeptId 当前部门。
*/
void insertParentList(@Param("parentDeptId") Long parentDeptId, @Param("myDeptId") Long myDeptId);
}

View File

@@ -0,0 +1,40 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysMenu;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 菜单数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysMenuMapper extends BaseDaoMapper<SysMenu> {
/**
* 获取登录用户的菜单列表。
*
* @param userId 登录用户。
* @return 菜单列表。
*/
List<SysMenu> getMenuListByUserId(@Param("userId") Long userId);
/**
* 获取指定角色Id集合的菜单列表。
*
* @param roleIds 角色Id集合。
* @return 菜单列表。
*/
List<SysMenu> getMenuListByRoleIds(@Param("roleIds") Set<Long> roleIds);
/**
* 查询包含指定菜单编码的菜单数量目前仅用于satoken的权限框架。
*
* @param menuCode 菜单编码。
* @return 查询数量
*/
int countMenuCode(@Param("menuCode") String menuCode);
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysPermWhitelist;
/**
* 权限资源白名单数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysPermWhitelistMapper extends BaseDaoMapper<SysPermWhitelist> {
}

View File

@@ -0,0 +1,52 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysPost;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 岗位管理数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysPostMapper extends BaseDaoMapper<SysPost> {
/**
* 获取过滤后的对象列表。
*
* @param sysPostFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<SysPost> getSysPostList(
@Param("sysPostFilter") SysPost sysPostFilter, @Param("orderBy") String orderBy);
/**
* 获取指定部门的岗位列表。
*
* @param deptId 部门Id。
* @param sysPostFilter 从表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 岗位数据列表。
*/
List<SysPost> getSysPostListByDeptId(
@Param("deptId") Long deptId,
@Param("sysPostFilter") SysPost sysPostFilter,
@Param("orderBy") String orderBy);
/**
* 根据关联主表Id获取关联从表中没有和主表建立关联关系的数据列表。
*
* @param deptId 关联主表Id。
* @param sysPostFilter 过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 与主表没有建立关联的从表数据列表。
*/
List<SysPost> getNotInSysPostListByDeptId(
@Param("deptId") Long deptId,
@Param("sysPostFilter") SysPost sysPostFilter,
@Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,25 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysRole;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 角色数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysRoleMapper extends BaseDaoMapper<SysRole> {
/**
* 获取对象列表过滤条件中包含like和between条件。
*
* @param sysRoleFilter 过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<SysRole> getSysRoleList(@Param("sysRoleFilter") SysRole sysRoleFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysRoleMenu;
/**
* 角色与菜单操作关联关系数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysRoleMenuMapper extends BaseDaoMapper<SysRoleMenu> {
}

View File

@@ -0,0 +1,188 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysUser;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 用户管理数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysUserMapper extends BaseDaoMapper<SysUser> {
/**
* 批量插入对象列表。
*
* @param sysUserList 新增对象列表。
*/
void insertList(List<SysUser> sysUserList);
/**
* 获取过滤后的对象列表。
*
* @param sysUserFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<SysUser> getSysUserList(
@Param("sysUserFilter") SysUser sysUserFilter, @Param("orderBy") String orderBy);
/**
* 根据部门Id集合获取关联的用户列表。
*
* @param deptIds 关联的部门Id集合。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和部门Id集合关联的用户列表。
*/
List<SysUser> getSysUserListByDeptIds(
@Param("deptIds") Set<Long> deptIds,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据登录名集合,获取关联的用户列表。
* @param loginNames 登录名集合。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和登录名集合关联的用户列表。
*/
List<SysUser> getSysUserListByLoginNames(
@Param("loginNames") List<String> loginNames,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据角色Id获取关联的用户列表。
*
* @param roleId 关联的角色Id。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和角色Id关联的用户列表。
*/
List<SysUser> getSysUserListByRoleId(
@Param("roleId") Long roleId,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据角色Id集合获取去重后的用户Id列表。
*
* @param roleIds 关联的角色Id集合。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和角色Id集合关联的去重后的用户Id列表。
*/
List<Long> getUserIdListByRoleIds(
@Param("roleIds") Set<Long> roleIds,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据角色Id获取和当前角色Id没有建立多对多关联关系的用户列表。
*
* @param roleId 关联的角色Id。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和RoleId没有建立关联关系的用户列表。
*/
List<SysUser> getNotInSysUserListByRoleId(
@Param("roleId") Long roleId,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据数据权限Id获取关联的用户列表。
*
* @param dataPermId 关联的数据权限Id。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和DataPermId关联的用户列表。
*/
List<SysUser> getSysUserListByDataPermId(
@Param("dataPermId") Long dataPermId,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据数据权限Id获取和当前数据权限Id没有建立多对多关联关系的用户列表。
*
* @param dataPermId 关联的数据权限Id。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和DataPermId没有建立关联关系的用户列表。
*/
List<SysUser> getNotInSysUserListByDataPermId(
@Param("dataPermId") Long dataPermId,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据部门岗位Id集合获取关联的去重后的用户Id列表。
*
* @param deptPostIds 关联的部门岗位Id集合。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和部门岗位Id集合关联的去重后的用户Id列表。
*/
List<Long> getUserIdListByDeptPostIds(
@Param("deptPostIds") Set<Long> deptPostIds,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据部门岗位Id获取关联的用户列表。
*
* @param deptPostId 关联的部门岗位Id。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和部门岗位Id关联的用户列表。
*/
List<SysUser> getSysUserListByDeptPostId(
@Param("deptPostId") Long deptPostId,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据部门岗位Id获取和当前部门岗位Id没有建立多对多关联关系的用户列表。
*
* @param deptPostId 关联的部门岗位Id。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和deptPostId没有建立关联关系的用户列表。
*/
List<SysUser> getNotInSysUserListByDeptPostId(
@Param("deptPostId") Long deptPostId,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据岗位Id集合获取关联的去重后的用户Id列表。
*
* @param postIds 关联的岗位Id集合。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和岗位Id集合关联的去重后的用户Id列表。
*/
List<Long> getUserIdListByPostIds(
@Param("postIds") Set<Long> postIds,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
/**
* 根据岗位Id获取关联的用户列表。
*
* @param postId 关联的岗位Id。
* @param sysUserFilter 用户过滤条件对象。
* @param orderBy order by从句的参数。
* @return 和岗位Id关联的用户列表。
*/
List<SysUser> getSysUserListByPostId(
@Param("postId") Long postId,
@Param("sysUserFilter") SysUser sysUserFilter,
@Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysUserPost;
/**
* 用户岗位数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysUserPostMapper extends BaseDaoMapper<SysUserPost> {
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.webadmin.upms.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.model.SysUserRole;
/**
* 用户与角色关联关系数据访问操作接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysUserRoleMapper extends BaseDaoMapper<SysUserRole> {
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysDataPermDeptMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysDataPermDept">
<id column="data_perm_id" jdbcType="BIGINT" property="dataPermId"/>
<id column="dept_id" jdbcType="BIGINT" property="deptId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysDataPermMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysDataPerm">
<id column="data_perm_id" jdbcType="BIGINT" property="dataPermId"/>
<result column="data_perm_name" jdbcType="VARCHAR" property="dataPermName"/>
<result column="rule_type" jdbcType="INTEGER" property="ruleType"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<resultMap id="BaseResultMapEx" type="com.orangeforms.webadmin.upms.model.SysDataPerm" extends="BaseResultMap">
<collection property="dataPermDeptList" column="data_perm_id" javaType="ArrayList"
ofType="com.orangeforms.webadmin.upms.model.SysDataPermDept" notNullColumn="dept_id"
resultMap="com.orangeforms.webadmin.upms.dao.SysDataPermDeptMapper.BaseResultMap">
</collection>
<collection property="dataPermMenuList" column="data_perm_id" javaType="ArrayList"
ofType="com.orangeforms.webadmin.upms.model.SysDataPermMenu" notNullColumn="menu_id"
resultMap="com.orangeforms.webadmin.upms.dao.SysDataPermMenuMapper.BaseResultMap">
</collection>
</resultMap>
<sql id="filterRef">
<if test="sysDataPermFilter != null">
<if test="sysDataPermFilter.ruleType != null">
AND zz_sys_data_perm.rule_type = #{sysDataPermFilter.ruleType}
</if>
<if test="sysDataPermFilter.searchString != null and sysDataPermFilter.searchString != ''">
<bind name= "safeSearchString" value= "'%' + sysDataPermFilter.searchString + '%'" />
AND IFNULL(zz_sys_data_perm.data_perm_name, '') LIKE #{safeSearchString}
</if>
</if>
</sql>
<select id="getSysDataPermList" resultMap="BaseResultMap" parameterType="com.orangeforms.webadmin.upms.model.SysDataPerm">
SELECT
zz_sys_data_perm.*
FROM
zz_sys_data_perm
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysDataPermListByUserId" resultMap="BaseResultMapEx" parameterType="com.orangeforms.webadmin.upms.model.SysDataPerm">
SELECT
zz_sys_data_perm.*,
zz_sys_data_perm_dept.*,
zz_sys_data_perm_menu.*
FROM
zz_sys_data_perm_user
INNER JOIN
zz_sys_data_perm ON zz_sys_data_perm_user.data_perm_id = zz_sys_data_perm.data_perm_id
LEFT JOIN
zz_sys_data_perm_dept ON zz_sys_data_perm.data_perm_id = zz_sys_data_perm_dept.data_perm_id
LEFT JOIN
zz_sys_data_perm_menu ON zz_sys_data_perm.data_perm_id = zz_sys_data_perm_menu.data_perm_id
<where>
AND zz_sys_data_perm_user.user_id = #{userId}
</where>
</select>
<select id="getSysDataPermListByMenuId" resultMap="BaseResultMap" parameterType="com.orangeforms.webadmin.upms.model.SysDataPerm">
SELECT
zz_sys_data_perm.*
FROM
zz_sys_data_perm,
zz_sys_data_perm_menu
<where>
zz_sys_data_perm.data_perm_id = zz_sys_data_perm_menu.data_perm_id
AND zz_sys_data_perm_menu.menu_id = #{menuId}
</where>
</select>
</mapper>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysDataPermMenuMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysDataPermMenu">
<id column="data_perm_id" jdbcType="BIGINT" property="dataPermId"/>
<id column="menu_id" jdbcType="BIGINT" property="menuId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysDataPermUserMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysDataPermUser">
<id column="data_perm_id" jdbcType="BIGINT" property="dataPermId"/>
<id column="user_id" jdbcType="BIGINT" property="userId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysDeptMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysDept">
<id column="dept_id" jdbcType="BIGINT" property="deptId"/>
<result column="dept_name" jdbcType="VARCHAR" property="deptName"/>
<result column="show_order" jdbcType="INTEGER" property="showOrder"/>
<result column="parent_id" jdbcType="BIGINT" property="parentId"/>
<result column="deleted_flag" jdbcType="INTEGER" property="deletedFlag"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<insert id="insertList">
INSERT INTO zz_sys_dept
(dept_id,
dept_name,
show_order,
parent_id,
deleted_flag,
create_user_id,
update_user_id,
create_time,
update_time)
VALUES
<foreach collection="list" index="index" item="item" separator="," >
(#{item.deptId},
#{item.deptName},
#{item.showOrder},
#{item.parentId},
#{item.deletedFlag},
#{item.createUserId},
#{item.updateUserId},
#{item.createTime},
#{item.updateTime})
</foreach>
</insert>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名否则当filterRef被其他Mapper.xml包含引用的时候就会调用Mapper.xml中的该SQL片段 -->
<include refid="com.orangeforms.webadmin.upms.dao.SysDeptMapper.inputFilterRef"/>
AND zz_sys_dept.deleted_flag = ${@com.orangeforms.common.core.constant.GlobalDeletedFlag@NORMAL}
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="sysDeptFilter != null">
<if test="sysDeptFilter.deptName != null and sysDeptFilter.deptName != ''">
<bind name = "safeSysDeptDeptName" value = "'%' + sysDeptFilter.deptName + '%'" />
AND zz_sys_dept.dept_name LIKE #{safeSysDeptDeptName}
</if>
<if test="sysDeptFilter.parentId != null">
AND zz_sys_dept.parent_id = #{sysDeptFilter.parentId}
</if>
</if>
</sql>
<select id="getSysDeptList" resultMap="BaseResultMap" parameterType="com.orangeforms.webadmin.upms.model.SysDept">
SELECT * FROM zz_sys_dept
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysDeptPostMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysDeptPost">
<id column="dept_post_id" jdbcType="BIGINT" property="deptPostId"/>
<result column="dept_id" jdbcType="BIGINT" property="deptId"/>
<result column="post_id" jdbcType="BIGINT" property="postId"/>
<result column="post_show_name" jdbcType="VARCHAR" property="postShowName"/>
</resultMap>
<select id="getSysDeptPostListWithRelationByDeptId" resultType="map">
SELECT
a.dept_post_id deptPostId,
a.dept_id deptId,
a.post_id postId,
a.post_show_name postShowName,
b.dept_name deptName,
c.post_level postLevel,
c.leader_post leaderPost
FROM
zz_sys_dept_post a,
zz_sys_dept b,
zz_sys_post c
<where>
a.dept_id = b.dept_id
AND a.post_id = c.post_id
<if test="deptId != null">
AND a.dept_id = #{deptId}
</if>
</where>
</select>
<select id="getLeaderDeptPostList" resultMap="BaseResultMap">
SELECT
a.*
FROM
zz_sys_dept_post a,
zz_sys_post b
WHERE
a.post_id = b.post_id
AND b.leader_post = 1
AND a.dept_id = #{deptId}
ORDER BY
b.post_level
</select>
</mapper>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysDeptRelationMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysDeptRelation">
<id column="parent_dept_id" jdbcType="BIGINT" property="parentDeptId"/>
<id column="dept_id" jdbcType="BIGINT" property="deptId"/>
</resultMap>
<delete id="removeBetweenChildrenAndParents">
DELETE a FROM zz_sys_dept_relation a
INNER JOIN zz_sys_dept_relation b ON a.dept_id = b.dept_id
WHERE b.parent_dept_id = #{myDeptId} AND a.parent_dept_id IN
<foreach collection="parentDeptIds" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</delete>
<insert id="insertList">
INSERT INTO zz_sys_dept_relation(parent_dept_id, dept_id) VALUES
<foreach collection="list" index="index" item="item" separator=",">
(#{item.parentDeptId}, #{item.deptId})
</foreach>
</insert>
<insert id="insertParentList">
INSERT INTO zz_sys_dept_relation(parent_dept_id, dept_id)
SELECT t.parent_dept_id, #{myDeptId} FROM zz_sys_dept_relation t
WHERE t.dept_id = #{parentDeptId}
UNION ALL
SELECT #{myDeptId}, #{myDeptId}
</insert>
</mapper>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysMenuMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysMenu">
<id column="menu_id" jdbcType="BIGINT" property="menuId"/>
<result column="parent_id" jdbcType="BIGINT" property="parentId"/>
<result column="menu_name" jdbcType="VARCHAR" property="menuName"/>
<result column="menu_type" jdbcType="INTEGER" property="menuType"/>
<result column="form_router_name" jdbcType="VARCHAR" property="formRouterName"/>
<result column="online_form_id" jdbcType="BIGINT" property="onlineFormId"/>
<result column="online_menu_perm_type" jdbcType="INTEGER" property="onlineMenuPermType"/>
<result column="report_page_id" jdbcType="BIGINT" property="reportPageId"/>
<result column="online_flow_entry_id" jdbcType="BIGINT" property="onlineFlowEntryId"/>
<result column="show_order" jdbcType="INTEGER" property="showOrder"/>
<result column="icon" jdbcType="VARCHAR" property="icon"/>
<result column="extra_data" jdbcType="VARCHAR" property="extraData"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<select id="getMenuListByUserId" resultMap="BaseResultMap">
SELECT
m.*
FROM
zz_sys_user_role ur,
zz_sys_role_menu rm,
zz_sys_menu m
<where>
AND ur.user_id = #{userId}
AND ur.role_id = rm.role_id
AND rm.menu_id = m.menu_id
</where>
ORDER BY m.show_order
</select>
<select id="getMenuListByRoleIds" resultMap="BaseResultMap">
SELECT
m.*
FROM
zz_sys_role_menu rm,
zz_sys_menu m
<where>
rm.role_id IN
<foreach collection="roleIds" item="item" separator="," open="(" close=")">
#{item}
</foreach>
AND rm.menu_id = m.menu_id
</where>
ORDER BY m.show_order
</select>
<select id="countMenuCode" resultType="java.lang.Integer">
<bind name= "safeMenuCode" value= "'%' + menuCode + '%'"/>
SELECT COUNT(*) FROM zz_sys_menu WHERE extra_data LIKE #{safeMenuCode}
</select>
</mapper>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysPermWhitelistMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysPermWhitelist">
<id column="perm_url" jdbcType="VARCHAR" property="permUrl"/>
<result column="module_name" jdbcType="VARCHAR" property="moduleName"/>
<result column="perm_name" jdbcType="VARCHAR" property="permName"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysPostMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysPost">
<id column="post_id" jdbcType="BIGINT" property="postId"/>
<result column="post_name" jdbcType="VARCHAR" property="postName"/>
<result column="post_level" jdbcType="INTEGER" property="postLevel"/>
<result column="leader_post" jdbcType="BOOLEAN" property="leaderPost"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<resultMap id="BaseResultMapWithSysDeptPost" type="com.orangeforms.webadmin.upms.model.SysPost" extends="BaseResultMap">
<association property="sysDeptPost" column="post_id" foreignColumn="post_id"
notNullColumn="post_id" resultMap="com.orangeforms.webadmin.upms.dao.SysDeptPostMapper.BaseResultMap" />
</resultMap>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名否则当filterRef被其他Mapper.xml包含引用的时候就会调用Mapper.xml中的该SQL片段 -->
<include refid="com.orangeforms.webadmin.upms.dao.SysPostMapper.inputFilterRef"/>
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="sysPostFilter != null">
<if test="sysPostFilter.postName != null and sysPostFilter.postName != ''">
<bind name = "safeSysPostPostName" value = "'%' + sysPostFilter.postName + '%'" />
AND zz_sys_post.post_name LIKE #{safeSysPostPostName}
</if>
<if test="sysPostFilter.leaderPost != null">
AND zz_sys_post.leader_post = #{sysPostFilter.leaderPost}
</if>
</if>
</sql>
<select id="getSysPostList" resultMap="BaseResultMap" parameterType="com.orangeforms.webadmin.upms.model.SysPost">
SELECT * FROM zz_sys_post
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysPostListByDeptId" resultMap="BaseResultMapWithSysDeptPost">
SELECT
zz_sys_post.*,
zz_sys_dept_post.*
FROM
zz_sys_post,
zz_sys_dept_post
<where>
AND zz_sys_dept_post.dept_id = #{deptId}
AND zz_sys_dept_post.post_id = zz_sys_post.post_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getNotInSysPostListByDeptId" resultMap="BaseResultMap">
SELECT
zz_sys_post.*
FROM
zz_sys_post
<where>
AND NOT EXISTS (SELECT * FROM zz_sys_dept_post
WHERE zz_sys_dept_post.dept_id = #{deptId} AND zz_sys_dept_post.post_id = zz_sys_post.post_id)
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysRoleMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysRole">
<id column="role_id" jdbcType="BIGINT" property="roleId"/>
<result column="role_name" jdbcType="VARCHAR" property="roleName"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<sql id="filterRef">
<if test="sysRoleFilter != null">
<if test="sysRoleFilter.roleName != null and sysRoleFilter.roleName != ''">
<bind name= "safeRoleName" value= "'%' + sysRoleFilter.roleName + '%'"/>
AND role_name LIKE #{safeRoleName}
</if>
</if>
</sql>
<select id="getSysRoleList" resultMap="BaseResultMap" parameterType="com.orangeforms.webadmin.upms.model.SysRole">
SELECT * FROM zz_sys_role
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysRoleMenuMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysRoleMenu">
<id column="role_id" jdbcType="BIGINT" property="roleId"/>
<id column="menu_id" jdbcType="BIGINT" property="menuId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysUserMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysUser">
<id column="user_id" jdbcType="BIGINT" property="userId"/>
<result column="login_name" jdbcType="VARCHAR" property="loginName"/>
<result column="password" jdbcType="VARCHAR" property="password"/>
<result column="dept_id" jdbcType="BIGINT" property="deptId"/>
<result column="show_name" jdbcType="VARCHAR" property="showName"/>
<result column="user_type" jdbcType="INTEGER" property="userType"/>
<result column="head_image_url" jdbcType="VARCHAR" property="headImageUrl"/>
<result column="user_status" jdbcType="INTEGER" property="userStatus"/>
<result column="email" jdbcType="VARCHAR" property="email"/>
<result column="mobile" jdbcType="VARCHAR" property="mobile"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="deleted_flag" jdbcType="INTEGER" property="deletedFlag"/>
</resultMap>
<insert id="insertList">
INSERT INTO zz_sys_user
(user_id,
login_name,
password,
dept_id,
show_name,
user_type,
head_image_url,
user_status,
email,
mobile,
create_user_id,
update_user_id,
create_time,
update_time,
deleted_flag)
VALUES
<foreach collection="list" index="index" item="item" separator="," >
(#{item.userId},
#{item.loginName},
#{item.password},
#{item.deptId},
#{item.showName},
#{item.userType},
#{item.headImageUrl},
#{item.userStatus},
#{item.email},
#{item.mobile},
#{item.createUserId},
#{item.updateUserId},
#{item.createTime},
#{item.updateTime},
#{item.deletedFlag})
</foreach>
</insert>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名否则当filterRef被其他Mapper.xml包含引用的时候就会调用Mapper.xml中的该SQL片段 -->
<include refid="com.orangeforms.webadmin.upms.dao.SysUserMapper.inputFilterRef"/>
AND zz_sys_user.deleted_flag = ${@com.orangeforms.common.core.constant.GlobalDeletedFlag@NORMAL}
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="sysUserFilter != null">
<if test="sysUserFilter.loginName != null and sysUserFilter.loginName != ''">
<bind name = "safeSysUserLoginName" value = "'%' + sysUserFilter.loginName + '%'" />
AND zz_sys_user.login_name LIKE #{safeSysUserLoginName}
</if>
<if test="sysUserFilter.deptId != null">
AND (EXISTS (SELECT 1 FROM zz_sys_dept_relation WHERE
zz_sys_dept_relation.parent_dept_id = #{sysUserFilter.deptId}
AND zz_sys_user.dept_id = zz_sys_dept_relation.dept_id))
</if>
<if test="sysUserFilter.showName != null and sysUserFilter.showName != ''">
<bind name = "safeSysUserShowName" value = "'%' + sysUserFilter.showName + '%'" />
AND zz_sys_user.show_name LIKE #{safeSysUserShowName}
</if>
<if test="sysUserFilter.userStatus != null">
AND zz_sys_user.user_status = #{sysUserFilter.userStatus}
</if>
<if test="sysUserFilter.createTimeStart != null and sysUserFilter.createTimeStart != ''">
AND zz_sys_user.create_time &gt;= #{sysUserFilter.createTimeStart}
</if>
<if test="sysUserFilter.createTimeEnd != null and sysUserFilter.createTimeEnd != ''">
AND zz_sys_user.create_time &lt;= #{sysUserFilter.createTimeEnd}
</if>
</if>
</sql>
<select id="getSysUserList" resultMap="BaseResultMap" parameterType="com.orangeforms.webadmin.upms.model.SysUser">
SELECT * FROM zz_sys_user
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysUserListByDeptIds" resultMap="BaseResultMap">
SELECT * FROM zz_sys_user
<where>
<if test="deptIds != null">
AND (EXISTS (SELECT 1 FROM zz_sys_dept_relation WHERE
zz_sys_dept_relation.parent_dept_id IN
<foreach collection="deptIds" item="item" separator="," open="(" close=")">
#{item}
</foreach>
AND zz_sys_user.dept_id = zz_sys_dept_relation.dept_id))
</if>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysUserListByLoginNames" resultMap="BaseResultMap">
SELECT * FROM zz_sys_user
<where>
<if test="loginNames != null">
AND zz_sys_user.login_name IN
<foreach collection="loginNames" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</if>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getUserIdListByRoleIds" resultType="java.lang.Long">
SELECT
DISTINCT zz_sys_user.user_id
FROM
zz_sys_user_role,
zz_sys_user
<where>
AND zz_sys_user_role.role_id IN
<foreach collection="roleIds" item="item" separator="," open="(" close=")">
#{item}
</foreach>
AND zz_sys_user_role.user_id = zz_sys_user.user_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysUserListByRoleId" resultMap="BaseResultMap">
SELECT
zz_sys_user.*
FROM
zz_sys_user_role,
zz_sys_user
<where>
AND zz_sys_user_role.role_id = #{roleId}
AND zz_sys_user_role.user_id = zz_sys_user.user_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getNotInSysUserListByRoleId" resultMap="BaseResultMap">
SELECT * FROM zz_sys_user
<where>
NOT EXISTS (SELECT * FROM zz_sys_user_role
WHERE zz_sys_user_role.role_id = #{roleId} AND zz_sys_user_role.user_id = zz_sys_user.user_id)
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysUserListByDataPermId" resultMap="BaseResultMap">
SELECT
zz_sys_user.*
FROM
zz_sys_data_perm_user,
zz_sys_user
<where>
AND zz_sys_data_perm_user.data_perm_id = #{dataPermId}
AND zz_sys_data_perm_user.user_id = zz_sys_user.user_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getNotInSysUserListByDataPermId" resultMap="BaseResultMap">
SELECT * FROM zz_sys_user
<where>
NOT EXISTS (SELECT * FROM zz_sys_data_perm_user
WHERE zz_sys_data_perm_user.data_perm_id = #{dataPermId} AND zz_sys_data_perm_user.user_id = zz_sys_user.user_id)
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getUserIdListByDeptPostIds" resultType="java.lang.Long">
SELECT
DISTINCT zz_sys_user.user_id
FROM
zz_sys_user_post,
zz_sys_user
<where>
AND zz_sys_user_post.dept_post_id IN
<foreach collection="deptPostIds" item="item" separator="," open="(" close=")">
#{item}
</foreach>
AND zz_sys_user_post.user_id = zz_sys_user.user_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysUserListByDeptPostId" resultMap="BaseResultMap">
SELECT
zz_sys_user.*
FROM
zz_sys_user_post,
zz_sys_user
<where>
AND zz_sys_user_post.dept_post_id = #{deptPostId}
AND zz_sys_user_post.user_id = zz_sys_user.user_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getNotInSysUserListByDeptPostId" resultMap="BaseResultMap">
SELECT * FROM zz_sys_user
<where>
NOT EXISTS (SELECT * FROM zz_sys_user_post
WHERE zz_sys_user_post.dept_post_id = #{deptPostId} AND zz_sys_user_post.user_id = zz_sys_user.user_id)
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getUserIdListByPostIds" resultType="java.lang.Long">
SELECT
DISTINCT zz_sys_user.user_id
FROM
zz_sys_user_post,
zz_sys_user
<where>
AND zz_sys_user_post.post_id IN
<foreach collection="postIds" item="item" separator="," open="(" close=")">
#{item}
</foreach>
AND zz_sys_user_post.user_id = zz_sys_user.user_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getSysUserListByPostId" resultMap="BaseResultMap">
SELECT
zz_sys_user.*
FROM
zz_sys_user_post,
zz_sys_user
<where>
AND zz_sys_user_post.post_id = #{postId}
AND zz_sys_user_post.user_id = zz_sys_user.user_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysUserPostMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysUserPost">
<id column="user_id" jdbcType="BIGINT" property="userId"/>
<id column="dept_post_id" jdbcType="BIGINT" property="deptPostId"/>
<id column="post_id" jdbcType="BIGINT" property="postId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orangeforms.webadmin.upms.dao.SysUserRoleMapper">
<resultMap id="BaseResultMap" type="com.orangeforms.webadmin.upms.model.SysUserRole">
<id column="user_id" jdbcType="BIGINT" property="userId"/>
<id column="role_id" jdbcType="BIGINT" property="roleId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,27 @@
package com.orangeforms.webadmin.upms.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 数据权限与部门关联Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "数据权限与部门关联Dto")
@Data
public class SysDataPermDeptDto {
/**
* 数据权限Id。
*/
@Schema(description = "数据权限Id", requiredMode = Schema.RequiredMode.REQUIRED)
private Long dataPermId;
/**
* 关联部门Id。
*/
@Schema(description = "关联部门Id", requiredMode = Schema.RequiredMode.REQUIRED)
private Long deptId;
}

View File

@@ -0,0 +1,55 @@
package com.orangeforms.webadmin.upms.dto;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.common.core.validator.ConstDictRef;
import com.orangeforms.common.core.constant.DataPermRuleType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.*;
/**
* 数据权限Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "数据权限Dto")
@Data
public class SysDataPermDto {
/**
* 数据权限Id。
*/
@Schema(description = "数据权限Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据权限Id不能为空", groups = {UpdateGroup.class})
private Long dataPermId;
/**
* 显示名称。
*/
@Schema(description = "显示名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "数据权限名称不能为空!")
private String dataPermName;
/**
* 数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。
*/
@Schema(description = "数据权限规则类型", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据权限规则类型不能为空!")
@ConstDictRef(constDictClass = DataPermRuleType.class)
private Integer ruleType;
/**
* 部门Id列表(逗号分隔)。
*/
@Schema(hidden = true)
private String deptIdListString;
/**
* 搜索字符串。
*/
@Schema(description = "LIKE 模糊搜索字符串")
private String searchString;
}

View File

@@ -0,0 +1,27 @@
package com.orangeforms.webadmin.upms.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 数据权限与菜单关联Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "数据权限与菜单关联Dto")
@Data
public class SysDataPermMenuDto {
/**
* 数据权限Id。
*/
@Schema(description = "数据权限Id", requiredMode = Schema.RequiredMode.REQUIRED)
private Long dataPermId;
/**
* 关联菜单Id。
*/
@Schema(description = "关联菜单Id", requiredMode = Schema.RequiredMode.REQUIRED)
private Long menuId;
}

View File

@@ -0,0 +1,48 @@
package com.orangeforms.webadmin.upms.dto;
import com.orangeforms.common.core.validator.UpdateGroup;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.*;
/**
* 部门管理Dto对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "SysDeptDto对象")
@Data
public class SysDeptDto {
/**
* 部门Id。
*/
@Schema(description = "部门Id。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败部门Id不能为空", groups = {UpdateGroup.class})
private Long deptId;
/**
* 部门名称。
* NOTE: 可支持等于操作符的列表数据过滤。
*/
@Schema(description = "部门名称。可支持等于操作符的列表数据过滤。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "数据验证失败,部门名称不能为空!")
private String deptName;
/**
* 显示顺序。
*/
@Schema(description = "显示顺序。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败,显示顺序不能为空!")
private Integer showOrder;
/**
* 父部门Id。
* NOTE: 可支持等于操作符的列表数据过滤。
*/
@Schema(description = "父部门Id。可支持等于操作符的列表数据过滤。")
private Long parentId;
}

View File

@@ -0,0 +1,47 @@
package com.orangeforms.webadmin.upms.dto;
import com.orangeforms.common.core.validator.UpdateGroup;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.*;
/**
* 部门岗位Dto对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "部门岗位Dto")
@Data
public class SysDeptPostDto {
/**
* 部门岗位Id。
*/
@Schema(description = "部门岗位Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败部门岗位Id不能为空", groups = {UpdateGroup.class})
private Long deptPostId;
/**
* 部门Id。
*/
@Schema(description = "部门Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败部门Id不能为空", groups = {UpdateGroup.class})
private Long deptId;
/**
* 岗位Id。
*/
@Schema(description = "岗位Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败岗位Id不能为空", groups = {UpdateGroup.class})
private Long postId;
/**
* 部门岗位显示名称。
*/
@Schema(description = "部门岗位显示名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "数据验证失败,部门岗位显示名称不能为空!")
private String postShowName;
}

View File

@@ -0,0 +1,92 @@
package com.orangeforms.webadmin.upms.dto;
import com.orangeforms.common.core.validator.ConstDictRef;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.webadmin.upms.model.constant.SysMenuType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* 菜单Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "菜单Dto")
@Data
public class SysMenuDto {
/**
* 菜单Id。
*/
@Schema(description = "菜单Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "菜单Id不能为空", groups = {UpdateGroup.class})
private Long menuId;
/**
* 父菜单Id目录菜单的父菜单为null
*/
@Schema(description = "父菜单Id")
private Long parentId;
/**
* 菜单显示名称。
*/
@Schema(description = "菜单显示名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "菜单显示名称不能为空!")
private String menuName;
/**
* 菜单类型 (0: 目录 1: 菜单 2: 按钮 3: UI片段)。
*/
@Schema(description = "菜单类型", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "菜单类型不能为空!")
@ConstDictRef(constDictClass = SysMenuType.class, message = "数据验证失败,菜单类型为无效值!")
private Integer menuType;
/**
* 前端表单路由名称仅用于menu_type为1的菜单类型。
*/
@Schema(description = "前端表单路由名称")
private String formRouterName;
/**
* 在线表单主键Id仅用于在线表单绑定的菜单。
*/
@Schema(description = "在线表单主键Id")
private Long onlineFormId;
/**
* 统计页面主键Id仅用于统计页面绑定的菜单。
*/
@Schema(description = "统计页面主键Id")
private Long reportPageId;
/**
* 仅用于在线表单的流程Id。
*/
@Schema(description = "仅用于在线表单的流程Id")
private Long onlineFlowEntryId;
/**
* 菜单显示顺序 (值越小,排序越靠前)。
*/
@Schema(description = "菜单显示顺序", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "菜单显示顺序不能为空!")
private Integer showOrder;
/**
* 菜单图标。
*/
@Schema(description = "菜单显示图标")
private String icon;
/**
* 附加信息。
*/
@Schema(description = "附加信息")
private String extraData;
}

View File

@@ -0,0 +1,47 @@
package com.orangeforms.webadmin.upms.dto;
import com.orangeforms.common.core.validator.UpdateGroup;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.*;
/**
* 岗位Dto对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "岗位Dto")
@Data
public class SysPostDto {
/**
* 岗位Id。
*/
@Schema(description = "岗位Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败岗位Id不能为空", groups = {UpdateGroup.class})
private Long postId;
/**
* 岗位名称。
*/
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "数据验证失败,岗位名称不能为空!")
private String postName;
/**
* 岗位层级,数值越小级别越高。
*/
@Schema(description = "岗位层级", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败,岗位层级不能为空!")
private Integer postLevel;
/**
* 是否领导岗位。
*/
@Schema(description = "是否领导岗位", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败,领导岗位不能为空!", groups = {UpdateGroup.class})
private Boolean leaderPost;
}

View File

@@ -0,0 +1,32 @@
package com.orangeforms.webadmin.upms.dto;
import com.orangeforms.common.core.validator.UpdateGroup;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.*;
/**
* 角色Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "角色Dto")
@Data
public class SysRoleDto {
/**
* 角色Id。
*/
@Schema(description = "角色Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "角色Id不能为空", groups = {UpdateGroup.class})
private Long roleId;
/**
* 角色名称。
*/
@Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "角色名称不能为空!")
private String roleName;
}

View File

@@ -0,0 +1,110 @@
package com.orangeforms.webadmin.upms.dto;
import com.orangeforms.common.core.validator.AddGroup;
import com.orangeforms.common.core.validator.UpdateGroup;
import com.orangeforms.common.core.validator.ConstDictRef;
import com.orangeforms.webadmin.upms.model.constant.SysUserType;
import com.orangeforms.webadmin.upms.model.constant.SysUserStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.*;
/**
* 用户管理Dto对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "SysUserDto对象")
@Data
public class SysUserDto {
/**
* 用户Id。
*/
@Schema(description = "用户Id。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败用户Id不能为空", groups = {UpdateGroup.class})
private Long userId;
/**
* 登录用户名。
* NOTE: 可支持等于操作符的列表数据过滤。
*/
@Schema(description = "登录用户名。可支持等于操作符的列表数据过滤。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "数据验证失败,登录用户名不能为空!")
private String loginName;
/**
* 用户密码。
*/
@Schema(description = "用户密码。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "数据验证失败,用户密码不能为空!", groups = {AddGroup.class})
private String password;
/**
* 用户部门Id。
* NOTE: 可支持等于操作符的列表数据过滤。
*/
@Schema(description = "用户部门Id。可支持等于操作符的列表数据过滤。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败用户部门Id不能为空")
private Long deptId;
/**
* 用户显示名称。
* NOTE: 可支持等于操作符的列表数据过滤。
*/
@Schema(description = "用户显示名称。可支持等于操作符的列表数据过滤。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "数据验证失败,用户显示名称不能为空!")
private String showName;
/**
* 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。
*/
@Schema(description = "用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)不能为空!")
@ConstDictRef(constDictClass = SysUserType.class, message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)为无效值!")
private Integer userType;
/**
* 用户头像的Url。
*/
@Schema(description = "用户头像的Url。")
private String headImageUrl;
/**
* 用户状态(0: 正常 1: 锁定)。
* NOTE: 可支持等于操作符的列表数据过滤。
*/
@Schema(description = "用户状态(0: 正常 1: 锁定)。可支持等于操作符的列表数据过滤。", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据验证失败,用户状态(0: 正常 1: 锁定)不能为空!")
@ConstDictRef(constDictClass = SysUserStatus.class, message = "数据验证失败,用户状态(0: 正常 1: 锁定)为无效值!")
private Integer userStatus;
/**
* 用户邮箱。
*/
@Schema(description = "用户邮箱。")
private String email;
/**
* 用户手机。
*/
@Schema(description = "用户手机。")
private String mobile;
/**
* createTime 范围过滤起始值(>=)。
* NOTE: 可支持范围操作符的列表数据过滤。
*/
@Schema(description = "createTime 范围过滤起始值(>=)。可支持范围操作符的列表数据过滤。")
private String createTimeStart;
/**
* createTime 范围过滤结束值(<=)。
* NOTE: 可支持范围操作符的列表数据过滤。
*/
@Schema(description = "createTime 范围过滤结束值(<=)。可支持范围操作符的列表数据过滤。")
private String createTimeEnd;
}

View File

@@ -0,0 +1,62 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import com.orangeforms.common.core.util.MyCommonUtil;
import com.orangeforms.common.core.annotation.RelationManyToMany;
import com.orangeforms.common.core.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.*;
/**
* 数据权限实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Table(value = "zz_sys_data_perm")
public class SysDataPerm extends BaseModel {
/**
* 主键Id。
*/
@Id(value = "data_perm_id")
private Long dataPermId;
/**
* 显示名称。
*/
@Column(value = "data_perm_name")
private String dataPermName;
/**
* 数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。
*/
@Column(value = "rule_type")
private Integer ruleType;
@Column(ignore = true)
private String deptIdListString;
@RelationManyToMany(
relationMasterIdField = "dataPermId",
relationModelClass = SysDataPermDept.class)
@Column(ignore = true)
private List<SysDataPermDept> dataPermDeptList;
@RelationManyToMany(
relationMasterIdField = "dataPermId",
relationModelClass = SysDataPermMenu.class)
@Column(ignore = true)
private List<SysDataPermMenu> dataPermMenuList;
@Column(ignore = true)
private String searchString;
public void setSearchString(String searchString) {
this.searchString = MyCommonUtil.replaceSqlWildcard(searchString);
}
}

View File

@@ -0,0 +1,29 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
import lombok.ToString;
/**
* 数据权限与部门关联实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@ToString(of = {"deptId"})
@Table(value = "zz_sys_data_perm_dept")
public class SysDataPermDept {
/**
* 数据权限Id。
*/
@Column(value = "data_perm_id")
private Long dataPermId;
/**
* 关联部门Id。
*/
@Column(value = "dept_id")
private Long deptId;
}

View File

@@ -0,0 +1,29 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
import lombok.ToString;
/**
* 数据权限与菜单关联实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@ToString(of = {"menuId"})
@Table(value = "zz_sys_data_perm_menu")
public class SysDataPermMenu {
/**
* 数据权限Id。
*/
@Column(value = "data_perm_id")
private Long dataPermId;
/**
* 关联菜单Id。
*/
@Column(value = "menu_id")
private Long menuId;
}

View File

@@ -0,0 +1,27 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
/**
* 数据权限与用户关联实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_data_perm_user")
public class SysDataPermUser {
/**
* 数据权限Id。
*/
@Column(value = "data_perm_id")
private Long dataPermId;
/**
* 用户Id。
*/
@Column(value = "user_id")
private Long userId;
}

View File

@@ -0,0 +1,73 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import lombok.Data;
import java.util.Date;
/**
* 部门管理实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_dept")
public class SysDept {
/**
* 部门Id。
*/
@Id(value = "dept_id")
private Long deptId;
/**
* 部门名称。
*/
@Column(value = "dept_name")
private String deptName;
/**
* 显示顺序。
*/
@Column(value = "show_order")
private Integer showOrder;
/**
* 父部门Id。
*/
@Column(value = "parent_id")
private Long parentId;
/**
* 逻辑删除标记字段(1: 正常 -1: 已删除)。
*/
@Column(value = "deleted_flag", isLogicDelete = true)
private Integer deletedFlag;
/**
* 创建者Id。
*/
@Column(value = "create_user_id")
private Long createUserId;
/**
* 更新者Id。
*/
@Column(value = "update_user_id")
private Long updateUserId;
/**
* 创建时间。
*/
@Column(value = "create_time")
private Date createTime;
/**
* 更新时间。
*/
@Column(value = "update_time")
private Date updateTime;
}

View File

@@ -0,0 +1,39 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
/**
* 部门岗位多对多关联实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_dept_post")
public class SysDeptPost {
/**
* 部门岗位Id。
*/
@Id(value = "dept_post_id")
private Long deptPostId;
/**
* 部门Id。
*/
@Column(value = "dept_id")
private Long deptId;
/**
* 岗位Id。
*/
@Column(value = "post_id")
private Long postId;
/**
* 部门岗位显示名称。
*/
@Column(value = "post_show_name")
private String postShowName;
}

View File

@@ -0,0 +1,31 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 部门关联实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(value = "zz_sys_dept_relation")
public class SysDeptRelation {
/**
* 上级部门Id。
*/
@Column(value = "parent_dept_id")
private Long parentDeptId;
/**
* 部门Id。
*/
@Column(value = "dept_id")
private Long deptId;
}

View File

@@ -0,0 +1,96 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import com.orangeforms.common.core.base.model.BaseModel;
import com.orangeforms.webadmin.upms.bo.SysMenuExtraData;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 菜单实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Table(value = "zz_sys_menu")
public class SysMenu extends BaseModel {
/**
* 菜单Id。
*/
@Id(value = "menu_id")
private Long menuId;
/**
* 父菜单Id目录菜单的父菜单为null。
*/
@Column(value = "parent_id")
private Long parentId;
/**
* 菜单显示名称。
*/
@Column(value = "menu_name")
private String menuName;
/**
* 菜单类型(0: 目录 1: 菜单 2: 按钮 3: UI片段)。
*/
@Column(value = "menu_type")
private Integer menuType;
/**
* 前端表单路由名称仅用于menu_type为1的菜单类型。
*/
@Column(value = "form_router_name")
private String formRouterName;
/**
* 在线表单主键Id仅用于在线表单绑定的菜单。
*/
@Column(value = "online_form_id")
private Long onlineFormId;
/**
* 在线表单菜单的权限控制类型具体值可参考SysOnlineMenuPermType常量对象。
*/
@Column(value = "online_menu_perm_type")
private Integer onlineMenuPermType;
/**
* 统计页面主键Id仅用于统计页面绑定的菜单。
*/
@Column(value = "report_page_id")
private Long reportPageId;
/**
* 仅用于在线表单的流程Id。
*/
@Column(value = "online_flow_entry_id")
private Long onlineFlowEntryId;
/**
* 菜单显示顺序 (值越小,排序越靠前)。
*/
@Column(value = "show_order")
private Integer showOrder;
/**
* 菜单图标。
*/
private String icon;
/**
* 附加信息。
*/
@Column(value = "extra_data")
private String extraData;
/**
* extraData字段解析后的对象数据。
*/
@Column(ignore = true)
private SysMenuExtraData extraObject;
}

View File

@@ -0,0 +1,33 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
/**
* 白名单实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_perm_whitelist")
public class SysPermWhitelist {
/**
* 权限资源的URL。
*/
@Id(value = "perm_url")
private String permUrl;
/**
* 权限资源所属模块名字(通常是Controller的名字)。
*/
@Column(value = "module_name")
private String moduleName;
/**
* 权限的名称。
*/
@Column(value = "perm_name")
private String permName;
}

View File

@@ -0,0 +1,48 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import com.orangeforms.common.core.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 岗位实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Table(value = "zz_sys_post")
public class SysPost extends BaseModel {
/**
* 岗位Id。
*/
@Id(value = "post_id")
private Long postId;
/**
* 岗位名称。
*/
@Column(value = "post_name")
private String postName;
/**
* 岗位层级,数值越小级别越高。
*/
@Column(value = "post_level")
private Integer postLevel;
/**
* 是否领导岗位。
*/
@Column(value = "leader_post")
private Boolean leaderPost;
/**
* postId 的多对多关联表数据对象。
*/
@Column(ignore = true)
private SysDeptPost sysDeptPost;
}

View File

@@ -0,0 +1,39 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import com.orangeforms.common.core.annotation.RelationManyToMany;
import com.orangeforms.common.core.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.*;
/**
* 角色实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Table(value = "zz_sys_role")
public class SysRole extends BaseModel {
/**
* 角色Id。
*/
@Id(value = "role_id")
private Long roleId;
/**
* 角色名称。
*/
@Column(value = "role_name")
private String roleName;
@RelationManyToMany(
relationMasterIdField = "roleId",
relationModelClass = SysRoleMenu.class)
@Column(ignore = true)
private List<SysRoleMenu> sysRoleMenuList;
}

View File

@@ -0,0 +1,27 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
/**
* 角色菜单实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_role_menu")
public class SysRoleMenu {
/**
* 角色Id。
*/
@Column(value = "role_id")
private Long roleId;
/**
* 菜单Id。
*/
@Column(value = "menu_id")
private Long menuId;
}

View File

@@ -0,0 +1,172 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import com.orangeforms.webadmin.upms.model.constant.SysUserType;
import com.orangeforms.webadmin.upms.model.constant.SysUserStatus;
import com.orangeforms.common.core.upload.UploadStoreTypeEnum;
import com.orangeforms.common.core.annotation.*;
import lombok.Data;
import java.util.Date;
import java.util.Map;
import java.util.List;
/**
* 用户管理实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_user")
public class SysUser {
/**
* 用户Id。
*/
@Id(value = "user_id")
private Long userId;
/**
* 登录用户名。
*/
@Column(value = "login_name")
private String loginName;
/**
* 用户密码。
*/
private String password;
/**
* 用户部门Id。
*/
@Column(value = "dept_id")
private Long deptId;
/**
* 用户显示名称。
*/
@Column(value = "show_name")
private String showName;
/**
* 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。
*/
@Column(value = "user_type")
private Integer userType;
/**
* 用户头像的Url。
*/
@UploadFlagColumn(storeType = UploadStoreTypeEnum.LOCAL_SYSTEM)
@Column(value = "head_image_url")
private String headImageUrl;
/**
* 用户状态(0: 正常 1: 锁定)。
*/
@Column(value = "user_status")
private Integer userStatus;
/**
* 用户邮箱。
*/
private String email;
/**
* 用户手机。
*/
private String mobile;
/**
* 创建者Id。
*/
@Column(value = "create_user_id")
private Long createUserId;
/**
* 更新者Id。
*/
@Column(value = "update_user_id")
private Long updateUserId;
/**
* 创建时间。
*/
@Column(value = "create_time")
private Date createTime;
/**
* 更新时间。
*/
@Column(value = "update_time")
private Date updateTime;
/**
* 逻辑删除标记字段(1: 正常 -1: 已删除)。
*/
@Column(value = "deleted_flag", isLogicDelete = true)
private Integer deletedFlag;
/**
* createTime 范围过滤起始值(>=)。
*/
@Column(ignore = true)
private String createTimeStart;
/**
* createTime 范围过滤结束值(<=)。
*/
@Column(ignore = true)
private String createTimeEnd;
/**
* 多对多用户部门岗位数据集合。
*/
@RelationManyToMany(
relationMasterIdField = "userId",
relationModelClass = SysUserPost.class)
@Column(ignore = true)
private List<SysUserPost> sysUserPostList;
/**
* 多对多用户角色数据集合。
*/
@RelationManyToMany(
relationMasterIdField = "userId",
relationModelClass = SysUserRole.class)
@Column(ignore = true)
private List<SysUserRole> sysUserRoleList;
/**
* 多对多用户数据权限数据集合。
*/
@RelationManyToMany(
relationMasterIdField = "userId",
relationModelClass = SysDataPermUser.class)
@Column(ignore = true)
private List<SysDataPermUser> sysDataPermUserList;
@RelationDict(
masterIdField = "deptId",
slaveModelClass = SysDept.class,
slaveIdField = "deptId",
slaveNameField = "deptName")
@Column(ignore = true)
private Map<String, Object> deptIdDictMap;
@RelationConstDict(
masterIdField = "userType",
constantDictClass = SysUserType.class)
@Column(ignore = true)
private Map<String, Object> userTypeDictMap;
@RelationConstDict(
masterIdField = "userStatus",
constantDictClass = SysUserStatus.class)
@Column(ignore = true)
private Map<String, Object> userStatusDictMap;
}

View File

@@ -0,0 +1,33 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
/**
* 用户岗位多对多关系实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_user_post")
public class SysUserPost {
/**
* 用户Id。
*/
@Column(value = "user_id")
private Long userId;
/**
* 部门岗位Id。
*/
@Column(value = "dept_post_id")
private Long deptPostId;
/**
* 岗位Id。
*/
@Column(value = "post_id")
private Long postId;
}

View File

@@ -0,0 +1,27 @@
package com.orangeforms.webadmin.upms.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
/**
* 用户角色实体对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_sys_user_role")
public class SysUserRole {
/**
* 用户Id。
*/
@Column(value = "user_id")
private Long userId;
/**
* 角色Id。
*/
@Column(value = "role_id")
private Long roleId;
}

View File

@@ -0,0 +1,54 @@
package com.orangeforms.webadmin.upms.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 菜单类型常量对象。
*
* @author Jerry
* @date 2024-07-02
*/
public final class SysMenuType {
/**
* 目录菜单。
*/
public static final int TYPE_DIRECTORY = 0;
/**
* 普通菜单。
*/
public static final int TYPE_MENU = 1;
/**
* 表单片段类型。
*/
public static final int TYPE_UI_FRAGMENT = 2;
/**
* 按钮类型。
*/
public static final int TYPE_BUTTON = 3;
private static final Map<Object, String> DICT_MAP = new HashMap<>(4);
static {
DICT_MAP.put(TYPE_DIRECTORY, "目录菜单");
DICT_MAP.put(TYPE_MENU, "普通菜单");
DICT_MAP.put(TYPE_UI_FRAGMENT, "表单片段类型");
DICT_MAP.put(TYPE_BUTTON, "按钮类型");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private SysMenuType() {
}
}

View File

@@ -0,0 +1,44 @@
package com.orangeforms.webadmin.upms.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 菜单关联在线表单的控制权限类型。
*
* @author Jerry
* @date 2024-07-02
*/
public final class SysOnlineMenuPermType {
/**
* 查看。
*/
public static final int TYPE_VIEW = 0;
/**
* 编辑。
*/
public static final int TYPE_EDIT = 1;
private static final Map<Object, String> DICT_MAP = new HashMap<>(4);
static {
DICT_MAP.put(TYPE_VIEW, "查看");
DICT_MAP.put(TYPE_EDIT, "编辑");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private SysOnlineMenuPermType() {
}
}

View File

@@ -0,0 +1,44 @@
package com.orangeforms.webadmin.upms.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 用户状态常量字典对象。
*
* @author Jerry
* @date 2024-07-02
*/
public final class SysUserStatus {
/**
* 正常状态。
*/
public static final int STATUS_NORMAL = 0;
/**
* 锁定状态。
*/
public static final int STATUS_LOCKED = 1;
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
static {
DICT_MAP.put(STATUS_NORMAL, "正常状态");
DICT_MAP.put(STATUS_LOCKED, "锁定状态");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private SysUserStatus() {
}
}

View File

@@ -0,0 +1,49 @@
package com.orangeforms.webadmin.upms.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 用户类型常量字典对象。
*
* @author Jerry
* @date 2024-07-02
*/
public final class SysUserType {
/**
* 管理员。
*/
public static final int TYPE_ADMIN = 0;
/**
* 系统操作员。
*/
public static final int TYPE_SYSTEM = 1;
/**
* 普通操作员。
*/
public static final int TYPE_OPERATOR = 2;
private static final Map<Object, String> DICT_MAP = new HashMap<>(3);
static {
DICT_MAP.put(TYPE_ADMIN, "管理员");
DICT_MAP.put(TYPE_SYSTEM, "系统操作员");
DICT_MAP.put(TYPE_OPERATOR, "普通操作员");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private SysUserType() {
}
}

View File

@@ -0,0 +1,114 @@
package com.orangeforms.webadmin.upms.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.common.core.object.CallResult;
import com.orangeforms.webadmin.upms.model.*;
import java.util.*;
/**
* 数据权限数据服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDataPermService extends IBaseService<SysDataPerm, Long> {
/**
* 保存新增的数据权限对象。
*
* @param dataPerm 新增的数据权限对象。
* @param deptIdSet 关联的部门Id列表。
* @param menuIdSet 关联的菜单Id列表。
* @return 新增后的数据权限对象。
*/
SysDataPerm saveNew(SysDataPerm dataPerm, Set<Long> deptIdSet, Set<Long> menuIdSet);
/**
* 更新数据权限对象。
*
* @param dataPerm 更新的数据权限对象。
* @param originalDataPerm 原有的数据权限对象。
* @param deptIdSet 关联的部门Id列表。
* @param menuIdSet 关联的菜单Id列表。
* @return 更新成功返回true否则false。
*/
boolean update(SysDataPerm dataPerm, SysDataPerm originalDataPerm, Set<Long> deptIdSet, Set<Long> menuIdSet);
/**
* 删除指定数据权限。
*
* @param dataPermId 数据权限主键Id。
* @return 删除成功返回true否则false。
*/
boolean remove(Long dataPermId);
/**
* 获取数据权限列表及其关联数据。
*
* @param filter 数据权限过滤对象。
* @param orderBy 排序参数。
* @return 数据权限查询列表。
*/
List<SysDataPerm> getSysDataPermListWithRelation(SysDataPerm filter, String orderBy);
/**
* 将指定用户的指定会话的数据权限集合存入缓存。
*
* @param sessionId 会话Id。
* @param userId 用户主键Id。
* @param deptId 用户所属部门主键Id。
*/
void putDataPermCache(String sessionId, Long userId, Long deptId);
/**
* 将指定会话的数据权限集合从缓存中移除。
*
* @param sessionId 会话Id。
*/
void removeDataPermCache(String sessionId);
/**
* 获取指定用户Id的数据权限列表。并基于menuId和权限规则类型进行了一级分组。
*
* @param userId 指定的用户Id。
* @param deptId 用户所属部门主键Id。
* @return 合并优化后的数据权限列表。返回格式为Map<MenuId, Map<RuleType, DeptIdString>>。
*/
Map<String, Map<Integer, String>> getSysDataPermListByUserId(Long userId, Long deptId);
/**
* 查询与指定菜单关联的数据权限列表。
*
* @param menuId 菜单Id。
* @return 与菜单Id关联的数据权限列表。
*/
List<SysDataPerm> getSysDataPermListByMenuId(Long menuId);
/**
* 添加用户和数据权限之间的多对多关联关系。
*
* @param dataPermId 数据权限Id。
* @param userIdSet 关联的用户Id列表。
*/
void addDataPermUserList(Long dataPermId, Set<Long> userIdSet);
/**
* 移除用户和数据权限之间的多对多关联关系。
*
* @param dataPermId 数据权限主键Id。
* @param userId 用户主键Id。
* @return true移除成功否则false。
*/
boolean removeDataPermUser(Long dataPermId, Long userId);
/**
* 验证数据权限对象关联菜单数据是否都合法。
*
* @param dataPerm 数据权限关对象。
* @param deptIdListString 与数据权限关联的部门Id列表。
* @param menuIdListString 与数据权限关联的菜单Id列表。
* @return 验证结果。
*/
CallResult verifyRelatedData(SysDataPerm dataPerm, String deptIdListString, String menuIdListString);
}

View File

@@ -0,0 +1,170 @@
package com.orangeforms.webadmin.upms.service;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.common.core.base.service.IBaseService;
import java.util.*;
/**
* 部门管理数据操作服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysDeptService extends IBaseService<SysDept, Long> {
/**
* 保存新增的部门对象。
*
* @param sysDept 新增的部门对象。
* @param parentSysDept 上级部门对象。
* @return 新增后的部门对象。
*/
SysDept saveNew(SysDept sysDept, SysDept parentSysDept);
/**
* 更新部门对象。
*
* @param sysDept 更新的部门对象。
* @param originalSysDept 原有的部门对象。
* @return 更新成功返回true否则false。
*/
boolean update(SysDept sysDept, SysDept originalSysDept);
/**
* 删除指定数据。
*
* @param deptId 主键Id。
* @return 成功返回true否则false。
*/
boolean remove(Long deptId);
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getSysDeptListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysDept> getSysDeptList(SysDept filter, String orderBy);
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
* 如果仅仅需要获取主表数据,请移步(getSysDeptList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysDept> getSysDeptListWithRelation(SysDept filter, String orderBy);
/**
* 判断指定对象是否包含下级对象。
*
* @param deptId 主键Id。
* @return 存在返回true否则false。
*/
boolean hasChildren(Long deptId);
/**
* 判断指定部门Id是否包含用户对象。
*
* @param deptId 部门主键Id。
* @return 存在返回true否则false。
*/
boolean hasChildrenUser(Long deptId);
/**
* 批量添加多对多关联关系。
*
* @param sysDeptPostList 多对多关联表对象集合。
* @param deptId 主表Id。
*/
void addSysDeptPostList(List<SysDeptPost> sysDeptPostList, Long deptId);
/**
* 更新中间表数据。
*
* @param sysDeptPost 中间表对象。
* @return 更新成功与否。
*/
boolean updateSysDeptPost(SysDeptPost sysDeptPost);
/**
* 移除单条多对多关系。
*
* @param deptId 主表Id。
* @param postId 从表Id。
* @return 成功返回true否则false。
*/
boolean removeSysDeptPost(Long deptId, Long postId);
/**
* 获取中间表数据。
*
* @param deptId 主表Id。
* @param postId 从表Id。
* @return 中间表对象。
*/
SysDeptPost getSysDeptPost(Long deptId, Long postId);
/**
* 根据部门岗位Id获取部门岗位关联对象。
*
* @param deptPostId 部门岗位Id。
* @return 部门岗位对象。
*/
SysDeptPost getSysDeptPost(Long deptPostId);
/**
* 获取指定部门Id的部门岗位多对多关联数据列表以及关联的部门和岗位数据。
*
* @param deptId 部门Id。如果参数为空则返回全部数据。
* @return 部门岗位多对多数据列表。
*/
List<Map<String, Object>> getSysDeptPostListWithRelationByDeptId(Long deptId);
/**
* 获取指定部门Id和岗位Id集合的部门岗位多对多关联数据列表。
*
* @param deptId 部门Id。
* @param postIdSet 指定的岗位Id集合。
* @return 部门岗位多对多数据列表。
*/
List<SysDeptPost> getSysDeptPostList(Long deptId, Set<Long> postIdSet);
/**
* 获取与指定部门Id同级部门和岗位Id集合的部门岗位多对多关联数据列表。
*
* @param deptId 部门Id。
* @param postIdSet 指定的岗位Id集合。
* @return 部门岗位多对多数据列表。
*/
List<SysDeptPost> getSiblingSysDeptPostList(Long deptId, Set<Long> postIdSet);
/**
* 根据部门Id获取该部门领导岗位的部门岗位Id集合。
*
* @param deptId 部门Id。
* @return 部门领导岗位的部门岗位Id集合。
*/
List<Long> getLeaderDeptPostIdList(Long deptId);
/**
* 根据部门Id获取上级部门领导岗位的部门岗位Id集合。
*
* @param deptId 部门Id。
* @return 上级部门领导岗位的部门岗位Id集合。
*/
List<Long> getUpLeaderDeptPostIdList(Long deptId);
/**
* 根据父主键Id列表获取当前部门Id及其所有下级部门Id列表。
*
* @param parentIds 父主键Id列表。
* @return 获取当前部门Id及其所有下级部门Id列表。
*/
List<Long> getAllChildDeptIdByParentIds(List<Long> parentIds);
}

View File

@@ -0,0 +1,72 @@
package com.orangeforms.webadmin.upms.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.webadmin.upms.model.SysMenu;
import java.util.*;
/**
* 菜单数据服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysMenuService extends IBaseService<SysMenu, Long> {
/**
* 保存新增的菜单对象。
*
* @param sysMenu 新增的菜单对象。
* @return 新增后的菜单对象。
*/
SysMenu saveNew(SysMenu sysMenu);
/**
* 更新菜单对象。
*
* @param sysMenu 更新的菜单对象。
* @param originalSysMenu 原有的菜单对象。
* @return 更新成功返回true否则false。
*/
boolean update(SysMenu sysMenu, SysMenu originalSysMenu);
/**
* 删除指定的菜单。
*
* @param menu 菜单对象。
* @return 删除成功返回true否则false。
*/
boolean remove(SysMenu menu);
/**
* 获取指定用户Id的菜单列表已去重。
*
* @param userId 用户主键Id。
* @return 用户关联的菜单列表。
*/
Collection<SysMenu> getMenuListByUserId(Long userId);
/**
* 根据角色Id集合获取菜单对象列表。
*
* @param roleIds 逗号分隔的角色Id集合。
* @return 菜单对象列表。
*/
Collection<SysMenu> getMenuListByRoleIds(String roleIds);
/**
* 判断当前菜单是否存在子菜单。
*
* @param menuId 菜单主键Id。
* @return 存在返回true否则false。
*/
boolean hasChildren(Long menuId);
/**
* 获取指定类型的所有在线表单的菜单。
*
* @param menuType 菜单类型NULL则返回全部类型。
* @return 在线表单关联的菜单列表。
*/
List<SysMenu> getAllOnlineMenuList(Integer menuType);
}

View File

@@ -0,0 +1,23 @@
package com.orangeforms.webadmin.upms.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.webadmin.upms.model.SysPermWhitelist;
import java.util.List;
/**
* 权限资源白名单数据服务接口。
* 白名单中的权限资源,可以不受权限控制,任何用户皆可访问,一般用于常用的字典数据列表接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysPermWhitelistService extends IBaseService<SysPermWhitelist, String> {
/**
* 获取白名单权限资源的列表。
*
* @return 白名单权限资源地址列表。
*/
List<String> getWhitelistPermList();
}

View File

@@ -0,0 +1,99 @@
package com.orangeforms.webadmin.upms.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.webadmin.upms.model.SysPost;
import com.orangeforms.webadmin.upms.model.SysUserPost;
import java.util.*;
/**
* 岗位管理数据操作服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysPostService extends IBaseService<SysPost, Long> {
/**
* 保存新增对象。
*
* @param sysPost 新增对象。
* @return 返回新增对象。
*/
SysPost saveNew(SysPost sysPost);
/**
* 更新数据对象。
*
* @param sysPost 更新的对象。
* @param originalSysPost 原有数据对象。
* @return 成功返回true否则false。
*/
boolean update(SysPost sysPost, SysPost originalSysPost);
/**
* 删除指定数据。
*
* @param postId 主键Id。
* @return 成功返回true否则false。
*/
boolean remove(Long postId);
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getSysPostListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysPost> getSysPostList(SysPost filter, String orderBy);
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
* 如果仅仅需要获取主表数据,请移步(getSysPostList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysPost> getSysPostListWithRelation(SysPost filter, String orderBy);
/**
* 在多对多关系中当前Service的数据表为从表返回不与指定主表主键Id存在对多对关系的列表。
*
* @param deptId 主表主键Id。
* @param filter 从表的过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysPost> getNotInSysPostListByDeptId(Long deptId, SysPost filter, String orderBy);
/**
* 获取指定部门的岗位列表。
*
* @param deptId 部门Id。
* @param filter 从表的过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysPost> getSysPostListByDeptId(Long deptId, SysPost filter, String orderBy);
/**
* 获取指定用户的用户岗位多对多关联数据列表。
*
* @param userId 用户Id。
* @return 用户岗位多对多关联数据列表。
*/
List<SysUserPost> getSysUserPostListByUserId(Long userId);
/**
* 判断指定的部门岗位Id集合是否都属于指定的部门Id。
*
* @param deptPostIdSet 部门岗位Id集合。
* @param deptId 部门Id。
* @return 全部是返回true否则false。
*/
boolean existAllPrimaryKeys(Set<Long> deptPostIdSet, Long deptId);
}

View File

@@ -0,0 +1,87 @@
package com.orangeforms.webadmin.upms.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.common.core.object.CallResult;
import com.orangeforms.webadmin.upms.model.SysRole;
import com.orangeforms.webadmin.upms.model.SysUserRole;
import java.util.*;
/**
* 角色数据服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysRoleService extends IBaseService<SysRole, Long> {
/**
* 保存新增的角色对象。
*
* @param role 新增的角色对象。
* @param menuIdSet 菜单Id列表。
* @return 新增后的角色对象。
*/
SysRole saveNew(SysRole role, Set<Long> menuIdSet);
/**
* 更新角色对象。
*
* @param role 更新的角色对象。
* @param originalRole 原有的角色对象。
* @param menuIdSet 菜单Id列表。
* @return 更新成功返回true否则false。
*/
boolean update(SysRole role, SysRole originalRole, Set<Long> menuIdSet);
/**
* 删除指定角色。
*
* @param roleId 角色主键Id。
* @return 删除成功返回true否则false。
*/
boolean remove(Long roleId);
/**
* 获取角色列表。
*
* @param filter 角色过滤对象。
* @param orderBy 排序参数。
* @return 角色列表。
*/
List<SysRole> getSysRoleList(SysRole filter, String orderBy);
/**
* 获取用户的用户角色对象列表。
*
* @param userId 用户Id。
* @return 用户角色对象列表。
*/
List<SysUserRole> getSysUserRoleListByUserId(Long userId);
/**
* 批量新增用户角色关联。
*
* @param userRoleList 用户角色关系数据列表。
*/
void addUserRoleList(List<SysUserRole> userRoleList);
/**
* 移除指定用户和指定角色的关联关系。
*
* @param roleId 角色主键Id。
* @param userId 用户主键Id。
* @return 移除成功返回true否则false。
*/
boolean removeUserRole(Long roleId, Long userId);
/**
* 验证角色对象关联的数据是否都合法。
*
* @param sysRole 当前操作的对象。
* @param originalSysRole 原有对象。
* @param menuIdListString 逗号分隔的menuId列表。
* @return 验证结果。
*/
CallResult verifyRelatedData(SysRole sysRole, SysRole originalSysRole, String menuIdListString);
}

View File

@@ -0,0 +1,176 @@
package com.orangeforms.webadmin.upms.service;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.common.core.object.CallResult;
import com.orangeforms.common.core.base.service.IBaseService;
import java.util.*;
/**
* 用户管理数据操作服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface SysUserService extends IBaseService<SysUser, Long> {
/**
* 获取指定登录名的用户对象。
*
* @param loginName 指定登录用户名。
* @return 用户对象。
*/
SysUser getSysUserByLoginName(String loginName);
/**
* 保存新增的用户对象。
*
* @param user 新增的用户对象。
* @param roleIdSet 用户角色Id集合。
* @param deptPostIdSet 部门岗位Id集合。
* @param dataPermIdSet 数据权限Id集合。
* @return 新增后的用户对象。
*/
SysUser saveNew(SysUser user, Set<Long> roleIdSet, Set<Long> deptPostIdSet, Set<Long> dataPermIdSet);
/**
* 更新用户对象。
*
* @param user 更新的用户对象。
* @param originalUser 原有的用户对象。
* @param roleIdSet 用户角色Id列表。
* @param deptPostIdSet 部门岗位Id集合。
* @param dataPermIdSet 数据权限Id集合。
* @return 更新成功返回true否则false。
*/
boolean update(SysUser user, SysUser originalUser, Set<Long> roleIdSet, Set<Long> deptPostIdSet, Set<Long> dataPermIdSet);
/**
* 修改用户密码。
* @param userId 用户主键Id。
* @param newPass 新密码。
* @return 成功返回true否则false。
*/
boolean changePassword(Long userId, String newPass);
/**
* 修改用户头像。
*
* @param userId 用户主键Id。
* @param newHeadImage 新的头像信息。
* @return 成功返回true否则false。
*/
boolean changeHeadImage(Long userId, String newHeadImage);
/**
* 删除指定数据。
*
* @param userId 主键Id。
* @return 成功返回true否则false。
*/
boolean remove(Long userId);
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getSysUserListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysUser> getSysUserList(SysUser filter, String orderBy);
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
* 如果仅仅需要获取主表数据,请移步(getSysUserList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<SysUser> getSysUserListWithRelation(SysUser filter, String orderBy);
/**
* 获取指定角色的用户列表。
*
* @param roleId 角色主键Id。
* @param filter 用户过滤对象。
* @param orderBy 排序参数。
* @return 用户列表。
*/
List<SysUser> getSysUserListByRoleId(Long roleId, SysUser filter, String orderBy);
/**
* 获取不属于指定角色的用户列表。
*
* @param roleId 角色主键Id。
* @param filter 用户过滤对象。
* @param orderBy 排序参数。
* @return 用户列表。
*/
List<SysUser> getNotInSysUserListByRoleId(Long roleId, SysUser filter, String orderBy);
/**
* 获取指定数据权限的用户列表。
*
* @param dataPermId 数据权限主键Id。
* @param filter 用户过滤对象。
* @param orderBy 排序参数。
* @return 用户列表。
*/
List<SysUser> getSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy);
/**
* 获取不属于指定数据权限的用户列表。
*
* @param dataPermId 数据权限主键Id。
* @param filter 用户过滤对象。
* @param orderBy 排序参数。
* @return 用户列表。
*/
List<SysUser> getNotInSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy);
/**
* 获取指定部门岗位的用户列表。
*
* @param deptPostId 部门岗位主键Id。
* @param filter 用户过滤对象。
* @param orderBy 排序参数。
* @return 用户列表。
*/
List<SysUser> getSysUserListByDeptPostId(Long deptPostId, SysUser filter, String orderBy);
/**
* 获取不属于指定部门岗位的用户列表。
*
* @param deptPostId 部门岗位主键Id。
* @param filter 用户过滤对象。
* @param orderBy 排序参数。
* @return 用户列表。
*/
List<SysUser> getNotInSysUserListByDeptPostId(Long deptPostId, SysUser filter, String orderBy);
/**
* 获取指定岗位的用户列表。
*
* @param postId 岗位主键Id。
* @param filter 用户过滤对象。
* @param orderBy 排序参数。
* @return 用户列表。
*/
List<SysUser> getSysUserListByPostId(Long postId, SysUser filter, String orderBy);
/**
* 验证用户对象关联的数据是否都合法。
*
* @param sysUser 当前操作的对象。
* @param originalSysUser 原有对象。
* @param roleIds 逗号分隔的角色Id列表字符串。
* @param deptPostIds 逗号分隔的部门岗位Id列表字符串。
* @param dataPermIds 逗号分隔的数据权限Id列表字符串。
* @return 验证结果。
*/
CallResult verifyRelatedData(
SysUser sysUser, SysUser originalSysUser, String roleIds, String deptPostIds, String dataPermIds);
}

View File

@@ -0,0 +1,335 @@
package com.orangeforms.webadmin.upms.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mybatisflex.core.query.QueryWrapper;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import com.orangeforms.common.core.constant.DataPermRuleType;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.object.MyRelationParam;
import com.orangeforms.common.core.object.CallResult;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.RedisKeyUtil;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.webadmin.config.ApplicationConfig;
import com.orangeforms.webadmin.upms.dao.SysDataPermDeptMapper;
import com.orangeforms.webadmin.upms.dao.SysDataPermMapper;
import com.orangeforms.webadmin.upms.dao.SysDataPermUserMapper;
import com.orangeforms.webadmin.upms.dao.SysDataPermMenuMapper;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.webadmin.upms.service.SysDataPermService;
import com.orangeforms.webadmin.upms.service.SysDeptService;
import com.orangeforms.webadmin.upms.service.SysMenuService;
import com.orangeforms.webadmin.upms.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 数据权限数据服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Service("sysDataPermService")
public class SysDataPermServiceImpl extends BaseService<SysDataPerm, Long> implements SysDataPermService {
@Autowired
private SysDataPermMapper sysDataPermMapper;
@Autowired
private SysDataPermDeptMapper sysDataPermDeptMapper;
@Autowired
private SysDataPermUserMapper sysDataPermUserMapper;
@Autowired
private SysDataPermMenuMapper sysDataPermMenuMapper;
@Autowired
private SysUserService sysUserService;
@Autowired
private SysDeptService sysDeptService;
@Autowired
private SysMenuService sysMenuService;
@Autowired
private RedissonClient redissonClient;
@Autowired
private ApplicationConfig applicationConfig;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回主对象的Mapper对象。
*
* @return 主对象的Mapper对象。
*/
@Override
protected BaseDaoMapper<SysDataPerm> mapper() {
return sysDataPermMapper;
}
@Transactional(rollbackFor = Exception.class)
@Override
public SysDataPerm saveNew(SysDataPerm dataPerm, Set<Long> deptIdSet, Set<Long> menuIdSet) {
dataPerm.setDataPermId(idGenerator.nextLongId());
MyModelUtil.fillCommonsForInsert(dataPerm);
sysDataPermMapper.insert(dataPerm);
this.insertRelationData(dataPerm, deptIdSet, menuIdSet);
return dataPerm;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(
SysDataPerm dataPerm, SysDataPerm originalDataPerm, Set<Long> deptIdSet, Set<Long> menuIdSet) {
MyModelUtil.fillCommonsForUpdate(dataPerm, originalDataPerm);
if (sysDataPermMapper.update(dataPerm, false) != 1) {
return false;
}
sysDataPermDeptMapper.deleteByQuery(
new QueryWrapper().eq(SysDataPermDept::getDataPermId, dataPerm.getDataPermId()));
sysDataPermMenuMapper.deleteByQuery(
new QueryWrapper().eq(SysDataPermMenu::getDataPermId, dataPerm.getDataPermId()));
this.insertRelationData(dataPerm, deptIdSet, menuIdSet);
return true;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long dataPermId) {
if (sysDataPermMapper.deleteById(dataPermId) != 1) {
return false;
}
sysDataPermDeptMapper.deleteByQuery(new QueryWrapper().eq(SysDataPermDept::getDataPermId, dataPermId));
sysDataPermUserMapper.deleteByQuery(new QueryWrapper().eq(SysDataPermUser::getDataPermId, dataPermId));
sysDataPermMenuMapper.deleteByQuery(new QueryWrapper().eq(SysDataPermMenu::getDataPermId, dataPermId));
return true;
}
@Override
public List<SysDataPerm> getSysDataPermListWithRelation(SysDataPerm filter, String orderBy) {
List<SysDataPerm> resultList = sysDataPermMapper.getSysDataPermList(filter, orderBy);
buildRelationForDataList(resultList, MyRelationParam.full(), CollUtil.newHashSet("dataPermDeptList"));
return resultList;
}
@Override
public void putDataPermCache(String sessionId, Long userId, Long deptId) {
Map<String, Map<Integer, String>> menuDataPermMap = getSysDataPermListByUserId(userId, deptId);
if (menuDataPermMap.size() > 0) {
String dataPermSessionKey = RedisKeyUtil.makeSessionDataPermIdKey(sessionId);
RBucket<String> bucket = redissonClient.getBucket(dataPermSessionKey);
bucket.set(JSON.toJSONString(menuDataPermMap),
applicationConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS);
}
}
@Override
public void removeDataPermCache(String sessionId) {
String sessionPermKey = RedisKeyUtil.makeSessionDataPermIdKey(sessionId);
redissonClient.getBucket(sessionPermKey).deleteAsync();
}
@Override
public Map<String, Map<Integer, String>> getSysDataPermListByUserId(Long userId, Long deptId) {
List<SysDataPerm> dataPermList = sysDataPermMapper.getSysDataPermListByUserId(userId);
dataPermList.forEach(dataPerm -> {
if (CollUtil.isNotEmpty(dataPerm.getDataPermDeptList())) {
Set<Long> deptIdSet = dataPerm.getDataPermDeptList().stream()
.map(SysDataPermDept::getDeptId).collect(Collectors.toSet());
dataPerm.setDeptIdListString(StrUtil.join(",", deptIdSet));
}
});
Map<String, List<SysDataPerm>> menuIdMap = new HashMap<>(4);
for (SysDataPerm dataPerm : dataPermList) {
if (CollUtil.isNotEmpty(dataPerm.getDataPermMenuList())) {
for (SysDataPermMenu dataPermMenu : dataPerm.getDataPermMenuList()) {
menuIdMap.computeIfAbsent(
dataPermMenu.getMenuId().toString(), k -> new LinkedList<>()).add(dataPerm);
}
} else {
menuIdMap.computeIfAbsent(
ApplicationConstant.DATA_PERM_ALL_MENU_ID, k -> new LinkedList<>()).add(dataPerm);
}
}
Map<String, Map<Integer, String>> menuResultMap = new HashMap<>(menuIdMap.size());
for (Map.Entry<String, List<SysDataPerm>> entry : menuIdMap.entrySet()) {
Map<Integer, String> resultMap = this.mergeAndOptimizeDataPermRule(entry.getValue(), deptId);
menuResultMap.put(entry.getKey(), resultMap);
}
return menuResultMap;
}
@Override
public List<SysDataPerm> getSysDataPermListByMenuId(Long menuId) {
return sysDataPermMapper.getSysDataPermListByMenuId(menuId);
}
private Map<Integer, String> mergeAndOptimizeDataPermRule(List<SysDataPerm> dataPermList, Long deptId) {
// 为了更方便进行后续的合并优化处理这里再基于菜单Id和规则类型进行分组。ruleMap的key是规则类型。
Map<Integer, List<SysDataPerm>> ruleMap =
dataPermList.stream().collect(Collectors.groupingBy(SysDataPerm::getRuleType));
Map<Integer, String> resultMap = new HashMap<>(ruleMap.size());
// 如有有ALL存在就可以直接退出了没有必要在处理后续的规则了。
if (ruleMap.containsKey(DataPermRuleType.TYPE_ALL)) {
resultMap.put(DataPermRuleType.TYPE_ALL, "null");
return resultMap;
}
// 这里优先合并最复杂的多部门及子部门场景。
String deptIds = processMultiDeptAndChildren(ruleMap, deptId);
if (deptIds != null) {
resultMap.put(DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT, deptIds);
}
// 合并当前部门及子部门的优化
if (ruleMap.get(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT) != null) {
// 需要与仅仅当前部门规则进行合并。
ruleMap.remove(DataPermRuleType.TYPE_DEPT_ONLY);
resultMap.put(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT, "null");
}
// 合并自定义部门了。
deptIds = processMultiDept(ruleMap, deptId);
if (deptIds != null) {
resultMap.put(DataPermRuleType.TYPE_CUSTOM_DEPT_LIST, deptIds);
}
// 最后处理当前部门和当前用户。
if (ruleMap.get(DataPermRuleType.TYPE_DEPT_ONLY) != null) {
resultMap.put(DataPermRuleType.TYPE_DEPT_ONLY, "null");
}
if (ruleMap.get(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT_USERS) != null) {
// 合并当前部门用户和当前用户
ruleMap.remove(DataPermRuleType.TYPE_USER_ONLY);
ruleMap.remove(DataPermRuleType.TYPE_DEPT_USERS);
SysUser filter = new SysUser();
filter.setDeptId(deptId);
List<SysUser> userList = sysUserService.getSysUserList(filter, null);
Set<Long> userIdSet = userList.stream().map(SysUser::getUserId).collect(Collectors.toSet());
resultMap.put(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT_USERS, CollUtil.join(userIdSet, ","));
}
if (ruleMap.get(DataPermRuleType.TYPE_DEPT_USERS) != null) {
SysUser filter = new SysUser();
filter.setDeptId(deptId);
List<SysUser> userList = sysUserService.getListByFilter(filter);
Set<Long> userIdSet = userList.stream().map(SysUser::getUserId).collect(Collectors.toSet());
// 合并仅当前用户
ruleMap.remove(DataPermRuleType.TYPE_USER_ONLY);
resultMap.put(DataPermRuleType.TYPE_DEPT_USERS, CollUtil.join(userIdSet, ","));
}
if (ruleMap.get(DataPermRuleType.TYPE_USER_ONLY) != null) {
resultMap.put(DataPermRuleType.TYPE_USER_ONLY, "null");
}
return resultMap;
}
private String processMultiDeptAndChildren(Map<Integer, List<SysDataPerm>> ruleMap, Long deptId) {
List<SysDataPerm> parentDeptList = ruleMap.get(DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT);
if (parentDeptList == null) {
return null;
}
Set<Long> deptIdSet = new HashSet<>();
for (SysDataPerm parentDept : parentDeptList) {
deptIdSet.addAll(StrUtil.split(parentDept.getDeptIdListString(), ',')
.stream().map(Long::valueOf).collect(Collectors.toSet()));
}
// 在合并所有的多父部门Id之后需要判断是否有本部门及子部门的规则。如果有就继续合并。
if (ruleMap.containsKey(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT)) {
// 如果多父部门列表中包含当前部门那么可以直接删除该规则了如果没包含就加入到多部门的DEPT_ID的IN LIST中。
deptIdSet.add(deptId);
ruleMap.remove(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT);
}
// 需要与仅仅当前部门规则进行合并。
if (ruleMap.containsKey(DataPermRuleType.TYPE_DEPT_ONLY) && deptIdSet.contains(deptId)) {
ruleMap.remove(DataPermRuleType.TYPE_DEPT_ONLY);
}
return StrUtil.join(",", deptIdSet);
}
private String processMultiDept(Map<Integer, List<SysDataPerm>> ruleMap, Long deptId) {
List<SysDataPerm> customDeptList = ruleMap.get(DataPermRuleType.TYPE_CUSTOM_DEPT_LIST);
if (customDeptList == null) {
return null;
}
Set<Long> deptIdSet = new HashSet<>();
for (SysDataPerm customDept : customDeptList) {
deptIdSet.addAll(StrUtil.split(customDept.getDeptIdListString(), ',')
.stream().map(Long::valueOf).collect(Collectors.toSet()));
}
if (ruleMap.containsKey(DataPermRuleType.TYPE_DEPT_ONLY)) {
deptIdSet.add(deptId);
ruleMap.remove(DataPermRuleType.TYPE_DEPT_ONLY);
}
return StrUtil.join(",", deptIdSet);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void addDataPermUserList(Long dataPermId, Set<Long> userIdSet) {
for (Long userId : userIdSet) {
SysDataPermUser dataPermUser = new SysDataPermUser();
dataPermUser.setDataPermId(dataPermId);
dataPermUser.setUserId(userId);
sysDataPermUserMapper.insert(dataPermUser);
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean removeDataPermUser(Long dataPermId, Long userId) {
SysDataPermUser dataPermUser = new SysDataPermUser();
dataPermUser.setDataPermId(dataPermId);
dataPermUser.setUserId(userId);
return sysDataPermUserMapper.deleteByQuery(QueryWrapper.create(dataPermUser)) == 1;
}
@Override
public CallResult verifyRelatedData(SysDataPerm dataPerm, String deptIdListString, String menuIdListString) {
JSONObject jsonObject = new JSONObject();
if (dataPerm.getRuleType() == DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT
|| dataPerm.getRuleType() == DataPermRuleType.TYPE_CUSTOM_DEPT_LIST) {
if (StrUtil.isBlank(deptIdListString)) {
return CallResult.error("数据验证失败,部门列表不能为空!");
}
Set<Long> deptIdSet = StrUtil.split(
deptIdListString, ",").stream().map(Long::valueOf).collect(Collectors.toSet());
if (!sysDeptService.existAllPrimaryKeys(deptIdSet)) {
return CallResult.error("数据验证失败,存在不合法的部门数据,请刷新后重试!");
}
jsonObject.put("deptIdSet", deptIdSet);
}
if (StrUtil.isNotBlank(menuIdListString)) {
Set<Long> menuIdSet = StrUtil.split(
menuIdListString, ",").stream().map(Long::valueOf).collect(Collectors.toSet());
if (!sysMenuService.existAllPrimaryKeys(menuIdSet)) {
return CallResult.error("数据验证失败,存在不合法的菜单数据,请刷新后重试!");
}
jsonObject.put("menuIdSet", menuIdSet);
}
return CallResult.ok(jsonObject);
}
private void insertRelationData(SysDataPerm dataPerm, Set<Long> deptIdSet, Set<Long> menuIdSet) {
if (CollUtil.isNotEmpty(deptIdSet)) {
for (Long deptId : deptIdSet) {
SysDataPermDept dataPermDept = new SysDataPermDept();
dataPermDept.setDataPermId(dataPerm.getDataPermId());
dataPermDept.setDeptId(deptId);
sysDataPermDeptMapper.insert(dataPermDept);
}
}
if (CollUtil.isNotEmpty(menuIdSet)) {
for (Long menuId : menuIdSet) {
SysDataPermMenu dataPermMenu = new SysDataPermMenu();
dataPermMenu.setDataPermId(dataPerm.getDataPermId());
dataPermMenu.setMenuId(menuId);
sysDataPermMenuMapper.insert(dataPermMenu);
}
}
}
}

View File

@@ -0,0 +1,312 @@
package com.orangeforms.webadmin.upms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.webadmin.upms.service.*;
import com.orangeforms.webadmin.upms.dao.*;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.common.ext.util.BizWidgetDatasourceExtHelper;
import com.orangeforms.common.ext.base.BizWidgetDatasource;
import com.orangeforms.common.ext.constant.BizWidgetDatasourceType;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.MyPageUtil;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import com.github.pagehelper.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
* 部门管理数据操作服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Service("sysDeptService")
public class SysDeptServiceImpl extends BaseService<SysDept, Long> implements SysDeptService, BizWidgetDatasource {
@Autowired
private IdGeneratorWrapper idGenerator;
@Autowired
private SysDeptMapper sysDeptMapper;
@Autowired
private SysDeptRelationMapper sysDeptRelationMapper;
@Autowired
private SysUserService sysUserService;
@Autowired
private SysDeptPostMapper sysDeptPostMapper;
@Autowired
private SysDataPermDeptMapper sysDataPermDeptMapper;
@Autowired
private BizWidgetDatasourceExtHelper bizWidgetDatasourceExtHelper;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<SysDept> mapper() {
return sysDeptMapper;
}
@PostConstruct
private void registerBizWidgetDatasource() {
bizWidgetDatasourceExtHelper.registerDatasource(BizWidgetDatasourceType.UPMS_DEPT_TYPE, this);
}
@Override
public MyPageData<Map<String, Object>> getDataList(
String type, Map<String, Object> filter, MyOrderParam orderParam, MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
String orderBy = orderParam == null ? null : MyOrderParam.buildOrderBy(orderParam, SysDept.class);
SysDept deptFilter = filter == null ? null : BeanUtil.toBean(filter, SysDept.class);
List<SysDept> deptList = this.getSysDeptList(deptFilter, orderBy);
this.buildRelationForDataList(deptList, MyRelationParam.dictOnly());
return MyPageUtil.makeResponseData(deptList, BeanUtil::beanToMap);
}
@Override
public List<Map<String, Object>> getDataListWithInList(String type, String fieldName, List<String> fieldValues) {
List<SysDept> deptList;
if (StrUtil.isBlank(fieldName)) {
deptList = this.getInList(fieldValues.stream().map(Long::valueOf).collect(Collectors.toSet()));
} else {
deptList = this.getInList(fieldName, MyModelUtil.convertToTypeValues(SysDept.class, fieldName, fieldValues));
}
this.buildRelationForDataList(deptList, MyRelationParam.dictOnly());
return MyModelUtil.beanToMapList(deptList);
}
@Transactional(rollbackFor = Exception.class)
@Override
public SysDept saveNew(SysDept sysDept, SysDept parentSysDept) {
sysDept.setDeptId(idGenerator.nextLongId());
sysDept.setDeletedFlag(GlobalDeletedFlag.NORMAL);
MyModelUtil.fillCommonsForInsert(sysDept);
sysDeptMapper.insert(sysDept);
// 同步插入部门关联关系数据
if (parentSysDept == null) {
sysDeptRelationMapper.insert(new SysDeptRelation(sysDept.getDeptId(), sysDept.getDeptId()));
} else {
sysDeptRelationMapper.insertParentList(parentSysDept.getDeptId(), sysDept.getDeptId());
}
return sysDept;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(SysDept sysDept, SysDept originalSysDept) {
MyModelUtil.fillCommonsForUpdate(sysDept, originalSysDept);
sysDept.setDeletedFlag(GlobalDeletedFlag.NORMAL);
if (sysDeptMapper.update(sysDept, false) == 0) {
return false;
}
if (ObjectUtil.notEqual(sysDept.getParentId(), originalSysDept.getParentId())) {
this.updateParentRelation(sysDept, originalSysDept);
}
return true;
}
private void updateParentRelation(SysDept sysDept, SysDept originalSysDept) {
List<Long> originalParentIdList = null;
// 1. 因为层级关系变化了所以要先遍历出当前部门的原有父部门Id列表。
if (originalSysDept.getParentId() != null) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(SysDeptRelation::getDeptId, sysDept.getDeptId());
List<SysDeptRelation> relationList = sysDeptRelationMapper.selectListByQuery(queryWrapper);
originalParentIdList = relationList.stream()
.filter(c -> !c.getParentDeptId().equals(sysDept.getDeptId()))
.map(SysDeptRelation::getParentDeptId).collect(Collectors.toList());
}
// 2. 毕竟当前部门的上级部门变化了,所以当前部门和他的所有子部门,与当前部门的原有所有上级部门
// 之间的关联关系就要被移除。
// 这里先移除当前部门的所有子部门,与当前部门的所有原有上级部门之间的关联关系。
if (CollUtil.isNotEmpty(originalParentIdList)) {
sysDeptRelationMapper.removeBetweenChildrenAndParents(originalParentIdList, sysDept.getDeptId());
}
// 这里更进一步将当前部门Id与其原有所有上级部门Id之间的关联关系删除。
SysDeptRelation filter = new SysDeptRelation();
filter.setDeptId(sysDept.getDeptId());
sysDeptRelationMapper.deleteByQuery(QueryWrapper.create(filter));
// 3. 重新计算当前部门的新上级部门列表。
List<Long> newParentIdList = new LinkedList<>();
// 这里要重新计算出当前部门所有新的上级部门Id列表。
if (sysDept.getParentId() != null) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(SysDeptRelation::getDeptId, sysDept.getParentId());
List<SysDeptRelation> relationList = sysDeptRelationMapper.selectListByQuery(queryWrapper);
newParentIdList = relationList.stream()
.map(SysDeptRelation::getParentDeptId).collect(Collectors.toList());
}
// 4. 先查询出当前部门的所有下级子部门Id列表。
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(SysDeptRelation::getParentDeptId, sysDept.getDeptId());
List<SysDeptRelation> childRelationList = sysDeptRelationMapper.selectListByQuery(queryWrapper);
// 5. 将当前部门及其所有子部门Id与其新的所有上级部门Id之间建立关联关系。
List<SysDeptRelation> deptRelationList = new LinkedList<>();
deptRelationList.add(new SysDeptRelation(sysDept.getDeptId(), sysDept.getDeptId()));
for (Long newParentId : newParentIdList) {
deptRelationList.add(new SysDeptRelation(newParentId, sysDept.getDeptId()));
for (SysDeptRelation childDeptRelation : childRelationList) {
deptRelationList.add(new SysDeptRelation(newParentId, childDeptRelation.getDeptId()));
}
}
// 6. 执行批量插入SQL语句插入当前部门Id及其所有下级子部门Id与所有新上级部门Id之间的关联关系。
sysDeptRelationMapper.insertList(deptRelationList);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long deptId) {
if (sysDeptMapper.deleteById(deptId) == 0) {
return false;
}
// 这里删除当前部门及其父部门的关联关系。
// 当前部门和子部门的关系无需在这里删除,因为包含子部门时不能删除父部门。
SysDeptRelation deptRelation = new SysDeptRelation();
deptRelation.setDeptId(deptId);
sysDeptRelationMapper.deleteByQuery(QueryWrapper.create(deptRelation));
SysDataPermDept dataPermDept = new SysDataPermDept();
dataPermDept.setDeptId(deptId);
sysDataPermDeptMapper.deleteByQuery(QueryWrapper.create(dataPermDept));
return true;
}
@Override
public List<SysDept> getSysDeptList(SysDept filter, String orderBy) {
return sysDeptMapper.getSysDeptList(filter, orderBy);
}
@Override
public List<SysDept> getSysDeptListWithRelation(SysDept filter, String orderBy) {
List<SysDept> resultList = sysDeptMapper.getSysDeptList(filter, orderBy);
// 在缺省生成的代码中如果查询结果resultList不是Page对象说明没有分页那么就很可能是数据导出接口调用了当前方法。
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
int batchSize = resultList instanceof Page ? 0 : 1000;
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize);
return resultList;
}
@Override
public boolean hasChildren(Long deptId) {
SysDept filter = new SysDept();
filter.setParentId(deptId);
return getCountByFilter(filter) > 0;
}
@Override
public boolean hasChildrenUser(Long deptId) {
SysUser sysUser = new SysUser();
sysUser.setDeptId(deptId);
return sysUserService.getCountByFilter(sysUser) > 0;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void addSysDeptPostList(List<SysDeptPost> sysDeptPostList, Long deptId) {
for (SysDeptPost sysDeptPost : sysDeptPostList) {
sysDeptPost.setDeptPostId(idGenerator.nextLongId());
sysDeptPost.setDeptId(deptId);
sysDeptPostMapper.insert(sysDeptPost);
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateSysDeptPost(SysDeptPost sysDeptPost) {
SysDeptPost filter = new SysDeptPost();
filter.setDeptPostId(sysDeptPost.getDeptPostId());
filter.setDeptId(sysDeptPost.getDeptId());
filter.setPostId(sysDeptPost.getPostId());
return sysDeptPostMapper.updateByQuery(sysDeptPost, false, QueryWrapper.create(filter)) > 0;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean removeSysDeptPost(Long deptId, Long postId) {
SysDeptPost filter = new SysDeptPost();
filter.setDeptId(deptId);
filter.setPostId(postId);
return sysDeptPostMapper.deleteByQuery(QueryWrapper.create(filter)) > 0;
}
@Override
public SysDeptPost getSysDeptPost(Long deptId, Long postId) {
SysDeptPost filter = new SysDeptPost();
filter.setDeptId(deptId);
filter.setPostId(postId);
return sysDeptPostMapper.selectOneByQuery(QueryWrapper.create(filter));
}
@Override
public SysDeptPost getSysDeptPost(Long deptPostId) {
return sysDeptPostMapper.selectOneById(deptPostId);
}
@Override
public List<Map<String, Object>> getSysDeptPostListWithRelationByDeptId(Long deptId) {
return sysDeptPostMapper.getSysDeptPostListWithRelationByDeptId(deptId);
}
@Override
public List<SysDeptPost> getSysDeptPostList(Long deptId, Set<Long> postIdSet) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(SysDeptPost::getDeptId, deptId);
queryWrapper.in(SysDeptPost::getPostId, postIdSet);
return sysDeptPostMapper.selectListByQuery(queryWrapper);
}
@Override
public List<SysDeptPost> getSiblingSysDeptPostList(Long deptId, Set<Long> postIdSet) {
SysDept sysDept = this.getById(deptId);
if (sysDept == null) {
return new LinkedList<>();
}
List<SysDept> deptList = this.getListByParentId("parentId", sysDept.getParentId());
Set<Long> deptIdSet = deptList.stream().map(SysDept::getDeptId).collect(Collectors.toSet());
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.in(SysDeptPost::getDeptId, deptIdSet);
queryWrapper.in(SysDeptPost::getPostId, postIdSet);
return sysDeptPostMapper.selectListByQuery(queryWrapper);
}
@Override
public List<Long> getLeaderDeptPostIdList(Long deptId) {
List<SysDeptPost> resultList = sysDeptPostMapper.getLeaderDeptPostList(deptId);
return resultList.stream().map(SysDeptPost::getDeptPostId).collect(Collectors.toList());
}
@Override
public List<Long> getUpLeaderDeptPostIdList(Long deptId) {
SysDept sysDept = this.getById(deptId);
if (sysDept.getParentId() == null) {
return new LinkedList<>();
}
return this.getLeaderDeptPostIdList(sysDept.getParentId());
}
@Override
public List<Long> getAllChildDeptIdByParentIds(List<Long> parentIds) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.in(SysDeptRelation::getParentDeptId, parentIds);
return sysDeptRelationMapper.selectListByQuery(queryWrapper)
.stream().map(SysDeptRelation::getDeptId).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,233 @@
package com.orangeforms.webadmin.upms.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.mybatisflex.core.query.QueryWrapper;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.object.CallResult;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import com.orangeforms.webadmin.upms.bo.SysMenuExtraData;
import com.orangeforms.webadmin.upms.dao.SysMenuMapper;
import com.orangeforms.webadmin.upms.dao.SysRoleMenuMapper;
import com.orangeforms.webadmin.upms.model.SysMenu;
import com.orangeforms.webadmin.upms.model.SysRoleMenu;
import com.orangeforms.webadmin.upms.model.constant.SysMenuType;
import com.orangeforms.webadmin.upms.model.constant.SysOnlineMenuPermType;
import com.orangeforms.webadmin.upms.service.SysMenuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* 菜单数据服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Service("sysMenuService")
public class SysMenuServiceImpl extends BaseService<SysMenu, Long> implements SysMenuService {
@Autowired
private SysMenuMapper sysMenuMapper;
@Autowired
private SysRoleMenuMapper sysRoleMenuMapper;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回主对象的Mapper对象。
*
* @return 主对象的Mapper对象。
*/
@Override
protected BaseDaoMapper<SysMenu> mapper() {
return sysMenuMapper;
}
@Transactional(rollbackFor = Exception.class)
@Override
public SysMenu saveNew(SysMenu sysMenu) {
sysMenu.setMenuId(idGenerator.nextLongId());
MyModelUtil.fillCommonsForInsert(sysMenu);
sysMenuMapper.insert(sysMenu);
// 判断当前菜单是否为指向在线表单的菜单,并将根据约定,动态插入两个子菜单。
if (sysMenu.getOnlineFormId() != null && sysMenu.getOnlineFlowEntryId() == null) {
SysMenu viewSubMenu = new SysMenu();
viewSubMenu.setMenuId(idGenerator.nextLongId());
viewSubMenu.setParentId(sysMenu.getMenuId());
viewSubMenu.setMenuType(SysMenuType.TYPE_BUTTON);
viewSubMenu.setMenuName("查看");
viewSubMenu.setShowOrder(0);
viewSubMenu.setOnlineFormId(sysMenu.getOnlineFormId());
viewSubMenu.setOnlineMenuPermType(SysOnlineMenuPermType.TYPE_VIEW);
MyModelUtil.fillCommonsForInsert(viewSubMenu);
sysMenuMapper.insert(viewSubMenu);
SysMenu editSubMenu = new SysMenu();
editSubMenu.setMenuId(idGenerator.nextLongId());
editSubMenu.setParentId(sysMenu.getMenuId());
editSubMenu.setMenuType(SysMenuType.TYPE_BUTTON);
editSubMenu.setMenuName("编辑");
editSubMenu.setShowOrder(1);
editSubMenu.setOnlineFormId(sysMenu.getOnlineFormId());
editSubMenu.setOnlineMenuPermType(SysOnlineMenuPermType.TYPE_EDIT);
MyModelUtil.fillCommonsForInsert(editSubMenu);
sysMenuMapper.insert(editSubMenu);
}
return sysMenu;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(SysMenu sysMenu, SysMenu originalSysMenu) {
MyModelUtil.fillCommonsForUpdate(sysMenu, originalSysMenu);
sysMenu.setMenuType(originalSysMenu.getMenuType());
if (sysMenuMapper.update(sysMenu, false) != 1) {
return false;
}
// 如果当前菜单的在线表单Id变化了就需要同步更新他的内置子菜单也同步更新。
if (ObjectUtil.notEqual(originalSysMenu.getOnlineFormId(), sysMenu.getOnlineFormId())) {
SysMenu onlineSubMenu = new SysMenu();
onlineSubMenu.setOnlineFormId(sysMenu.getOnlineFormId());
sysMenuMapper.updateByQuery(onlineSubMenu,
new QueryWrapper().eq(SysMenu::getParentId, sysMenu.getMenuId()));
}
return true;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(SysMenu menu) {
Long menuId = menu.getMenuId();
if (sysMenuMapper.deleteByQuery(new QueryWrapper().eq(SysMenu::getMenuId, menuId)) != 1) {
return false;
}
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setMenuId(menuId);
sysRoleMenuMapper.deleteByQuery(QueryWrapper.create(roleMenu));
// 如果为指向在线表单的菜单,则连同删除子菜单
if (menu.getOnlineFormId() != null) {
SysMenu filter = new SysMenu();
filter.setParentId(menuId);
List<SysMenu> childMenus = sysMenuMapper.selectListByQuery(QueryWrapper.create(filter));
sysMenuMapper.deleteByQuery(new QueryWrapper().eq(SysMenu::getParentId, menuId));
if (CollUtil.isNotEmpty(childMenus)) {
List<Long> childMenuIds = childMenus.stream().map(SysMenu::getMenuId).collect(Collectors.toList());
sysRoleMenuMapper.deleteByQuery(new QueryWrapper().in(SysRoleMenu::getMenuId, childMenuIds));
}
}
return true;
}
@Override
public Collection<SysMenu> getMenuListByUserId(Long userId) {
List<SysMenu> menuList = sysMenuMapper.getMenuListByUserId(userId);
return this.distinctMenuList(menuList);
}
@Override
public Collection<SysMenu> getMenuListByRoleIds(String roleIds) {
if (StrUtil.isBlank(roleIds)) {
return CollUtil.empty(Long.class);
}
Set<Long> roleIdSet = StrUtil.split(roleIds, ",").stream().map(Long::valueOf).collect(Collectors.toSet());
List<SysMenu> menuList = sysMenuMapper.getMenuListByRoleIds(roleIdSet);
return this.distinctMenuList(menuList);
}
@Override
public boolean hasChildren(Long menuId) {
SysMenu menu = new SysMenu();
menu.setParentId(menuId);
return this.getCountByFilter(menu) > 0;
}
@Override
public CallResult verifyRelatedData(SysMenu sysMenu, SysMenu originalSysMenu) {
// menu、ui fragment和button类型的menu不能没有parentId
if (sysMenu.getParentId() == null && sysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) {
return CallResult.error("数据验证失败,当前类型菜单项的上级菜单不能为空!");
}
if (this.needToVerify(sysMenu, originalSysMenu, SysMenu::getParentId)) {
String errorMessage = checkErrorOfNonDirectoryMenu(sysMenu);
if (errorMessage != null) {
return CallResult.error(errorMessage);
}
}
if (!this.verifyMenuCode(sysMenu, originalSysMenu)) {
return CallResult.error("数据验证失败,菜单编码已存在,不能重复使用!");
}
return CallResult.ok();
}
@Override
public List<SysMenu> getAllOnlineMenuList(Integer menuType) {
QueryWrapper queryWrapper = new QueryWrapper().isNotNull(SysMenu::getOnlineFormId);
if (menuType != null) {
queryWrapper.eq(SysMenu::getMenuType, menuType);
}
return sysMenuMapper.selectListByQuery(queryWrapper);
}
private boolean verifyMenuCode(SysMenu sysMenu, SysMenu originalSysMenu) {
if (sysMenu.getExtraData() == null) {
return true;
}
String menuCode = JSON.parseObject(sysMenu.getExtraData(), SysMenuExtraData.class).getMenuCode();
if (StrUtil.isBlank(menuCode)) {
return true;
}
String originalMenuCode = "";
if (originalSysMenu != null && originalSysMenu.getExtraData() != null) {
originalMenuCode = JSON.parseObject(originalSysMenu.getExtraData(), SysMenuExtraData.class).getMenuCode();
}
return StrUtil.equals(menuCode, originalMenuCode)
|| sysMenuMapper.countMenuCode("\"menuCode\":\"" + menuCode + "\"") == 0;
}
private String checkErrorOfNonDirectoryMenu(SysMenu sysMenu) {
// 判断父节点是否存在
SysMenu parentSysMenu = getById(sysMenu.getParentId());
if (parentSysMenu == null) {
return "数据验证失败,关联的上级菜单并不存在,请刷新后重试!";
}
// 逐个判断每种类型的菜单,他的父菜单的合法性,先从目录类型和菜单类型开始
if (sysMenu.getMenuType() == SysMenuType.TYPE_DIRECTORY
|| sysMenu.getMenuType() == SysMenuType.TYPE_MENU) {
// 他们的上级只能是目录
if (parentSysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) {
return "数据验证失败,当前类型菜单项的上级菜单只能是目录类型!";
}
} else if (sysMenu.getMenuType() == SysMenuType.TYPE_UI_FRAGMENT) {
// ui fragment的上级只能是menu类型
if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU) {
return "数据验证失败,当前类型菜单项的上级菜单只能是菜单类型和按钮类型!";
}
} else if (sysMenu.getMenuType() == SysMenuType.TYPE_BUTTON) {
// button的上级只能是menu和ui fragment
if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU
&& parentSysMenu.getMenuType() != SysMenuType.TYPE_UI_FRAGMENT) {
return "数据验证失败当前类型菜单项的上级菜单只能是菜单类型和UI片段类型";
}
} else {
return "数据验证失败,不支持的菜单类型!";
}
return null;
}
private Collection<SysMenu> distinctMenuList(List<SysMenu> menuList) {
LinkedHashMap<Long, SysMenu> menuMap = new LinkedHashMap<>();
for (SysMenu menu : menuList) {
menuMap.put(menu.getMenuId(), menu);
}
return menuMap.values();
}
}

View File

@@ -0,0 +1,47 @@
package com.orangeforms.webadmin.upms.service.impl;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.webadmin.upms.dao.SysPermWhitelistMapper;
import com.orangeforms.webadmin.upms.model.SysPermWhitelist;
import com.orangeforms.webadmin.upms.service.SysPermWhitelistService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 权限资源白名单数据服务类。
* 白名单中的权限资源,可以不受权限控制,任何用户皆可访问,一般用于常用的字典数据列表接口。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Service("sysPermWhitelistService")
public class SysPermWhitelistServiceImpl extends BaseService<SysPermWhitelist, String> implements SysPermWhitelistService {
@Autowired
private SysPermWhitelistMapper sysPermWhitelistMapper;
/**
* 返回主对象的Mapper对象。
*
* @return 主对象的Mapper对象。
*/
@Override
protected BaseDaoMapper<SysPermWhitelist> mapper() {
return sysPermWhitelistMapper;
}
@Override
public List<String> getWhitelistPermList() {
List<SysPermWhitelist> dataList = this.getAllList();
Function<SysPermWhitelist, String> getterFunc = SysPermWhitelist::getPermUrl;
return dataList.stream()
.filter(x -> getterFunc.apply(x) != null).map(getterFunc).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,177 @@
package com.orangeforms.webadmin.upms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.object.MyOrderParam;
import com.orangeforms.common.core.object.MyPageData;
import com.orangeforms.common.core.object.MyPageParam;
import com.orangeforms.common.core.object.MyRelationParam;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.MyPageUtil;
import com.orangeforms.common.ext.base.BizWidgetDatasource;
import com.orangeforms.common.ext.constant.BizWidgetDatasourceType;
import com.orangeforms.common.ext.util.BizWidgetDatasourceExtHelper;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import com.orangeforms.webadmin.upms.dao.SysDeptPostMapper;
import com.orangeforms.webadmin.upms.dao.SysPostMapper;
import com.orangeforms.webadmin.upms.dao.SysUserPostMapper;
import com.orangeforms.webadmin.upms.model.SysDeptPost;
import com.orangeforms.webadmin.upms.model.SysPost;
import com.orangeforms.webadmin.upms.model.SysUserPost;
import com.orangeforms.webadmin.upms.service.SysDeptService;
import com.orangeforms.webadmin.upms.service.SysPostService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
* 岗位管理数据操作服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Service("sysPostService")
public class SysPostServiceImpl extends BaseService<SysPost, Long> implements SysPostService, BizWidgetDatasource {
@Autowired
private SysPostMapper sysPostMapper;
@Autowired
private SysUserPostMapper sysUserPostMapper;
@Autowired
private SysDeptPostMapper sysDeptPostMapper;
@Autowired
private SysDeptService sysDeptService;
@Autowired
private IdGeneratorWrapper idGenerator;
@Autowired
private BizWidgetDatasourceExtHelper bizWidgetDatasourceExtHelper;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<SysPost> mapper() {
return sysPostMapper;
}
@PostConstruct
private void registerBizWidgetDatasource() {
bizWidgetDatasourceExtHelper.registerDatasource(BizWidgetDatasourceType.UPMS_POST_TYPE, this);
bizWidgetDatasourceExtHelper.registerDatasource(BizWidgetDatasourceType.UPMS_DEPT_POST_TYPE, this);
}
@Override
public MyPageData<Map<String, Object>> getDataList(
String type, Map<String, Object> filter, MyOrderParam orderParam, MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
String orderBy = orderParam == null ? null : MyOrderParam.buildOrderBy(orderParam, SysPost.class);
SysPost postFilter = filter == null ? null : BeanUtil.toBean(filter, SysPost.class);
if (StrUtil.equals(type, BizWidgetDatasourceType.UPMS_POST_TYPE)) {
List<SysPost> postList = this.getSysPostList(postFilter, orderBy);
return MyPageUtil.makeResponseData(postList, BeanUtil::beanToMap);
}
Assert.notNull(filter, "filter can't be NULL.");
Long deptId = (Long) filter.get("deptId");
List<Map<String, Object>> dataList = sysDeptService.getSysDeptPostListWithRelationByDeptId(deptId);
return MyPageUtil.makeResponseData(dataList);
}
@Override
public List<Map<String, Object>> getDataListWithInList(String type, String fieldName, List<String> fieldValues) {
List<SysPost> postList;
if (StrUtil.isBlank(fieldName)) {
postList = this.getInList(fieldValues.stream().map(Long::valueOf).collect(Collectors.toSet()));
} else {
postList = this.getInList(fieldName, MyModelUtil.convertToTypeValues(SysPost.class, fieldName, fieldValues));
}
return MyModelUtil.beanToMapList(postList);
}
@Transactional(rollbackFor = Exception.class)
@Override
public SysPost saveNew(SysPost sysPost) {
sysPost.setPostId(idGenerator.nextLongId());
MyModelUtil.fillCommonsForInsert(sysPost);
MyModelUtil.setDefaultValue(sysPost, "leaderPost", false);
sysPostMapper.insert(sysPost);
return sysPost;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(SysPost sysPost, SysPost originalSysPost) {
MyModelUtil.fillCommonsForUpdate(sysPost, originalSysPost);
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
return sysPostMapper.update(sysPost, false) == 1;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long postId) {
if (sysPostMapper.deleteById(postId) != 1) {
return false;
}
// 开始删除多对多父表的关联
sysUserPostMapper.deleteByQuery(new QueryWrapper().eq(SysUserPost::getPostId, postId));
sysDeptPostMapper.deleteByQuery(new QueryWrapper().eq(SysDeptPost::getPostId, postId));
return true;
}
@Override
public List<SysPost> getSysPostList(SysPost filter, String orderBy) {
return sysPostMapper.getSysPostList(filter, orderBy);
}
@Override
public List<SysPost> getSysPostListWithRelation(SysPost filter, String orderBy) {
List<SysPost> resultList = sysPostMapper.getSysPostList(filter, orderBy);
// 在缺省生成的代码中如果查询结果resultList不是Page对象说明没有分页那么就很可能是数据导出接口调用了当前方法。
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
int batchSize = resultList instanceof Page ? 0 : 1000;
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize);
return resultList;
}
@Override
public List<SysPost> getNotInSysPostListByDeptId(Long deptId, SysPost filter, String orderBy) {
List<SysPost> resultList = sysPostMapper.getNotInSysPostListByDeptId(deptId, filter, orderBy);
this.buildRelationForDataList(resultList, MyRelationParam.dictOnly());
return resultList;
}
@Override
public List<SysPost> getSysPostListByDeptId(Long deptId, SysPost filter, String orderBy) {
List<SysPost> resultList = sysPostMapper.getSysPostListByDeptId(deptId, filter, orderBy);
this.buildRelationForDataList(resultList, MyRelationParam.dictOnly());
return resultList;
}
@Override
public List<SysUserPost> getSysUserPostListByUserId(Long userId) {
return sysUserPostMapper.selectListByQuery(new QueryWrapper().eq(SysUserPost::getUserId, userId));
}
@Override
public boolean existAllPrimaryKeys(Set<Long> deptPostIdSet, Long deptId) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(SysDeptPost::getDeptId, deptId);
queryWrapper.in(SysDeptPost::getDeptPostId, deptPostIdSet);
return sysDeptPostMapper.selectCountByQuery(queryWrapper) == deptPostIdSet.size();
}
}

View File

@@ -0,0 +1,188 @@
package com.orangeforms.webadmin.upms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.MyPageUtil;
import com.orangeforms.common.ext.base.BizWidgetDatasource;
import com.orangeforms.common.ext.constant.BizWidgetDatasourceType;
import com.orangeforms.common.ext.util.BizWidgetDatasourceExtHelper;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import com.orangeforms.webadmin.upms.dao.SysRoleMapper;
import com.orangeforms.webadmin.upms.dao.SysRoleMenuMapper;
import com.orangeforms.webadmin.upms.dao.SysUserRoleMapper;
import com.orangeforms.webadmin.upms.model.SysRole;
import com.orangeforms.webadmin.upms.model.SysRoleMenu;
import com.orangeforms.webadmin.upms.model.SysUserRole;
import com.orangeforms.webadmin.upms.service.SysMenuService;
import com.orangeforms.webadmin.upms.service.SysRoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
* 角色数据服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Service("sysRoleService")
public class SysRoleServiceImpl extends BaseService<SysRole, Long> implements SysRoleService, BizWidgetDatasource {
@Autowired
private SysRoleMapper sysRoleMapper;
@Autowired
private SysRoleMenuMapper sysRoleMenuMapper;
@Autowired
private SysUserRoleMapper sysUserRoleMapper;
@Autowired
private SysMenuService sysMenuService;
@Autowired
private IdGeneratorWrapper idGenerator;
@Autowired
private BizWidgetDatasourceExtHelper bizWidgetDatasourceExtHelper;
/**
* 返回主对象的Mapper对象。
*
* @return 主对象的Mapper对象。
*/
@Override
protected BaseDaoMapper<SysRole> mapper() {
return sysRoleMapper;
}
@PostConstruct
private void registerBizWidgetDatasource() {
bizWidgetDatasourceExtHelper.registerDatasource(BizWidgetDatasourceType.UPMS_ROLE_TYPE, this);
}
@Override
public MyPageData<Map<String, Object>> getDataList(
String type, Map<String, Object> filter, MyOrderParam orderParam, MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
String orderBy = orderParam == null ? null : MyOrderParam.buildOrderBy(orderParam, SysRole.class);
SysRole roleFilter = filter == null ? null : BeanUtil.toBean(filter, SysRole.class);
List<SysRole> roleList = this.getSysRoleList(roleFilter, orderBy);
return MyPageUtil.makeResponseData(roleList, BeanUtil::beanToMap);
}
@Override
public List<Map<String, Object>> getDataListWithInList(String type, String fieldName, List<String> fieldValues) {
List<SysRole> roleList;
if (StrUtil.isBlank(fieldName)) {
roleList = this.getInList(fieldValues.stream().map(Long::valueOf).collect(Collectors.toSet()));
} else {
roleList = this.getInList(fieldName, MyModelUtil.convertToTypeValues(SysRole.class, fieldName, fieldValues));
}
return MyModelUtil.beanToMapList(roleList);
}
@Transactional(rollbackFor = Exception.class)
@Override
public SysRole saveNew(SysRole role, Set<Long> menuIdSet) {
role.setRoleId(idGenerator.nextLongId());
MyModelUtil.fillCommonsForInsert(role);
sysRoleMapper.insert(role);
if (menuIdSet != null) {
for (Long menuId : menuIdSet) {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(role.getRoleId());
roleMenu.setMenuId(menuId);
sysRoleMenuMapper.insert(roleMenu);
}
}
return role;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(SysRole role, SysRole originalRole, Set<Long> menuIdSet) {
MyModelUtil.fillCommonsForUpdate(role, originalRole);
if (sysRoleMapper.update(role) != 1) {
return false;
}
SysRoleMenu deletedRoleMenu = new SysRoleMenu();
deletedRoleMenu.setRoleId(role.getRoleId());
sysRoleMenuMapper.deleteByQuery(QueryWrapper.create(deletedRoleMenu));
if (menuIdSet != null) {
for (Long menuId : menuIdSet) {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(role.getRoleId());
roleMenu.setMenuId(menuId);
sysRoleMenuMapper.insert(roleMenu);
}
}
return true;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long roleId) {
if (sysRoleMapper.deleteById(roleId) != 1) {
return false;
}
sysRoleMenuMapper.deleteByQuery(new QueryWrapper().eq(SysRoleMenu::getRoleId, roleId));
sysUserRoleMapper.deleteByQuery(new QueryWrapper().eq(SysUserRole::getRoleId, roleId));
return true;
}
@Override
public List<SysRole> getSysRoleList(SysRole filter, String orderBy) {
return sysRoleMapper.getSysRoleList(filter, orderBy);
}
@Override
public List<SysUserRole> getSysUserRoleListByUserId(Long userId) {
SysUserRole filter = new SysUserRole();
filter.setUserId(userId);
return sysUserRoleMapper.selectListByQuery(new QueryWrapper().eq(SysUserRole::getUserId, userId));
}
@Transactional(rollbackFor = Exception.class)
@Override
public void addUserRoleList(List<SysUserRole> userRoleList) {
for (SysUserRole userRole : userRoleList) {
sysUserRoleMapper.insert(userRole);
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean removeUserRole(Long roleId, Long userId) {
SysUserRole userRole = new SysUserRole();
userRole.setRoleId(roleId);
userRole.setUserId(userId);
return sysUserRoleMapper.deleteByQuery(QueryWrapper.create(userRole)) == 1;
}
@Override
public CallResult verifyRelatedData(SysRole sysRole, SysRole originalSysRole, String menuIdListString) {
JSONObject jsonObject = null;
if (StringUtils.isNotBlank(menuIdListString)) {
Set<Long> menuIdSet = Arrays.stream(
menuIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet());
if (!sysMenuService.existAllPrimaryKeys(menuIdSet)) {
return CallResult.error("数据验证失败,存在不合法的菜单权限,请刷新后重试!");
}
jsonObject = new JSONObject();
jsonObject.put("menuIdSet", menuIdSet);
}
return CallResult.ok(jsonObject);
}
}

View File

@@ -0,0 +1,383 @@
package com.orangeforms.webadmin.upms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mybatisflex.core.query.QueryWrapper;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.webadmin.upms.service.*;
import com.orangeforms.webadmin.upms.dao.*;
import com.orangeforms.webadmin.upms.model.*;
import com.orangeforms.webadmin.upms.model.constant.SysUserStatus;
import com.orangeforms.common.ext.util.BizWidgetDatasourceExtHelper;
import com.orangeforms.common.ext.base.BizWidgetDatasource;
import com.orangeforms.common.ext.constant.BizWidgetDatasourceType;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.constant.UserFilterGroup;
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
import com.orangeforms.common.core.object.*;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.MyPageUtil;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import com.github.pagehelper.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
* 用户管理数据操作服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Service("sysUserService")
public class SysUserServiceImpl extends BaseService<SysUser, Long> implements SysUserService, BizWidgetDatasource {
@Autowired
private IdGeneratorWrapper idGenerator;
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private SysUserRoleMapper sysUserRoleMapper;
@Autowired
private SysUserPostMapper sysUserPostMapper;
@Autowired
private SysDataPermUserMapper sysDataPermUserMapper;
@Autowired
private SysDeptService sysDeptService;
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysDataPermService sysDataPermService;
@Autowired
private SysPostService sysPostService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private BizWidgetDatasourceExtHelper bizWidgetDatasourceExtHelper;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<SysUser> mapper() {
return sysUserMapper;
}
@PostConstruct
private void registerBizWidgetDatasource() {
bizWidgetDatasourceExtHelper.registerDatasource(BizWidgetDatasourceType.UPMS_USER_TYPE, this);
}
@Override
public MyPageData<Map<String, Object>> getDataList(
String type, Map<String, Object> filter, MyOrderParam orderParam, MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
List<SysUser> userList = null;
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class, false);
SysUser userFilter = BeanUtil.toBean(filter, SysUser.class);
if (filter != null) {
Object group = filter.get("USER_FILTER_GROUP");
if (group != null) {
JSONObject filterGroupJson = JSON.parseObject(group.toString());
String groupType = filterGroupJson.getString("type");
String values = filterGroupJson.getString("values");
if (UserFilterGroup.USER.equals(groupType)) {
List<String> loginNames = StrUtil.splitTrim(values, ",");
userList = sysUserMapper.getSysUserListByLoginNames(loginNames, userFilter, orderBy);
} else {
Set<Long> groupIds = StrUtil.splitTrim(values, ",")
.stream().map(Long::valueOf).collect(Collectors.toSet());
userList = this.getUserListByGroupIds(groupType, groupIds, userFilter, orderBy);
}
}
}
if (userList == null) {
userList = this.getSysUserList(userFilter, orderBy);
}
this.buildRelationForDataList(userList, MyRelationParam.dictOnly());
return MyPageUtil.makeResponseData(userList, BeanUtil::beanToMap);
}
private List<SysUser> getUserListByGroupIds(String groupType, Set<Long> groupIds, SysUser filter, String orderBy) {
if (groupType.equals(UserFilterGroup.DEPT)) {
return sysUserMapper.getSysUserListByDeptIds(groupIds, filter, orderBy);
}
List<Long> userIds = null;
switch (groupType) {
case UserFilterGroup.ROLE:
userIds = sysUserMapper.getUserIdListByRoleIds(groupIds, filter, orderBy);
break;
case UserFilterGroup.POST:
userIds = sysUserMapper.getUserIdListByPostIds(groupIds, filter, orderBy);
break;
case UserFilterGroup.DEPT_POST:
userIds = sysUserMapper.getUserIdListByDeptPostIds(groupIds, filter, orderBy);
break;
default:
break;
}
if (CollUtil.isEmpty(userIds)) {
return CollUtil.empty(SysUser.class);
}
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.in(SysUser::getUserId, userIds);
if (StrUtil.isNotBlank(orderBy)) {
queryWrapper.orderBy(orderBy);
}
return sysUserMapper.selectListByQuery(queryWrapper);
}
@Override
public List<Map<String, Object>> getDataListWithInList(String type, String fieldName, List<String> fieldValues) {
List<SysUser> userList;
if (StrUtil.isBlank(fieldName)) {
userList = this.getInList(fieldValues.stream().map(Long::valueOf).collect(Collectors.toSet()));
} else {
userList = this.getInList(fieldName, MyModelUtil.convertToTypeValues(SysUser.class, fieldName, fieldValues));
}
this.buildRelationForDataList(userList, MyRelationParam.dictOnly());
return MyModelUtil.beanToMapList(userList);
}
/**
* 获取指定登录名的用户对象。
*
* @param loginName 指定登录用户名。
* @return 用户对象。
*/
@Override
public SysUser getSysUserByLoginName(String loginName) {
SysUser filter = new SysUser();
filter.setLoginName(loginName);
return sysUserMapper.selectOneByQuery(QueryWrapper.create(filter));
}
@Transactional(rollbackFor = Exception.class)
@Override
public SysUser saveNew(SysUser user, Set<Long> roleIdSet, Set<Long> deptPostIdSet, Set<Long> dataPermIdSet) {
user.setUserId(idGenerator.nextLongId());
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setUserStatus(SysUserStatus.STATUS_NORMAL);
user.setDeletedFlag(GlobalDeletedFlag.NORMAL);
MyModelUtil.fillCommonsForInsert(user);
sysUserMapper.insert(user);
if (CollUtil.isNotEmpty(deptPostIdSet)) {
for (Long deptPostId : deptPostIdSet) {
SysDeptPost deptPost = sysDeptService.getSysDeptPost(deptPostId);
SysUserPost userPost = new SysUserPost();
userPost.setUserId(user.getUserId());
userPost.setDeptPostId(deptPostId);
userPost.setPostId(deptPost.getPostId());
sysUserPostMapper.insert(userPost);
}
}
if (CollUtil.isNotEmpty(roleIdSet)) {
for (Long roleId : roleIdSet) {
SysUserRole userRole = new SysUserRole();
userRole.setUserId(user.getUserId());
userRole.setRoleId(roleId);
sysUserRoleMapper.insert(userRole);
}
}
if (CollUtil.isNotEmpty(dataPermIdSet)) {
for (Long dataPermId : dataPermIdSet) {
SysDataPermUser dataPermUser = new SysDataPermUser();
dataPermUser.setDataPermId(dataPermId);
dataPermUser.setUserId(user.getUserId());
sysDataPermUserMapper.insert(dataPermUser);
}
}
return user;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(SysUser user, SysUser originalUser, Set<Long> roleIdSet, Set<Long> deptPostIdSet, Set<Long> dataPermIdSet) {
user.setLoginName(originalUser.getLoginName());
user.setPassword(originalUser.getPassword());
user.setDeletedFlag(GlobalDeletedFlag.NORMAL);
MyModelUtil.fillCommonsForUpdate(user, originalUser);
if (sysUserMapper.update(user, false) != 1) {
return false;
}
// 先删除原有的User-Post关联关系再重新插入新的关联关系
SysUserPost deletedUserPost = new SysUserPost();
deletedUserPost.setUserId(user.getUserId());
sysUserPostMapper.deleteByQuery(QueryWrapper.create(deletedUserPost));
if (CollUtil.isNotEmpty(deptPostIdSet)) {
for (Long deptPostId : deptPostIdSet) {
SysDeptPost deptPost = sysDeptService.getSysDeptPost(deptPostId);
SysUserPost userPost = new SysUserPost();
userPost.setUserId(user.getUserId());
userPost.setDeptPostId(deptPostId);
userPost.setPostId(deptPost.getPostId());
sysUserPostMapper.insert(userPost);
}
}
// 先删除原有的User-Role关联关系再重新插入新的关联关系
SysUserRole deletedUserRole = new SysUserRole();
deletedUserRole.setUserId(user.getUserId());
sysUserRoleMapper.deleteByQuery(QueryWrapper.create(deletedUserRole));
if (CollUtil.isNotEmpty(roleIdSet)) {
for (Long roleId : roleIdSet) {
SysUserRole userRole = new SysUserRole();
userRole.setUserId(user.getUserId());
userRole.setRoleId(roleId);
sysUserRoleMapper.insert(userRole);
}
}
// 先删除原有的DataPerm-User关联关系在重新插入新的关联关系
SysDataPermUser deletedDataPermUser = new SysDataPermUser();
deletedDataPermUser.setUserId(user.getUserId());
sysDataPermUserMapper.deleteByQuery(QueryWrapper.create(deletedDataPermUser));
if (CollUtil.isNotEmpty(dataPermIdSet)) {
for (Long dataPermId : dataPermIdSet) {
SysDataPermUser dataPermUser = new SysDataPermUser();
dataPermUser.setDataPermId(dataPermId);
dataPermUser.setUserId(user.getUserId());
sysDataPermUserMapper.insert(dataPermUser);
}
}
return true;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean changePassword(Long userId, String newPass) {
SysUser updatedUser = new SysUser();
updatedUser.setUserId(userId);
updatedUser.setPassword(passwordEncoder.encode(newPass));
return sysUserMapper.update(updatedUser) == 1;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean changeHeadImage(Long userId, String newHeadImage) {
SysUser updatedUser = new SysUser();
updatedUser.setUserId(userId);
updatedUser.setHeadImageUrl(newHeadImage);
return sysUserMapper.update(updatedUser) == 1;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long userId) {
if (sysUserMapper.deleteById(userId) == 0) {
return false;
}
SysUserRole userRole = new SysUserRole();
userRole.setUserId(userId);
sysUserRoleMapper.deleteByQuery(QueryWrapper.create(userRole));
SysUserPost userPost = new SysUserPost();
userPost.setUserId(userId);
sysUserPostMapper.deleteByQuery(QueryWrapper.create(userPost));
SysDataPermUser dataPermUser = new SysDataPermUser();
dataPermUser.setUserId(userId);
sysDataPermUserMapper.deleteByQuery(QueryWrapper.create(dataPermUser));
return true;
}
@Override
public List<SysUser> getSysUserList(SysUser filter, String orderBy) {
return sysUserMapper.getSysUserList(filter, orderBy);
}
@Override
public List<SysUser> getSysUserListWithRelation(SysUser filter, String orderBy) {
List<SysUser> resultList = sysUserMapper.getSysUserList(filter, orderBy);
// 在缺省生成的代码中如果查询结果resultList不是Page对象说明没有分页那么就很可能是数据导出接口调用了当前方法。
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
int batchSize = resultList instanceof Page ? 0 : 1000;
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize);
return resultList;
}
@Override
public List<SysUser> getSysUserListByRoleId(Long roleId, SysUser filter, String orderBy) {
return sysUserMapper.getSysUserListByRoleId(roleId, filter, orderBy);
}
@Override
public List<SysUser> getNotInSysUserListByRoleId(Long roleId, SysUser filter, String orderBy) {
return sysUserMapper.getNotInSysUserListByRoleId(roleId, filter, orderBy);
}
@Override
public List<SysUser> getSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy) {
return sysUserMapper.getSysUserListByDataPermId(dataPermId, filter, orderBy);
}
@Override
public List<SysUser> getNotInSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy) {
return sysUserMapper.getNotInSysUserListByDataPermId(dataPermId, filter, orderBy);
}
@Override
public List<SysUser> getSysUserListByDeptPostId(Long deptPostId, SysUser filter, String orderBy) {
return sysUserMapper.getSysUserListByDeptPostId(deptPostId, filter, orderBy);
}
@Override
public List<SysUser> getNotInSysUserListByDeptPostId(Long deptPostId, SysUser filter, String orderBy) {
return sysUserMapper.getNotInSysUserListByDeptPostId(deptPostId, filter, orderBy);
}
@Override
public List<SysUser> getSysUserListByPostId(Long postId, SysUser filter, String orderBy) {
return sysUserMapper.getSysUserListByPostId(postId, filter, orderBy);
}
@Override
public CallResult verifyRelatedData(
SysUser sysUser, SysUser originalSysUser, String roleIds, String deptPostIds, String dataPermIds) {
JSONObject jsonObject = new JSONObject();
if (StrUtil.isBlank(deptPostIds)) {
return CallResult.error("数据验证失败,用户的部门岗位数据不能为空!");
}
Set<Long> deptPostIdSet =
Arrays.stream(deptPostIds.split(",")).map(Long::valueOf).collect(Collectors.toSet());
if (!sysPostService.existAllPrimaryKeys(deptPostIdSet, sysUser.getDeptId())) {
return CallResult.error("数据验证失败,存在不合法的用户岗位,请刷新后重试!");
}
jsonObject.put("deptPostIdSet", deptPostIdSet);
if (StrUtil.isBlank(roleIds)) {
return CallResult.error("数据验证失败,用户的角色数据不能为空!");
}
Set<Long> roleIdSet = Arrays.stream(
roleIds.split(",")).map(Long::valueOf).collect(Collectors.toSet());
if (!sysRoleService.existAllPrimaryKeys(roleIdSet)) {
return CallResult.error("数据验证失败,存在不合法的用户角色,请刷新后重试!");
}
jsonObject.put("roleIdSet", roleIdSet);
if (StrUtil.isBlank(dataPermIds)) {
return CallResult.error("数据验证失败,用户的数据权限不能为空!");
}
Set<Long> dataPermIdSet = Arrays.stream(
dataPermIds.split(",")).map(Long::valueOf).collect(Collectors.toSet());
if (!sysDataPermService.existAllPrimaryKeys(dataPermIdSet)) {
return CallResult.error("数据验证失败,存在不合法的数据权限,请刷新后重试!");
}
jsonObject.put("dataPermIdSet", dataPermIdSet);
//这里是基于字典的验证。
if (this.needToVerify(sysUser, originalSysUser, SysUser::getDeptId)
&& !sysDeptService.existId(sysUser.getDeptId())) {
return CallResult.error("数据验证失败关联的用户部门Id并不存在请刷新后重试");
}
return CallResult.ok(jsonObject);
}
}

View File

@@ -0,0 +1,27 @@
package com.orangeforms.webadmin.upms.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 数据权限与部门关联VO。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "数据权限与部门关联VO")
@Data
public class SysDataPermDeptVo {
/**
* 数据权限Id。
*/
@Schema(description = "数据权限Id")
private Long dataPermId;
/**
* 关联部门Id。
*/
@Schema(description = "关联部门Id")
private Long deptId;
}

View File

@@ -0,0 +1,27 @@
package com.orangeforms.webadmin.upms.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 数据权限与菜单关联VO。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "数据权限与菜单关联VO")
@Data
public class SysDataPermMenuVo {
/**
* 数据权限Id。
*/
@Schema(description = "数据权限Id")
private Long dataPermId;
/**
* 关联菜单Id。
*/
@Schema(description = "关联菜单Id")
private Long menuId;
}

View File

@@ -0,0 +1,57 @@
package com.orangeforms.webadmin.upms.vo;
import com.orangeforms.common.core.base.vo.BaseVo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
import java.util.Map;
/**
* 数据权限VO。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "数据权限VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysDataPermVo extends BaseVo {
/**
* 数据权限Id。
*/
@Schema(description = "数据权限Id")
private Long dataPermId;
/**
* 显示名称。
*/
@Schema(description = "显示名称")
private String dataPermName;
/**
* 数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。
*/
@Schema(description = "数据权限规则类型")
private Integer ruleType;
/**
* 部门Id列表(逗号分隔)。
*/
@Schema(description = "部门Id列表")
private String deptIdListString;
/**
* 数据权限与部门关联对象列表。
*/
@Schema(description = "数据权限与部门关联对象列表")
private List<Map<String, Object>> dataPermDeptList;
/**
* 数据权限与菜单关联对象列表。
*/
@Schema(description = "数据权限与菜单关联对象列表")
private List<Map<String, Object>> dataPermMenuList;
}

View File

@@ -0,0 +1,39 @@
package com.orangeforms.webadmin.upms.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 部门岗位VO对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "部门岗位VO")
@Data
public class SysDeptPostVo {
/**
* 部门岗位Id。
*/
@Schema(description = "部门岗位Id")
private Long deptPostId;
/**
* 部门Id。
*/
@Schema(description = "部门Id")
private Long deptId;
/**
* 岗位Id。
*/
@Schema(description = "岗位Id")
private Long postId;
/**
* 部门岗位显示名称。
*/
@Schema(description = "部门岗位显示名称")
private String postShowName;
}

View File

@@ -0,0 +1,65 @@
package com.orangeforms.webadmin.upms.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 部门管理VO视图对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "SysDeptVO视图对象")
@Data
public class SysDeptVo {
/**
* 部门Id。
*/
@Schema(description = "部门Id")
private Long deptId;
/**
* 部门名称。
*/
@Schema(description = "部门名称")
private String deptName;
/**
* 显示顺序。
*/
@Schema(description = "显示顺序")
private Integer showOrder;
/**
* 父部门Id。
*/
@Schema(description = "父部门Id")
private Long parentId;
/**
* 创建者Id。
*/
@Schema(description = "创建者Id")
private Long createUserId;
/**
* 更新者Id。
*/
@Schema(description = "更新者Id")
private Long updateUserId;
/**
* 创建时间。
*/
@Schema(description = "创建时间")
private Date createTime;
/**
* 更新时间。
*/
@Schema(description = "更新时间")
private Date updateTime;
}

View File

@@ -0,0 +1,90 @@
package com.orangeforms.webadmin.upms.vo;
import com.orangeforms.common.core.base.vo.BaseVo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 菜单VO。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "菜单VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysMenuVo extends BaseVo {
/**
* 菜单Id。
*/
@Schema(description = "菜单Id")
private Long menuId;
/**
* 父菜单Id目录菜单的父菜单为null
*/
@Schema(description = "父菜单Id")
private Long parentId;
/**
* 菜单显示名称。
*/
@Schema(description = "菜单显示名称")
private String menuName;
/**
* 菜单类型 (0: 目录 1: 菜单 2: 按钮 3: UI片段)。
*/
@Schema(description = "菜单类型")
private Integer menuType;
/**
* 前端表单路由名称仅用于menu_type为1的菜单类型。
*/
@Schema(description = "前端表单路由名称")
private String formRouterName;
/**
* 在线表单主键Id仅用于在线表单绑定的菜单。
*/
@Schema(description = "在线表单主键Id")
private Long onlineFormId;
/**
* 在线表单菜单的权限控制类型具体值可参考SysOnlineMenuPermType常量对象。
*/
@Schema(description = "在线表单菜单的权限控制类型")
private Integer onlineMenuPermType;
/**
* 统计页面主键Id仅用于统计页面绑定的菜单。
*/
@Schema(description = "统计页面主键Id")
private Long reportPageId;
/**
* 仅用于在线表单的流程Id。
*/
@Schema(description = "仅用于在线表单的流程Id")
private Long onlineFlowEntryId;
/**
* 菜单显示顺序 (值越小,排序越靠前)。
*/
@Schema(description = "菜单显示顺序")
private Integer showOrder;
/**
* 菜单图标。
*/
@Schema(description = "菜单显示图标")
private String icon;
/**
* 附加信息。
*/
@Schema(description = "附加信息")
private String extraData;
}

View File

@@ -0,0 +1,50 @@
package com.orangeforms.webadmin.upms.vo;
import com.orangeforms.common.core.base.vo.BaseVo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Map;
/**
* 岗位VO对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "岗位VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysPostVo extends BaseVo {
/**
* 岗位Id。
*/
@Schema(description = "岗位Id")
private Long postId;
/**
* 岗位名称。
*/
@Schema(description = "岗位名称")
private String postName;
/**
* 岗位层级,数值越小级别越高。
*/
@Schema(description = "岗位层级,数值越小级别越高")
private Integer postLevel;
/**
* 是否领导岗位。
*/
@Schema(description = "是否领导岗位")
private Boolean leaderPost;
/**
* postId 的多对多关联表数据对象数据对应类型为SysDeptPostVo。
*/
@Schema(description = "postId 的多对多关联表数据对象")
private Map<String, Object> sysDeptPost;
}

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