mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-13 14:09:00 +08:00
feat(upms): ❕ 增强多租户支持,支持在线切换租户
- 新增SysTenantUser实体类及Mapper用于租户用户关系管理 - 新增SysUserDept实体类及Mapper实现用户多部门支持 - 重构用户信息查询逻辑,支持跨租户查询 - 优化部门管理,支持多租户下的部门树查询 - 扩展UserInfo DTO增加deptId字段 - 重构Redis授权服务,优化租户信息存储结构 # Conflicts: # pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantController.java # pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysUserService.java
This commit is contained in:
1 parent
8227768849
commit
7205251977
31 files changed
+1008
-634
No files matched your search
+13
-3
@@ -23,19 +23,29 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
|
||||
/**
|
||||
* 租户信息拦截配置类
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2020/4/29
|
||||
* <p>
|
||||
* 租户信息拦截
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@Configuration
|
||||
public class PigxTenantConfiguration {
|
||||
|
||||
/**
|
||||
* 创建并返回PigxFeignTenantInterceptor实例
|
||||
*
|
||||
* @return RequestInterceptor实例
|
||||
*/
|
||||
@Bean
|
||||
public RequestInterceptor pigxFeignTenantInterceptor() {
|
||||
return new PigxFeignTenantInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并返回一个租户请求拦截器实例
|
||||
*
|
||||
* @return 配置好的租户请求拦截器
|
||||
*/
|
||||
@Bean
|
||||
public ClientHttpRequestInterceptor pigxTenantRequestInterceptor() {
|
||||
return new TenantRequestInterceptor();
|
||||
|
||||
+130
-87
@@ -43,105 +43,148 @@ import java.util.function.Supplier;
|
||||
@UtilityClass
|
||||
public class TenantBroker {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface RunAs<T> {
|
||||
/**
|
||||
* 以指定租户身份执行操作
|
||||
*
|
||||
* @param tenant 租户ID
|
||||
* @param func 需要执行的操作
|
||||
* @throws TenantBrokerExceptionWrapper 执行过程中发生异常时抛出
|
||||
*/
|
||||
public void runAs(Long tenant, RunAs<Long> func) {
|
||||
final Long pre = TenantContextHolder.getTenantId();
|
||||
try {
|
||||
log.trace("TenantBroker 切换租户{} -> {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(tenant);
|
||||
func.run(tenant);
|
||||
} catch (Exception e) {
|
||||
throw new TenantBrokerExceptionWrapper(e.getMessage(), e);
|
||||
} finally {
|
||||
log.trace("TenantBroker 还原租户{} <- {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(pre);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行业务逻辑
|
||||
* @param tenantId
|
||||
* @throws Exception
|
||||
*/
|
||||
void run(T tenantId) throws Exception;
|
||||
/**
|
||||
* 以指定租户身份执行操作
|
||||
*
|
||||
* @param tenant 租户ID
|
||||
* @param func 需要执行的操作函数
|
||||
* @param <T> 操作返回的数据类型
|
||||
* @return 操作函数的执行结果
|
||||
* @throws TenantBrokerExceptionWrapper 执行过程中发生异常时抛出
|
||||
*/
|
||||
public <T> T applyAs(Long tenant, ApplyAs<Long, T> func) {
|
||||
final Long pre = TenantContextHolder.getTenantId();
|
||||
try {
|
||||
log.trace("TenantBroker 切换租户{} -> {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(tenant);
|
||||
return func.apply(tenant);
|
||||
} catch (Exception e) {
|
||||
throw new TenantBrokerExceptionWrapper(e.getMessage(), e);
|
||||
} finally {
|
||||
log.trace("TenantBroker 还原租户{} <- {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(pre);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 以指定租户的身份执行操作
|
||||
*
|
||||
* @param supplier 租户ID提供者
|
||||
* @param func 要执行的操作
|
||||
*/
|
||||
public void runAs(Supplier<Long> supplier, RunAs<Long> func) {
|
||||
runAs(supplier.get(), func);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ApplyAs<T, R> {
|
||||
/**
|
||||
* 执行给定的NoneAs操作,临时跳过租户上下文
|
||||
*
|
||||
* @param noneAs 要执行的操作
|
||||
* @param <T> 返回值的类型
|
||||
* @return 操作执行结果
|
||||
* @throws TenantBrokerExceptionWrapper 执行过程中\发生异常时抛出
|
||||
*/
|
||||
public <T> T noneAs(NoneAs<T> noneAs) {
|
||||
try {
|
||||
TenantContextHolder.setTenantSkip();
|
||||
return noneAs.run();
|
||||
} catch (Exception e) {
|
||||
throw new TenantBrokerExceptionWrapper(e.getMessage(), e);
|
||||
} finally {
|
||||
TenantContextHolder.unsetTenantSkip();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行业务逻辑,返回一个值
|
||||
* @param tenantId
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
R apply(T tenantId) throws Exception;
|
||||
/**
|
||||
* 以指定租户的身份执行操作
|
||||
*
|
||||
* @param supplier 租户ID提供者
|
||||
* @param func 要执行的操作函数
|
||||
* @param <T> 返回数据的类型
|
||||
* @return 操作函数的执行结果
|
||||
*/
|
||||
public <T> T applyAs(Supplier<Long> supplier, ApplyAs<Long, T> func) {
|
||||
return applyAs(supplier.get(), func);
|
||||
}
|
||||
|
||||
}
|
||||
@FunctionalInterface
|
||||
public interface RunAs<T> {
|
||||
|
||||
/**
|
||||
* 以某个租户的身份运行
|
||||
* @param tenant 租户ID
|
||||
* @param func
|
||||
*/
|
||||
public void runAs(Long tenant, RunAs<Long> func) {
|
||||
final Long pre = TenantContextHolder.getTenantId();
|
||||
try {
|
||||
log.trace("TenantBroker 切换租户{} -> {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(tenant);
|
||||
func.run(tenant);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TenantBrokerExceptionWrapper(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
log.trace("TenantBroker 还原租户{} <- {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(pre);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 执行业务逻辑
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @throws Exception 执行过程中可能抛出的异常
|
||||
*/
|
||||
void run(T tenantId) throws Exception;
|
||||
|
||||
/**
|
||||
* 以某个租户的身份运行
|
||||
* @param tenant 租户ID
|
||||
* @param func
|
||||
* @param <T> 返回数据类型
|
||||
* @return
|
||||
*/
|
||||
public <T> T applyAs(Long tenant, ApplyAs<Long, T> func) {
|
||||
final Long pre = TenantContextHolder.getTenantId();
|
||||
try {
|
||||
log.trace("TenantBroker 切换租户{} -> {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(tenant);
|
||||
return func.apply(tenant);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new TenantBrokerExceptionWrapper(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
log.trace("TenantBroker 还原租户{} <- {}", pre, tenant);
|
||||
TenantContextHolder.setTenantId(pre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以某个租户的身份运行
|
||||
* @param supplier
|
||||
* @param func
|
||||
*/
|
||||
public void runAs(Supplier<Long> supplier, RunAs<Long> func) {
|
||||
runAs(supplier.get(), func);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以某个租户的身份运行
|
||||
* @param supplier
|
||||
* @param func
|
||||
* @param <T> 返回数据类型
|
||||
* @return
|
||||
*/
|
||||
public <T> T applyAs(Supplier<Long> supplier, ApplyAs<Long, T> func) {
|
||||
return applyAs(supplier.get(), func);
|
||||
}
|
||||
@FunctionalInterface
|
||||
public interface ApplyAs<T, R> {
|
||||
|
||||
public static class TenantBrokerExceptionWrapper extends RuntimeException {
|
||||
/**
|
||||
* 执行业务逻辑,返回一个值
|
||||
*
|
||||
* @param tenantId
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
R apply(T tenantId) throws Exception;
|
||||
|
||||
public TenantBrokerExceptionWrapper(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
public TenantBrokerExceptionWrapper(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
/**
|
||||
* 无参数函数式接口:用于定义无参数但有返回值的业务逻辑执行方法
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface NoneAs<R> {
|
||||
|
||||
}
|
||||
/**
|
||||
* 执行业务逻辑
|
||||
*
|
||||
* @return 业务执行结果
|
||||
* @throws Exception 执行过程中发生异常时抛出
|
||||
*/
|
||||
R run() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
public static class TenantBrokerExceptionWrapper extends RuntimeException {
|
||||
|
||||
public TenantBrokerExceptionWrapper(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public TenantBrokerExceptionWrapper(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -48,6 +48,13 @@ public class TenantContextHolder {
|
||||
THREAD_LOCAL_TENANT_SKIP_FLAG.set(Boolean.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前线程的租户跳过标记
|
||||
*/
|
||||
public void unsetTenantSkip() {
|
||||
THREAD_LOCAL_TENANT_SKIP_FLAG.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取TTL中的租户ID
|
||||
* @return
|
||||
|
||||
+12
-3
@@ -9,13 +9,22 @@ import org.springframework.http.client.ClientHttpResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* RestTemplate 请求拦截器,用于传递租户ID
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2020/4/29
|
||||
* <p>
|
||||
* 传递 RestTemplate 请求的租户ID
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
public class TenantRequestInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
/**
|
||||
* 拦截HTTP请求,添加租户ID到请求头
|
||||
*
|
||||
* @param request HTTP请求对象
|
||||
* @param body 请求体字节数组
|
||||
* @param execution 请求执行器
|
||||
* @return 客户端HTTP响应
|
||||
* @throws IOException 当I/O操作失败时抛出
|
||||
*/
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
|
||||
throws IOException {
|
||||
|
||||
+16
-14
@@ -2,11 +2,11 @@ package com.pig4cloud.pigx.common.security.service;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
|
||||
import com.pig4cloud.pigx.common.core.util.KeyStrResolver;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
@@ -17,6 +17,7 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -37,8 +38,6 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS
|
||||
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
private final KeyStrResolver tenantKeyStrResolver;
|
||||
|
||||
private static boolean isState(OAuth2Authorization authorization) {
|
||||
return Objects.nonNull(authorization.getAttribute("state"));
|
||||
}
|
||||
@@ -97,10 +96,14 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS
|
||||
.set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()), authorization, between,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
|
||||
String tokenUsername = String.format("%s::%s::%s::%s::%s", tenantKeyStrResolver.key(), AUTHORIZATION,
|
||||
SecurityConstants.DETAILS_USERNAME, authorization.getPrincipalName(), accessToken.getTokenValue());
|
||||
redisTemplate.opsForValue().set(tokenUsername, accessToken.getTokenValue(), between, TimeUnit.SECONDS);
|
||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = authorization.getAttribute(Principal.class.getName());
|
||||
|
||||
if (Objects.nonNull(usernamePasswordAuthenticationToken) && usernamePasswordAuthenticationToken.getPrincipal() instanceof PigxUser pigxUser) {
|
||||
// 扩展记录 access-token 、username 的关系 token::username::admin::tenantId::xxx
|
||||
String tokenUsername = String.format("%s::%s::%s::%s::%s::%s", AUTHORIZATION,
|
||||
SecurityConstants.DETAILS_USERNAME, authorization.getPrincipalName(), authorization.getRegisteredClientId(), pigxUser.getTenantId(), accessToken.getTokenValue());
|
||||
redisTemplate.opsForValue().set(tokenUsername, accessToken.getTokenValue(), between, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,8 +134,8 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS
|
||||
keys.add(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()));
|
||||
|
||||
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
|
||||
String key = String.format("%s::%s::%s::%s::%s", tenantKeyStrResolver.key(), AUTHORIZATION,
|
||||
SecurityConstants.DETAILS_USERNAME, authorization.getPrincipalName(), accessToken.getTokenValue());
|
||||
String key = String.format("%s::%s::%s::%s::*::%s", AUTHORIZATION,
|
||||
SecurityConstants.DETAILS_USERNAME, authorization.getPrincipalName(), authorization.getRegisteredClientId(), accessToken.getTokenValue());
|
||||
keys.add(key);
|
||||
}
|
||||
|
||||
@@ -155,21 +158,20 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS
|
||||
}
|
||||
|
||||
private String buildKey(String type, String id) {
|
||||
return String.format("%s::%s::%s::%s", tenantKeyStrResolver.key(), AUTHORIZATION, type, id);
|
||||
return String.format("%s::%s::%s", AUTHORIZATION, type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展方法根据 username 查询是否存在存储的
|
||||
* 根据用户名移除相关授权信息
|
||||
*
|
||||
* @param authentication
|
||||
* @return
|
||||
* @param authentication 认证信息,包含用户名
|
||||
*/
|
||||
public void removeByUsername(Authentication authentication) {
|
||||
// 根据 username查询对应access-token
|
||||
String authenticationName = authentication.getName();
|
||||
|
||||
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
|
||||
String tokenUsernameKey = String.format("%s::%s::%s::%s::*", tenantKeyStrResolver.key(), AUTHORIZATION,
|
||||
String tokenUsernameKey = String.format("%s::%s::%s::*", AUTHORIZATION,
|
||||
SecurityConstants.DETAILS_USERNAME, authenticationName);
|
||||
Set<String> keys = redisTemplate.keys(tokenUsernameKey);
|
||||
if (CollUtil.isEmpty(keys)) {
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ public interface PigxUserDetailsService extends UserDetailsService, Ordered {
|
||||
SysUser user = info.getSysUser();
|
||||
|
||||
// 构造security用户
|
||||
return new PigxUser(user.getUserId(), user.getUsername(), user.getDeptId(), user.getPhone(), user.getAvatar(),
|
||||
return new PigxUser(user.getUserId(), user.getUsername(), info.getDeptId(), user.getPhone(), user.getAvatar(),
|
||||
user.getNickname(), user.getName(), user.getEmail(), user.getTenantId(),
|
||||
SecurityConstants.BCRYPT + user.getPassword()
|
||||
, true, true, UserTypeEnum.TOB.getStatus()
|
||||
|
||||
+21
-15
@@ -33,22 +33,28 @@ import java.io.Serializable;
|
||||
@Schema(description = "用户信息")
|
||||
public class UserInfo implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户基本信息
|
||||
*/
|
||||
@Schema(description = "用户基本信息")
|
||||
private SysUser sysUser;
|
||||
/**
|
||||
* 用户基本信息
|
||||
*/
|
||||
@Schema(description = "用户基本信息")
|
||||
private SysUser sysUser;
|
||||
|
||||
/**
|
||||
* 权限标识集合
|
||||
*/
|
||||
@Schema(description = "权限标识集合")
|
||||
private String[] permissions;
|
||||
/**
|
||||
* 权限标识集合
|
||||
*/
|
||||
@Schema(description = "权限标识集合")
|
||||
private String[] permissions;
|
||||
|
||||
/**
|
||||
* 角色集合
|
||||
*/
|
||||
@Schema(description = "角色标识集合")
|
||||
private Long[] roles;
|
||||
/**
|
||||
* 角色集合
|
||||
*/
|
||||
@Schema(description = "角色标识集合")
|
||||
private Long[] roles;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@Schema(description = "用户所属部门id")
|
||||
private Long deptId;
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2018-2025, lengleng All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the pig4cloud.com developer nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* Author: lengleng (wangiegie@gmail.com)
|
||||
*
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pigx.admin.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 租户用户信息实体类
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "租户用户信息")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysTenantUser extends Model<SysTenantUser> {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
@@ -146,11 +146,6 @@ public class SysUser extends Model<SysUser> implements Serializable {
|
||||
@Schema(description = "头像地址")
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@Schema(description = "用户所属部门id")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
@@ -219,5 +214,4 @@ public class SysUser extends Model<SysUser> implements Serializable {
|
||||
@PropertyName("邮箱")
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pigx.admin.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.pig4cloud.pigx.common.core.util.TenantTable;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 系统用户部门关联实体类
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@Data
|
||||
@TenantTable
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysUserDept extends Model<SysUserDept> {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 岗位ID
|
||||
*/
|
||||
@Schema(description = "岗位id")
|
||||
private Long deptId;
|
||||
|
||||
}
|
||||
+8
-4
@@ -17,21 +17,25 @@
|
||||
package com.pig4cloud.pigx.admin.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.pig4cloud.pigx.common.core.util.TenantTable;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户岗位表
|
||||
* </p>
|
||||
* 用户岗位表实体类
|
||||
*
|
||||
* @author fxz
|
||||
* @author lengleng
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@Data
|
||||
@TenantTable
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysUserPost extends Model<SysUserPost> {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
|
||||
+23
-11
@@ -20,10 +20,13 @@
|
||||
package com.pig4cloud.pigx.admin.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.pig4cloud.pigx.common.core.util.TenantTable;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户角色表
|
||||
@@ -33,22 +36,31 @@ import lombok.EqualsAndHashCode;
|
||||
* @since 2017-10-29
|
||||
*/
|
||||
@Data
|
||||
@TenantTable
|
||||
@Schema(description = "用户角色")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysUserRole extends Model<SysUserRole> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@Schema(description = "角色id")
|
||||
private Long roleId;
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@Schema(description = "角色id")
|
||||
private Long roleId;
|
||||
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
+2
-2
@@ -4,9 +4,9 @@ import com.alibaba.excel.annotation.ExcelIgnore;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.pig4cloud.pigx.common.excel.annotation.ExcelLine;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -75,7 +75,7 @@ public class UserExcelVO implements Serializable {
|
||||
*/
|
||||
@NotBlank(message = "部门名称不能为空")
|
||||
@ExcelProperty("部门名称")
|
||||
private String deptName;
|
||||
private String deptNameList;
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
|
||||
+128
-131
@@ -20,6 +20,7 @@
|
||||
package com.pig4cloud.pigx.admin.api.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysDept;
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysPost;
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysRole;
|
||||
import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive;
|
||||
@@ -27,6 +28,7 @@ import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
@@ -39,163 +41,158 @@ import java.util.List;
|
||||
@Schema(description = "前端用户展示对象")
|
||||
public class UserVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@Schema(description = "主键")
|
||||
private Long userId;
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@Schema(description = "主键")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String password;
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 随机盐
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String salt;
|
||||
/**
|
||||
* 随机盐
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String salt;
|
||||
|
||||
/**
|
||||
* 微信openid
|
||||
*/
|
||||
@Schema(description = "微信open id")
|
||||
private String wxOpenid;
|
||||
/**
|
||||
* 微信openid
|
||||
*/
|
||||
@Schema(description = "微信open id")
|
||||
private String wxOpenid;
|
||||
|
||||
/**
|
||||
* QQ openid
|
||||
*/
|
||||
@Schema(description = "qq open id")
|
||||
private String qqOpenid;
|
||||
/**
|
||||
* QQ openid
|
||||
*/
|
||||
@Schema(description = "qq open id")
|
||||
private String qqOpenid;
|
||||
|
||||
/**
|
||||
* gitee openid
|
||||
*/
|
||||
@Schema(description = "gitee open id")
|
||||
private String giteeOpenId;
|
||||
/**
|
||||
* gitee openid
|
||||
*/
|
||||
@Schema(description = "gitee open id")
|
||||
private String giteeOpenId;
|
||||
|
||||
/**
|
||||
* 开源中国 openid
|
||||
*/
|
||||
@Schema(description = "开源中国 open id")
|
||||
private String oscOpenId;
|
||||
/**
|
||||
* 开源中国 openid
|
||||
*/
|
||||
@Schema(description = "开源中国 open id")
|
||||
private String oscOpenId;
|
||||
|
||||
/**
|
||||
* 企微微信 userid
|
||||
*/
|
||||
@Schema(description = "企微微信 userid")
|
||||
private String wxCpUserid;
|
||||
/**
|
||||
* 企微微信 userid
|
||||
*/
|
||||
@Schema(description = "企微微信 userid")
|
||||
private String wxCpUserid;
|
||||
|
||||
/**
|
||||
* 钉钉 userid
|
||||
*/
|
||||
@Schema(description = "钉钉 userid")
|
||||
private String wxDingUserid;
|
||||
/**
|
||||
* 钉钉 userid
|
||||
*/
|
||||
@Schema(description = "钉钉 userid")
|
||||
private String wxDingUserid;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@Schema(description = "修改时间")
|
||||
private LocalDateTime updateTime;
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@Schema(description = "修改时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 0-正常,1-删除
|
||||
*/
|
||||
@Schema(description = "删除标记,1:已删除,0:正常")
|
||||
private String delFlag;
|
||||
/**
|
||||
* 0-正常,1-删除
|
||||
*/
|
||||
@Schema(description = "删除标记,1:已删除,0:正常")
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 锁定标记
|
||||
*/
|
||||
@Schema(description = "锁定标记,0:正常,9:已锁定")
|
||||
private String lockFlag;
|
||||
/**
|
||||
* 锁定标记
|
||||
*/
|
||||
@Schema(description = "锁定标记,0:正常,9:已锁定")
|
||||
private String lockFlag;
|
||||
|
||||
/**
|
||||
* 密码过期标记
|
||||
*/
|
||||
@Schema(description = "密码过期标记")
|
||||
private String passwordExpireFlag;
|
||||
/**
|
||||
* 密码过期标记
|
||||
*/
|
||||
@Schema(description = "密码过期标记")
|
||||
private String passwordExpireFlag;
|
||||
|
||||
/**
|
||||
* 密码修改时间
|
||||
*/
|
||||
@Schema(description = "密码修改时间")
|
||||
private LocalDateTime passwordModifyTime;
|
||||
/**
|
||||
* 密码修改时间
|
||||
*/
|
||||
@Schema(description = "密码修改时间")
|
||||
private LocalDateTime passwordModifyTime;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@Sensitive(type = SensitiveTypeEnum.MOBILE_PHONE)
|
||||
@Schema(description = "手机号")
|
||||
private String phone;
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@Sensitive(type = SensitiveTypeEnum.MOBILE_PHONE)
|
||||
@Schema(description = "手机号")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
@Schema(description = "头像")
|
||||
private String avatar;
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
@Schema(description = "头像")
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@Schema(description = "所属部门")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@Schema(description = "所属租户")
|
||||
private Long tenantId;
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@Schema(description = "所属租户")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@Schema(description = "所属部门名称")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
*/
|
||||
@Schema(description = "拥有的角色列表")
|
||||
private List<SysRole> roleList;
|
||||
@Schema(description = "所属部门名称")
|
||||
private List<SysDept> deptList;
|
||||
|
||||
/**
|
||||
* 岗位列表
|
||||
*/
|
||||
private List<SysPost> postList;
|
||||
/**
|
||||
* 角色列表
|
||||
*/
|
||||
@Schema(description = "拥有的角色列表")
|
||||
private List<SysRole> roleList;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@Schema(description = "昵称")
|
||||
private String nickname;
|
||||
/**
|
||||
* 岗位列表
|
||||
*/
|
||||
@Schema(description = "拥有的岗位列表")
|
||||
private List<SysPost> postList;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
@Schema(description = "姓名")
|
||||
private String name;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@Schema(description = "昵称")
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
@Schema(description = "姓名")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
|
||||
}
|
||||
+126
-101
@@ -59,118 +59,143 @@ import java.util.List;
|
||||
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
|
||||
public class SysTenantController {
|
||||
|
||||
private final SysTenantService sysTenantService;
|
||||
private final SysTenantService sysTenantService;
|
||||
|
||||
private final SysMenuService sysMenuService;
|
||||
private final SysMenuService sysMenuService;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param page 分页对象
|
||||
* @param sysTenant 租户
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public R getSysTenantPage(@ParameterObject Page page, @ParameterObject SysTenant sysTenant) {
|
||||
return R.ok(sysTenantService.page(page, Wrappers.<SysTenant>lambdaQuery()
|
||||
.like(StrUtil.isNotBlank(sysTenant.getName()), SysTenant::getName, sysTenant.getName())));
|
||||
}
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param sysTenant 租户
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public R getSysTenantPage(@ParameterObject Page page, @ParameterObject SysTenant sysTenant) {
|
||||
return R.ok(sysTenantService.page(page, Wrappers.<SysTenant>lambdaQuery()
|
||||
.like(StrUtil.isNotBlank(sysTenant.getName()), SysTenant::getName, sysTenant.getName())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过ID 查询租户信息
|
||||
* @param id ID
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/details/{id}")
|
||||
public R getById(@PathVariable Long id) {
|
||||
return R.ok(sysTenantService.getById(id));
|
||||
}
|
||||
/**
|
||||
* 通过ID 查询租户信息
|
||||
*
|
||||
* @param id ID
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/details/{id}")
|
||||
public R getById(@PathVariable Long id) {
|
||||
return R.ok(sysTenantService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询租户信息
|
||||
* @param query 查询条件
|
||||
* @return 租户信息
|
||||
*/
|
||||
@GetMapping("/details")
|
||||
public R getDetails(@ParameterObject SysTenant query) {
|
||||
return R.ok(sysTenantService.getOne(Wrappers.query(query), false));
|
||||
}
|
||||
/**
|
||||
* 查询租户信息
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @return 租户信息
|
||||
*/
|
||||
@GetMapping("/details")
|
||||
public R getDetails(@ParameterObject SysTenant query) {
|
||||
return R.ok(sysTenantService.getOne(Wrappers.query(query), false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增租户
|
||||
* @param sysTenant 租户
|
||||
* @return R
|
||||
*/
|
||||
@SysLog("新增租户")
|
||||
@PostMapping
|
||||
@HasPermission("sys_systenant_add")
|
||||
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
|
||||
public R save(@RequestBody SysTenant sysTenant) {
|
||||
return R.ok(sysTenantService.saveTenant(sysTenant));
|
||||
}
|
||||
/**
|
||||
* 新增租户
|
||||
*
|
||||
* @param sysTenant 租户
|
||||
* @return R
|
||||
*/
|
||||
@SysLog("新增租户")
|
||||
@PostMapping
|
||||
@HasPermission("sys_systenant_add")
|
||||
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
|
||||
public R save(@RequestBody SysTenant sysTenant) {
|
||||
return R.ok(sysTenantService.saveTenant(sysTenant));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改租户
|
||||
* @param sysTenant 租户
|
||||
* @return R
|
||||
*/
|
||||
@SysLog("修改租户")
|
||||
@PutMapping
|
||||
@HasPermission("sys_systenant_edit")
|
||||
public R updateById(@RequestBody SysTenant sysTenant) {
|
||||
return R.ok(sysTenantService.updateTenant(sysTenant));
|
||||
}
|
||||
/**
|
||||
* 修改租户
|
||||
*
|
||||
* @param sysTenant 租户
|
||||
* @return R
|
||||
*/
|
||||
@SysLog("修改租户")
|
||||
@PutMapping
|
||||
@HasPermission("sys_systenant_edit")
|
||||
public R updateById(@RequestBody SysTenant sysTenant) {
|
||||
return R.ok(sysTenantService.updateTenant(sysTenant));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除租户
|
||||
* <p>
|
||||
* 为了保证安全,这里只删除租户表的数据,不删除基础表中的租户初始化数据。
|
||||
* @param ids id 列表
|
||||
* @return R
|
||||
*/
|
||||
@SysLog("删除租户")
|
||||
@DeleteMapping
|
||||
@HasPermission("sys_systenant_del")
|
||||
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
|
||||
public R removeById(@RequestBody Long[] ids) {
|
||||
return R.ok(sysTenantService.removeBatchByIds(CollUtil.toList(ids)));
|
||||
}
|
||||
/**
|
||||
* 通过id删除租户
|
||||
* <p>
|
||||
* 为了保证安全,这里只删除租户表的数据,不删除基础表中的租户初始化数据。
|
||||
*
|
||||
* @param ids id 列表
|
||||
* @return R
|
||||
*/
|
||||
@SysLog("删除租户")
|
||||
@DeleteMapping
|
||||
@HasPermission("sys_systenant_del")
|
||||
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
|
||||
public R removeById(@RequestBody Long[] ids) {
|
||||
return R.ok(sysTenantService.removeBatchByIds(CollUtil.toList(ids)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部有效的租户
|
||||
* @return
|
||||
*/
|
||||
@Inner(value = false)
|
||||
@GetMapping("/list")
|
||||
public R list() {
|
||||
List<SysTenant> tenants = sysTenantService.getNormalTenant()
|
||||
.stream()
|
||||
.filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now()))
|
||||
.filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now()))
|
||||
/**
|
||||
* 查询全部有效的租户列表
|
||||
*
|
||||
* @return 包含有效租户列表的响应结果
|
||||
*/
|
||||
@Inner(value = false)
|
||||
@GetMapping("/list")
|
||||
public R list() {
|
||||
List<SysTenant> tenants = sysTenantService.getNormalTenant()
|
||||
.stream()
|
||||
.filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now()))
|
||||
.filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now()))
|
||||
.toList();
|
||||
return R.ok(tenants);
|
||||
}
|
||||
return R.ok(tenants);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel 表格
|
||||
* @return
|
||||
*/
|
||||
@ResponseExcel
|
||||
@GetMapping("/export")
|
||||
@HasPermission("sys_systenant_export")
|
||||
public List<SysTenant> export(SysTenant sysTenant, Long[] ids) {
|
||||
return sysTenantService
|
||||
.list(Wrappers.lambdaQuery(sysTenant).in(ArrayUtil.isNotEmpty(ids), SysTenant::getId, CollUtil.toList(ids)));
|
||||
}
|
||||
/**
|
||||
* 导出租户信息到Excel
|
||||
*
|
||||
* @param sysTenant 租户查询条件
|
||||
* @param ids 租户ID数组
|
||||
* @return 符合条件的租户列表
|
||||
*/
|
||||
@ResponseExcel
|
||||
@GetMapping("/export")
|
||||
@HasPermission("sys_systenant_export")
|
||||
public List<SysTenant> export(SysTenant sysTenant, Long[] ids) {
|
||||
return sysTenantService
|
||||
.list(Wrappers.lambdaQuery(sysTenant).in(ArrayUtil.isNotEmpty(ids), SysTenant::getId, CollUtil.toList(ids)));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/tree/menu")
|
||||
public R getTree() {
|
||||
Long defaultId = ParamResolver.getLong("TENANT_DEFAULT_ID", 1L);
|
||||
List<Tree<Long>> trees = new ArrayList<>();
|
||||
TenantBroker.runAs(defaultId, (id) -> {
|
||||
trees.addAll(sysMenuService.treeMenu(null, null, null));
|
||||
});
|
||||
/**
|
||||
* 获取租户菜单
|
||||
*
|
||||
* @return 包含菜单树结构的响应结果
|
||||
*/
|
||||
@GetMapping(value = "/tree/menu")
|
||||
public R getTree() {
|
||||
Long defaultId = ParamResolver.getLong("TENANT_DEFAULT_ID", 1L);
|
||||
List<Tree<Long>> trees = new ArrayList<>();
|
||||
TenantBroker.runAs(defaultId, (id) -> {
|
||||
trees.addAll(sysMenuService.treeMenu(null, null, null));
|
||||
});
|
||||
|
||||
return R.ok(trees);
|
||||
}
|
||||
return R.ok(trees);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户租户信息
|
||||
*
|
||||
* @return 包含用户租户信息的响应结果
|
||||
*/
|
||||
@GetMapping("/user-tenant")
|
||||
public R getUserTenant() {
|
||||
return R.ok(sysTenantService.getUserTenant());
|
||||
}
|
||||
|
||||
}
|
||||
+31
-9
@@ -31,6 +31,7 @@ import com.pig4cloud.pigx.common.core.constant.CommonConstants;
|
||||
import com.pig4cloud.pigx.common.core.exception.ErrorCodes;
|
||||
import com.pig4cloud.pigx.common.core.util.MsgUtils;
|
||||
import com.pig4cloud.pigx.common.core.util.R;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantBroker;
|
||||
import com.pig4cloud.pigx.common.excel.annotation.RequestExcel;
|
||||
import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
|
||||
import com.pig4cloud.pigx.common.log.annotation.SysLog;
|
||||
@@ -50,8 +51,10 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户管理控制器:提供用户相关的REST接口
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2018/12/16
|
||||
* @date 2025/07/04
|
||||
*/
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@@ -70,11 +73,12 @@ public class SysUserController {
|
||||
@Inner
|
||||
@GetMapping("/info/{username}")
|
||||
public R info(@PathVariable String username) {
|
||||
SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
|
||||
SysUser user = TenantBroker.noneAs(() -> userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username), false));
|
||||
if (user == null) {
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_USERINFO_EMPTY, username));
|
||||
}
|
||||
return R.ok(userService.findUserInfo(user));
|
||||
|
||||
return TenantBroker.applyAs(user.getTenantId(), tenantId -> R.ok(userService.findUserInfo(user)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,15 +89,18 @@ public class SysUserController {
|
||||
@GetMapping(value = {"/info"})
|
||||
public R info() {
|
||||
String username = SecurityUtils.getUser().getUsername();
|
||||
SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
|
||||
SysUser user = TenantBroker.noneAs(() -> userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username), false));
|
||||
if (user == null) {
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
|
||||
}
|
||||
|
||||
// UserInfo 是复用对象,不能通过设置 @jsonIgnore 来忽略密码字段
|
||||
UserInfo userInfo = userService.findUserInfo(user);
|
||||
userInfo.getSysUser().setPassword(null);
|
||||
return R.ok(userInfo);
|
||||
|
||||
return TenantBroker.applyAs(user.getTenantId(), tenantId -> {
|
||||
// UserInfo 是复用对象,不能通过设置 @jsonIgnore 来忽略密码字段
|
||||
UserInfo userInfo = userService.findUserInfo(user);
|
||||
userInfo.getSysUser().setPassword(null);
|
||||
return R.ok(userInfo);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,12 +198,27 @@ public class SysUserController {
|
||||
* @return R 返回结果对象,包含修改密码操作的结果信息
|
||||
*/
|
||||
@PutMapping("/personal/password")
|
||||
public R updatePassword(@RequestBody UserDTO userDto) {
|
||||
public R updateUserPassword(@RequestBody UserDTO userDto) {
|
||||
String username = SecurityUtils.getUser().getUsername();
|
||||
userDto.setUsername(username);
|
||||
return userService.changePassword(userDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户租户信息
|
||||
*
|
||||
* @param userDto 用户数据传输对象,包含需要更新的用户信息
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/personal/tenant")
|
||||
public R updateUserTenant(@RequestBody UserDTO userDto) {
|
||||
String username = SecurityUtils.getUser().getUsername();
|
||||
userDto.setUsername(username);
|
||||
userDto.setUserId(SecurityUtils.getUser().getId());
|
||||
return userService.updateUserTenant(userDto);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param username 用户名称
|
||||
* @return 上级部门用户列表
|
||||
|
||||
+15
-3
@@ -19,19 +19,31 @@
|
||||
|
||||
package com.pig4cloud.pigx.admin.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysDept;
|
||||
import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 部门管理 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author lengleng
|
||||
* @since 2018-01-20
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysDeptMapper extends PigxBaseMapper<SysDept> {
|
||||
|
||||
/**
|
||||
* 根据用户ID和租户ID查询部门列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param tenantId 租户ID
|
||||
* @return 部门列表
|
||||
*/
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
List<SysDept> listDeptsByUserId(@Param("userId") Long userId, @Param("tenantId") Long tenantId);
|
||||
|
||||
}
|
||||
+11
-6
@@ -17,9 +17,11 @@
|
||||
|
||||
package com.pig4cloud.pigx.admin.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysPost;
|
||||
import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -32,11 +34,14 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface SysPostMapper extends PigxBaseMapper<SysPost> {
|
||||
|
||||
/**
|
||||
* 通过用户ID,查询岗位信息
|
||||
* @param userId 用户id
|
||||
* @return 岗位信息
|
||||
*/
|
||||
List<SysPost> listPostsByUserId(Long userId);
|
||||
/**
|
||||
* 通过用户ID和租户ID查询岗位信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param tenantId 租户ID
|
||||
* @return 岗位信息列表
|
||||
*/
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
List<SysPost> listPostsByUserId(@Param("userId") Long userId, @Param("tenantId") Long tenantId);
|
||||
|
||||
}
|
||||
+11
-6
@@ -19,9 +19,11 @@
|
||||
|
||||
package com.pig4cloud.pigx.admin.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysRole;
|
||||
import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -36,11 +38,14 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface SysRoleMapper extends PigxBaseMapper<SysRole> {
|
||||
|
||||
/**
|
||||
* 通过用户ID,查询角色信息
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
List<SysRole> listRolesByUserId(Long userId);
|
||||
/**
|
||||
* 通过用户ID查询角色信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param tenantId 租户ID
|
||||
* @return 角色信息列表
|
||||
*/
|
||||
@InterceptorIgnore(tenantLine = "true")
|
||||
List<SysRole> listRolesByUserId(@Param("userId") Long userId, @Param("tenantId") Long tenantId);
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2018-2025, lengleng All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the pig4cloud.com developer nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* Author: lengleng (wangiegie@gmail.com)
|
||||
*
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pigx.admin.mapper;
|
||||
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysTenantUser;
|
||||
import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
||||
/**
|
||||
* 系统租户用户映射接口
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysTenantUserMapper extends PigxBaseMapper<SysTenantUser> {
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pigx.admin.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.pig4cloud.pigx.admin.api.entity.SysUserDept;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
||||
/**
|
||||
* 系统用户部门关联Mapper接口
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2025/06/27
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysUserDeptMapper extends BaseMapper<SysUserDept> {
|
||||
|
||||
}
|
||||
+17
-8
@@ -31,23 +31,32 @@ import java.util.List;
|
||||
public interface SysTenantService extends IService<SysTenant> {
|
||||
|
||||
/**
|
||||
* 获取正常的租户
|
||||
* @return
|
||||
* 获取正常的租户列表
|
||||
*
|
||||
* @return 正常的租户列表
|
||||
*/
|
||||
List<SysTenant> getNormalTenant();
|
||||
|
||||
/**
|
||||
* 保存租户
|
||||
* @param sysTenant
|
||||
* @return
|
||||
* 保存租户信息
|
||||
*
|
||||
* @param sysTenant 租户信息对象
|
||||
* @return 保存是否成功
|
||||
*/
|
||||
Boolean saveTenant(SysTenant sysTenant);
|
||||
|
||||
/**
|
||||
* 修改租户
|
||||
* @param sysTenant
|
||||
* @return
|
||||
* 修改租户信息
|
||||
*
|
||||
* @param sysTenant 租户信息对象
|
||||
* @return 修改是否成功
|
||||
*/
|
||||
Boolean updateTenant(SysTenant sysTenant);
|
||||
|
||||
/**
|
||||
* 获取用户所属租户列表
|
||||
*
|
||||
* @return 用户所属租户列表
|
||||
*/
|
||||
List<SysTenant> getUserTenant();
|
||||
}
|
||||
+8
@@ -195,4 +195,12 @@ public interface SysUserService extends IService<SysUser> {
|
||||
* @return
|
||||
*/
|
||||
R<Boolean> forgetUserPassword(RegisterUserDTO userDto, String code);
|
||||
|
||||
/**
|
||||
* 更新用户租户信息
|
||||
*
|
||||
* @param userDto 用户数据传输对象
|
||||
* @return 更新结果
|
||||
*/
|
||||
R updateUserTenant(UserDTO userDto);
|
||||
}
|
||||
+72
-58
@@ -27,6 +27,7 @@ import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import com.pig4cloud.pigx.admin.api.constant.OrgTypeEnum;
|
||||
import com.pig4cloud.pigx.admin.api.constant.PostCodeEnum;
|
||||
import com.pig4cloud.pigx.admin.api.entity.*;
|
||||
@@ -66,10 +67,13 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
|
||||
private final SysRoleMapper roleMapper;
|
||||
|
||||
private final SysUserDeptMapper userDeptMapper;
|
||||
|
||||
private final SysUserPostMapper userPostMapper;
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
*
|
||||
* @param id 部门 ID
|
||||
* @return 成功、失败
|
||||
*/
|
||||
@@ -86,6 +90,7 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
|
||||
/**
|
||||
* 查询全部部门树
|
||||
*
|
||||
* @param deptName
|
||||
* @param parentId
|
||||
* @return 树 部门名称
|
||||
@@ -94,33 +99,33 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
public List<Tree<Long>> selectTree(String deptName, Long parentId) {
|
||||
// 查询全部部门
|
||||
List<SysDept> deptAllList = deptMapper
|
||||
.selectList(Wrappers.<SysDept>lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName));
|
||||
.selectList(Wrappers.<SysDept>lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName));
|
||||
// 查询数据权限内部门
|
||||
List<Long> deptOwnIdList = deptMapper
|
||||
.selectListByScope(
|
||||
Wrappers.<SysDept>lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName),
|
||||
DataScope.of())
|
||||
.stream()
|
||||
.map(SysDept::getDeptId)
|
||||
.toList();
|
||||
.selectListByScope(
|
||||
Wrappers.<SysDept>lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName),
|
||||
DataScope.of())
|
||||
.stream()
|
||||
.map(SysDept::getDeptId)
|
||||
.toList();
|
||||
|
||||
// 权限内部门
|
||||
List<TreeNode<Long>> collect = deptAllList.stream()
|
||||
.filter(dept -> dept.getDeptId().intValue() != dept.getParentId())
|
||||
.sorted(Comparator.comparingInt(SysDept::getSortOrder))
|
||||
.map(dept -> {
|
||||
TreeNode<Long> treeNode = new TreeNode<>();
|
||||
treeNode.setId(dept.getDeptId());
|
||||
treeNode.setParentId(dept.getParentId());
|
||||
treeNode.setName(dept.getName());
|
||||
treeNode.setWeight(dept.getSortOrder());
|
||||
// 有权限不返回标识
|
||||
Map<String, Object> extra = new HashMap<>(8);
|
||||
extra.put("isLock", !deptOwnIdList.contains(dept.getDeptId()));
|
||||
extra.put("createTime", dept.getCreateTime());
|
||||
treeNode.setExtra(extra);
|
||||
return treeNode;
|
||||
})
|
||||
.filter(dept -> dept.getDeptId().intValue() != dept.getParentId())
|
||||
.sorted(Comparator.comparingInt(SysDept::getSortOrder))
|
||||
.map(dept -> {
|
||||
TreeNode<Long> treeNode = new TreeNode<>();
|
||||
treeNode.setId(dept.getDeptId());
|
||||
treeNode.setParentId(dept.getParentId());
|
||||
treeNode.setName(dept.getName());
|
||||
treeNode.setWeight(dept.getSortOrder());
|
||||
// 有权限不返回标识
|
||||
Map<String, Object> extra = new HashMap<>(8);
|
||||
extra.put("isLock", !deptOwnIdList.contains(dept.getDeptId()));
|
||||
extra.put("createTime", dept.getCreateTime());
|
||||
treeNode.setExtra(extra);
|
||||
return treeNode;
|
||||
})
|
||||
.toList();
|
||||
|
||||
// 模糊查询 不组装树结构 直接返回 表格方便编辑
|
||||
@@ -138,6 +143,7 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
|
||||
/**
|
||||
* 导出部门
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
@@ -147,10 +153,10 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
DeptExcelVO deptExcelVo = new DeptExcelVO();
|
||||
deptExcelVo.setName(item.getName());
|
||||
Optional<String> first = this.list()
|
||||
.stream()
|
||||
.filter(it -> item.getParentId().equals(it.getDeptId()))
|
||||
.map(SysDept::getName)
|
||||
.findFirst();
|
||||
.stream()
|
||||
.filter(it -> item.getParentId().equals(it.getDeptId()))
|
||||
.map(SysDept::getName)
|
||||
.findFirst();
|
||||
deptExcelVo.setParentName(first.orElse("根部门"));
|
||||
deptExcelVo.setSortOrder(item.getSortOrder());
|
||||
return deptExcelVo;
|
||||
@@ -183,8 +189,7 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
sysDept.setParentId(one.getDeptId());
|
||||
sysDept.setSortOrder(item.getSortOrder());
|
||||
baseMapper.insert(sysDept);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// 数据不合法情况
|
||||
errorMessageList.add(new ErrorMessage(item.getLineNum(), errorMsg));
|
||||
}
|
||||
@@ -197,6 +202,7 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
|
||||
/**
|
||||
* 查询所有子节点 (包含当前节点)
|
||||
*
|
||||
* @param deptId 部门ID 目标部门ID
|
||||
* @return ID
|
||||
*/
|
||||
@@ -216,37 +222,39 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
|
||||
/**
|
||||
* 获取部门负责人
|
||||
*
|
||||
* <p>
|
||||
* 1. 根据dept 查询用户 2. 筛选用户列表中 post
|
||||
*
|
||||
* @param deptId deptId
|
||||
* @return user id list
|
||||
*/
|
||||
@Override
|
||||
public List<Long> listDeptLeader(Long deptId) {
|
||||
List<SysUser> sysUserList = userMapper
|
||||
.selectList(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getDeptId, deptId));
|
||||
if (CollUtil.isEmpty(sysUserList)) {
|
||||
|
||||
List<SysUserDept> userDeptList = userDeptMapper.selectList(Wrappers.<SysUserDept>lambdaQuery().eq(SysUserDept::getDeptId, deptId));
|
||||
if (CollUtil.isEmpty(userDeptList)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SysPost deptLeader = postMapper
|
||||
.selectOne(Wrappers.<SysPost>lambdaQuery().eq(SysPost::getPostCode, PostCodeEnum.TEAM_LEADER.getCode()));
|
||||
.selectOne(Wrappers.<SysPost>lambdaQuery().eq(SysPost::getPostCode, PostCodeEnum.TEAM_LEADER.getCode()));
|
||||
if (deptLeader == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Long> userIdList = sysUserList.stream().map(SysUser::getUserId).toList();
|
||||
List<Long> userIdList = userDeptList.stream().map(SysUserDept::getUserId).toList();
|
||||
return userPostMapper.selectList(Wrappers.<SysUserPost>lambdaQuery().in(SysUserPost::getUserId, userIdList))
|
||||
.stream()
|
||||
.filter(post -> Objects.equals(post.getPostId(), deptLeader.getPostId()))
|
||||
.map(SysUserPost::getUserId)
|
||||
.toList();
|
||||
.stream()
|
||||
.filter(post -> Objects.equals(post.getPostId(), deptLeader.getPostId()))
|
||||
.map(SysUserPost::getUserId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据父部门ID和类型获取组织树
|
||||
*
|
||||
* @param parentDeptId 父部门ID
|
||||
* @param type 类型
|
||||
* @param type 类型
|
||||
* @return 组织树信息
|
||||
*/
|
||||
public Map<String, Object> listOrgTree(Long parentDeptId, String type) {
|
||||
@@ -267,15 +275,15 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
});
|
||||
|
||||
return Dict.create()
|
||||
.set("roleList", orgs)
|
||||
.set("childDepartments", orgs)
|
||||
.set("employees", new ArrayList<>());
|
||||
.set("roleList", orgs)
|
||||
.set("childDepartments", orgs)
|
||||
.set("employees", new ArrayList<>());
|
||||
}
|
||||
|
||||
Dict dict = Dict.create()
|
||||
.set("titleDepartments", new ArrayList<>())
|
||||
.set("roleList", new ArrayList<>())
|
||||
.set("employees", new ArrayList<>());
|
||||
.set("titleDepartments", new ArrayList<>())
|
||||
.set("roleList", new ArrayList<>())
|
||||
.set("employees", new ArrayList<>());
|
||||
|
||||
List<SysDept> deptList = this.list(
|
||||
Wrappers.<SysDept>lambdaQuery().eq(Objects.nonNull(parentDeptId), SysDept::getParentId, parentDeptId));
|
||||
@@ -296,8 +304,12 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
|
||||
List<OrgTreeVO> userVoList = new ArrayList<>();
|
||||
|
||||
List<SysUser> userList = userMapper
|
||||
.selectList(Wrappers.<SysUser>lambdaQuery().in(SysUser::getDeptId, CollUtil.toList(parentDeptId)));
|
||||
MPJLambdaWrapper<SysUser> userQuery = new MPJLambdaWrapper<>();
|
||||
userQuery.selectAll(SysUser.class)
|
||||
.leftJoin(SysUserDept.class, SysUserDept::getUserId, SysUser::getUserId)
|
||||
.eq(SysUserDept::getDeptId, parentDeptId);
|
||||
|
||||
List<SysUser> userList = userMapper.selectJoinList(userQuery);
|
||||
|
||||
userList.forEach(user -> {
|
||||
OrgTreeVO orgTreeVo = new OrgTreeVO();
|
||||
@@ -322,28 +334,30 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
|
||||
|
||||
/**
|
||||
* 模糊搜索用户
|
||||
*
|
||||
* @param username 用户名/拼音/首字母
|
||||
* @return 匹配到的用户
|
||||
*/
|
||||
public List<OrgTreeVO> getOrgTreeUser(String username) {
|
||||
return userMapper.selectList(Wrappers.<SysUser>lambdaQuery().like(SysUser::getUsername, username))
|
||||
.stream()
|
||||
.map(user -> {
|
||||
OrgTreeVO orgTreeVo = new OrgTreeVO();
|
||||
orgTreeVo.setId(user.getUserId());
|
||||
orgTreeVo.setName(user.getUsername());
|
||||
orgTreeVo.setType(OrgTypeEnum.USER.getType());
|
||||
orgTreeVo.setSelected(false);
|
||||
orgTreeVo.setAvatar(user.getAvatar());
|
||||
return orgTreeVo;
|
||||
})
|
||||
.stream()
|
||||
.map(user -> {
|
||||
OrgTreeVO orgTreeVo = new OrgTreeVO();
|
||||
orgTreeVo.setId(user.getUserId());
|
||||
orgTreeVo.setName(user.getUsername());
|
||||
orgTreeVo.setType(OrgTypeEnum.USER.getType());
|
||||
orgTreeVo.setSelected(false);
|
||||
orgTreeVo.setAvatar(user.getAvatar());
|
||||
return orgTreeVo;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归查询所有子节点。
|
||||
*
|
||||
* @param allDeptList 所有部门列表
|
||||
* @param parentId 父部门ID
|
||||
* @param parentId 父部门ID
|
||||
* @param resDeptList 结果集合
|
||||
*/
|
||||
private void recursiveDept(List<SysDept> allDeptList, Long parentId, List<SysDept> resDeptList) {
|
||||
|
||||
+6
-4
@@ -35,6 +35,7 @@ import com.pig4cloud.pigx.common.core.constant.CacheConstants;
|
||||
import com.pig4cloud.pigx.common.core.exception.ErrorCodes;
|
||||
import com.pig4cloud.pigx.common.core.util.MsgUtils;
|
||||
import com.pig4cloud.pigx.common.core.util.R;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.common.excel.vo.ErrorMessage;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
@@ -61,13 +62,14 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
|
||||
private SysRoleMenuService roleMenuService;
|
||||
|
||||
/**
|
||||
* 通过用户ID,查询角色信息
|
||||
* @param userId
|
||||
* @return
|
||||
* 通过用户ID查询角色信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色信息列表
|
||||
*/
|
||||
@Override
|
||||
public List findRolesByUserId(Long userId) {
|
||||
return baseMapper.listRolesByUserId(userId);
|
||||
return baseMapper.listRolesByUserId(userId, TenantContextHolder.getTenantId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+19
-1
@@ -22,11 +22,13 @@ import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import com.pig4cloud.pigx.admin.api.constant.TenantStateEnum;
|
||||
import com.pig4cloud.pigx.admin.api.entity.*;
|
||||
import com.pig4cloud.pigx.admin.config.ClientDetailsInitRunner;
|
||||
import com.pig4cloud.pigx.admin.mapper.SysRoleMenuMapper;
|
||||
import com.pig4cloud.pigx.admin.mapper.SysTenantMapper;
|
||||
import com.pig4cloud.pigx.admin.mapper.SysTenantUserMapper;
|
||||
import com.pig4cloud.pigx.admin.service.*;
|
||||
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
|
||||
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
|
||||
@@ -34,6 +36,7 @@ import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
|
||||
import com.pig4cloud.pigx.common.data.datascope.DataScopeTypeEnum;
|
||||
import com.pig4cloud.pigx.common.data.resolver.ParamResolver;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantBroker;
|
||||
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -84,6 +87,8 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
|
||||
|
||||
private final SysDictService dictService;
|
||||
|
||||
private final SysTenantUserMapper tenantUserMapper;
|
||||
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
@@ -153,7 +158,6 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
|
||||
user.setUsername(tenantDefault.getTenantDefaultUsername());
|
||||
user.setPasswordModifyTime(LocalDateTime.now());
|
||||
user.setPassword(ENCODER.encode(tenantDefault.getTenantDefaultPassword()));
|
||||
user.setDeptId(dept.getDeptId());
|
||||
userService.save(user);
|
||||
|
||||
// 构造普通用户角色
|
||||
@@ -305,6 +309,20 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所属租户列表
|
||||
*
|
||||
* @return 用户所属租户列表
|
||||
*/
|
||||
@Override
|
||||
public List<SysTenant> getUserTenant() {
|
||||
MPJLambdaWrapper<SysTenant> wrapper = new MPJLambdaWrapper<SysTenant>()
|
||||
.selectAll(SysTenant.class)
|
||||
.leftJoin(SysTenantUser.class, SysTenantUser::getTenantId, SysTenant::getId)
|
||||
.eq(SysTenantUser::getUserId, SecurityUtils.getUser().getId());
|
||||
return baseMapper.selectJoinList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新的租户菜单,维护成新的菜单
|
||||
*
|
||||
|
||||
+84
-14
@@ -36,9 +36,7 @@ import com.pig4cloud.pigx.admin.api.dto.UserInfo;
|
||||
import com.pig4cloud.pigx.admin.api.entity.*;
|
||||
import com.pig4cloud.pigx.admin.api.vo.UserExcelVO;
|
||||
import com.pig4cloud.pigx.admin.api.vo.UserVO;
|
||||
import com.pig4cloud.pigx.admin.mapper.SysUserMapper;
|
||||
import com.pig4cloud.pigx.admin.mapper.SysUserPostMapper;
|
||||
import com.pig4cloud.pigx.admin.mapper.SysUserRoleMapper;
|
||||
import com.pig4cloud.pigx.admin.mapper.*;
|
||||
import com.pig4cloud.pigx.admin.service.*;
|
||||
import com.pig4cloud.pigx.common.audit.annotation.Audit;
|
||||
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
|
||||
@@ -49,6 +47,7 @@ import com.pig4cloud.pigx.common.core.util.MsgUtils;
|
||||
import com.pig4cloud.pigx.common.core.util.R;
|
||||
import com.pig4cloud.pigx.common.data.datascope.DataScope;
|
||||
import com.pig4cloud.pigx.common.data.resolver.ParamResolver;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantBroker;
|
||||
import com.pig4cloud.pigx.common.excel.vo.ErrorMessage;
|
||||
import com.pig4cloud.pigx.common.security.service.PigxUser;
|
||||
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
|
||||
@@ -92,7 +91,12 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
private final SysUserPostMapper sysUserPostMapper;
|
||||
|
||||
private final SysUserDeptMapper sysUserDeptMapper;
|
||||
|
||||
private final SysTenantUserMapper sysTenantUserMapper;
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
private final SysDeptMapper sysDeptMapper;
|
||||
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
@@ -141,14 +145,30 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
userRole.setRoleId(roleId);
|
||||
return userRole;
|
||||
}).forEach(sysUserRoleMapper::insert);
|
||||
|
||||
// 插入用户部门信息
|
||||
if (Objects.nonNull(userDto.getDeptId())) {
|
||||
SysUserDept sysUserDept = new SysUserDept();
|
||||
sysUserDept.setUserId(sysUser.getUserId());
|
||||
sysUserDept.setDeptId(userDto.getDeptId());
|
||||
sysUserDeptMapper.insertOrUpdate(List.of(sysUserDept), (batchSqlSession, sysUserDept1) -> sysUserDeptMapper.exists(Wrappers.<SysUserDept>lambdaQuery()
|
||||
.eq(SysUserDept::getDeptId, userDto.getDeptId())
|
||||
.eq(SysUserDept::getUserId, sysUserDept1.getUserId())));
|
||||
}
|
||||
|
||||
// 插入用户租户关系表
|
||||
SysTenantUser sysTenantUser = new SysTenantUser();
|
||||
sysTenantUser.setUserId(sysUser.getUserId());
|
||||
sysTenantUser.setTenantId(SecurityUtils.getUser().getTenantId());
|
||||
sysTenantUserMapper.insert(sysTenantUser);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过查用户的全部信息
|
||||
* 查询用户全部信息,包括角色和权限
|
||||
*
|
||||
* @param sysUser 用户
|
||||
* @return
|
||||
* @param sysUser 用户信息
|
||||
* @return 包含用户角色和权限的用户信息对象
|
||||
*/
|
||||
@Override
|
||||
public UserInfo findUserInfo(SysUser sysUser) {
|
||||
@@ -184,6 +204,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
*/
|
||||
@Override
|
||||
public IPage getUsersWithRolePage(Page page, UserDTO userDTO) {
|
||||
userDTO.setTenantId(SecurityUtils.getUser().getTenantId());
|
||||
return baseMapper.getUserVosPage(page, userDTO, DataScope.of());
|
||||
}
|
||||
|
||||
@@ -214,7 +235,12 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
cache.evict(sysUser.getUsername());
|
||||
}
|
||||
|
||||
// 删除用户角色
|
||||
sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().in(SysUserRole::getUserId, CollUtil.toList(ids)));
|
||||
sysUserDeptMapper.delete(Wrappers.<SysUserDept>lambdaQuery().in(SysUserDept::getUserId, CollUtil.toList(ids)));
|
||||
sysUserPostMapper.delete(Wrappers.<SysUserPost>lambdaQuery().in(SysUserPost::getUserId, CollUtil.toList(ids)));
|
||||
sysTenantUserMapper.delete(Wrappers.<SysTenantUser>lambdaQuery().in(SysTenantUser::getUserId, CollUtil.toList(ids))
|
||||
.eq(SysTenantUser::getTenantId, SecurityUtils.getUser().getTenantId()));
|
||||
this.removeBatchByIds(CollUtil.toList(ids));
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
@@ -273,6 +299,15 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
}).forEach(SysUserPost::insert);
|
||||
}
|
||||
|
||||
// 更新用户部门表
|
||||
if (Objects.nonNull(userDto.getDeptId())) {
|
||||
sysUserDeptMapper.delete(Wrappers.<SysUserDept>lambdaQuery().eq(SysUserDept::getUserId, userDto.getUserId()));
|
||||
SysUserDept sysUserDept = new SysUserDept();
|
||||
sysUserDept.setUserId(sysUser.getUserId());
|
||||
sysUserDept.setDeptId(userDto.getDeptId());
|
||||
sysUserDept.insert();
|
||||
}
|
||||
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
@@ -286,13 +321,17 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
public List<SysUser> listAncestorUsers(String username) {
|
||||
SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
|
||||
|
||||
SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
|
||||
if (sysDept == null) {
|
||||
// 查询所属部门
|
||||
List<SysDept> sysDeptList = sysDeptMapper.listDeptsByUserId(sysUser.getUserId(), sysUser.getTenantId());
|
||||
if (CollUtil.isEmpty(sysDeptList)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Long parentId = sysDept.getParentId();
|
||||
return this.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getDeptId, parentId));
|
||||
// 查询用户部门ID
|
||||
List<Long> parentDeptList = sysDeptList.stream().map(SysDept::getParentId).toList();
|
||||
List<Long> userIdList = sysUserDeptMapper.selectList(Wrappers.<SysUserDept>lambdaQuery().in(SysUserDept::getDeptId, parentDeptList))
|
||||
.stream().map(SysUserDept::getUserId).toList();
|
||||
return this.list(Wrappers.<SysUser>lambdaQuery().in(SysUser::getUserId, userIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,21 +344,29 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
@Override
|
||||
public List<UserExcelVO> listUser(UserDTO userDTO, Long[] ids) {
|
||||
// 根据数据权限查询全部的用户信息
|
||||
userDTO.setTenantId(SecurityUtils.getUser().getTenantId());
|
||||
List<UserVO> voList = baseMapper.selectVoListByScope(userDTO, ids, DataScope.of());
|
||||
// 转换成execl 对象输出
|
||||
List<UserExcelVO> userExcelVOList = voList.stream().map(userVO -> {
|
||||
UserExcelVO excelVO = new UserExcelVO();
|
||||
BeanUtils.copyProperties(userVO, excelVO);
|
||||
// 转换角色名称
|
||||
String roleNameList = userVO.getRoleList()
|
||||
.stream()
|
||||
.map(SysRole::getRoleName)
|
||||
.collect(Collectors.joining(StrUtil.COMMA));
|
||||
excelVO.setRoleNameList(roleNameList);
|
||||
// 转化岗位名称
|
||||
String postNameList = userVO.getPostList()
|
||||
.stream()
|
||||
.map(SysPost::getPostName)
|
||||
.collect(Collectors.joining(StrUtil.COMMA));
|
||||
excelVO.setPostNameList(postNameList);
|
||||
// 转化部门名称
|
||||
String deptNameList = userVO.getDeptList().stream()
|
||||
.map(SysDept::getName)
|
||||
.collect(Collectors.joining(StrUtil.COMMA));
|
||||
excelVO.setDeptNameList(deptNameList);
|
||||
return excelVO;
|
||||
}).toList();
|
||||
return userExcelVOList;
|
||||
@@ -356,10 +403,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
// 判断输入的部门名称列表是否合法
|
||||
Optional<SysDept> deptOptional = deptList.stream()
|
||||
.filter(dept -> excel.getDeptName().equals(dept.getName()))
|
||||
.filter(dept -> excel.getDeptNameList().equals(dept.getName()))
|
||||
.findFirst();
|
||||
if (!deptOptional.isPresent()) {
|
||||
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_DEPT_DEPTNAME_INEXISTENCE, excel.getDeptName()));
|
||||
errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_DEPT_DEPTNAME_INEXISTENCE, excel.getDeptNameList()));
|
||||
}
|
||||
|
||||
// 判断输入的角色名称列表是否合法
|
||||
@@ -423,6 +470,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
userDTO.setRole(roleIdList);
|
||||
// 插入用户
|
||||
this.saveUser(userDTO);
|
||||
// 插入用户租户关系表
|
||||
SysTenantUser sysTenantUser = new SysTenantUser();
|
||||
sysTenantUser.setUserId(userDTO.getUserId());
|
||||
sysTenantUser.setTenantId(SecurityUtils.getUser().getTenantId());
|
||||
sysTenantUserMapper.insert(sysTenantUser);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,6 +551,21 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新用户租户信息
|
||||
*
|
||||
* @param userDto 用户数据传输对象
|
||||
* @return 更新结果
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
|
||||
public R updateUserTenant(UserDTO userDto) {
|
||||
return R.ok(TenantBroker.noneAs(() -> this.update(Wrappers.<SysUser>lambdaUpdate()
|
||||
.set(SysUser::getTenantId, userDto.getTenantId())
|
||||
.eq(SysUser::getUserId, userDto.getUserId()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R unbinding(String type) {
|
||||
PigxUser user = SecurityUtils.getUser();
|
||||
@@ -588,7 +655,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
return R.failed("验证码错误");
|
||||
}
|
||||
|
||||
String username = lambdaQuery().select(SysUser::getUsername).eq(SysUser::getPhone, userDto.getPhone()).one().getUsername();
|
||||
String username = lambdaQuery().select(SysUser::getUsername).
|
||||
eq(SysUser::getPhone, userDto.getPhone()).one().getUsername();
|
||||
|
||||
// 重置密码
|
||||
String password = ENCODER.encode(userDto.getNewpassword1());
|
||||
@@ -617,7 +685,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
*/
|
||||
@Override
|
||||
public List<SysUser> listUserIdByDeptIds(List<Long> deptIdList) {
|
||||
return baseMapper.selectList(Wrappers.<SysUser>lambdaQuery().in(SysUser::getDeptId, deptIdList));
|
||||
List<Long> userList = sysUserDeptMapper.selectList(Wrappers.<SysUserDept>lambdaQuery().in(SysUserDept::getDeptId, deptIdList))
|
||||
.stream().map(SysUserDept::getUserId).toList();
|
||||
return baseMapper.selectList(Wrappers.<SysUser>lambdaQuery().in(SysUser::getUserId, userList));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,4 +20,15 @@
|
||||
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pig4cloud.pigx.admin.mapper.SysDeptMapper">
|
||||
<select id="listDeptsByUserId" resultType="com.pig4cloud.pigx.admin.api.entity.SysDept">
|
||||
SELECT sys_dept.dept_id,
|
||||
sys_dept.name,
|
||||
sys_dept.sort_order
|
||||
FROM sys_dept,
|
||||
sys_user_dept
|
||||
WHERE sys_dept.dept_id = sys_user_dept.dept_id
|
||||
AND sys_dept.del_flag = '0'
|
||||
and sys_user_dept.user_id = #{userId}
|
||||
and sys_user_dept.tenant_id = #{tenantId}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -48,6 +48,7 @@
|
||||
WHERE p.post_id = up.post_id
|
||||
AND p.del_flag = '0'
|
||||
and up.user_id = #{userId}
|
||||
and up.tenant_id = #{tenantId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -49,5 +49,6 @@
|
||||
WHERE sys_role.role_id = sys_user_role.role_id
|
||||
AND sys_role.del_flag = '0'
|
||||
and sys_user_role.user_id = #{userId}
|
||||
and sys_user_role.tenant_id = #{tenantId}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -1,22 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~
|
||||
~ Copyright (c) 2018-2025, lengleng All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without
|
||||
~ modification, are permitted provided that the following conditions are met:
|
||||
~
|
||||
~ Redistributions of source code must retain the above copyright notice,
|
||||
~ this list of conditions and the following disclaimer.
|
||||
~ Redistributions in binary form must reproduce the above copyright
|
||||
~ notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~ Neither the name of the pig4cloud.com developer nor the names of its
|
||||
~ contributors may be used to endorse or promote products derived from
|
||||
~ this software without specific prior written permission.
|
||||
~ Author: lengleng (wangiegie@gmail.com)
|
||||
~
|
||||
-->
|
||||
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pig4cloud.pigx.admin.mapper.SysUserMapper">
|
||||
@@ -28,203 +10,131 @@
|
||||
<result column="salt" property="salt"/>
|
||||
<result column="phone" property="phone"/>
|
||||
<result column="avatar" property="avatar"/>
|
||||
<result column="nickname" property="nickname"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="email" property="email"/>
|
||||
<result column="wx_openid" property="wxOpenid"/>
|
||||
<result column="qq_openid" property="qqOpenid"/>
|
||||
<result column="gitee_login" property="giteeOpenId"/>
|
||||
<result column="osc_id" property="oscOpenId"/>
|
||||
<result column="wx_cp_userid" property="wxCpUserid"/>
|
||||
<result column="wx_ding_userid" property="wxDingUserid"/>
|
||||
<result column="ucreate_time" property="createTime"/>
|
||||
<result column="uupdate_time" property="updateTime"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="lock_flag" property="lockFlag"/>
|
||||
<result column="password_expire_flag" property="passwordExpireFlag"/>
|
||||
<result column="password_modify_time" property="passwordModifyTime"/>
|
||||
<result column="del_flag" property="delFlag"/>
|
||||
<result column="dept_id" property="deptId"/>
|
||||
<result column="tenant_id" property="tenantId"/>
|
||||
<result column="dept_name" property="deptName"/>
|
||||
<result column="nickname" property="nickname"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="email" property="email"/>
|
||||
<collection property="deptList" ofType="com.pig4cloud.pigx.admin.api.entity.SysDept"
|
||||
select="com.pig4cloud.pigx.admin.mapper.SysDeptMapper.listDeptsByUserId"
|
||||
column="{userId=user_id, tenantId=tenant_id}">
|
||||
</collection>
|
||||
<collection property="roleList" ofType="com.pig4cloud.pigx.admin.api.entity.SysRole"
|
||||
select="com.pig4cloud.pigx.admin.mapper.SysRoleMapper.listRolesByUserId" column="user_id">
|
||||
select="com.pig4cloud.pigx.admin.mapper.SysRoleMapper.listRolesByUserId"
|
||||
column="{userId=user_id, tenantId=tenant_id}">
|
||||
</collection>
|
||||
<collection property="postList" ofType="com.pig4cloud.pigx.admin.api.entity.SysPost"
|
||||
select="com.pig4cloud.pigx.admin.mapper.SysPostMapper.listPostsByUserId" column="user_id">
|
||||
select="com.pig4cloud.pigx.admin.mapper.SysPostMapper.listPostsByUserId"
|
||||
column="{userId=user_id, tenantId=tenant_id}">
|
||||
</collection>
|
||||
</resultMap>
|
||||
|
||||
<sql id="userRoleSql">
|
||||
<sql id="userColumns">
|
||||
u.user_id,
|
||||
u.username,
|
||||
u.password,
|
||||
u.salt,
|
||||
u.phone,
|
||||
u.avatar,
|
||||
u.wx_openid,
|
||||
u.qq_openid,
|
||||
u.gitee_login,
|
||||
u.osc_id,
|
||||
u.wx_cp_userid,
|
||||
u.wx_ding_userid,
|
||||
u.dept_id,
|
||||
u.del_flag,
|
||||
u.lock_flag,
|
||||
u.password_expire_flag,
|
||||
u.password_modify_time,
|
||||
u.tenant_id,
|
||||
u.create_by,
|
||||
u.create_time ucreate_time,
|
||||
u.update_time uupdate_time,
|
||||
r.role_id,
|
||||
r.role_name,
|
||||
r.role_code,
|
||||
r.role_desc,
|
||||
r.create_time rcreate_time,
|
||||
r.update_time rupdate_time
|
||||
</sql>
|
||||
|
||||
<sql id="userRoleDeptSql">
|
||||
u.user_id,
|
||||
u.username,
|
||||
u.password,
|
||||
u.salt,
|
||||
u.phone,
|
||||
u.avatar,
|
||||
u.wx_openid,
|
||||
u.qq_openid,
|
||||
u.gitee_login,
|
||||
u.osc_id,
|
||||
u.wx_cp_userid,
|
||||
u.wx_ding_userid,
|
||||
u.del_flag,
|
||||
u.lock_flag,
|
||||
u.password_expire_flag,
|
||||
u.password_modify_time,
|
||||
u.tenant_id,
|
||||
u.nickname,
|
||||
u.name,
|
||||
u.nickname,
|
||||
u.email,
|
||||
u.wx_openid,
|
||||
u.qq_openid,
|
||||
u.gitee_login,
|
||||
u.osc_id,
|
||||
u.wx_cp_userid,
|
||||
u.wx_ding_userid,
|
||||
u.del_flag,
|
||||
u.lock_flag,
|
||||
u.password_expire_flag,
|
||||
u.password_modify_time,
|
||||
u.tenant_id,
|
||||
u.create_by,
|
||||
u.create_time ucreate_time,
|
||||
u.update_time uupdate_time,
|
||||
d.name dept_name,
|
||||
d.dept_id
|
||||
u.create_time,
|
||||
u.update_time
|
||||
</sql>
|
||||
|
||||
<select id="getUserVoByUsername" resultMap="baseResultMap">
|
||||
SELECT
|
||||
<include refid="userRoleSql"/>
|
||||
<include refid="userColumns"/>
|
||||
FROM
|
||||
sys_user u
|
||||
LEFT JOIN sys_user_role urole ON urole.user_id = u.user_id
|
||||
LEFT JOIN sys_role r ON r.role_id = urole.role_id and r.del_flag = '0'
|
||||
WHERE u.username = #{username} and u.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="getUserVoById" resultMap="baseResultMap">
|
||||
SELECT
|
||||
<include refid="userRoleDeptSql"/>
|
||||
<include refid="userColumns"/>
|
||||
FROM
|
||||
sys_user u
|
||||
LEFT JOIN sys_dept d ON d.dept_id = u.dept_id and d.del_flag = '0'
|
||||
WHERE
|
||||
u.user_id = #{id} and u.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="getUserVosPage" resultMap="baseResultMap">
|
||||
SELECT
|
||||
u.user_id,
|
||||
u.username,
|
||||
u.password,
|
||||
u.salt,
|
||||
u.phone,
|
||||
u.avatar,
|
||||
u.wx_openid,
|
||||
u.qq_openid,
|
||||
u.gitee_login,
|
||||
u.osc_id,
|
||||
u.wx_cp_userid,
|
||||
u.wx_ding_userid,
|
||||
u.dept_id,
|
||||
u.create_by,
|
||||
u.create_time ucreate_time,
|
||||
u.update_time uupdate_time,
|
||||
u.del_flag,
|
||||
u.lock_flag,
|
||||
u.password_expire_flag,
|
||||
u.password_modify_time,
|
||||
u.tenant_id,
|
||||
u.nickname,
|
||||
u.name,
|
||||
u.email,
|
||||
d.name dept_name
|
||||
<include refid="userColumns"/>
|
||||
FROM
|
||||
sys_user u
|
||||
LEFT JOIN sys_dept d ON d.dept_id = u.dept_id
|
||||
<where>
|
||||
u.del_flag = '0'
|
||||
INNER JOIN sys_user_dept ud ON u.user_id = ud.user_id
|
||||
WHERE
|
||||
ud.tenant_id = #{query.tenantId}
|
||||
AND u.del_flag = '0'
|
||||
<!-- 用户名模糊查询 -->
|
||||
<if test="query.username != null and query.username != ''">
|
||||
<bind name="usernameLike" value="'%'+query.username+'%'"/>
|
||||
<bind name="usernameLike" value="'%' + query.username + '%'"/>
|
||||
AND u.username LIKE #{usernameLike}
|
||||
</if>
|
||||
<!-- 部门精确查询 -->
|
||||
<if test="query.deptId != null and query.deptId != ''">
|
||||
AND u.dept_id = #{query.deptId}
|
||||
AND ud.dept_id = #{query.deptId}
|
||||
</if>
|
||||
<!-- 手机号模糊查询 -->
|
||||
<if test="query.phone != null and query.phone != ''">
|
||||
<bind name="phoneLike" value="'%'+query.phone+'%'"/>
|
||||
<bind name="phoneLike" value="'%' + query.phone + '%'"/>
|
||||
AND u.phone LIKE #{phoneLike}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY u.create_time DESC
|
||||
ORDER BY
|
||||
u.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectVoListByScope" resultMap="baseResultMap">
|
||||
SELECT
|
||||
u.user_id,
|
||||
u.username,
|
||||
u.password,
|
||||
u.salt,
|
||||
u.phone,
|
||||
u.avatar,
|
||||
u.wx_openid,
|
||||
u.qq_openid,
|
||||
u.gitee_login,
|
||||
u.osc_id,
|
||||
u.wx_cp_userid,
|
||||
u.wx_ding_userid,
|
||||
u.dept_id,
|
||||
u.create_by,
|
||||
u.create_time ucreate_time,
|
||||
u.update_time uupdate_time,
|
||||
u.del_flag,
|
||||
u.lock_flag,
|
||||
u.password_expire_flag,
|
||||
u.password_modify_time,
|
||||
u.tenant_id,
|
||||
u.nickname,
|
||||
u.name,
|
||||
u.email,
|
||||
d.name dept_name
|
||||
<include refid="userColumns"/>
|
||||
FROM
|
||||
sys_user u
|
||||
LEFT JOIN sys_dept d ON d.dept_id = u.dept_id
|
||||
<where>
|
||||
u.del_flag = '0'
|
||||
INNER JOIN sys_user_dept ud ON u.user_id = ud.user_id
|
||||
WHERE
|
||||
ud.tenant_id = #{query.tenantId}
|
||||
AND u.del_flag = '0'
|
||||
<!-- 用户名模糊查询 -->
|
||||
<if test="query.username != null and query.username != ''">
|
||||
<bind name="usernameLike" value="'%'+query.username+'%'"/>
|
||||
<bind name="usernameLike" value="'%' + query.username + '%'"/>
|
||||
AND u.username LIKE #{usernameLike}
|
||||
</if>
|
||||
<!-- 部门精确查询 -->
|
||||
<if test="query.deptId != null and query.deptId != ''">
|
||||
AND u.dept_id = #{query.deptId}
|
||||
AND ud.dept_id = #{query.deptId}
|
||||
</if>
|
||||
<!-- 用户ID范围查询 -->
|
||||
<if test="ids != null and ids.length > 0">
|
||||
AND u.user_id in
|
||||
<foreach collection="ids" index="index" item="id" open="(" separator="," close=")">
|
||||
AND u.user_id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY u.create_time DESC
|
||||
ORDER BY
|
||||
u.create_time DESC
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in new issue
Block a user