mirror of
https://github.com/cool-team-official/cool-admin-java.git
synced 2026-10-07 06:23:54 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ec1ef7605 | ||
|
|
4eb0a51569 | ||
|
|
fcc52c317b | ||
|
|
3c339f7f43 | ||
|
|
8e87c94053 | ||
|
|
85c9929b27 | ||
|
|
24e18d9327 | ||
|
|
7ab1c7590e | ||
|
|
f51ebc99d1 | ||
|
|
937d95ae74 | ||
|
|
bf7c79c87f | ||
|
|
28bbb285c2 | ||
|
|
3dde0f2aa0 | ||
|
|
a45704af72 | ||
|
|
d5992198d2 | ||
|
|
861d7cba46 | ||
|
|
e7ed654abd | ||
|
|
c49925636e | ||
|
|
5e8bfebfdc | ||
|
|
b42b5750ac | ||
|
|
a650a852c0 | ||
|
|
87b743ae11 | ||
|
|
80dc8a0c07 | ||
|
|
1ecb285fd0 | ||
|
|
ef9c06edf6 | ||
|
|
5024d53095 | ||
|
|
9e6aede480 | ||
|
|
4ce7801737 | ||
|
|
2a9453af15 | ||
|
|
f42c2433d0 | ||
|
|
f9fd0a42dd | ||
|
|
7fc636a020 | ||
|
|
f5205ef0e9 | ||
|
|
453514017c | ||
|
|
5de3b3e08c | ||
|
|
a5aece156c | ||
|
|
0b6ee96645 | ||
|
|
98d262a68c | ||
|
|
13a90c2573 | ||
|
|
37df40f5e4 | ||
|
|
e02c7a02dc | ||
|
|
17e74bb247 | ||
|
|
0591f2ae46 | ||
|
|
1d880951b1 | ||
|
|
791f006ce1 | ||
|
|
4bd3c7ab40 | ||
|
|
1379855230 | ||
|
|
6233e119d4 | ||
|
|
754b7f4782 | ||
|
|
34e224c922 | ||
|
|
fdf88ffa8a | ||
|
|
5116128355 |
@@ -0,0 +1,7 @@
|
|||||||
|
.git
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
.vscode
|
||||||
|
.DS_Store
|
||||||
+4
-6
@@ -1,14 +1,12 @@
|
|||||||
# 使用 GraalVM 17 作为基础镜像
|
FROM eclipse-temurin:21-jre
|
||||||
FROM ghcr.io/graalvm/graalvm-ce:latest
|
|
||||||
|
ENV TZ=Asia/Shanghai
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
# 设置容器内的工作目录
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 将可执行的jar文件复制到容器内
|
|
||||||
COPY target/cool-admin-8.0.0.jar /app/cool-admin-8.0.0.jar
|
COPY target/cool-admin-8.0.0.jar /app/cool-admin-8.0.0.jar
|
||||||
|
|
||||||
# 暴露Spring Boot应用程序运行的端口
|
|
||||||
EXPOSE 8001
|
EXPOSE 8001
|
||||||
|
|
||||||
# 运行Spring Boot应用程序的命令
|
|
||||||
ENTRYPOINT ["java", "-jar", "/app/cool-admin-8.0.0.jar", "--spring.profiles.active=prod"]
|
ENTRYPOINT ["java", "-jar", "/app/cool-admin-8.0.0.jar", "--spring.profiles.active=prod"]
|
||||||
|
|||||||
@@ -71,6 +71,10 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-aop</artifactId>
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- springframework end -->
|
<!-- springframework end -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
|||||||
@Operation(summary = "新增", description = "新增信息,对应后端的实体类")
|
@Operation(summary = "新增", description = "新增信息,对应后端的实体类")
|
||||||
@PostMapping("/add")
|
@PostMapping("/add")
|
||||||
protected R add(@RequestAttribute() JSONObject requestParams) {
|
protected R add(@RequestAttribute() JSONObject requestParams) {
|
||||||
|
checkPermission("add");
|
||||||
String body = requestParams.getStr("body");
|
String body = requestParams.getStr("body");
|
||||||
if (JSONUtil.isTypeJSONArray(body)) {
|
if (JSONUtil.isTypeJSONArray(body)) {
|
||||||
JSONArray array = JSONUtil.parseArray(body);
|
JSONArray array = JSONUtil.parseArray(body);
|
||||||
@@ -135,6 +136,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
|||||||
@PostMapping("/delete")
|
@PostMapping("/delete")
|
||||||
protected R delete(HttpServletRequest request, @RequestBody Map<String, Object> params,
|
protected R delete(HttpServletRequest request, @RequestBody Map<String, Object> params,
|
||||||
@RequestAttribute() JSONObject requestParams) {
|
@RequestAttribute() JSONObject requestParams) {
|
||||||
|
checkPermission("delete");
|
||||||
service.delete(requestParams, Convert.toLongArray(getIds(params)));
|
service.delete(requestParams, Convert.toLongArray(getIds(params)));
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
@@ -147,6 +149,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
|||||||
@Operation(summary = "修改", description = "根据ID修改")
|
@Operation(summary = "修改", description = "根据ID修改")
|
||||||
@PostMapping("/update")
|
@PostMapping("/update")
|
||||||
protected R update(@RequestBody T t, @RequestAttribute() JSONObject requestParams) {
|
protected R update(@RequestBody T t, @RequestAttribute() JSONObject requestParams) {
|
||||||
|
checkPermission("update");
|
||||||
Long id = t.getId();
|
Long id = t.getId();
|
||||||
JSONObject info = JSONUtil.parseObj(JSONUtil.toJsonStr(service.getById(id)));
|
JSONObject info = JSONUtil.parseObj(JSONUtil.toJsonStr(service.getById(id)));
|
||||||
requestParams.forEach(info::set);
|
requestParams.forEach(info::set);
|
||||||
@@ -286,4 +289,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
|||||||
page.setRecords(transformList(page.getRecords(), asType));
|
page.setRecords(transformList(page.getRecords(), asType));
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkPermission(String action) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -31,6 +31,10 @@ public abstract class BaseEntity<T extends Model<T>> extends Model<T> implements
|
|||||||
@ColumnDefine(comment = "更新时间")
|
@ColumnDefine(comment = "更新时间")
|
||||||
protected Date updateTime;
|
protected Date updateTime;
|
||||||
|
|
||||||
|
@Column(isLogicDelete = true)
|
||||||
|
@ColumnDefine(comment = "删除标记 0:未删除 1:已删除", defaultValue = "0")
|
||||||
|
protected Integer delFlag;
|
||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
@Column(ignore = true)
|
@Column(ignore = true)
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.TimeZone;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||||
@@ -29,6 +30,7 @@ public class JacksonConfig {
|
|||||||
objectMapper.registerModule(simpleModule);
|
objectMapper.registerModule(simpleModule);
|
||||||
// 配置日期格式为 yyyy-MM-dd HH:mm:ss
|
// 配置日期格式为 yyyy-MM-dd HH:mm:ss
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||||
objectMapper.setDateFormat(dateFormat);
|
objectMapper.setDateFormat(dateFormat);
|
||||||
return new MappingJackson2HttpMessageConverter(objectMapper);
|
return new MappingJackson2HttpMessageConverter(objectMapper);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.cool.core.request;
|
package com.cool.core.request;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
@@ -37,7 +38,7 @@ public class RequestParamsFilter implements Filter {
|
|||||||
JSONObject requestParams = new JSONObject();
|
JSONObject requestParams = new JSONObject();
|
||||||
String language = request.getHeader("language");
|
String language = request.getHeader("language");
|
||||||
String coolEid = request.getHeader("cool-admin-eid");
|
String coolEid = request.getHeader("cool-admin-eid");
|
||||||
Long tenantId = StrUtil.isEmpty(coolEid) ? null : Long.parseLong(coolEid);
|
Long tenantId = null;
|
||||||
if (StrUtil.isNotEmpty(request.getContentType()) && request.getContentType().contains("multipart/form-data")) {
|
if (StrUtil.isNotEmpty(request.getContentType()) && request.getContentType().contains("multipart/form-data")) {
|
||||||
servletRequest.setAttribute("requestParams", requestParams);
|
servletRequest.setAttribute("requestParams", requestParams);
|
||||||
servletRequest.setAttribute("cool-language", language);
|
servletRequest.setAttribute("cool-language", language);
|
||||||
@@ -81,7 +82,17 @@ public class RequestParamsFilter implements Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// app端,userId 为当前登录的用户id
|
// app端,userId 为当前登录的用户id
|
||||||
case APP -> requestParams.set("userId", CoolSecurityUtil.getCurrentUserId());
|
case APP -> {
|
||||||
|
requestParams.set("userId", CoolSecurityUtil.getCurrentUserId());
|
||||||
|
// App端:从tokenInfo中读取orgId作为tenantId,实现组织级数据隔离
|
||||||
|
Object jwtObj = requestParams.get("tokenInfo");
|
||||||
|
if (jwtObj instanceof Map) {
|
||||||
|
Object orgId = ((Map<?, ?>) jwtObj).get("orgId");
|
||||||
|
if (ObjUtil.isNotNull(orgId)) {
|
||||||
|
requestParams.set("tenantId", Convert.toLong(orgId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return CoolSecurityUtil.getTenantId(requestParams);
|
return CoolSecurityUtil.getTenantId(requestParams);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package com.cool.core.security;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.cool.core.exception.CoolException;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
|
import com.cool.modules.org.entity.AppOrgEntity;
|
||||||
|
import com.cool.modules.org.entity.AppOrgModuleEntity;
|
||||||
|
import com.cool.modules.org.entity.AppOrgUserEntity;
|
||||||
|
import com.cool.modules.org.service.AppOrgModuleService;
|
||||||
|
import com.cool.modules.org.service.AppOrgUserService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Order(3)
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppOrgAuthFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final AppOrgUserService appOrgUserService;
|
||||||
|
private final AppOrgModuleService appOrgModuleService;
|
||||||
|
|
||||||
|
private static final Map<String, String> MODULE_PATH_MAP = Map.of(
|
||||||
|
"/app/fruit/", "fruit",
|
||||||
|
"/app/order/", "order",
|
||||||
|
"/app/book/", "book",
|
||||||
|
"/app/ticket/", "ticket",
|
||||||
|
"/app/product/", "product",
|
||||||
|
"/app/agent/", "agent"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
FilterChain chain) throws ServletException, IOException {
|
||||||
|
String uri = request.getRequestURI();
|
||||||
|
|
||||||
|
if (!uri.startsWith("/app/") || uri.startsWith("/app/org/") || uri.startsWith("/app/user/") || uri.startsWith("/app/base/") || uri.startsWith("/app/dict/")) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (com.cool.core.enums.UserTypeEnum.APP != CoolSecurityUtil.getCurrentUserType()) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String moduleKey = resolveModuleKey(uri);
|
||||||
|
if (moduleKey == null) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Long userId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
String orgIdStr = request.getHeader("X-Org-Id");
|
||||||
|
if (StrUtil.isBlank(orgIdStr)) {
|
||||||
|
throw new CoolException("缺少组织信息", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long orgId;
|
||||||
|
try {
|
||||||
|
orgId = Long.parseLong(orgIdStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new CoolException("无效的组织ID", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!appOrgUserService.isOrgMember(userId, orgId)) {
|
||||||
|
throw new CoolException("未加入该组织", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!appOrgModuleService.isModuleAuthorized(orgId, moduleKey)) {
|
||||||
|
throw new CoolException("该组织未授权此模块", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveModuleKey(String uri) {
|
||||||
|
for (Map.Entry<String, String> entry : MODULE_PATH_MAP.entrySet()) {
|
||||||
|
if (uri.startsWith(entry.getKey())) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,12 +15,14 @@ import org.springframework.security.authentication.AuthenticationManager;
|
|||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;
|
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
@@ -32,6 +34,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
|||||||
import org.springframework.web.util.pattern.PathPattern;
|
import org.springframework.web.util.pattern.PathPattern;
|
||||||
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@EnableMethodSecurity
|
||||||
@Configuration
|
@Configuration
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -40,6 +43,7 @@ public class JwtSecurityConfig {
|
|||||||
// 用户详情
|
// 用户详情
|
||||||
final private UserDetailsService userDetailsService;
|
final private UserDetailsService userDetailsService;
|
||||||
final private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
|
final private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
|
||||||
|
final private AppOrgAuthFilter appOrgAuthFilter;
|
||||||
// 401
|
// 401
|
||||||
final private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;
|
final private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;
|
||||||
// 403
|
// 403
|
||||||
@@ -69,6 +73,8 @@ public class JwtSecurityConfig {
|
|||||||
.sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.addFilterBefore(jwtAuthenticationTokenFilter,
|
.addFilterBefore(jwtAuthenticationTokenFilter,
|
||||||
UsernamePasswordAuthenticationFilter.class)
|
UsernamePasswordAuthenticationFilter.class)
|
||||||
|
.addFilterAfter(appOrgAuthFilter,
|
||||||
|
JwtAuthenticationTokenFilter.class)
|
||||||
.exceptionHandling(config -> {
|
.exceptionHandling(config -> {
|
||||||
config.authenticationEntryPoint(entryPointUnauthorizedHandler);
|
config.authenticationEntryPoint(entryPointUnauthorizedHandler);
|
||||||
config.accessDeniedHandler(restAccessDeniedHandler);
|
config.accessDeniedHandler(restAccessDeniedHandler);
|
||||||
@@ -123,15 +129,19 @@ public class JwtSecurityConfig {
|
|||||||
@Bean
|
@Bean
|
||||||
public PasswordEncoder passwordEncoder() {
|
public PasswordEncoder passwordEncoder() {
|
||||||
return new PasswordEncoder() {
|
return new PasswordEncoder() {
|
||||||
|
private final BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String encode(CharSequence rawPassword) {
|
public String encode(CharSequence rawPassword) {
|
||||||
return DigestUtils.md5DigestAsHex(((String) rawPassword).getBytes());
|
return bcrypt.encode(rawPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||||
return encodedPassword.equals(
|
if (encodedPassword.startsWith("$2a$") || encodedPassword.startsWith("$2b$") || encodedPassword.startsWith("$2y$")) {
|
||||||
DigestUtils.md5DigestAsHex(((String) rawPassword).getBytes()));
|
return bcrypt.matches(rawPassword, encodedPassword);
|
||||||
|
}
|
||||||
|
return encodedPassword.equals(DigestUtils.md5DigestAsHex(((String) rawPassword).getBytes()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.cool.core.security;
|
package com.cool.core.security;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.cool.core.enums.UserTypeEnum;
|
||||||
|
import com.cool.core.security.jwt.JwtUser;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -27,20 +30,22 @@ public class MyAccessDecisionManager implements AccessDecisionManager {
|
|||||||
@Override
|
@Override
|
||||||
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes)
|
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes)
|
||||||
throws AccessDeniedException, InsufficientAuthenticationException {
|
throws AccessDeniedException, InsufficientAuthenticationException {
|
||||||
if (configAttributes == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<String> urls = ignoredUrlsProperties.getAdminAuthUrls();
|
List<String> urls = ignoredUrlsProperties.getAdminAuthUrls();
|
||||||
String url = ((FilterInvocation) o).getRequestUrl().split("[?]")[0];
|
String url = ((FilterInvocation) o).getRequestUrl().split("[?]")[0];
|
||||||
if (urls.contains(url)) {
|
if (urls.contains(url)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (configAttributes == null) {
|
||||||
|
if (isSuperAdmin(authentication)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new AccessDeniedException("抱歉,您没有访问权限");
|
||||||
|
}
|
||||||
Iterator<ConfigAttribute> iterator = configAttributes.iterator();
|
Iterator<ConfigAttribute> iterator = configAttributes.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
ConfigAttribute c = iterator.next();
|
ConfigAttribute c = iterator.next();
|
||||||
String needPerm = c.getAttribute();
|
String needPerm = c.getAttribute();
|
||||||
for (GrantedAuthority ga : authentication.getAuthorities()) {
|
for (GrantedAuthority ga : authentication.getAuthorities()) {
|
||||||
// 匹配用户拥有的ga 和 系统中的needPerm
|
|
||||||
if (needPerm.trim().equals(ga.getAuthority())) {
|
if (needPerm.trim().equals(ga.getAuthority())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -49,6 +54,18 @@ public class MyAccessDecisionManager implements AccessDecisionManager {
|
|||||||
throw new AccessDeniedException("抱歉,您没有访问权限");
|
throw new AccessDeniedException("抱歉,您没有访问权限");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSuperAdmin(Authentication authentication) {
|
||||||
|
Object principal = authentication.getPrincipal();
|
||||||
|
if (principal instanceof JwtUser) {
|
||||||
|
JwtUser jwtUser = (JwtUser) principal;
|
||||||
|
if (ObjectUtil.equal(jwtUser.getUserTypeEnum(), UserTypeEnum.APP)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return "admin".equals(jwtUser.getUsername());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(ConfigAttribute configAttribute) {
|
public boolean supports(ConfigAttribute configAttribute) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -7,10 +7,16 @@ import com.cool.core.enums.UserTypeEnum;
|
|||||||
import com.cool.core.exception.CoolPreconditions;
|
import com.cool.core.exception.CoolPreconditions;
|
||||||
import com.cool.core.security.jwt.JwtUser;
|
import com.cool.core.security.jwt.JwtUser;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysUserRoleEntity;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysUserRoleMapper;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Security 工具类
|
* Security 工具类
|
||||||
*/
|
*/
|
||||||
@@ -30,7 +36,22 @@ public class CoolSecurityUtil {
|
|||||||
* 是否为超级管理员
|
* 是否为超级管理员
|
||||||
*/
|
*/
|
||||||
public static boolean isSuperAdmin() {
|
public static boolean isSuperAdmin() {
|
||||||
return "admin".equals(getAdminUsername());
|
return isSuperAdmin(getAdminUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSuperAdmin(String username) {
|
||||||
|
BaseSysUserEntity userEntity = SpringUtil.getBean(BaseSysUserMapper.class)
|
||||||
|
.selectOneByQuery(com.mybatisflex.core.query.QueryWrapper.create()
|
||||||
|
.eq(BaseSysUserEntity::getUsername, username));
|
||||||
|
if (userEntity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BaseSysUserRoleMapper userRoleMapper = SpringUtil.getBean(BaseSysUserRoleMapper.class);
|
||||||
|
List<BaseSysUserRoleEntity> userRoles = userRoleMapper
|
||||||
|
.selectListByQuery(com.mybatisflex.core.query.QueryWrapper.create()
|
||||||
|
.eq(BaseSysUserRoleEntity::getUserId, userEntity.getId())
|
||||||
|
.eq(BaseSysUserRoleEntity::getRoleId, 1L));
|
||||||
|
return !userRoles.isEmpty();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获得jwt中的信息
|
* 获得jwt中的信息
|
||||||
@@ -64,7 +85,8 @@ public class CoolSecurityUtil {
|
|||||||
*/
|
*/
|
||||||
public static void adminLogout(Long adminUserId, String username) {
|
public static void adminLogout(Long adminUserId, String username) {
|
||||||
coolCache.del("admin:department:" + adminUserId, "admin:passwordVersion:" + adminUserId,
|
coolCache.del("admin:department:" + adminUserId, "admin:passwordVersion:" + adminUserId,
|
||||||
"admin:userInfo:" + adminUserId, "admin:userDetails:" + username);
|
"admin:userInfo:" + adminUserId, "admin:userDetails:" + username,
|
||||||
|
"admin:roleIds:" + adminUserId, "admin:perms:" + adminUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.cool.modules.agent.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.agent.entity.AgentInfoEntity;
|
||||||
|
import com.cool.modules.agent.service.AgentInfoService;
|
||||||
|
import com.cool.modules.agent.service.SayssService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "代理管理", description = "代理信息管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"})
|
||||||
|
public class AdminAgentInfoController extends BaseController<AgentInfoService, AgentInfoEntity> {
|
||||||
|
|
||||||
|
private final SayssService sayssService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "登录SaySS")
|
||||||
|
@PostMapping("/loginSayss")
|
||||||
|
public R loginSayss(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
String authData = sayssService.loginAndSave(id);
|
||||||
|
if (authData == null) {
|
||||||
|
return R.error("登录SaySS失败,请检查用户名密码");
|
||||||
|
}
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "验证SaySS Token")
|
||||||
|
@PostMapping("/checkToken")
|
||||||
|
public R checkToken(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
boolean valid = sayssService.checkTokenValid(id);
|
||||||
|
return R.ok(new JSONObject().set("valid", valid));
|
||||||
|
}
|
||||||
|
}
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
package com.cool.modules.agent.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.agent.entity.AgentInfoEntity;
|
||||||
|
import com.cool.modules.agent.entity.AgentWhitelistEntity;
|
||||||
|
import com.cool.modules.agent.service.AgentInfoService;
|
||||||
|
import com.cool.modules.agent.service.AgentWhitelistService;
|
||||||
|
import com.cool.modules.agent.service.SayssService;
|
||||||
|
import com.cool.modules.user.entity.UserInfoEntity;
|
||||||
|
import com.cool.modules.user.service.UserInfoService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "白名单管理", description = "代理白名单管理")
|
||||||
|
@CoolRestController(api = {"delete", "page"})
|
||||||
|
public class AdminAgentWhitelistController extends BaseController<AgentWhitelistService, AgentWhitelistEntity> {
|
||||||
|
|
||||||
|
private final AgentInfoService agentInfoService;
|
||||||
|
private final UserInfoService userInfoService;
|
||||||
|
private final SayssService sayssService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp().transformValue(o -> {
|
||||||
|
AgentWhitelistEntity entity = (AgentWhitelistEntity) o;
|
||||||
|
AgentInfoEntity agent = (AgentInfoEntity) agentInfoService.info(entity.getAgentInfoId());
|
||||||
|
if (agent != null) {
|
||||||
|
entity.setAgentName(agent.getName());
|
||||||
|
}
|
||||||
|
if (entity.getAddedByUserId() != null) {
|
||||||
|
UserInfoEntity user = (UserInfoEntity) userInfoService.info(entity.getAddedByUserId());
|
||||||
|
if (user != null) {
|
||||||
|
entity.setAddedByName(user.getNickName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "删除", description = "先从SaySS删除白名单,成功后再从本地删除")
|
||||||
|
@PostMapping("/delete")
|
||||||
|
protected R delete(HttpServletRequest request, @RequestBody Map<String, Object> params,
|
||||||
|
@RequestAttribute() JSONObject requestParams) {
|
||||||
|
Long[] ids = Convert.toLongArray(getIds(params));
|
||||||
|
for (Long id : ids) {
|
||||||
|
AgentWhitelistEntity entity = service.getById(id);
|
||||||
|
if (entity == null) continue;
|
||||||
|
boolean sayssDeleted;
|
||||||
|
if (entity.getSayssTrustedIpId() != null) {
|
||||||
|
sayssDeleted = sayssService.deleteTrustedIp(entity.getAgentInfoId(), entity.getSayssTrustedIpId());
|
||||||
|
} else {
|
||||||
|
sayssDeleted = sayssService.deleteTrustedIpByIp(entity.getAgentInfoId(), entity.getIpAddress());
|
||||||
|
}
|
||||||
|
if (!sayssDeleted) {
|
||||||
|
return R.error("从SaySS删除白名单失败,IP: " + entity.getIpAddress() + ",请检查代理账号是否正确");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
service.delete(requestParams, ids);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package com.cool.modules.agent.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
|
import com.cool.modules.agent.entity.AgentInfoEntity;
|
||||||
|
import com.cool.modules.agent.entity.AgentWhitelistEntity;
|
||||||
|
import com.cool.modules.agent.service.AgentInfoService;
|
||||||
|
import com.cool.modules.agent.service.AgentWhitelistService;
|
||||||
|
import com.cool.modules.agent.service.SayssService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
import static com.cool.modules.agent.entity.table.AgentInfoEntityTableDef.AGENT_INFO_ENTITY;
|
||||||
|
import static com.cool.modules.agent.entity.table.AgentWhitelistEntityTableDef.AGENT_WHITELIST_ENTITY;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "代理", description = "App端代理")
|
||||||
|
@CoolRestController(api = {"list"})
|
||||||
|
public class AppAgentInfoController {
|
||||||
|
|
||||||
|
private final AgentInfoService agentInfoService;
|
||||||
|
private final AgentWhitelistService agentWhitelistService;
|
||||||
|
private final SayssService sayssService;
|
||||||
|
|
||||||
|
@Operation(summary = "代理列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public R list(@RequestAttribute JSONObject requestParams) {
|
||||||
|
return R.ok(agentInfoService.list(requestParams,
|
||||||
|
QueryWrapper.create().where(AGENT_INFO_ENTITY.STATUS.eq(1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "代理详情")
|
||||||
|
@GetMapping("/detail")
|
||||||
|
public R detail(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
AgentInfoEntity agent = (AgentInfoEntity) agentInfoService.info(id);
|
||||||
|
if (agent == null || agent.getStatus() == null || agent.getStatus() != 1) {
|
||||||
|
return R.error("代理已停用");
|
||||||
|
}
|
||||||
|
return R.ok(agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "获取当前IP")
|
||||||
|
@GetMapping("/currentIp")
|
||||||
|
public R currentIp(HttpServletRequest request) {
|
||||||
|
String ip = request.getHeader("X-Forwarded-For");
|
||||||
|
if (ip == null || ip.isEmpty()) {
|
||||||
|
ip = request.getHeader("X-Real-IP");
|
||||||
|
}
|
||||||
|
if (ip == null || ip.isEmpty()) {
|
||||||
|
ip = request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
if (ip != null && ip.contains(",")) {
|
||||||
|
ip = ip.split(",")[0].trim();
|
||||||
|
}
|
||||||
|
JSONObject result = new JSONObject();
|
||||||
|
result.set("ip", ip);
|
||||||
|
return R.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "添加白名单IP")
|
||||||
|
@PostMapping("/addWhitelist")
|
||||||
|
public R addWhitelist(@RequestAttribute JSONObject requestParams, HttpServletRequest request) {
|
||||||
|
Long agentInfoId = requestParams.getLong("agentInfoId");
|
||||||
|
String ipAddress = requestParams.getStr("ipAddress");
|
||||||
|
|
||||||
|
Long sayssTrustedIpId = sayssService.addTrustedIp(agentInfoId, ipAddress);
|
||||||
|
if (sayssTrustedIpId == null) {
|
||||||
|
log.warn("SaySS添加白名单失败,agentInfoId={}, ip={}", agentInfoId, ipAddress);
|
||||||
|
return R.error("添加白名单到SaySS失败,请检查代理账号是否正确");
|
||||||
|
}
|
||||||
|
|
||||||
|
Long addedByUserId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
|
||||||
|
AgentWhitelistEntity entity = new AgentWhitelistEntity();
|
||||||
|
entity.setAgentInfoId(agentInfoId);
|
||||||
|
entity.setIpAddress(ipAddress);
|
||||||
|
entity.setAddedByUserId(addedByUserId);
|
||||||
|
entity.setSayssTrustedIpId(sayssTrustedIpId);
|
||||||
|
agentWhitelistService.save(entity);
|
||||||
|
|
||||||
|
return R.ok(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "获取白名单列表")
|
||||||
|
@GetMapping("/whitelist")
|
||||||
|
public R whitelist(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long agentInfoId = requestParams.getLong("agentInfoId");
|
||||||
|
QueryWrapper qw = QueryWrapper.create()
|
||||||
|
.where(AGENT_WHITELIST_ENTITY.AGENT_INFO_ID.eq(agentInfoId));
|
||||||
|
return R.ok(agentWhitelistService.list(requestParams, qw));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "检查IP是否在白名单")
|
||||||
|
@GetMapping("/checkIpInWhitelist")
|
||||||
|
public R checkIpInWhitelist(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long agentInfoId = requestParams.getLong("agentInfoId");
|
||||||
|
String ip = requestParams.getStr("ip");
|
||||||
|
boolean inWhitelist = sayssService.isIpInTrustedIps(agentInfoId, ip);
|
||||||
|
JSONObject result = new JSONObject();
|
||||||
|
result.set("inWhitelist", inWhitelist);
|
||||||
|
return R.ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.cool.modules.agent.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "agent_info", comment = "代理信息表")
|
||||||
|
public class AgentInfoEntity extends TenantEntity<AgentInfoEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "代理名称", notNull = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "用户名")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "密码")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "描述", type = "text")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:停用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "Token状态 0:失效 1:生效", defaultValue = "0")
|
||||||
|
private Integer tokenStatus;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "SaySS认证Token(auth_data)")
|
||||||
|
private String sayssAuthData;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.cool.modules.agent.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "agent_whitelist", comment = "代理白名单表")
|
||||||
|
public class AgentWhitelistEntity extends TenantEntity<AgentWhitelistEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "代理信息ID", notNull = true)
|
||||||
|
private Long agentInfoId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "IP地址", notNull = true)
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "添加者用户ID")
|
||||||
|
private Long addedByUserId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "SaySS白名单记录ID")
|
||||||
|
private Long sayssTrustedIpId;
|
||||||
|
|
||||||
|
@com.mybatisflex.annotation.Column(ignore = true)
|
||||||
|
private String agentName;
|
||||||
|
|
||||||
|
@com.mybatisflex.annotation.Column(ignore = true)
|
||||||
|
private String addedByName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.agent.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.agent.entity.AgentInfoEntity;
|
||||||
|
|
||||||
|
public interface AgentInfoMapper extends BaseMapper<AgentInfoEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.agent.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.agent.entity.AgentWhitelistEntity;
|
||||||
|
|
||||||
|
public interface AgentWhitelistMapper extends BaseMapper<AgentWhitelistEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.agent.service;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.agent.entity.AgentInfoEntity;
|
||||||
|
|
||||||
|
public interface AgentInfoService extends BaseService<AgentInfoEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.agent.service;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.agent.entity.AgentWhitelistEntity;
|
||||||
|
|
||||||
|
public interface AgentWhitelistService extends BaseService<AgentWhitelistEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
package com.cool.modules.agent.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.Mode;
|
||||||
|
import cn.hutool.crypto.Padding;
|
||||||
|
import cn.hutool.crypto.symmetric.AES;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.cool.modules.agent.entity.AgentInfoEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@ConfigurationProperties(prefix = "sayss")
|
||||||
|
@Data
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SayssService {
|
||||||
|
|
||||||
|
private String middlewareUrl;
|
||||||
|
private String middlewareKey;
|
||||||
|
private String middlewarePath;
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
private final AgentInfoService agentInfoService;
|
||||||
|
|
||||||
|
private String encryptPath(String path, String iv) {
|
||||||
|
AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, middlewareKey.getBytes(), iv.getBytes());
|
||||||
|
return aes.encryptBase64(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] buildEncryptedUrlWithIv(String path) {
|
||||||
|
String iv = RandomUtil.randomString("0123456789abcdef", 16);
|
||||||
|
String encrypted = encryptPath(path, iv);
|
||||||
|
String encoded = Base64.encode(encrypted);
|
||||||
|
return new String[]{middlewareUrl + middlewarePath + "/" + encoded, iv};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String login(String email, String password) {
|
||||||
|
if (!enabled) return null;
|
||||||
|
try {
|
||||||
|
String[] urlAndIv = buildEncryptedUrlWithIv("/passport/auth/login");
|
||||||
|
JSONObject body = new JSONObject();
|
||||||
|
body.set("email", email);
|
||||||
|
body.set("password", password);
|
||||||
|
HttpResponse resp = HttpRequest.post(urlAndIv[0])
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "application/json, text/plain, */*")
|
||||||
|
.header("X-IV", urlAndIv[1])
|
||||||
|
.body(body.toString())
|
||||||
|
.timeout(10000).execute();
|
||||||
|
JSONObject json = JSONUtil.parseObj(resp.body());
|
||||||
|
if ("success".equals(json.getStr("status")) && json.get("data") != null) {
|
||||||
|
return json.getJSONObject("data").getStr("auth_data");
|
||||||
|
}
|
||||||
|
log.error("SaySS登录失败: {}", json.getStr("message"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SaySS登录异常: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String loginAndSave(Long agentInfoId) {
|
||||||
|
if (!enabled) return null;
|
||||||
|
AgentInfoEntity agent = (AgentInfoEntity) agentInfoService.info(agentInfoId);
|
||||||
|
if (agent == null || StrUtil.isBlank(agent.getUsername()) || StrUtil.isBlank(agent.getPassword())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String authData = login(agent.getUsername(), agent.getPassword());
|
||||||
|
if (authData != null) {
|
||||||
|
agent.setSayssAuthData(authData);
|
||||||
|
agent.setTokenStatus(1);
|
||||||
|
agentInfoService.update(agent);
|
||||||
|
}
|
||||||
|
return authData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkTokenValid(Long agentInfoId) {
|
||||||
|
if (!enabled) return false;
|
||||||
|
AgentInfoEntity agent = (AgentInfoEntity) agentInfoService.info(agentInfoId);
|
||||||
|
if (agent == null || StrUtil.isBlank(agent.getSayssAuthData())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String[] urlAndIv = buildEncryptedUrlWithIv("/user/info");
|
||||||
|
HttpResponse resp = HttpRequest.get(urlAndIv[0])
|
||||||
|
.header("Accept", "application/json, text/plain, */*")
|
||||||
|
.header("X-IV", urlAndIv[1])
|
||||||
|
.header("Authorization", agent.getSayssAuthData())
|
||||||
|
.timeout(10000).execute();
|
||||||
|
JSONObject json = JSONUtil.parseObj(resp.body());
|
||||||
|
if ("未登录或登陆已过期".equals(json.getStr("message"))) {
|
||||||
|
agent.setSayssAuthData(null);
|
||||||
|
agent.setTokenStatus(0);
|
||||||
|
agentInfoService.update(agent);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean valid = "success".equals(json.getStr("status"));
|
||||||
|
if (!valid) {
|
||||||
|
agent.setTokenStatus(0);
|
||||||
|
agentInfoService.update(agent);
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SaySS验证Token异常: {}", e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject sayssGet(String authData, String path) {
|
||||||
|
if (!enabled) return new JSONObject().set("status", "error").set("message", "SaySS未启用");
|
||||||
|
try {
|
||||||
|
String[] urlAndIv = buildEncryptedUrlWithIv(path);
|
||||||
|
HttpResponse resp = HttpRequest.get(urlAndIv[0])
|
||||||
|
.header("Accept", "application/json, text/plain, */*")
|
||||||
|
.header("X-IV", urlAndIv[1])
|
||||||
|
.header("Authorization", authData)
|
||||||
|
.timeout(10000).execute();
|
||||||
|
return JSONUtil.parseObj(resp.body());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SaySS GET请求失败: {}", e.getMessage());
|
||||||
|
return new JSONObject().set("status", "error").set("message", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject sayssPost(String authData, String path, Object body) {
|
||||||
|
if (!enabled) return new JSONObject().set("status", "error").set("message", "SaySS未启用");
|
||||||
|
try {
|
||||||
|
String[] urlAndIv = buildEncryptedUrlWithIv(path);
|
||||||
|
HttpResponse resp = HttpRequest.post(urlAndIv[0])
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Accept", "application/json, text/plain, */*")
|
||||||
|
.header("X-IV", urlAndIv[1])
|
||||||
|
.header("Authorization", authData)
|
||||||
|
.body(body instanceof String ? (String) body : body.toString())
|
||||||
|
.timeout(10000).execute();
|
||||||
|
return JSONUtil.parseObj(resp.body());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SaySS POST请求失败: {}", e.getMessage());
|
||||||
|
return new JSONObject().set("status", "error").set("message", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject sayssDelete(String authData, String path) {
|
||||||
|
if (!enabled) return new JSONObject().set("status", "error").set("message", "SaySS未启用");
|
||||||
|
try {
|
||||||
|
String[] urlAndIv = buildEncryptedUrlWithIv(path);
|
||||||
|
HttpResponse resp = HttpRequest.delete(urlAndIv[0])
|
||||||
|
.header("Accept", "application/json, text/plain, */*")
|
||||||
|
.header("X-IV", urlAndIv[1])
|
||||||
|
.header("Authorization", authData)
|
||||||
|
.timeout(10000).execute();
|
||||||
|
return JSONUtil.parseObj(resp.body());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SaySS DELETE请求失败: {}", e.getMessage());
|
||||||
|
return new JSONObject().set("status", "error").set("message", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAuthData(Long agentInfoId) {
|
||||||
|
AgentInfoEntity agent = (AgentInfoEntity) agentInfoService.info(agentInfoId);
|
||||||
|
if (agent == null || StrUtil.isBlank(agent.getUsername()) || StrUtil.isBlank(agent.getPassword())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(agent.getSayssAuthData())) {
|
||||||
|
return agent.getSayssAuthData();
|
||||||
|
}
|
||||||
|
String authData = login(agent.getUsername(), agent.getPassword());
|
||||||
|
if (authData != null) {
|
||||||
|
agent.setSayssAuthData(authData);
|
||||||
|
agent.setTokenStatus(1);
|
||||||
|
agentInfoService.update(agent);
|
||||||
|
}
|
||||||
|
return authData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long addTrustedIp(Long agentInfoId, String ip) {
|
||||||
|
if (!enabled) {
|
||||||
|
log.warn("SaySS未启用,跳过添加白名单到SaySS");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String authData = getAuthData(agentInfoId);
|
||||||
|
if (authData == null) {
|
||||||
|
log.error("无法获取SaySS认证信息,agentInfoId={}", agentInfoId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject body = new JSONObject();
|
||||||
|
body.set("ip", ip);
|
||||||
|
body.set("ip_type", "home");
|
||||||
|
JSONObject result = sayssPost(authData, "/user/subscribe-guard/trusted-ips", body);
|
||||||
|
if ("success".equals(result.getStr("status")) && result.get("data") != null) {
|
||||||
|
Object data = result.get("data");
|
||||||
|
if (data instanceof JSONObject) {
|
||||||
|
return ((JSONObject) data).getLong("id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.error("SaySS添加白名单失败: {}", result.getStr("message"));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteTrustedIp(Long agentInfoId, Long sayssTrustedIpId) {
|
||||||
|
if (!enabled) {
|
||||||
|
log.warn("SaySS未启用,跳过从SaySS删除白名单");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String authData = getAuthData(agentInfoId);
|
||||||
|
if (authData == null) {
|
||||||
|
log.error("无法获取SaySS认证信息,agentInfoId={}", agentInfoId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sayssTrustedIpId == null) {
|
||||||
|
log.warn("SaySS白名单记录ID为空,无法从SaySS删除");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JSONObject result = sayssDelete(authData, "/user/subscribe-guard/trusted-ips/" + sayssTrustedIpId);
|
||||||
|
if ("success".equals(result.getStr("status"))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
log.error("SaySS删除白名单失败: {}", result.getStr("message"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteTrustedIpByIp(Long agentInfoId, String ip) {
|
||||||
|
if (!enabled) {
|
||||||
|
log.warn("SaySS未启用,跳过从SaySS删除白名单");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Long trustedIpId = findTrustedIpId(agentInfoId, ip);
|
||||||
|
if (trustedIpId == null) {
|
||||||
|
log.warn("在SaySS中未找到IP: {},可能已被删除", ip);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return deleteTrustedIp(agentInfoId, trustedIpId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long findTrustedIpId(Long agentInfoId, String ip) {
|
||||||
|
if (!enabled) return null;
|
||||||
|
String authData = getAuthData(agentInfoId);
|
||||||
|
if (authData == null) return null;
|
||||||
|
JSONObject result = sayssGet(authData, "/user/subscribe-guard/trusted-ips");
|
||||||
|
if ("success".equals(result.getStr("status")) && result.get("data") != null) {
|
||||||
|
Object data = result.get("data");
|
||||||
|
JSONArray list = data instanceof JSONArray ? (JSONArray) data : new JSONArray().put(data);
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
JSONObject item = list.getJSONObject(i);
|
||||||
|
if (ip.equals(item.getStr("ip_address"))) {
|
||||||
|
return item.getLong("id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIpInTrustedIps(Long agentInfoId, String ip) {
|
||||||
|
return findTrustedIpId(agentInfoId, ip) != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cool.modules.agent.service.impl;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.modules.agent.entity.AgentInfoEntity;
|
||||||
|
import com.cool.modules.agent.mapper.AgentInfoMapper;
|
||||||
|
import com.cool.modules.agent.service.AgentInfoService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AgentInfoServiceImpl extends BaseServiceImpl<AgentInfoMapper, AgentInfoEntity> implements
|
||||||
|
AgentInfoService {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cool.modules.agent.service.impl;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.modules.agent.entity.AgentWhitelistEntity;
|
||||||
|
import com.cool.modules.agent.mapper.AgentWhitelistMapper;
|
||||||
|
import com.cool.modules.agent.service.AgentWhitelistService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AgentWhitelistServiceImpl extends BaseServiceImpl<AgentWhitelistMapper, AgentWhitelistEntity> implements
|
||||||
|
AgentWhitelistService {
|
||||||
|
}
|
||||||
@@ -24,14 +24,12 @@ public class AdminBaseCodingController {
|
|||||||
|
|
||||||
private final BaseCodingService baseCodingService;
|
private final BaseCodingService baseCodingService;
|
||||||
|
|
||||||
@TokenIgnore
|
|
||||||
@Operation(summary = "获取模块目录结构", description = "获取模块目录结构")
|
@Operation(summary = "获取模块目录结构", description = "获取模块目录结构")
|
||||||
@GetMapping("/getModuleTree")
|
@GetMapping("/getModuleTree")
|
||||||
public R getModuleTree() {
|
public R getModuleTree() {
|
||||||
return R.ok(baseCodingService.getModuleTree());
|
return R.ok(baseCodingService.getModuleTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
@TokenIgnore
|
|
||||||
@Operation(summary = "创建代码", description = "创建代码")
|
@Operation(summary = "创建代码", description = "创建代码")
|
||||||
@PostMapping("/createCode")
|
@PostMapping("/createCode")
|
||||||
public R createCode(@RequestAttribute JSONObject requestParams) {
|
public R createCode(@RequestAttribute JSONObject requestParams) {
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ public class AdminBaseCommController {
|
|||||||
|
|
||||||
final private FileUploadStrategyFactory fileUploadStrategyFactory;
|
final private FileUploadStrategyFactory fileUploadStrategyFactory;
|
||||||
|
|
||||||
@TokenIgnore
|
|
||||||
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
|
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
|
||||||
@GetMapping("/eps")
|
@GetMapping("/eps")
|
||||||
public R eps() {
|
public R eps() {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.cool.core.plugin.service.CoolPluginService;
|
|||||||
import com.cool.core.request.R;
|
import com.cool.core.request.R;
|
||||||
import com.cool.core.util.CoolPluginInvokers;
|
import com.cool.core.util.CoolPluginInvokers;
|
||||||
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
|
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
|
||||||
|
import com.cool.modules.base.dto.sys.BaseSysRegisterDto;
|
||||||
import com.cool.modules.base.service.sys.BaseSysLoginService;
|
import com.cool.modules.base.service.sys.BaseSysLoginService;
|
||||||
import com.cool.modules.plugin.entity.PluginInfoEntity;
|
import com.cool.modules.plugin.entity.PluginInfoEntity;
|
||||||
import io.micrometer.common.util.StringUtils;
|
import io.micrometer.common.util.StringUtils;
|
||||||
@@ -55,6 +56,12 @@ public class AdminBaseOpenController {
|
|||||||
return R.ok(baseSysLoginService.login(baseSysLoginDto));
|
return R.ok(baseSysLoginService.login(baseSysLoginDto));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "注册")
|
||||||
|
@PostMapping("/register")
|
||||||
|
public R register(@RequestBody BaseSysRegisterDto baseSysRegisterDto) {
|
||||||
|
return R.ok(baseSysLoginService.register(baseSysRegisterDto));
|
||||||
|
}
|
||||||
|
|
||||||
@Operation(summary = "验证码")
|
@Operation(summary = "验证码")
|
||||||
@GetMapping("/captcha")
|
@GetMapping("/captcha")
|
||||||
public R captcha(@Parameter(description = "类型:svg|base64") @RequestParam(defaultValue = "base64") String type,
|
public R captcha(@Parameter(description = "类型:svg|base64") @RequestParam(defaultValue = "base64") String type,
|
||||||
@@ -118,4 +125,10 @@ public class AdminBaseOpenController {
|
|||||||
}
|
}
|
||||||
return R.ok(Map.of("mode", "common"));
|
return R.ok(Map.of("mode", "common"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "管理端验证码是否启用")
|
||||||
|
@GetMapping("/captchaEnabled")
|
||||||
|
public R captchaEnabled() {
|
||||||
|
return R.ok(Map.of("enabled", baseSysLoginService.isCaptchaEnabled("admin", "adminLogin")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -4,10 +4,12 @@ import cn.hutool.json.JSONObject;
|
|||||||
import com.cool.core.annotation.CoolRestController;
|
import com.cool.core.annotation.CoolRestController;
|
||||||
import com.cool.core.base.BaseController;
|
import com.cool.core.base.BaseController;
|
||||||
import com.cool.core.request.R;
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
|
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
|
||||||
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
|
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
@@ -22,6 +24,13 @@ import java.util.List;
|
|||||||
public class AdminBaseSysDepartmentController
|
public class AdminBaseSysDepartmentController
|
||||||
extends BaseController<BaseSysDepartmentService, BaseSysDepartmentEntity> {
|
extends BaseController<BaseSysDepartmentService, BaseSysDepartmentEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkPermission(String action) {
|
||||||
|
if (("add".equals(action) || "delete".equals(action) || "update".equals(action)) && !CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
throw new AccessDeniedException("仅超级管理员可操作部门");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
}
|
}
|
||||||
|
|||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package com.cool.modules.base.controller.admin.sys;
|
||||||
|
|
||||||
|
import static com.cool.modules.base.entity.sys.table.BaseSysEmailConfigEntityTableDef.BASE_SYS_EMAIL_CONFIG_ENTITY;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.core.exception.CoolPreconditions;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysEmailConfigEntity;
|
||||||
|
import com.cool.modules.base.service.sys.BaseSysEmailConfigService;
|
||||||
|
import com.cool.modules.base.service.sys.EmailSendService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@Tag(name = "邮箱配置管理", description = "邮箱配置管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"}, cname = "emailConfig")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AdminBaseSysEmailConfigController extends BaseController<BaseSysEmailConfigService, BaseSysEmailConfigEntity> {
|
||||||
|
|
||||||
|
private final EmailSendService emailSendService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp().fieldEq(BASE_SYS_EMAIL_CONFIG_ENTITY.ENABLED)
|
||||||
|
.keyWordLikeFields(BASE_SYS_EMAIL_CONFIG_ENTITY.EMAIL, BASE_SYS_EMAIL_CONFIG_ENTITY.REMARK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkPermission(String action) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "设为当前使用")
|
||||||
|
@PostMapping("/setActive")
|
||||||
|
public R setActive(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
CoolPreconditions.checkEmpty(id, "id不能为空");
|
||||||
|
|
||||||
|
BaseSysEmailConfigEntity entity = service.getById(id);
|
||||||
|
CoolPreconditions.checkEmpty(entity, "邮箱配置不存在");
|
||||||
|
CoolPreconditions.check(ObjUtil.equals(entity.getEnabled(), 0), "该邮箱配置已禁用,无法设为使用");
|
||||||
|
|
||||||
|
List<BaseSysEmailConfigEntity> activeList = service.list(
|
||||||
|
QueryWrapper.create().eq(BaseSysEmailConfigEntity::getIsActive, 1));
|
||||||
|
for (BaseSysEmailConfigEntity active : activeList) {
|
||||||
|
active.setIsActive(0);
|
||||||
|
active.updateById();
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setIsActive(1);
|
||||||
|
entity.updateById();
|
||||||
|
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "发送测试邮件")
|
||||||
|
@PostMapping("/test")
|
||||||
|
public R test(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
CoolPreconditions.checkEmpty(id, "id不能为空");
|
||||||
|
|
||||||
|
BaseSysEmailConfigEntity entity = service.getById(id);
|
||||||
|
CoolPreconditions.checkEmpty(entity, "邮箱配置不存在");
|
||||||
|
|
||||||
|
emailSendService.sendTestMail(entity);
|
||||||
|
|
||||||
|
return R.okMsg("测试邮件发送成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-1
@@ -6,11 +6,13 @@ import cn.hutool.json.JSONArray;
|
|||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.cool.core.annotation.CoolRestController;
|
import com.cool.core.annotation.CoolRestController;
|
||||||
import com.cool.core.base.BaseController;
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
|
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
|
||||||
import com.cool.modules.base.service.sys.BaseSysRoleService;
|
import com.cool.modules.base.service.sys.BaseSysRoleService;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统角色
|
* 系统角色
|
||||||
@@ -19,10 +21,19 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
|
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
|
||||||
public class AdminBaseSysRoleController extends BaseController<BaseSysRoleService, BaseSysRoleEntity> {
|
public class AdminBaseSysRoleController extends BaseController<BaseSysRoleService, BaseSysRoleEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkPermission(String action) {
|
||||||
|
if ("add".equals(action) || "delete".equals(action) || "update".equals(action)) {
|
||||||
|
if (!CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
throw new AccessDeniedException("仅超级管理员可操作角色");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
JSONObject tokenInfo = requestParams.getJSONObject("tokenInfo");
|
JSONObject tokenInfo = requestParams.getJSONObject("tokenInfo");
|
||||||
boolean isAdmin = tokenInfo.getStr("username").equals("admin");
|
boolean isAdmin = CoolSecurityUtil.isSuperAdmin(tokenInfo.getStr("username"));
|
||||||
|
|
||||||
setPageOption(createOp().keyWordLikeFields(BASE_SYS_ROLE_ENTITY.NAME, BASE_SYS_ROLE_ENTITY.LABEL).queryWrapper(QueryWrapper.create().and(qw -> {
|
setPageOption(createOp().keyWordLikeFields(BASE_SYS_ROLE_ENTITY.NAME, BASE_SYS_ROLE_ENTITY.LABEL).queryWrapper(QueryWrapper.create().and(qw -> {
|
||||||
qw.eq(BASE_SYS_ROLE_ENTITY.USER_ID.getName(), tokenInfo.getLong("userId")).or(w -> {
|
qw.eq(BASE_SYS_ROLE_ENTITY.USER_ID.getName(), tokenInfo.getLong("userId")).or(w -> {
|
||||||
|
|||||||
+9
@@ -8,9 +8,11 @@ import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
|||||||
import com.cool.modules.base.service.sys.BaseSysUserService;
|
import com.cool.modules.base.service.sys.BaseSysUserService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestAttribute;
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,6 +22,13 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
@CoolRestController(api = { "add", "delete", "update", "page", "info" })
|
@CoolRestController(api = { "add", "delete", "update", "page", "info" })
|
||||||
public class AdminBaseSysUserController extends BaseController<BaseSysUserService, BaseSysUserEntity> {
|
public class AdminBaseSysUserController extends BaseController<BaseSysUserService, BaseSysUserEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkPermission(String action) {
|
||||||
|
if ("delete".equals(action) && !CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
throw new AccessDeniedException("仅超级管理员可删除用户");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,8 @@ public class BaseSysLoginDto {
|
|||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Schema(description = "验证码ID")
|
@Schema(description = "验证码ID")
|
||||||
@NotBlank
|
|
||||||
private String captchaId;
|
private String captchaId;
|
||||||
|
|
||||||
@Schema(description = "验证码")
|
@Schema(description = "验证码")
|
||||||
@NotBlank
|
|
||||||
private String verifyCode;
|
private String verifyCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.cool.modules.base.dto.sys;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "注册参数")
|
||||||
|
public class BaseSysRegisterDto {
|
||||||
|
|
||||||
|
@Schema(description = "用户名")
|
||||||
|
@NotBlank
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Schema(description = "密码")
|
||||||
|
@NotBlank
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Schema(description = "昵称")
|
||||||
|
private String nickName;
|
||||||
|
|
||||||
|
@Schema(description = "手机号")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Schema(description = "邮箱")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Schema(description = "验证码ID")
|
||||||
|
private String captchaId;
|
||||||
|
|
||||||
|
@Schema(description = "验证码")
|
||||||
|
private String verifyCode;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.cool.modules.base.entity.sys;
|
package com.cool.modules.base.entity.sys;
|
||||||
|
|
||||||
import com.cool.core.base.BaseEntity;
|
import com.cool.core.base.TenantEntity;
|
||||||
import com.mybatisflex.annotation.Column;
|
import com.mybatisflex.annotation.Column;
|
||||||
|
|
||||||
import com.cool.core.annotation.ColumnDefine;
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
@@ -14,7 +14,7 @@ import lombok.Setter;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@Table(value = "base_sys_department", comment = "系统部门")
|
@Table(value = "base_sys_department", comment = "系统部门")
|
||||||
public class BaseSysDepartmentEntity extends BaseEntity<BaseSysDepartmentEntity> {
|
public class BaseSysDepartmentEntity extends TenantEntity<BaseSysDepartmentEntity> {
|
||||||
@ColumnDefine(comment = "部门名称", notNull = true)
|
@ColumnDefine(comment = "部门名称", notNull = true)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@@ -24,7 +24,9 @@ public class BaseSysDepartmentEntity extends BaseEntity<BaseSysDepartmentEntity>
|
|||||||
@ColumnDefine(comment = "排序", defaultValue = "0")
|
@ColumnDefine(comment = "排序", defaultValue = "0")
|
||||||
private Integer orderNum;
|
private Integer orderNum;
|
||||||
|
|
||||||
// 父菜单名称
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
@Column(ignore = true)
|
@Column(ignore = true)
|
||||||
private String parentName;
|
private String parentName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.cool.modules.base.entity.sys;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "base_sys_email_config", comment = "邮箱配置")
|
||||||
|
public class BaseSysEmailConfigEntity extends BaseEntity<BaseSysEmailConfigEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "邮箱地址", notNull = true)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "SMTP主机", notNull = true)
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "SMTP端口", notNull = true)
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "用户名", notNull = true)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "密码/授权码", notNull = true)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "是否启用SSL", defaultValue = "1")
|
||||||
|
private Integer sslEnable;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "是否启用 0-禁用 1-启用", defaultValue = "1")
|
||||||
|
private Integer enabled;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "是否为当前使用 0-否 1-是", defaultValue = "0")
|
||||||
|
private Integer isActive;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "备注")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.cool.modules.base.entity.sys;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseEntity;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.mybatis.handler.Fastjson2TypeHandler;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.dromara.autotable.annotation.Index;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "base_sys_perms_audit_log", comment = "权限变更审计日志表")
|
||||||
|
public class BaseSysPermsAuditLogEntity extends BaseEntity<BaseSysPermsAuditLogEntity> {
|
||||||
|
|
||||||
|
@Index
|
||||||
|
@ColumnDefine(comment = "操作用户ID", type = "bigint")
|
||||||
|
private Long operatorUserId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "操作用户名")
|
||||||
|
private String operatorUsername;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "变更类型: ROLE_ASSIGN/PERMS_UPDATE/ROLE_DISABLE/ROLE_ENABLE/USER_ROLE_UPDATE")
|
||||||
|
private String changeType;
|
||||||
|
|
||||||
|
@Index
|
||||||
|
@ColumnDefine(comment = "目标ID(角色ID或用户ID)", type = "bigint")
|
||||||
|
private Long targetId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "变更前值", type = "json")
|
||||||
|
@Column(typeHandler = Fastjson2TypeHandler.class)
|
||||||
|
private Object beforeValue;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "变更后值", type = "json")
|
||||||
|
@Column(typeHandler = Fastjson2TypeHandler.class)
|
||||||
|
private Object afterValue;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "IP地址", length = 50)
|
||||||
|
private String ip;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.cool.modules.base.entity.sys;
|
package com.cool.modules.base.entity.sys;
|
||||||
|
|
||||||
import com.cool.core.base.BaseEntity;
|
import com.cool.core.base.TenantEntity;
|
||||||
import com.mybatisflex.annotation.Column;
|
import com.mybatisflex.annotation.Column;
|
||||||
import com.mybatisflex.annotation.Table;
|
import com.mybatisflex.annotation.Table;
|
||||||
import com.cool.core.mybatis.handler.Fastjson2TypeHandler;
|
import com.cool.core.mybatis.handler.Fastjson2TypeHandler;
|
||||||
@@ -14,7 +14,7 @@ import org.dromara.autotable.annotation.enums.IndexTypeEnum;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@Table(value = "base_sys_role", comment = "系统角色表")
|
@Table(value = "base_sys_role", comment = "系统角色表")
|
||||||
public class BaseSysRoleEntity extends BaseEntity<BaseSysRoleEntity> {
|
public class BaseSysRoleEntity extends TenantEntity<BaseSysRoleEntity> {
|
||||||
|
|
||||||
@Index
|
@Index
|
||||||
@ColumnDefine(comment = "用户ID", notNull = true, type = "bigint")
|
@ColumnDefine(comment = "用户ID", notNull = true, type = "bigint")
|
||||||
@@ -30,9 +30,15 @@ public class BaseSysRoleEntity extends BaseEntity<BaseSysRoleEntity> {
|
|||||||
@ColumnDefine(comment = "备注")
|
@ColumnDefine(comment = "备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
@ColumnDefine(comment = "数据权限是否关联上下级", defaultValue = "1")
|
@ColumnDefine(comment = "数据权限是否关联上下级", defaultValue = "1")
|
||||||
private Integer relevance;
|
private Integer relevance;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "父角色ID", type = "bigint")
|
||||||
|
private Long parentId;
|
||||||
|
|
||||||
@ColumnDefine(comment = "菜单权限", type = "json")
|
@ColumnDefine(comment = "菜单权限", type = "json")
|
||||||
@Column(typeHandler = Fastjson2TypeHandler.class)
|
@Column(typeHandler = Fastjson2TypeHandler.class)
|
||||||
private List<Long> menuIdList;
|
private List<Long> menuIdList;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.base.mapper.sys;
|
||||||
|
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysEmailConfigEntity;
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
|
||||||
|
public interface BaseSysEmailConfigMapper extends BaseMapper<BaseSysEmailConfigEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.base.mapper.sys;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysPermsAuditLogEntity;
|
||||||
|
|
||||||
|
public interface BaseSysPermsAuditLogMapper extends BaseMapper<BaseSysPermsAuditLogEntity> {
|
||||||
|
}
|
||||||
@@ -47,6 +47,13 @@ public class MySecurityMetadataSource implements FilterInvocationSecurityMetadat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除权限映射缓存,下次请求时重新加载
|
||||||
|
*/
|
||||||
|
public void clearCache() {
|
||||||
|
map = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判定用户请求的url是否在权限表中 如果在权限表中,则返回给decide方法,用来判定用户是否有此权限 如果不在权限表中则放行
|
* 判定用户请求的url是否在权限表中 如果在权限表中,则返回给decide方法,用来判定用户是否有此权限 如果不在权限表中则放行
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.cool.modules.base.service.sys;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysEmailConfigEntity;
|
||||||
|
|
||||||
|
public interface BaseSysEmailConfigService extends BaseService<BaseSysEmailConfigEntity> {
|
||||||
|
|
||||||
|
BaseSysEmailConfigEntity getActiveConfig();
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.cool.modules.base.service.sys;
|
|||||||
|
|
||||||
import com.cool.core.enums.UserTypeEnum;
|
import com.cool.core.enums.UserTypeEnum;
|
||||||
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
|
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
|
||||||
|
import com.cool.modules.base.dto.sys.BaseSysRegisterDto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统登录
|
* 系统登录
|
||||||
@@ -22,6 +23,8 @@ public interface BaseSysLoginService {
|
|||||||
*/
|
*/
|
||||||
void captchaCheck(String captchaId, String code);
|
void captchaCheck(String captchaId, String code);
|
||||||
|
|
||||||
|
boolean isCaptchaEnabled(String side, String sceneKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
*
|
*
|
||||||
@@ -45,4 +48,12 @@ public interface BaseSysLoginService {
|
|||||||
* @return 新的token
|
* @return 新的token
|
||||||
*/
|
*/
|
||||||
Object refreshToken(String refreshToken);
|
Object refreshToken(String refreshToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*
|
||||||
|
* @param baseSysRegisterDto 注册必要信息
|
||||||
|
* @return token与相关的过期信息
|
||||||
|
*/
|
||||||
|
Object register(BaseSysRegisterDto baseSysRegisterDto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,4 +165,18 @@ public interface BaseSysPermsService {
|
|||||||
*/
|
*/
|
||||||
void refreshPermsByRoleId(Long roleId);
|
void refreshPermsByRoleId(Long roleId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验当前用户是否有权访问指定部门的数据
|
||||||
|
*
|
||||||
|
* @param departmentId 部门ID
|
||||||
|
* @return true=有权访问
|
||||||
|
*/
|
||||||
|
boolean hasDepartmentPermission(Long departmentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户可访问的部门ID集合,超管返回null表示全部
|
||||||
|
*
|
||||||
|
* @return 部门ID数组,超管返回null
|
||||||
|
*/
|
||||||
|
Long[] getCurrentUserDepartmentIds();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.cool.modules.base.service.sys;
|
||||||
|
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysEmailConfigEntity;
|
||||||
|
import jakarta.mail.internet.MimeMessage;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSender;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||||
|
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EmailSendService {
|
||||||
|
|
||||||
|
private final BaseSysEmailConfigService emailConfigService;
|
||||||
|
|
||||||
|
public void sendCode(String toEmail, String code) {
|
||||||
|
BaseSysEmailConfigEntity config = emailConfigService.getActiveConfig();
|
||||||
|
if (config == null) {
|
||||||
|
throw new RuntimeException("未配置可用的邮箱服务,请在系统管理中配置邮箱");
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaMailSender mailSender = buildMailSender(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
|
||||||
|
helper.setFrom(config.getEmail());
|
||||||
|
helper.setTo(toEmail);
|
||||||
|
helper.setSubject("验证码");
|
||||||
|
helper.setText("<div style=\"padding:20px;font-family:sans-serif;\">"
|
||||||
|
+ "<h2>验证码</h2>"
|
||||||
|
+ "<p>您的验证码为:<strong style=\"font-size:24px;color:#14b8a6;\">" + code + "</strong></p>"
|
||||||
|
+ "<p style=\"color:#999;font-size:12px;\">验证码10分钟内有效,请勿泄露给他人。</p>"
|
||||||
|
+ "</div>", true);
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("验证码邮件发送成功: to={}", toEmail);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("验证码邮件发送失败: to={}, error={}", toEmail, e.getMessage());
|
||||||
|
throw new RuntimeException("邮件发送失败,请检查邮箱配置");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendTestMail(BaseSysEmailConfigEntity config) {
|
||||||
|
JavaMailSender mailSender = buildMailSender(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
MimeMessage message = mailSender.createMimeMessage();
|
||||||
|
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
|
||||||
|
helper.setFrom(config.getEmail());
|
||||||
|
helper.setTo(config.getEmail());
|
||||||
|
helper.setSubject("测试邮件");
|
||||||
|
helper.setText("<div style=\"padding:20px;font-family:sans-serif;\">"
|
||||||
|
+ "<h2>测试邮件</h2>"
|
||||||
|
+ "<p>这是一封测试邮件,如果您收到了说明邮箱配置正确。</p>"
|
||||||
|
+ "<p style=\"color:#999;font-size:12px;\">发送时间:" + java.time.LocalDateTime.now() + "</p>"
|
||||||
|
+ "</div>", true);
|
||||||
|
mailSender.send(message);
|
||||||
|
log.info("测试邮件发送成功: to={}", config.getEmail());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("测试邮件发送失败: to={}, error={}", config.getEmail(), e.getMessage());
|
||||||
|
throw new RuntimeException("邮件发送失败,请检查邮箱配置:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JavaMailSender buildMailSender(BaseSysEmailConfigEntity config) {
|
||||||
|
JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||||
|
sender.setHost(config.getHost());
|
||||||
|
sender.setPort(config.getPort());
|
||||||
|
sender.setUsername(config.getUsername());
|
||||||
|
sender.setPassword(config.getPassword());
|
||||||
|
sender.setDefaultEncoding("UTF-8");
|
||||||
|
|
||||||
|
java.util.Properties props = sender.getJavaMailProperties();
|
||||||
|
props.put("mail.transport.protocol", "smtp");
|
||||||
|
props.put("mail.smtp.auth", "true");
|
||||||
|
if (config.getSslEnable() != null && config.getSslEnable() == 1) {
|
||||||
|
props.put("mail.smtp.ssl.enable", "true");
|
||||||
|
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||||
|
} else {
|
||||||
|
props.put("mail.smtp.starttls.enable", "true");
|
||||||
|
}
|
||||||
|
props.put("mail.smtp.timeout", "5000");
|
||||||
|
props.put("mail.smtp.connectiontimeout", "5000");
|
||||||
|
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
-16
@@ -2,10 +2,13 @@ package com.cool.modules.base.service.sys.impl;
|
|||||||
|
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.cool.core.base.BaseServiceImpl;
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.core.exception.CoolPreconditions;
|
||||||
import com.cool.core.util.CoolSecurityUtil;
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
|
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysRoleDepartmentEntity;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysRoleDepartmentMapper;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
||||||
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
|
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
|
||||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
@@ -15,6 +18,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统部门
|
* 系统部门
|
||||||
@@ -29,6 +33,8 @@ public class BaseSysDepartmentServiceImpl extends
|
|||||||
|
|
||||||
final private BaseSysPermsService baseSysPermsService;
|
final private BaseSysPermsService baseSysPermsService;
|
||||||
|
|
||||||
|
final private BaseSysRoleDepartmentMapper baseSysRoleDepartmentMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void order(List<BaseSysDepartmentEntity> list) {
|
public void order(List<BaseSysDepartmentEntity> list) {
|
||||||
list.forEach(baseSysDepartmentEntity -> {
|
list.forEach(baseSysDepartmentEntity -> {
|
||||||
@@ -48,7 +54,7 @@ public class BaseSysDepartmentServiceImpl extends
|
|||||||
}
|
}
|
||||||
List<BaseSysDepartmentEntity> list = this.list(
|
List<BaseSysDepartmentEntity> list = this.list(
|
||||||
QueryWrapper.create()
|
QueryWrapper.create()
|
||||||
.in(BaseSysDepartmentEntity::getId, loginDepartmentIds, !username.equals("admin"))
|
.in(BaseSysDepartmentEntity::getId, loginDepartmentIds, !CoolSecurityUtil.isSuperAdmin(username))
|
||||||
.orderBy(BaseSysDepartmentEntity::getOrderNum, false));
|
.orderBy(BaseSysDepartmentEntity::getOrderNum, false));
|
||||||
list.forEach(e -> {
|
list.forEach(e -> {
|
||||||
List<BaseSysDepartmentEntity> parentDepartment = list.stream()
|
List<BaseSysDepartmentEntity> parentDepartment = list.stream()
|
||||||
@@ -63,22 +69,26 @@ public class BaseSysDepartmentServiceImpl extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean delete(JSONObject requestParams, Long... ids) {
|
public boolean delete(JSONObject requestParams, Long... ids) {
|
||||||
super.delete(ids);
|
List<Long> allDeptIds = new ArrayList<>(List.of(ids));
|
||||||
// 是否删除对应用户 否则移动到顶层部门
|
for (Long id : ids) {
|
||||||
if (requestParams.getBool("deleteUser")) {
|
collectChildDeptIds(id, allDeptIds);
|
||||||
return baseSysUserMapper
|
}
|
||||||
.deleteByQuery(
|
long userCount = baseSysUserMapper.selectCountByQuery(
|
||||||
QueryWrapper.create().in(BaseSysUserEntity::getDepartmentId, (Object) ids)) > 0;
|
QueryWrapper.create().in(BaseSysUserEntity::getDepartmentId, allDeptIds));
|
||||||
} else {
|
CoolPreconditions.check(userCount > 0, "该部门或其子部门下存在用户,无法删除");
|
||||||
BaseSysDepartmentEntity topDepartment = getOne(
|
baseSysRoleDepartmentMapper.deleteByQuery(
|
||||||
QueryWrapper.create().isNull(BaseSysDepartmentEntity::getParentId));
|
QueryWrapper.create().in(BaseSysRoleDepartmentEntity::getDepartmentId, allDeptIds));
|
||||||
if (topDepartment != null) {
|
return super.delete(ids);
|
||||||
UpdateChain.of(BaseSysUserEntity.class)
|
}
|
||||||
.set(BaseSysUserEntity::getDepartmentId, topDepartment.getId())
|
|
||||||
.in(BaseSysUserEntity::getDepartmentId, (Object) ids).update();
|
private void collectChildDeptIds(Long parentId, List<Long> result) {
|
||||||
}
|
List<BaseSysDepartmentEntity> children = list(
|
||||||
|
QueryWrapper.create().eq(BaseSysDepartmentEntity::getParentId, parentId));
|
||||||
|
for (BaseSysDepartmentEntity child : children) {
|
||||||
|
result.add(child.getId());
|
||||||
|
collectChildDeptIds(child.getId(), result);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package com.cool.modules.base.service.sys.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.core.exception.CoolPreconditions;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysEmailConfigEntity;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysEmailConfigMapper;
|
||||||
|
import com.cool.modules.base.service.sys.BaseSysEmailConfigService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BaseSysEmailConfigServiceImpl extends BaseServiceImpl<BaseSysEmailConfigMapper, BaseSysEmailConfigEntity>
|
||||||
|
implements BaseSysEmailConfigService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseSysEmailConfigEntity getActiveConfig() {
|
||||||
|
return getOne(QueryWrapper.create()
|
||||||
|
.eq(BaseSysEmailConfigEntity::getIsActive, 1)
|
||||||
|
.eq(BaseSysEmailConfigEntity::getEnabled, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifyAfter(cn.hutool.json.JSONObject requestParams, BaseSysEmailConfigEntity entity, com.cool.core.base.ModifyEnum type) {
|
||||||
|
if (type == com.cool.core.base.ModifyEnum.ADD || type == com.cool.core.base.ModifyEnum.UPDATE) {
|
||||||
|
if (ObjUtil.isNotEmpty(entity.getIsActive()) && entity.getIsActive() == 1) {
|
||||||
|
CoolPreconditions.check(entity.getId() == null && type == com.cool.core.base.ModifyEnum.UPDATE,
|
||||||
|
"新增时无法设置活跃状态");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,10 +15,16 @@ import com.cool.core.exception.CoolPreconditions;
|
|||||||
import com.cool.core.security.jwt.JwtTokenUtil;
|
import com.cool.core.security.jwt.JwtTokenUtil;
|
||||||
import com.cool.core.util.CoolSecurityUtil;
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
|
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
|
||||||
|
import com.cool.modules.base.dto.sys.BaseSysRegisterDto;import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysRoleMapper;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
||||||
import com.cool.modules.base.service.sys.BaseSysLoginService;
|
import com.cool.modules.base.service.sys.BaseSysLoginService;
|
||||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
|
import com.cool.modules.user.entity.UserCaptchaConfigEntity;
|
||||||
|
import com.cool.modules.user.service.UserCaptchaConfigService;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -42,8 +48,19 @@ public class BaseSysLoginServiceImpl implements BaseSysLoginService {
|
|||||||
|
|
||||||
private final BaseSysUserMapper baseSysUserMapper;
|
private final BaseSysUserMapper baseSysUserMapper;
|
||||||
|
|
||||||
|
private final BaseSysRoleMapper baseSysRoleMapper;
|
||||||
|
|
||||||
|
private final BaseSysDepartmentMapper baseSysDepartmentMapper;
|
||||||
|
|
||||||
private final BaseSysPermsService baseSysPermsService;
|
private final BaseSysPermsService baseSysPermsService;
|
||||||
|
|
||||||
|
private final UserCaptchaConfigService userCaptchaConfigService;
|
||||||
|
|
||||||
|
private final org.springframework.security.crypto.password.PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
@org.springframework.beans.factory.annotation.Value("${cool.captcha.enable:true}")
|
||||||
|
private boolean captchaEnable;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object captcha(UserTypeEnum userTypeEnum, String type, Integer width, Integer height) {
|
public Object captcha(UserTypeEnum userTypeEnum, String type, Integer width, Integer height) {
|
||||||
// 1、生成验证码 2、生成对应的ID并设置在缓存中,验证码过期时间30分钟;
|
// 1、生成验证码 2、生成对应的ID并设置在缓存中,验证码过期时间30分钟;
|
||||||
@@ -77,10 +94,23 @@ public class BaseSysLoginServiceImpl implements BaseSysLoginService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCaptchaEnabled(String side, String sceneKey) {
|
||||||
|
UserCaptchaConfigEntity config = userCaptchaConfigService.getOne(
|
||||||
|
QueryWrapper.create()
|
||||||
|
.eq(UserCaptchaConfigEntity::getSide, side)
|
||||||
|
.eq(UserCaptchaConfigEntity::getSceneKey, sceneKey));
|
||||||
|
if (config != null) {
|
||||||
|
return ObjUtil.equals(config.getEnabled(), 1);
|
||||||
|
}
|
||||||
|
return captchaEnable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object login(BaseSysLoginDto baseSysLoginDto) {
|
public Object login(BaseSysLoginDto baseSysLoginDto) {
|
||||||
// 1、检查验证码是否正确 2、执行登录操作
|
if (isCaptchaEnabled("admin", "adminLogin")) {
|
||||||
captchaCheck(baseSysLoginDto.getCaptchaId(), baseSysLoginDto.getVerifyCode());
|
captchaCheck(baseSysLoginDto.getCaptchaId(), baseSysLoginDto.getVerifyCode());
|
||||||
|
}
|
||||||
UsernamePasswordAuthenticationToken upToken =
|
UsernamePasswordAuthenticationToken upToken =
|
||||||
new UsernamePasswordAuthenticationToken(
|
new UsernamePasswordAuthenticationToken(
|
||||||
baseSysLoginDto.getUsername(), baseSysLoginDto.getPassword());
|
baseSysLoginDto.getUsername(), baseSysLoginDto.getPassword());
|
||||||
@@ -94,7 +124,9 @@ public class BaseSysLoginServiceImpl implements BaseSysLoginService {
|
|||||||
CoolPreconditions.check(
|
CoolPreconditions.check(
|
||||||
ObjectUtil.isEmpty(baseSysUserEntity) || baseSysUserEntity.getStatus() == 0, "用户已禁用");
|
ObjectUtil.isEmpty(baseSysUserEntity) || baseSysUserEntity.getStatus() == 0, "用户已禁用");
|
||||||
Long[] roleIds = baseSysPermsService.getRoles(baseSysUserEntity);
|
Long[] roleIds = baseSysPermsService.getRoles(baseSysUserEntity);
|
||||||
coolCache.del("verify:img:" + baseSysLoginDto.getCaptchaId());
|
if (isCaptchaEnabled("admin", "adminLogin")) {
|
||||||
|
coolCache.del("verify:img:" + baseSysLoginDto.getCaptchaId());
|
||||||
|
}
|
||||||
return generateToken(roleIds, baseSysUserEntity, null);
|
return generateToken(roleIds, baseSysUserEntity, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +147,40 @@ public class BaseSysLoginServiceImpl implements BaseSysLoginService {
|
|||||||
return generateToken(roleIds, baseSysUserEntity, refreshToken);
|
return generateToken(roleIds, baseSysUserEntity, refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object register(BaseSysRegisterDto baseSysRegisterDto) {
|
||||||
|
if (isCaptchaEnabled("admin", "adminRegister")) {
|
||||||
|
captchaCheck(baseSysRegisterDto.getCaptchaId(), baseSysRegisterDto.getVerifyCode());
|
||||||
|
}
|
||||||
|
BaseSysUserEntity existUser = baseSysUserMapper.selectOneByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysUserEntity::getUsername, baseSysRegisterDto.getUsername()));
|
||||||
|
CoolPreconditions.check(existUser != null, "用户名已存在");
|
||||||
|
BaseSysRoleEntity normalRole = baseSysRoleMapper.selectOneByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysRoleEntity::getLabel, "user"));
|
||||||
|
CoolPreconditions.check(normalRole == null, "系统未配置普通用户角色,请联系管理员");
|
||||||
|
BaseSysDepartmentEntity defaultDepartment = baseSysDepartmentMapper.selectOneByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysDepartmentEntity::getName, "待分配部门")
|
||||||
|
.eq(BaseSysDepartmentEntity::getStatus, 1));
|
||||||
|
CoolPreconditions.check(defaultDepartment == null, "系统未配置部门,请联系管理员");
|
||||||
|
BaseSysUserEntity userEntity = new BaseSysUserEntity();
|
||||||
|
userEntity.setUsername(baseSysRegisterDto.getUsername());
|
||||||
|
userEntity.setPassword(passwordEncoder.encode(baseSysRegisterDto.getPassword()));
|
||||||
|
userEntity.setPasswordV(1);
|
||||||
|
userEntity.setNickName(StrUtil.isNotEmpty(baseSysRegisterDto.getNickName())
|
||||||
|
? baseSysRegisterDto.getNickName() : baseSysRegisterDto.getUsername());
|
||||||
|
userEntity.setName(userEntity.getNickName());
|
||||||
|
userEntity.setPhone(baseSysRegisterDto.getPhone());
|
||||||
|
userEntity.setEmail(baseSysRegisterDto.getEmail());
|
||||||
|
userEntity.setStatus(1);
|
||||||
|
userEntity.setDepartmentId(defaultDepartment.getId());
|
||||||
|
baseSysUserMapper.insertSelective(userEntity);
|
||||||
|
baseSysPermsService.updateUserRole(userEntity.getId(), new Long[]{normalRole.getId()});
|
||||||
|
if (isCaptchaEnabled("admin", "adminRegister")) {
|
||||||
|
coolCache.del("verify:img:" + baseSysRegisterDto.getCaptchaId());
|
||||||
|
}
|
||||||
|
return Dict.create().set("message", "注册成功");
|
||||||
|
}
|
||||||
|
|
||||||
private Dict generateToken(Long[] roleIds, BaseSysUserEntity baseSysUserEntity, String refreshToken) {
|
private Dict generateToken(Long[] roleIds, BaseSysUserEntity baseSysUserEntity, String refreshToken) {
|
||||||
Dict tokenInfo =
|
Dict tokenInfo =
|
||||||
Dict.create()
|
Dict.create()
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import com.cool.core.util.CompilerUtils;
|
|||||||
import com.cool.core.util.CoolSecurityUtil;
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
import com.cool.core.util.PathUtils;
|
import com.cool.core.util.PathUtils;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysRoleMenuEntity;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysMenuMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysMenuMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysRoleMenuMapper;
|
||||||
import com.cool.modules.base.service.sys.BaseSysMenuService;
|
import com.cool.modules.base.service.sys.BaseSysMenuService;
|
||||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
@@ -37,6 +39,8 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, B
|
|||||||
|
|
||||||
final private CoolEps coolEps;
|
final private CoolEps coolEps;
|
||||||
|
|
||||||
|
final private BaseSysRoleMenuMapper baseSysRoleMenuMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object list(JSONObject requestParams, QueryWrapper queryWrapper) {
|
public Object list(JSONObject requestParams, QueryWrapper queryWrapper) {
|
||||||
List<BaseSysMenuEntity> list = baseSysPermsService.getMenus(CoolSecurityUtil.getAdminUsername());
|
List<BaseSysMenuEntity> list = baseSysPermsService.getMenus(CoolSecurityUtil.getAdminUsername());
|
||||||
@@ -71,6 +75,10 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, B
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean delete(Long... ids) {
|
public boolean delete(Long... ids) {
|
||||||
|
for (Long id : ids) {
|
||||||
|
baseSysRoleMenuMapper.deleteByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysRoleMenuEntity::getMenuId, id));
|
||||||
|
}
|
||||||
super.delete(ids);
|
super.delete(ids);
|
||||||
for (Long id : ids) {
|
for (Long id : ids) {
|
||||||
this.delChildMenu(id);
|
this.delChildMenu(id);
|
||||||
|
|||||||
+131
-12
@@ -15,16 +15,21 @@ import com.cool.core.util.CoolSecurityUtil;
|
|||||||
import com.cool.core.util.SpringContextUtils;
|
import com.cool.core.util.SpringContextUtils;
|
||||||
import com.cool.modules.base.entity.sys.*;
|
import com.cool.modules.base.entity.sys.*;
|
||||||
import com.cool.modules.base.mapper.sys.*;
|
import com.cool.modules.base.mapper.sys.*;
|
||||||
|
import com.cool.modules.base.security.MySecurityMetadataSource;
|
||||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.mybatisflex.core.row.Row;
|
import com.mybatisflex.core.row.Row;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
||||||
@@ -38,16 +43,20 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
|
|
||||||
final private BaseSysRoleMenuMapper baseSysRoleMenuMapper;
|
final private BaseSysRoleMenuMapper baseSysRoleMenuMapper;
|
||||||
|
|
||||||
|
final private BaseSysRoleMapper baseSysRoleMapper;
|
||||||
|
|
||||||
final private BaseSysRoleDepartmentMapper baseSysRoleDepartmentMapper;
|
final private BaseSysRoleDepartmentMapper baseSysRoleDepartmentMapper;
|
||||||
|
|
||||||
final private BaseSysDepartmentMapper baseSysDepartmentMapper;
|
final private BaseSysDepartmentMapper baseSysDepartmentMapper;
|
||||||
|
|
||||||
final private ExecutorService cachedThreadPool;
|
final private ExecutorService cachedThreadPool;
|
||||||
|
|
||||||
|
final private BaseSysPermsAuditLogMapper baseSysPermsAuditLogMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long[] loginDepartmentIds() {
|
public Long[] loginDepartmentIds() {
|
||||||
String username = CoolSecurityUtil.getAdminUsername();
|
String username = CoolSecurityUtil.getAdminUsername();
|
||||||
if (username.equals("admin")) {
|
if (CoolSecurityUtil.isSuperAdmin(username)) {
|
||||||
return baseSysDepartmentMapper.selectAll().stream().map(BaseSysDepartmentEntity::getId)
|
return baseSysDepartmentMapper.selectAll().stream().map(BaseSysDepartmentEntity::getId)
|
||||||
.toArray(Long[]::new);
|
.toArray(Long[]::new);
|
||||||
} else {
|
} else {
|
||||||
@@ -72,9 +81,30 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
if (!CollUtil.toList(roleIds).contains(1L)) {
|
if (!CollUtil.toList(roleIds).contains(1L)) {
|
||||||
queryWrapper.in(BaseSysRoleDepartmentEntity::getRoleId, (Object) roleIds);
|
queryWrapper.in(BaseSysRoleDepartmentEntity::getRoleId, (Object) roleIds);
|
||||||
}
|
}
|
||||||
return baseSysRoleDepartmentMapper
|
List<Long> deptIds = baseSysRoleDepartmentMapper
|
||||||
.selectListByQuery(queryWrapper)
|
.selectListByQuery(queryWrapper)
|
||||||
.stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new);
|
.stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).collect(java.util.stream.Collectors.toList());
|
||||||
|
Set<Long> expandedDeptIds = new LinkedHashSet<>(deptIds);
|
||||||
|
for (Long roleId : roleIds) {
|
||||||
|
if (roleId == 1L) continue;
|
||||||
|
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(roleId);
|
||||||
|
if (role != null && role.getRelevance() != null && role.getRelevance() == 1) {
|
||||||
|
for (Long deptId : deptIds) {
|
||||||
|
collectChildDeptIds(deptId, expandedDeptIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expandedDeptIds.toArray(Long[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectChildDeptIds(Long parentId, Set<Long> result) {
|
||||||
|
List<BaseSysDepartmentEntity> children = baseSysDepartmentMapper
|
||||||
|
.selectListByQuery(QueryWrapper.create().eq(BaseSysDepartmentEntity::getParentId, parentId));
|
||||||
|
for (BaseSysDepartmentEntity child : children) {
|
||||||
|
if (result.add(child.getId())) {
|
||||||
|
collectChildDeptIds(child.getId(), result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -111,11 +141,18 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
@Override
|
@Override
|
||||||
public Long[] getRoles(BaseSysUserEntity userEntity) {
|
public Long[] getRoles(BaseSysUserEntity userEntity) {
|
||||||
Long[] roleIds = null;
|
Long[] roleIds = null;
|
||||||
if (!userEntity.getUsername().equals("admin")) {
|
if (!CoolSecurityUtil.isSuperAdmin(userEntity.getUsername())) {
|
||||||
List<BaseSysUserRoleEntity> list = baseSysUserRoleMapper
|
List<BaseSysUserRoleEntity> list = baseSysUserRoleMapper
|
||||||
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userEntity.getId()));
|
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userEntity.getId()));
|
||||||
roleIds = list.stream().map(BaseSysUserRoleEntity::getRoleId).toArray(Long[]::new);
|
List<Long> activeRoleIds = new ArrayList<>();
|
||||||
if (Arrays.asList(roleIds).contains(1L)) {
|
for (BaseSysUserRoleEntity userRole : list) {
|
||||||
|
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(userRole.getRoleId());
|
||||||
|
if (role != null && role.getStatus() != 0) {
|
||||||
|
activeRoleIds.add(userRole.getRoleId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roleIds = activeRoleIds.toArray(Long[]::new);
|
||||||
|
if (roleIds.length > 0 && Arrays.asList(roleIds).contains(1L)) {
|
||||||
roleIds = null;
|
roleIds = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +166,7 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getPerms(Long[] roleIds) {
|
public String[] getPerms(Long[] roleIds) {
|
||||||
List<BaseSysMenuEntity> menus = getMenus(roleIds);
|
List<BaseSysMenuEntity> menus = getMenus(expandWithParentRoles(roleIds));
|
||||||
Set<String> perms = new HashSet<>();
|
Set<String> perms = new HashSet<>();
|
||||||
String[] permsData = menus.stream().map(BaseSysMenuEntity::getPerms)
|
String[] permsData = menus.stream().map(BaseSysMenuEntity::getPerms)
|
||||||
.filter(itemPerms -> !StrUtil.isEmpty(itemPerms)).toArray(String[]::new);
|
.filter(itemPerms -> !StrUtil.isEmpty(itemPerms)).toArray(String[]::new);
|
||||||
@@ -141,6 +178,10 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BaseSysMenuEntity> getMenus(Long[] roleIds) {
|
public List<BaseSysMenuEntity> getMenus(Long[] roleIds) {
|
||||||
|
return getMenusInner(expandWithParentRoles(roleIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BaseSysMenuEntity> getMenusInner(Long[] roleIds) {
|
||||||
if (CollUtil.toList(roleIds).contains(1L)) {
|
if (CollUtil.toList(roleIds).contains(1L)) {
|
||||||
roleIds = null;
|
roleIds = null;
|
||||||
}
|
}
|
||||||
@@ -178,7 +219,14 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updatePerms(Long roleId, Long[] menuIdList, Long[] departmentIds) {
|
public void updatePerms(Long roleId, Long[] menuIdList, Long[] departmentIds) {
|
||||||
|
Long[] beforeMenuIds = baseSysRoleMenuMapper.selectListByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, roleId))
|
||||||
|
.stream().map(BaseSysRoleMenuEntity::getMenuId).toArray(Long[]::new);
|
||||||
|
Long[] beforeDeptIds = baseSysRoleDepartmentMapper.selectListByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysRoleDepartmentEntity::getRoleId, roleId))
|
||||||
|
.stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new);
|
||||||
// 更新菜单权限
|
// 更新菜单权限
|
||||||
baseSysRoleMenuMapper.deleteByQuery(QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, roleId));
|
baseSysRoleMenuMapper.deleteByQuery(QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, roleId));
|
||||||
List<BaseSysRoleMenuEntity> batchRoleMenuList = new ArrayList<>();
|
List<BaseSysRoleMenuEntity> batchRoleMenuList = new ArrayList<>();
|
||||||
@@ -204,6 +252,10 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
if (ObjectUtil.isNotEmpty(batchRoleDepartmentList)) {
|
if (ObjectUtil.isNotEmpty(batchRoleDepartmentList)) {
|
||||||
baseSysRoleDepartmentMapper.insertBatch(batchRoleDepartmentList);
|
baseSysRoleDepartmentMapper.insertBatch(batchRoleDepartmentList);
|
||||||
}
|
}
|
||||||
|
SpringContextUtils.getBean(MySecurityMetadataSource.class).clearCache();
|
||||||
|
logPermsAudit("PERMS_UPDATE", roleId,
|
||||||
|
Dict.create().set("menuIds", beforeMenuIds).set("deptIds", beforeDeptIds),
|
||||||
|
Dict.create().set("menuIds", menuIdList).set("deptIds", departmentIds));
|
||||||
cachedThreadPool.submit(() -> {
|
cachedThreadPool.submit(() -> {
|
||||||
// 刷新对应角色用户的权限
|
// 刷新对应角色用户的权限
|
||||||
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper
|
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper
|
||||||
@@ -215,7 +267,11 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateUserRole(Long userId, Long[] roleIdList) {
|
public void updateUserRole(Long userId, Long[] roleIdList) {
|
||||||
|
Long[] beforeRoleIds = baseSysUserRoleMapper.selectListByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId))
|
||||||
|
.stream().map(BaseSysUserRoleEntity::getRoleId).toArray(Long[]::new);
|
||||||
baseSysUserRoleMapper.deleteByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId));
|
baseSysUserRoleMapper.deleteByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId));
|
||||||
if (roleIdList == null) {
|
if (roleIdList == null) {
|
||||||
roleIdList = new Long[0];
|
roleIdList = new Long[0];
|
||||||
@@ -226,6 +282,9 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
sysUserRoleEntity.setUserId(userId);
|
sysUserRoleEntity.setUserId(userId);
|
||||||
baseSysUserRoleMapper.insert(sysUserRoleEntity);
|
baseSysUserRoleMapper.insert(sysUserRoleEntity);
|
||||||
}
|
}
|
||||||
|
logPermsAudit("USER_ROLE_UPDATE", userId,
|
||||||
|
Dict.create().set("roleIds", beforeRoleIds),
|
||||||
|
Dict.create().set("roleIds", roleIdList));
|
||||||
refreshPerms(userId);
|
refreshPerms(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,10 +302,13 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
@Async
|
@Async
|
||||||
@Override
|
@Override
|
||||||
public void refreshPermsByMenuId(Long menuId) {
|
public void refreshPermsByMenuId(Long menuId) {
|
||||||
// 刷新超管权限、 找出这个菜单的所有用户、 刷新用户权限
|
SpringContextUtils.getBean(MySecurityMetadataSource.class).clearCache();
|
||||||
BaseSysUserEntity admin = baseSysUserMapper
|
List<BaseSysUserEntity> superAdmins = baseSysUserMapper
|
||||||
.selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, "admin"));
|
.selectListByQuery(QueryWrapper.create()
|
||||||
refreshPerms(admin.getId());
|
.eq(BaseSysUserEntity::getUsername, "admin"));
|
||||||
|
for (BaseSysUserEntity admin : superAdmins) {
|
||||||
|
refreshPerms(admin.getId());
|
||||||
|
}
|
||||||
List<Row> list = baseSysRoleMenuMapper.selectRowsByQuery(QueryWrapper.create().select(BASE_SYS_USER_ROLE_ENTITY.USER_ID)
|
List<Row> list = baseSysRoleMenuMapper.selectRowsByQuery(QueryWrapper.create().select(BASE_SYS_USER_ROLE_ENTITY.USER_ID)
|
||||||
.from(BASE_SYS_ROLE_MENU_ENTITY).leftJoin(BASE_SYS_USER_ROLE_ENTITY)
|
.from(BASE_SYS_ROLE_MENU_ENTITY).leftJoin(BASE_SYS_USER_ROLE_ENTITY)
|
||||||
.on(BASE_SYS_ROLE_MENU_ENTITY.ROLE_ID.eq(BASE_SYS_USER_ROLE_ENTITY.ROLE_ID)).and(BASE_SYS_ROLE_MENU_ENTITY.MENU_ID.eq(menuId, ObjectUtil.isNotEmpty(menuId))).groupBy(BASE_SYS_USER_ROLE_ENTITY.USER_ID));
|
.on(BASE_SYS_ROLE_MENU_ENTITY.ROLE_ID.eq(BASE_SYS_USER_ROLE_ENTITY.ROLE_ID)).and(BASE_SYS_ROLE_MENU_ENTITY.MENU_ID.eq(menuId, ObjectUtil.isNotEmpty(menuId))).groupBy(BASE_SYS_USER_ROLE_ENTITY.USER_ID));
|
||||||
@@ -257,11 +319,68 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refreshPermsByRoleId(Long roleId) {
|
public void refreshPermsByRoleId(Long roleId) {
|
||||||
// 找出角色对应的所有用户
|
|
||||||
List<BaseSysUserRoleEntity> list = baseSysUserRoleMapper
|
List<BaseSysUserRoleEntity> list = baseSysUserRoleMapper
|
||||||
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId));
|
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId));
|
||||||
list.forEach(e -> {
|
list.forEach(e -> {
|
||||||
refreshPerms(e.getUserId());
|
refreshPerms(e.getUserId());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDepartmentPermission(Long departmentId) {
|
||||||
|
if (CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Long[] permittedIds = getDepartmentIdsByUserId(CoolSecurityUtil.getCurrentUserId());
|
||||||
|
if (ObjectUtil.isEmpty(permittedIds)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Arrays.asList(permittedIds).contains(departmentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long[] getCurrentUserDepartmentIds() {
|
||||||
|
if (CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getDepartmentIdsByUserId(CoolSecurityUtil.getCurrentUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long[] expandWithParentRoles(Long[] roleIds) {
|
||||||
|
if (ObjectUtil.isEmpty(roleIds)) {
|
||||||
|
return roleIds;
|
||||||
|
}
|
||||||
|
Set<Long> expanded = new LinkedHashSet<>(Arrays.asList(roleIds));
|
||||||
|
for (Long roleId : roleIds) {
|
||||||
|
collectParentRoleIds(roleId, expanded);
|
||||||
|
}
|
||||||
|
return expanded.toArray(Long[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectParentRoleIds(Long roleId, Set<Long> result) {
|
||||||
|
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(roleId);
|
||||||
|
if (role == null || role.getParentId() == null || result.contains(role.getParentId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BaseSysRoleEntity parentRole = baseSysRoleMapper.selectOneById(role.getParentId());
|
||||||
|
if (parentRole != null && parentRole.getStatus() != 0) {
|
||||||
|
result.add(parentRole.getId());
|
||||||
|
collectParentRoleIds(parentRole.getId(), result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logPermsAudit(String changeType, Long targetId, Object beforeValue, Object afterValue) {
|
||||||
|
try {
|
||||||
|
BaseSysPermsAuditLogEntity auditLog = new BaseSysPermsAuditLogEntity();
|
||||||
|
auditLog.setOperatorUserId(CoolSecurityUtil.getCurrentUserId());
|
||||||
|
auditLog.setOperatorUsername(CoolSecurityUtil.getAdminUsername());
|
||||||
|
auditLog.setChangeType(changeType);
|
||||||
|
auditLog.setTargetId(targetId);
|
||||||
|
auditLog.setBeforeValue(beforeValue);
|
||||||
|
auditLog.setAfterValue(afterValue);
|
||||||
|
baseSysPermsAuditLogMapper.insertSelective(auditLog);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("记录权限审计日志失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import com.cool.core.util.CoolSecurityUtil;
|
|||||||
import com.cool.modules.base.entity.sys.BaseSysRoleDepartmentEntity;
|
import com.cool.modules.base.entity.sys.BaseSysRoleDepartmentEntity;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
|
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysRoleMenuEntity;
|
import com.cool.modules.base.entity.sys.BaseSysRoleMenuEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysUserRoleEntity;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysRoleDepartmentMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysRoleDepartmentMapper;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysRoleMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysRoleMapper;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysRoleMenuMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysRoleMenuMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysUserRoleMapper;
|
||||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
import com.cool.modules.base.service.sys.BaseSysRoleService;
|
import com.cool.modules.base.service.sys.BaseSysRoleService;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
@@ -37,6 +39,8 @@ public class BaseSysRoleServiceImpl extends BaseServiceImpl<BaseSysRoleMapper, B
|
|||||||
|
|
||||||
final private BaseSysPermsService baseSysPermsService;
|
final private BaseSysPermsService baseSysPermsService;
|
||||||
|
|
||||||
|
final private BaseSysUserRoleMapper baseSysUserRoleMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object add(JSONObject requestParams, BaseSysRoleEntity entity) {
|
public Object add(JSONObject requestParams, BaseSysRoleEntity entity) {
|
||||||
BaseSysRoleEntity checkLabel = getOne(QueryWrapper.create().eq(BaseSysRoleEntity::getLabel, entity.getLabel()));
|
BaseSysRoleEntity checkLabel = getOne(QueryWrapper.create().eq(BaseSysRoleEntity::getLabel, entity.getLabel()));
|
||||||
@@ -77,11 +81,20 @@ public class BaseSysRoleServiceImpl extends BaseServiceImpl<BaseSysRoleMapper, B
|
|||||||
if (type == ModifyEnum.DELETE) {
|
if (type == ModifyEnum.DELETE) {
|
||||||
Long[] ids = requestParams.get("ids", Long[].class);
|
Long[] ids = requestParams.get("ids", Long[].class);
|
||||||
for (Long id : ids) {
|
for (Long id : ids) {
|
||||||
|
baseSysRoleMenuMapper.deleteByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, id));
|
||||||
|
baseSysRoleDepartmentMapper.deleteByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysRoleDepartmentEntity::getRoleId, id));
|
||||||
|
baseSysUserRoleMapper.deleteByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, id));
|
||||||
baseSysPermsService.refreshPermsByRoleId(id);
|
baseSysPermsService.refreshPermsByRoleId(id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
baseSysPermsService.updatePerms(baseSysRoleEntity.getId(), requestParams.get("menuIdList", Long[].class),
|
baseSysPermsService.updatePerms(baseSysRoleEntity.getId(), requestParams.get("menuIdList", Long[].class),
|
||||||
requestParams.get("departmentIdList", Long[].class));
|
requestParams.get("departmentIdList", Long[].class));
|
||||||
|
if (baseSysRoleEntity.getStatus() != null && baseSysRoleEntity.getStatus() == 0) {
|
||||||
|
baseSysPermsService.refreshPermsByRoleId(baseSysRoleEntity.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +106,6 @@ public class BaseSysRoleServiceImpl extends BaseServiceImpl<BaseSysRoleMapper, B
|
|||||||
w.in(BaseSysRoleEntity::getId,
|
w.in(BaseSysRoleEntity::getId,
|
||||||
(Object) object.get("roleIds", Long[].class));
|
(Object) object.get("roleIds", Long[].class));
|
||||||
});
|
});
|
||||||
}, !CoolSecurityUtil.getAdminUsername().equals("admin")));
|
}, !CoolSecurityUtil.isSuperAdmin()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,8 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.lang.Dict;
|
import cn.hutool.core.lang.Dict;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.crypto.digest.MD5;
|
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.cool.core.base.BaseServiceImpl;
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
import com.cool.core.base.ModifyEnum;
|
import com.cool.core.base.ModifyEnum;
|
||||||
@@ -20,15 +20,21 @@ import com.cool.core.exception.CoolPreconditions;
|
|||||||
import com.cool.core.util.CoolSecurityUtil;
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
import com.cool.core.util.DatabaseDialectUtils;
|
import com.cool.core.util.DatabaseDialectUtils;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
|
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
|
||||||
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysUserRoleEntity;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysRoleMapper;
|
||||||
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysUserRoleMapper;
|
||||||
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
import com.cool.modules.base.service.sys.BaseSysUserService;
|
import com.cool.modules.base.service.sys.BaseSysUserService;
|
||||||
import com.mybatisflex.core.paginate.Page;
|
import com.mybatisflex.core.paginate.Page;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.mybatisflex.core.update.UpdateChain;
|
import com.mybatisflex.core.update.UpdateChain;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -38,7 +44,6 @@ import java.util.List;
|
|||||||
* 系统用户
|
* 系统用户
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, BaseSysUserEntity>
|
public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, BaseSysUserEntity>
|
||||||
implements BaseSysUserService {
|
implements BaseSysUserService {
|
||||||
|
|
||||||
@@ -48,6 +53,23 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
|||||||
|
|
||||||
final private BaseSysDepartmentMapper baseSysDepartmentMapper;
|
final private BaseSysDepartmentMapper baseSysDepartmentMapper;
|
||||||
|
|
||||||
|
final private BaseSysUserRoleMapper baseSysUserRoleMapper;
|
||||||
|
|
||||||
|
final private BaseSysRoleMapper baseSysRoleMapper;
|
||||||
|
|
||||||
|
final private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
public BaseSysUserServiceImpl(CoolCache coolCache, BaseSysPermsService baseSysPermsService,
|
||||||
|
BaseSysDepartmentMapper baseSysDepartmentMapper, BaseSysUserRoleMapper baseSysUserRoleMapper,
|
||||||
|
BaseSysRoleMapper baseSysRoleMapper, @Lazy PasswordEncoder passwordEncoder) {
|
||||||
|
this.coolCache = coolCache;
|
||||||
|
this.baseSysPermsService = baseSysPermsService;
|
||||||
|
this.baseSysDepartmentMapper = baseSysDepartmentMapper;
|
||||||
|
this.baseSysUserRoleMapper = baseSysUserRoleMapper;
|
||||||
|
this.baseSysRoleMapper = baseSysRoleMapper;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object page(JSONObject requestParams, Page<BaseSysUserEntity> page, QueryWrapper qw) {
|
public Object page(JSONObject requestParams, Page<BaseSysUserEntity> page, QueryWrapper qw) {
|
||||||
String keyWord = requestParams.getStr("keyWord");
|
String keyWord = requestParams.getStr("keyWord");
|
||||||
@@ -87,8 +109,12 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
|||||||
.leftJoin(BASE_SYS_DEPARTMENT_ENTITY)
|
.leftJoin(BASE_SYS_DEPARTMENT_ENTITY)
|
||||||
.on(BASE_SYS_USER_ENTITY.DEPARTMENT_ID.eq(BASE_SYS_DEPARTMENT_ENTITY.ID));
|
.on(BASE_SYS_USER_ENTITY.DEPARTMENT_ID.eq(BASE_SYS_DEPARTMENT_ENTITY.ID));
|
||||||
|
|
||||||
// 不显示admin用户
|
// 不显示超管用户
|
||||||
qw.and(BASE_SYS_USER_ENTITY.USERNAME.ne("admin"));
|
qw.and(BASE_SYS_USER_ENTITY.ID.notIn(
|
||||||
|
baseSysUserRoleMapper.selectListByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, 1L)
|
||||||
|
).stream().map(BaseSysUserRoleEntity::getUserId).toArray()
|
||||||
|
));
|
||||||
// 筛选状态
|
// 筛选状态
|
||||||
qw.and(BASE_SYS_USER_ENTITY.STATUS.eq(status, status != null));
|
qw.and(BASE_SYS_USER_ENTITY.STATUS.eq(status, status != null));
|
||||||
// 搜索关键字
|
// 搜索关键字
|
||||||
@@ -117,9 +143,9 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
|||||||
CoolPreconditions.checkEmpty(userEntity, "用户不存在");
|
CoolPreconditions.checkEmpty(userEntity, "用户不存在");
|
||||||
userEntity.setNickName(body.getStr("nickName"));
|
userEntity.setNickName(body.getStr("nickName"));
|
||||||
userEntity.setHeadImg(body.getStr("headImg"));
|
userEntity.setHeadImg(body.getStr("headImg"));
|
||||||
// 修改密码
|
if (StrUtil.isNotEmpty(body.getStr("password")) && StrUtil.isNotEmpty(body.getStr("newPassword"))) {
|
||||||
if (StrUtil.isNotEmpty(body.getStr("password"))) {
|
CoolPreconditions.check(!passwordEncoder.matches(body.getStr("password"), userEntity.getPassword()), "原密码错误");
|
||||||
userEntity.setPassword(MD5.create().digestHex(body.getStr("password")));
|
userEntity.setPassword(passwordEncoder.encode(body.getStr("newPassword")));
|
||||||
userEntity.setPasswordV(userEntity.getPasswordV() + 1);
|
userEntity.setPasswordV(userEntity.getPasswordV() + 1);
|
||||||
coolCache.set("admin:passwordVersion:" + userId, userEntity.getPasswordV());
|
coolCache.set("admin:passwordVersion:" + userId, userEntity.getPasswordV());
|
||||||
}
|
}
|
||||||
@@ -128,6 +154,7 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void move(Long departmentId, Long[] userIds) {
|
public void move(Long departmentId, Long[] userIds) {
|
||||||
|
CoolPreconditions.check(!baseSysPermsService.hasDepartmentPermission(departmentId), "无权将用户移动到该部门");
|
||||||
UpdateChain.of(BaseSysUserEntity.class)
|
UpdateChain.of(BaseSysUserEntity.class)
|
||||||
.set(BaseSysUserEntity::getDepartmentId, departmentId)
|
.set(BaseSysUserEntity::getDepartmentId, departmentId)
|
||||||
.in(BaseSysUserEntity::getId, (Object) userIds).update();
|
.in(BaseSysUserEntity::getId, (Object) userIds).update();
|
||||||
@@ -138,7 +165,7 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
|||||||
BaseSysUserEntity check = getOne(
|
BaseSysUserEntity check = getOne(
|
||||||
QueryWrapper.create().eq(BaseSysUserEntity::getUsername, entity.getUsername()));
|
QueryWrapper.create().eq(BaseSysUserEntity::getUsername, entity.getUsername()));
|
||||||
CoolPreconditions.check(check != null, "用户名已存在");
|
CoolPreconditions.check(check != null, "用户名已存在");
|
||||||
entity.setPassword(MD5.create().digestHex(entity.getPassword()));
|
entity.setPassword(passwordEncoder.encode(entity.getPassword()));
|
||||||
super.add(requestParams, entity);
|
super.add(requestParams, entity);
|
||||||
return entity.getId();
|
return entity.getId();
|
||||||
}
|
}
|
||||||
@@ -146,18 +173,18 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
|||||||
@Override
|
@Override
|
||||||
public boolean update(JSONObject requestParams, BaseSysUserEntity entity) {
|
public boolean update(JSONObject requestParams, BaseSysUserEntity entity) {
|
||||||
CoolPreconditions.check(
|
CoolPreconditions.check(
|
||||||
StrUtil.isNotEmpty(entity.getUsername()) && entity.getUsername().equals("admin"),
|
StrUtil.isNotEmpty(entity.getUsername()) && CoolSecurityUtil.isSuperAdmin(entity.getUsername()),
|
||||||
"非法操作");
|
"非法操作");
|
||||||
BaseSysUserEntity userEntity = getById(entity.getId());
|
BaseSysUserEntity userEntity = getById(entity.getId());
|
||||||
if (StrUtil.isNotEmpty(entity.getPassword())) {
|
String requestPassword = requestParams.getStr("password");
|
||||||
entity.setPasswordV(entity.getPasswordV() + 1);
|
if (StrUtil.isNotEmpty(requestPassword)) {
|
||||||
entity.setPassword(MD5.create().digestHex(entity.getPassword()));
|
entity.setPasswordV(userEntity.getPasswordV() + 1);
|
||||||
|
entity.setPassword(passwordEncoder.encode(requestPassword));
|
||||||
coolCache.set("admin:passwordVersion:" + entity.getId(), entity.getPasswordV());
|
coolCache.set("admin:passwordVersion:" + entity.getId(), entity.getPasswordV());
|
||||||
} else {
|
} else {
|
||||||
entity.setPassword(userEntity.getPassword());
|
entity.setPassword(userEntity.getPassword());
|
||||||
entity.setPasswordV(userEntity.getPasswordV());
|
entity.setPasswordV(userEntity.getPasswordV());
|
||||||
}
|
}
|
||||||
// 被禁用
|
|
||||||
if (entity.getStatus() == 0) {
|
if (entity.getStatus() == 0) {
|
||||||
CoolSecurityUtil.adminLogout(entity);
|
CoolSecurityUtil.adminLogout(entity);
|
||||||
}
|
}
|
||||||
@@ -167,25 +194,56 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
|||||||
@Override
|
@Override
|
||||||
public void modifyAfter(JSONObject requestParams, BaseSysUserEntity baseSysUserEntity,
|
public void modifyAfter(JSONObject requestParams, BaseSysUserEntity baseSysUserEntity,
|
||||||
ModifyEnum type) {
|
ModifyEnum type) {
|
||||||
if (type != ModifyEnum.DELETE && requestParams.get("roleIdList", Long[].class) != null) {
|
if (type == ModifyEnum.DELETE) {
|
||||||
// 刷新权限
|
Long[] ids = requestParams.get("ids", Long[].class);
|
||||||
baseSysPermsService.updateUserRole(baseSysUserEntity.getId(),
|
if (ids != null) {
|
||||||
requestParams.get("roleIdList", Long[].class));
|
for (Long id : ids) {
|
||||||
|
baseSysUserRoleMapper.deleteByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, id));
|
||||||
|
CoolSecurityUtil.adminLogout(id, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (requestParams.get("roleIdList", Long[].class) != null) {
|
||||||
|
Long[] roleIdList = requestParams.get("roleIdList", Long[].class);
|
||||||
|
validateRoleAssignment(roleIdList);
|
||||||
|
baseSysPermsService.updateUserRole(baseSysUserEntity.getId(), roleIdList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateRoleAssignment(Long[] roleIdList) {
|
||||||
|
if (ArrayUtil.isEmpty(roleIdList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Long> requestedRoles = CollUtil.toList(roleIdList);
|
||||||
|
CoolPreconditions.check(requestedRoles.contains(1L), "无权分配超级管理员角色");
|
||||||
|
Long[] currentRoleIds = baseSysPermsService.getRoles(CoolSecurityUtil.getCurrentUserId());
|
||||||
|
if (ObjectUtil.isEmpty(currentRoleIds)) {
|
||||||
|
CoolPreconditions.check(true, "无权分配任何角色");
|
||||||
|
}
|
||||||
|
List<Long> allowedRoles = CollUtil.toList(currentRoleIds);
|
||||||
|
for (Long roleId : requestedRoles) {
|
||||||
|
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(roleId);
|
||||||
|
CoolPreconditions.checkEmpty(role, "角色不存在: {}", roleId);
|
||||||
|
CoolPreconditions.check(!allowedRoles.contains(roleId), "无权分配角色: {}", role.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseSysUserEntity info(Long id) {
|
public BaseSysUserEntity info(Long id) {
|
||||||
BaseSysUserEntity userEntity = getById(id);
|
BaseSysUserEntity userEntity = getById(id);
|
||||||
|
CoolPreconditions.checkEmpty(userEntity, "用户不存在");
|
||||||
|
if (!CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
CoolPreconditions.check(!baseSysPermsService.hasDepartmentPermission(userEntity.getDepartmentId()), "无权查看该用户信息");
|
||||||
|
}
|
||||||
Long[] roleIdList = baseSysPermsService.getRoles(id);
|
Long[] roleIdList = baseSysPermsService.getRoles(id);
|
||||||
BaseSysDepartmentEntity departmentEntity = baseSysDepartmentMapper.selectOneById(
|
BaseSysDepartmentEntity departmentEntity = baseSysDepartmentMapper.selectOneById(
|
||||||
userEntity.getDepartmentId());
|
userEntity.getDepartmentId());
|
||||||
userEntity.setPassword(null);
|
userEntity.setPassword(null);
|
||||||
|
|
||||||
|
|
||||||
userEntity.setRoleIdList(List.of(roleIdList));
|
userEntity.setRoleIdList(List.of(roleIdList));
|
||||||
userEntity.setDepartmentName(departmentEntity != null ? departmentEntity.getName() : userEntity.getDepartmentName() );
|
userEntity.setDepartmentName(departmentEntity != null ? departmentEntity.getName() : userEntity.getDepartmentName());
|
||||||
|
|
||||||
return userEntity;
|
return userEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.cool.modules.fruit.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.modules.fruit.entity.FruitGoodsEntity;
|
||||||
|
import com.cool.modules.fruit.service.FruitGoodsService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "水果管理", description = "水果商品管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"})
|
||||||
|
public class AdminFruitGoodsController extends BaseController<FruitGoodsService, FruitGoodsEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.cool.modules.fruit.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
|
import com.cool.modules.fruit.entity.FruitGoodsEntity;
|
||||||
|
import com.cool.modules.fruit.service.FruitGoodsService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "水果", description = "App端水果")
|
||||||
|
@CoolRestController
|
||||||
|
public class AppFruitGoodsController {
|
||||||
|
|
||||||
|
private final FruitGoodsService fruitGoodsService;
|
||||||
|
|
||||||
|
@Operation(summary = "水果列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public R list(@RequestAttribute JSONObject requestParams) {
|
||||||
|
return R.ok(fruitGoodsService.list(requestParams, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "水果详情")
|
||||||
|
@GetMapping("/detail")
|
||||||
|
public R detail(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
return R.ok(fruitGoodsService.info(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.cool.modules.fruit.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "fruit_goods", comment = "水果商品表")
|
||||||
|
public class FruitGoodsEntity extends TenantEntity<FruitGoodsEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "商品名称", notNull = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "价格")
|
||||||
|
private Double price;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "单位")
|
||||||
|
private String unit;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "图片")
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "描述", type = "text")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "分类ID", type = "bigint")
|
||||||
|
private Long categoryId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:下架 1:上架", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.fruit.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.fruit.entity.FruitGoodsEntity;
|
||||||
|
|
||||||
|
public interface FruitGoodsMapper extends BaseMapper<FruitGoodsEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.fruit.service;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.fruit.entity.FruitGoodsEntity;
|
||||||
|
|
||||||
|
public interface FruitGoodsService extends BaseService<FruitGoodsEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cool.modules.fruit.service.impl;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.modules.fruit.entity.FruitGoodsEntity;
|
||||||
|
import com.cool.modules.fruit.mapper.FruitGoodsMapper;
|
||||||
|
import com.cool.modules.fruit.service.FruitGoodsService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FruitGoodsServiceImpl extends BaseServiceImpl<FruitGoodsMapper, FruitGoodsEntity> implements
|
||||||
|
FruitGoodsService {
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.cool.modules.order.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.modules.order.entity.OrderInfoEntity;
|
||||||
|
import com.cool.modules.order.service.OrderInfoService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "订单管理", description = "订单信息管理")
|
||||||
|
@CoolRestController(api = {"delete", "update", "page", "info"}, cname = "orderInfo")
|
||||||
|
public class AdminOrderInfoController extends BaseController<OrderInfoService, OrderInfoEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.cool.modules.order.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.order.entity.OrderInfoEntity;
|
||||||
|
import com.cool.modules.order.service.OrderInfoService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "订单", description = "App端订单")
|
||||||
|
@CoolRestController
|
||||||
|
public class AppOrderInfoController {
|
||||||
|
|
||||||
|
private final OrderInfoService orderInfoService;
|
||||||
|
|
||||||
|
@Operation(summary = "订单列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public R list(@RequestAttribute JSONObject requestParams) {
|
||||||
|
return R.ok(orderInfoService.list(requestParams, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "订单详情")
|
||||||
|
@GetMapping("/detail")
|
||||||
|
public R detail(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
return R.ok(orderInfoService.info(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.cool.modules.order.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "order_info", comment = "订单信息表")
|
||||||
|
public class OrderInfoEntity extends TenantEntity<OrderInfoEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "订单号", notNull = true)
|
||||||
|
private String orderNo;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "用户ID", type = "bigint")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "订单金额")
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:待支付 1:已支付 2:已完成 3:已取消", defaultValue = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "备注", type = "text")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.order.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.order.entity.OrderInfoEntity;
|
||||||
|
|
||||||
|
public interface OrderInfoMapper extends BaseMapper<OrderInfoEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.order.service;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.order.entity.OrderInfoEntity;
|
||||||
|
|
||||||
|
public interface OrderInfoService extends BaseService<OrderInfoEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cool.modules.order.service.impl;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.modules.order.entity.OrderInfoEntity;
|
||||||
|
import com.cool.modules.order.mapper.OrderInfoMapper;
|
||||||
|
import com.cool.modules.order.service.OrderInfoService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class OrderInfoServiceImpl extends BaseServiceImpl<OrderInfoMapper, OrderInfoEntity> implements
|
||||||
|
OrderInfoService {
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.cool.modules.org.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.org.entity.AppModuleEntity;
|
||||||
|
import com.cool.modules.org.service.AppModuleService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "模块市场", description = "功能模块管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"}, value = "/admin/module")
|
||||||
|
public class AdminAppModuleController extends BaseController<AppModuleService, AppModuleEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.cool.modules.org.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.org.entity.AppOrgEntity;
|
||||||
|
import com.cool.modules.org.entity.AppOrgUserEntity;
|
||||||
|
import com.cool.modules.org.service.AppOrgService;
|
||||||
|
import com.cool.modules.org.service.AppOrgUserService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "组织管理", description = "组织管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"}, value = "/admin/org")
|
||||||
|
public class AdminAppOrgController extends BaseController<AppOrgService, AppOrgEntity> {
|
||||||
|
|
||||||
|
private final AppOrgService appOrgService;
|
||||||
|
private final AppOrgUserService appOrgUserService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(
|
||||||
|
createOp().transformValue(obj -> {
|
||||||
|
if (obj instanceof AppOrgEntity entity) {
|
||||||
|
long count = appOrgUserService.count(
|
||||||
|
QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getOrgId, entity.getId())
|
||||||
|
.eq(AppOrgUserEntity::getStatus, 1)
|
||||||
|
);
|
||||||
|
entity.setMemberCount(count);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "创建组织")
|
||||||
|
@PostMapping("/add")
|
||||||
|
public R add(@RequestBody JSONObject requestParams) {
|
||||||
|
AppOrgEntity entity = requestParams.toBean(AppOrgEntity.class);
|
||||||
|
appOrgService.createOrg(requestParams, entity);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "授权模块")
|
||||||
|
@PostMapping("/authorizeModules")
|
||||||
|
public R authorizeModules(@RequestBody JSONObject requestParams) {
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
List<String> moduleKeys = requestParams.getBeanList("moduleKeys", String.class);
|
||||||
|
appOrgService.authorizeModules(orgId, moduleKeys);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "切换组织")
|
||||||
|
@PostMapping("/switch")
|
||||||
|
public R switchOrg(@RequestBody JSONObject requestParams) {
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
Long userId = com.cool.core.util.CoolSecurityUtil.getCurrentUserId();
|
||||||
|
return R.ok(appOrgService.switchOrg(userId, orgId, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "获取可切换的组织列表")
|
||||||
|
@PostMapping("/listForSwitch")
|
||||||
|
public R listForSwitch() {
|
||||||
|
Long userId = com.cool.core.util.CoolSecurityUtil.getCurrentUserId();
|
||||||
|
return R.ok(appOrgService.listForSwitch(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.cool.modules.org.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.modules.org.entity.AppOrgModuleEntity;
|
||||||
|
import com.cool.modules.org.service.AppOrgModuleService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "组织模块授权", description = "组织模块授权管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "list"}, value = "/admin/org/module")
|
||||||
|
public class AdminAppOrgModuleController extends BaseController<AppOrgModuleService, AppOrgModuleEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setListOption(createOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.cool.modules.org.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.org.entity.AppOrgUserEntity;
|
||||||
|
import com.cool.modules.org.service.AppOrgUserService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "组织成员管理", description = "组织成员管理")
|
||||||
|
@CoolRestController(api = {"page", "list", "update", "delete"}, value = "/admin/org/user")
|
||||||
|
public class AdminAppOrgUserController extends BaseController<AppOrgUserService, AppOrgUserEntity> {
|
||||||
|
|
||||||
|
private final AppOrgUserService appOrgUserService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "获取组织成员列表(分页)")
|
||||||
|
@PostMapping("/memberList")
|
||||||
|
public R memberList(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
String orgName = requestParams.getStr("orgName");
|
||||||
|
Integer page = requestParams.getInt("page");
|
||||||
|
Integer size = requestParams.getInt("size");
|
||||||
|
Map<String, Object> result = appOrgUserService.getMemberList(orgId, orgName, page, size);
|
||||||
|
return R.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "提升/降级App端管理员")
|
||||||
|
@PostMapping("/changeRole")
|
||||||
|
public R changeRole(@RequestBody JSONObject requestParams) {
|
||||||
|
Long orgUserId = requestParams.getLong("id");
|
||||||
|
String role = requestParams.getStr("role");
|
||||||
|
AppOrgUserEntity orgUser = appOrgUserService.getById(orgUserId);
|
||||||
|
com.cool.core.exception.CoolPreconditions.checkEmpty(orgUser, "记录不存在");
|
||||||
|
orgUser.setRole(role);
|
||||||
|
appOrgUserService.update(orgUser);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.cool.modules.org.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
|
import com.cool.modules.org.service.AppOrgService;
|
||||||
|
import com.cool.modules.org.service.AppOrgUserService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "组织", description = "App端组织管理")
|
||||||
|
@CoolRestController
|
||||||
|
public class AppOrgController {
|
||||||
|
|
||||||
|
private final AppOrgService appOrgService;
|
||||||
|
private final AppOrgUserService appOrgUserService;
|
||||||
|
|
||||||
|
@Operation(summary = "获取已加入的组织列表")
|
||||||
|
@GetMapping("/orgList")
|
||||||
|
public R list() {
|
||||||
|
Long userId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
List<Map<String, Object>> orgList = appOrgUserService.getOrgListByUserId(userId);
|
||||||
|
return R.ok(orgList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "通过邀请码加入组织")
|
||||||
|
@PostMapping("/join")
|
||||||
|
public R join(@RequestBody JSONObject requestParams) {
|
||||||
|
Long userId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
String inviteCode = requestParams.getStr("inviteCode");
|
||||||
|
appOrgUserService.joinOrg(userId, inviteCode);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "通过orgId加入组织")
|
||||||
|
@PostMapping("/joinById")
|
||||||
|
public R joinById(@RequestBody JSONObject requestParams) {
|
||||||
|
Long userId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
appOrgUserService.joinOrgById(userId, orgId);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "退出组织")
|
||||||
|
@PostMapping("/quit")
|
||||||
|
public R quit(@RequestBody JSONObject requestParams) {
|
||||||
|
Long userId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
appOrgUserService.quitOrg(userId, orgId);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "切换组织")
|
||||||
|
@PostMapping("/switch")
|
||||||
|
public R switchOrg(@RequestBody JSONObject requestParams) {
|
||||||
|
Long userId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
Object result = appOrgService.switchOrg(userId, orgId, false);
|
||||||
|
return R.ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.cool.modules.org.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.exception.CoolPreconditions;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
|
import com.cool.modules.org.service.AppOrgUserService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "组织成员", description = "App端组织成员管理")
|
||||||
|
@CoolRestController
|
||||||
|
public class AppOrgUserController {
|
||||||
|
|
||||||
|
private final AppOrgUserService appOrgUserService;
|
||||||
|
|
||||||
|
@Operation(summary = "获取组织成员列表")
|
||||||
|
@PostMapping("/memberList")
|
||||||
|
public R memberList(@RequestBody JSONObject requestParams) {
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
Long userId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
CoolPreconditions.check(!appOrgUserService.isOrgMember(userId, orgId), "无权查看该组织成员");
|
||||||
|
Map<String, Object> members = appOrgUserService.getMemberList(orgId, null, null);
|
||||||
|
return R.ok(members);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "审批成员加入")
|
||||||
|
@PostMapping("/approve")
|
||||||
|
public R approve(@RequestBody JSONObject requestParams) {
|
||||||
|
Long orgId = requestParams.getLong("orgId");
|
||||||
|
Long targetUserId = requestParams.getLong("userId");
|
||||||
|
Boolean approved = requestParams.getBool("approved", true);
|
||||||
|
Long adminUserId = CoolSecurityUtil.getCurrentUserId();
|
||||||
|
appOrgUserService.approve(adminUserId, orgId, targetUserId, approved);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.cool.modules.org.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "app_module", comment = "功能模块注册表")
|
||||||
|
public class AppModuleEntity extends BaseEntity<AppModuleEntity> {
|
||||||
|
|
||||||
|
@UniIndex
|
||||||
|
@ColumnDefine(comment = "模块标识", notNull = true)
|
||||||
|
private String moduleKey;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "模块名称", notNull = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "模块图标")
|
||||||
|
private String icon;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "模块描述", type = "text")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "关联的admin菜单ID列表", type = "text")
|
||||||
|
private String menuIds;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "关联的App页面路由配置", type = "text")
|
||||||
|
private String appPages;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "要求的最低App版本号")
|
||||||
|
private String minAppVersion;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.cool.modules.org.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Table(value = "app_org", comment = "组织表")
|
||||||
|
public class AppOrgEntity extends BaseEntity<AppOrgEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "组织名称", notNull = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "组织类型")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "组织图标/Logo")
|
||||||
|
private String icon;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "组织简介", type = "text")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@UniIndex
|
||||||
|
@ColumnDefine(comment = "邀请码")
|
||||||
|
private String inviteCode;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "加入方式 0:自由加入 1:需审批", defaultValue = "0")
|
||||||
|
private Integer joinType;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "Admin端组织管理员userId", type = "bigint")
|
||||||
|
private Long adminUserId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "组织级扩展配置", type = "text")
|
||||||
|
private String config;
|
||||||
|
|
||||||
|
@Column(ignore = true)
|
||||||
|
private Long memberCount;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.cool.modules.org.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.dromara.autotable.annotation.Index;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "app_org_module", comment = "组织模块关联表")
|
||||||
|
public class AppOrgModuleEntity extends BaseEntity<AppOrgModuleEntity> {
|
||||||
|
|
||||||
|
@Index
|
||||||
|
@ColumnDefine(comment = "组织ID", type = "bigint", notNull = true)
|
||||||
|
private Long orgId;
|
||||||
|
|
||||||
|
@Index
|
||||||
|
@ColumnDefine(comment = "模块标识", notNull = true)
|
||||||
|
private String moduleKey;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "组织级模块配置", type = "text")
|
||||||
|
private String config;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "排序号", type = "int", defaultValue = "0")
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.cool.modules.org.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseEntity;
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.dromara.autotable.annotation.Index;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "app_org_user", comment = "组织用户关联表")
|
||||||
|
public class AppOrgUserEntity extends BaseEntity<AppOrgUserEntity> {
|
||||||
|
|
||||||
|
@Index
|
||||||
|
@ColumnDefine(comment = "组织ID", type = "bigint", notNull = true)
|
||||||
|
private Long orgId;
|
||||||
|
|
||||||
|
@Index
|
||||||
|
@ColumnDefine(comment = "App用户ID", type = "bigint", notNull = true)
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "角色 member/admin", defaultValue = "member")
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:待审批 1:已加入 2:已拒绝 3:已退出", defaultValue = "0")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "加入时间")
|
||||||
|
private Date joinTime;
|
||||||
|
|
||||||
|
@Column(ignore = true)
|
||||||
|
private String orgName;
|
||||||
|
|
||||||
|
@Column(ignore = true)
|
||||||
|
private String nickName;
|
||||||
|
|
||||||
|
@Column(ignore = true)
|
||||||
|
private String avatarUrl;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.org.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.org.entity.AppModuleEntity;
|
||||||
|
|
||||||
|
public interface AppModuleMapper extends BaseMapper<AppModuleEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.org.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.org.entity.AppOrgEntity;
|
||||||
|
|
||||||
|
public interface AppOrgMapper extends BaseMapper<AppOrgEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.org.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.org.entity.AppOrgModuleEntity;
|
||||||
|
|
||||||
|
public interface AppOrgModuleMapper extends BaseMapper<AppOrgModuleEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.org.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.cool.modules.org.entity.AppOrgUserEntity;
|
||||||
|
|
||||||
|
public interface AppOrgUserMapper extends BaseMapper<AppOrgUserEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.cool.modules.org.service;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.org.entity.AppModuleEntity;
|
||||||
|
|
||||||
|
public interface AppModuleService extends BaseService<AppModuleEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cool.modules.org.service;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.org.entity.AppOrgModuleEntity;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AppOrgModuleService extends BaseService<AppOrgModuleEntity> {
|
||||||
|
|
||||||
|
List<String> getModuleKeysByOrgId(Long orgId);
|
||||||
|
|
||||||
|
boolean isModuleAuthorized(Long orgId, String moduleKey);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.cool.modules.org.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.org.entity.AppOrgEntity;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AppOrgService extends BaseService<AppOrgEntity> {
|
||||||
|
|
||||||
|
void createOrg(JSONObject requestParams, AppOrgEntity entity);
|
||||||
|
|
||||||
|
void authorizeModules(Long orgId, List<String> moduleKeys);
|
||||||
|
|
||||||
|
Dict switchOrg(Long userId, Long orgId, boolean isAdmin);
|
||||||
|
|
||||||
|
List<AppOrgEntity> listForSwitch(Long userId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.cool.modules.org.service;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseService;
|
||||||
|
import com.cool.modules.org.entity.AppOrgUserEntity;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface AppOrgUserService extends BaseService<AppOrgUserEntity> {
|
||||||
|
|
||||||
|
void joinOrg(Long userId, String inviteCode);
|
||||||
|
|
||||||
|
void joinOrgById(Long userId, Long orgId);
|
||||||
|
|
||||||
|
void quitOrg(Long userId, Long orgId);
|
||||||
|
|
||||||
|
void approve(Long adminUserId, Long orgId, Long targetUserId, boolean approved);
|
||||||
|
|
||||||
|
List<Map<String, Object>> getOrgListByUserId(Long userId);
|
||||||
|
|
||||||
|
Map<String, Object> getMemberList(Long orgId, Integer page, Integer size);
|
||||||
|
|
||||||
|
Map<String, Object> getMemberList(Long orgId, String orgName, Integer page, Integer size);
|
||||||
|
|
||||||
|
boolean isOrgAdmin(Long userId, Long orgId);
|
||||||
|
|
||||||
|
boolean isOrgMember(Long userId, Long orgId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package com.cool.modules.org.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ClassUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.core.base.ModifyEnum;
|
||||||
|
import com.cool.core.util.CoolSecurityUtil;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysMenuMapper;
|
||||||
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
|
import com.cool.modules.org.mapper.AppModuleMapper;
|
||||||
|
import com.cool.modules.org.entity.AppModuleEntity;
|
||||||
|
import com.cool.modules.org.service.AppModuleService;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppModuleServiceImpl extends BaseServiceImpl<AppModuleMapper, AppModuleEntity> implements
|
||||||
|
AppModuleService {
|
||||||
|
|
||||||
|
private final BaseSysMenuMapper baseSysMenuMapper;
|
||||||
|
private final BaseSysPermsService baseSysPermsService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifyAfter(JSONObject requestParams, AppModuleEntity entity, ModifyEnum type) {
|
||||||
|
if (type == ModifyEnum.ADD) {
|
||||||
|
createMenusForModule(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createMenusForModule(AppModuleEntity module) {
|
||||||
|
String moduleKey = module.getModuleKey();
|
||||||
|
if (StrUtil.isBlank(moduleKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String basePackage = "com.cool.modules." + moduleKey + ".controller.admin";
|
||||||
|
Set<Class<?>> controllerClasses = ClassUtil.scanPackageBySuper(basePackage, Object.class);
|
||||||
|
|
||||||
|
if (controllerClasses.isEmpty()) {
|
||||||
|
log.info("[AppModuleService] 未找到模块 {} 的Admin Controller,跳过菜单创建", moduleKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseSysMenuEntity dirMenu = new BaseSysMenuEntity();
|
||||||
|
dirMenu.setName(module.getName());
|
||||||
|
dirMenu.setType(0);
|
||||||
|
dirMenu.setIcon(module.getIcon());
|
||||||
|
dirMenu.setRouter("/" + moduleKey);
|
||||||
|
dirMenu.setOrderNum(0);
|
||||||
|
dirMenu.setKeepAlive(true);
|
||||||
|
dirMenu.setIsShow(true);
|
||||||
|
baseSysMenuMapper.insertSelective(dirMenu);
|
||||||
|
|
||||||
|
List<Long> menuIds = new ArrayList<>();
|
||||||
|
menuIds.add(dirMenu.getId());
|
||||||
|
|
||||||
|
for (Class<?> controllerClass : controllerClasses) {
|
||||||
|
String controllerName = controllerClass.getSimpleName();
|
||||||
|
if (!controllerName.startsWith("Admin")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String entityPath = resolveEntityPath(controllerName, moduleKey);
|
||||||
|
String menuName = resolveMenuName(controllerClass, entityPath);
|
||||||
|
|
||||||
|
BaseSysMenuEntity pageMenu = new BaseSysMenuEntity();
|
||||||
|
pageMenu.setName(menuName);
|
||||||
|
pageMenu.setType(1);
|
||||||
|
pageMenu.setRouter("/" + moduleKey + "/" + entityPath);
|
||||||
|
pageMenu.setViewPath(moduleKey + "/" + entityPath + "/list.vue");
|
||||||
|
pageMenu.setParentId(dirMenu.getId());
|
||||||
|
pageMenu.setOrderNum(0);
|
||||||
|
pageMenu.setKeepAlive(true);
|
||||||
|
pageMenu.setIsShow(true);
|
||||||
|
baseSysMenuMapper.insertSelective(pageMenu);
|
||||||
|
|
||||||
|
menuIds.add(pageMenu.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
module.setMenuIds(new cn.hutool.json.JSONArray(menuIds).toString());
|
||||||
|
this.update(module);
|
||||||
|
|
||||||
|
baseSysPermsService.refreshPermsByMenuId(null);
|
||||||
|
|
||||||
|
log.info("[AppModuleService] 模块 {} 自动创建菜单完成,menuIds={}", moduleKey, menuIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveEntityPath(String controllerName, String moduleKey) {
|
||||||
|
String name = controllerName;
|
||||||
|
if (name.startsWith("Admin")) {
|
||||||
|
name = name.substring(5);
|
||||||
|
}
|
||||||
|
if (name.endsWith("Controller")) {
|
||||||
|
name = name.substring(0, name.length() - 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
String modulePrefix = StrUtil.upperFirst(moduleKey);
|
||||||
|
if (name.startsWith(modulePrefix)) {
|
||||||
|
name = name.substring(modulePrefix.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
return StrUtil.toCamelCase(name).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveMenuName(Class<?> controllerClass, String entityPath) {
|
||||||
|
io.swagger.v3.oas.annotations.tags.Tag tag =
|
||||||
|
AnnotatedElementUtils.findMergedAnnotation(controllerClass, io.swagger.v3.oas.annotations.tags.Tag.class);
|
||||||
|
if (tag != null && StrUtil.isNotBlank(tag.name())) {
|
||||||
|
return tag.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
java.lang.reflect.ParameterizedType pt =
|
||||||
|
(java.lang.reflect.ParameterizedType) controllerClass.getGenericSuperclass();
|
||||||
|
Class<?> entityClass = (Class<?>) pt.getActualTypeArguments()[1];
|
||||||
|
Table tableAnno = AnnotatedElementUtils.findMergedAnnotation(entityClass, Table.class);
|
||||||
|
if (tableAnno != null && StrUtil.isNotBlank(tableAnno.comment())) {
|
||||||
|
return tableAnno.comment().replace("表", "");
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
return entityPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.cool.modules.org.service.impl;
|
||||||
|
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.modules.org.entity.AppOrgModuleEntity;
|
||||||
|
import com.cool.modules.org.mapper.AppOrgModuleMapper;
|
||||||
|
import com.cool.modules.org.service.AppOrgModuleService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AppOrgModuleServiceImpl extends BaseServiceImpl<AppOrgModuleMapper, AppOrgModuleEntity> implements
|
||||||
|
AppOrgModuleService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getModuleKeysByOrgId(Long orgId) {
|
||||||
|
List<AppOrgModuleEntity> modules = list(QueryWrapper.create()
|
||||||
|
.eq(AppOrgModuleEntity::getOrgId, orgId)
|
||||||
|
.eq(AppOrgModuleEntity::getStatus, 1)
|
||||||
|
.orderBy(AppOrgModuleEntity::getSortOrder, true));
|
||||||
|
return modules.stream()
|
||||||
|
.map(AppOrgModuleEntity::getModuleKey)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isModuleAuthorized(Long orgId, String moduleKey) {
|
||||||
|
AppOrgModuleEntity module = getOne(QueryWrapper.create()
|
||||||
|
.eq(AppOrgModuleEntity::getOrgId, orgId)
|
||||||
|
.eq(AppOrgModuleEntity::getModuleKey, moduleKey)
|
||||||
|
.eq(AppOrgModuleEntity::getStatus, 1));
|
||||||
|
return module != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
package com.cool.modules.org.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.core.cache.CoolCache;
|
||||||
|
import com.cool.core.enums.UserTypeEnum;
|
||||||
|
import com.cool.core.base.ModifyEnum;
|
||||||
|
import com.cool.core.exception.CoolPreconditions;
|
||||||
|
import com.cool.core.security.jwt.JwtTokenUtil;
|
||||||
|
import com.cool.core.security.jwt.JwtUser;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
|
||||||
|
import com.cool.modules.base.entity.sys.BaseSysUserRoleEntity;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysRoleMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
|
||||||
|
import com.cool.modules.base.mapper.sys.BaseSysUserRoleMapper;
|
||||||
|
import com.cool.modules.base.service.sys.BaseSysPermsService;
|
||||||
|
import com.cool.modules.org.entity.AppModuleEntity;
|
||||||
|
import com.cool.modules.org.entity.AppOrgEntity;
|
||||||
|
import com.cool.modules.org.entity.AppOrgModuleEntity;
|
||||||
|
import com.cool.modules.org.mapper.AppOrgMapper;
|
||||||
|
import com.cool.modules.org.mapper.AppModuleMapper;
|
||||||
|
import com.cool.modules.org.service.AppOrgModuleService;
|
||||||
|
import com.cool.modules.org.service.AppOrgService;
|
||||||
|
import com.cool.modules.org.service.AppOrgUserService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import com.mybatisflex.core.tenant.TenantManager;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppOrgServiceImpl extends BaseServiceImpl<AppOrgMapper, AppOrgEntity> implements
|
||||||
|
AppOrgService {
|
||||||
|
|
||||||
|
private final AppModuleMapper appModuleMapper;
|
||||||
|
private final BaseSysRoleMapper baseSysRoleMapper;
|
||||||
|
private final BaseSysUserRoleMapper baseSysUserRoleMapper;
|
||||||
|
private final BaseSysUserMapper baseSysUserMapper;
|
||||||
|
private final BaseSysPermsService baseSysPermsService;
|
||||||
|
private final AppOrgModuleService appOrgModuleService;
|
||||||
|
private final AppOrgUserService appOrgUserService;
|
||||||
|
private final CoolCache coolCache;
|
||||||
|
private final JwtTokenUtil jwtTokenUtil;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void modifyAfter(JSONObject requestParams, AppOrgEntity entity, ModifyEnum type) {
|
||||||
|
if (type == ModifyEnum.UPDATE && requestParams != null && requestParams.containsKey("moduleKeys")) {
|
||||||
|
List<String> moduleKeys = requestParams.getBeanList("moduleKeys", String.class);
|
||||||
|
if (moduleKeys != null) {
|
||||||
|
authorizeModules(entity.getId(), moduleKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void createOrg(JSONObject requestParams, AppOrgEntity entity) {
|
||||||
|
entity.setInviteCode(generateInviteCode());
|
||||||
|
this.add(entity);
|
||||||
|
|
||||||
|
Long orgId = entity.getId();
|
||||||
|
|
||||||
|
Long currentUserId = com.cool.core.util.CoolSecurityUtil.getCurrentUserId();
|
||||||
|
BaseSysRoleEntity role = new BaseSysRoleEntity();
|
||||||
|
role.setUserId(currentUserId);
|
||||||
|
role.setName(entity.getName() + "管理员");
|
||||||
|
role.setLabel("org_admin_" + orgId);
|
||||||
|
role.setRemark("组织[" + entity.getName() + "]自动创建的管理角色");
|
||||||
|
role.setStatus(1);
|
||||||
|
role.setTenantId(orgId);
|
||||||
|
TenantManager.withoutTenantCondition(() -> {
|
||||||
|
baseSysRoleMapper.insertSelective(role);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (entity.getAdminUserId() != null) {
|
||||||
|
BaseSysUserRoleEntity userRole = new BaseSysUserRoleEntity();
|
||||||
|
userRole.setUserId(entity.getAdminUserId());
|
||||||
|
userRole.setRoleId(role.getId());
|
||||||
|
TenantManager.withoutTenantCondition(() -> {
|
||||||
|
baseSysUserRoleMapper.insertSelective(userRole);
|
||||||
|
});
|
||||||
|
|
||||||
|
com.cool.modules.base.entity.sys.BaseSysUserEntity adminUser = baseSysUserMapper.selectOneById(entity.getAdminUserId());
|
||||||
|
if (adminUser != null) {
|
||||||
|
adminUser.setTenantId(orgId);
|
||||||
|
TenantManager.withoutTenantCondition(() -> {
|
||||||
|
baseSysUserMapper.update(adminUser);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParams != null) {
|
||||||
|
List<String> moduleKeys = requestParams.getBeanList("moduleKeys", String.class);
|
||||||
|
if (moduleKeys != null && !moduleKeys.isEmpty()) {
|
||||||
|
authorizeModules(orgId, moduleKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void authorizeModules(Long orgId, List<String> moduleKeys) {
|
||||||
|
QueryWrapper qw = QueryWrapper.create()
|
||||||
|
.eq(AppOrgModuleEntity::getOrgId, orgId);
|
||||||
|
appOrgModuleService.remove(qw);
|
||||||
|
|
||||||
|
for (int i = 0; i < moduleKeys.size(); i++) {
|
||||||
|
String moduleKey = moduleKeys.get(i);
|
||||||
|
AppModuleEntity module = appModuleMapper.selectOneByQuery(
|
||||||
|
QueryWrapper.create().eq(AppModuleEntity::getModuleKey, moduleKey)
|
||||||
|
);
|
||||||
|
CoolPreconditions.checkEmpty(module, "模块{}不存在", moduleKey);
|
||||||
|
|
||||||
|
AppOrgModuleEntity orgModule = new AppOrgModuleEntity();
|
||||||
|
orgModule.setOrgId(orgId);
|
||||||
|
orgModule.setModuleKey(moduleKey);
|
||||||
|
orgModule.setSortOrder(i);
|
||||||
|
orgModule.setStatus(1);
|
||||||
|
appOrgModuleService.add(orgModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseSysRoleEntity role = TenantManager.withoutTenantCondition(() ->
|
||||||
|
baseSysRoleMapper.selectOneByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysRoleEntity::getLabel, "org_admin_" + orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (role != null) {
|
||||||
|
List<Long> menuIds = new java.util.ArrayList<>();
|
||||||
|
for (String moduleKey : moduleKeys) {
|
||||||
|
AppModuleEntity module = appModuleMapper.selectOneByQuery(
|
||||||
|
QueryWrapper.create().eq(AppModuleEntity::getModuleKey, moduleKey)
|
||||||
|
);
|
||||||
|
if (module != null && StrUtil.isNotBlank(module.getMenuIds())) {
|
||||||
|
cn.hutool.json.JSONArray arr = new cn.hutool.json.JSONArray(module.getMenuIds());
|
||||||
|
for (Object o : arr) {
|
||||||
|
menuIds.add(Long.valueOf(o.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
baseSysPermsService.updatePerms(role.getId(), menuIds.toArray(new Long[0]), new Long[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dict switchOrg(Long userId, Long orgId, boolean isAdmin) {
|
||||||
|
if (isAdmin) {
|
||||||
|
if (com.cool.core.util.CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
// 超管可切换到任意组织
|
||||||
|
} else {
|
||||||
|
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper.selectListByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId)
|
||||||
|
);
|
||||||
|
boolean hasAccess = false;
|
||||||
|
for (BaseSysUserRoleEntity ur : userRoles) {
|
||||||
|
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(ur.getRoleId());
|
||||||
|
if (role != null && orgId.equals(role.getTenantId())) {
|
||||||
|
hasAccess = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CoolPreconditions.check(!hasAccess, "无权切换到该组织");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CoolPreconditions.check(!appOrgUserService.isOrgMember(userId, orgId), "未加入该组织");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppOrgEntity org = this.getById(orgId);
|
||||||
|
CoolPreconditions.checkEmpty(org, "组织不存在");
|
||||||
|
CoolPreconditions.check(org.getStatus() == 0, "组织已停用");
|
||||||
|
|
||||||
|
if (isAdmin) {
|
||||||
|
com.cool.modules.base.entity.sys.BaseSysUserEntity adminUser = baseSysUserMapper.selectOneById(userId);
|
||||||
|
CoolPreconditions.checkEmpty(adminUser, "用户不存在");
|
||||||
|
|
||||||
|
Dict tokenInfo = Dict.create()
|
||||||
|
.set("userType", UserTypeEnum.ADMIN.name())
|
||||||
|
.set("userId", userId)
|
||||||
|
.set("username", adminUser.getUsername())
|
||||||
|
.set("tenantId", orgId);
|
||||||
|
String token = jwtTokenUtil.generateToken(tokenInfo);
|
||||||
|
String refreshToken = jwtTokenUtil.generateRefreshToken(tokenInfo);
|
||||||
|
|
||||||
|
Long[] roleIds = baseSysPermsService.getRoles(userId);
|
||||||
|
List<org.springframework.security.core.GrantedAuthority> authorities = new java.util.ArrayList<>();
|
||||||
|
if (roleIds != null) {
|
||||||
|
for (Long rid : roleIds) {
|
||||||
|
authorities.add(new SimpleGrantedAuthority("ROLE_" + rid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JwtUser jwtUser = new JwtUser(userId, adminUser.getUsername(), adminUser.getPassword(),
|
||||||
|
authorities,
|
||||||
|
true);
|
||||||
|
coolCache.set("admin:userDetails:" + adminUser.getUsername(), jwtUser);
|
||||||
|
|
||||||
|
return Dict.create()
|
||||||
|
.set("token", token)
|
||||||
|
.set("expire", jwtTokenUtil.getExpire())
|
||||||
|
.set("refreshToken", refreshToken)
|
||||||
|
.set("refreshExpire", jwtTokenUtil.getRefreshExpire())
|
||||||
|
.set("orgId", orgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict tokenInfo = Dict.create()
|
||||||
|
.set("userType", UserTypeEnum.APP.name())
|
||||||
|
.set("userId", userId)
|
||||||
|
.set("orgId", orgId);
|
||||||
|
String token = jwtTokenUtil.generateToken(tokenInfo);
|
||||||
|
String refreshToken = jwtTokenUtil.generateRefreshToken(tokenInfo);
|
||||||
|
|
||||||
|
JwtUser jwtUser = new JwtUser(userId,
|
||||||
|
List.of(new SimpleGrantedAuthority("ROLE_" + UserTypeEnum.APP.name())),
|
||||||
|
true);
|
||||||
|
coolCache.set("app:userDetails:" + userId, jwtUser);
|
||||||
|
|
||||||
|
return Dict.create()
|
||||||
|
.set("token", token)
|
||||||
|
.set("expire", jwtTokenUtil.getExpire())
|
||||||
|
.set("refreshToken", refreshToken)
|
||||||
|
.set("refreshExpire", jwtTokenUtil.getRefreshExpire())
|
||||||
|
.set("orgId", orgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AppOrgEntity> listForSwitch(Long userId) {
|
||||||
|
if (com.cool.core.util.CoolSecurityUtil.isSuperAdmin()) {
|
||||||
|
return this.list(QueryWrapper.create()
|
||||||
|
.eq(AppOrgEntity::getStatus, 1)
|
||||||
|
.orderBy(AppOrgEntity::getId, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper.selectListByQuery(
|
||||||
|
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId)
|
||||||
|
);
|
||||||
|
List<Long> orgIds = new java.util.ArrayList<>();
|
||||||
|
for (BaseSysUserRoleEntity ur : userRoles) {
|
||||||
|
BaseSysRoleEntity role = baseSysRoleMapper.selectOneById(ur.getRoleId());
|
||||||
|
if (role != null && role.getTenantId() != null && role.getStatus() != 0) {
|
||||||
|
orgIds.add(role.getTenantId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (orgIds.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return this.list(QueryWrapper.create()
|
||||||
|
.in(AppOrgEntity::getId, orgIds)
|
||||||
|
.eq(AppOrgEntity::getStatus, 1)
|
||||||
|
.orderBy(AppOrgEntity::getId, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateInviteCode() {
|
||||||
|
String code;
|
||||||
|
do {
|
||||||
|
code = RandomUtil.randomStringUpper(6);
|
||||||
|
} while (this.getOne(
|
||||||
|
QueryWrapper.create().eq(AppOrgEntity::getInviteCode, code)
|
||||||
|
) != null);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
package com.cool.modules.org.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.cool.core.base.BaseServiceImpl;
|
||||||
|
import com.cool.core.exception.CoolPreconditions;
|
||||||
|
import com.cool.modules.org.entity.AppOrgEntity;
|
||||||
|
import com.cool.modules.org.entity.AppOrgModuleEntity;
|
||||||
|
import com.cool.modules.org.entity.AppOrgUserEntity;
|
||||||
|
import com.cool.modules.org.mapper.AppOrgMapper;
|
||||||
|
import com.cool.modules.org.mapper.AppOrgUserMapper;
|
||||||
|
import com.cool.modules.org.service.AppOrgModuleService;
|
||||||
|
import com.cool.modules.org.service.AppOrgUserService;
|
||||||
|
import com.cool.modules.user.entity.UserInfoEntity;
|
||||||
|
import com.cool.modules.user.mapper.UserInfoMapper;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppOrgUserServiceImpl extends BaseServiceImpl<AppOrgUserMapper, AppOrgUserEntity> implements
|
||||||
|
AppOrgUserService {
|
||||||
|
|
||||||
|
private final AppOrgModuleService appOrgModuleService;
|
||||||
|
private final UserInfoMapper userInfoMapper;
|
||||||
|
private final AppOrgMapper appOrgMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void joinOrg(Long userId, String inviteCode) {
|
||||||
|
CoolPreconditions.check(StrUtil.isBlank(inviteCode), "邀请码不能为空");
|
||||||
|
|
||||||
|
AppOrgEntity orgEntity = appOrgMapper.selectOneByQuery(
|
||||||
|
QueryWrapper.create().eq(AppOrgEntity::getInviteCode, inviteCode)
|
||||||
|
);
|
||||||
|
CoolPreconditions.checkEmpty(orgEntity, "邀请码无效");
|
||||||
|
CoolPreconditions.check(orgEntity.getStatus() == 0, "组织已停用");
|
||||||
|
|
||||||
|
joinOrgById(userId, orgEntity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void joinOrgById(Long userId, Long orgId) {
|
||||||
|
AppOrgUserEntity existing = getOne(QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getOrgId, orgId)
|
||||||
|
.eq(AppOrgUserEntity::getUserId, userId));
|
||||||
|
CoolPreconditions.check(existing != null && existing.getStatus() == 1, "已加入该组织");
|
||||||
|
CoolPreconditions.check(existing != null && existing.getStatus() == 0, "已申请加入,等待审批");
|
||||||
|
|
||||||
|
AppOrgEntity orgEntity = appOrgMapper.selectOneById(orgId);
|
||||||
|
CoolPreconditions.checkEmpty(orgEntity, "组织不存在");
|
||||||
|
CoolPreconditions.check(orgEntity.getStatus() == 0, "组织已停用");
|
||||||
|
|
||||||
|
AppOrgUserEntity orgUser = new AppOrgUserEntity();
|
||||||
|
orgUser.setOrgId(orgId);
|
||||||
|
orgUser.setUserId(userId);
|
||||||
|
orgUser.setRole("member");
|
||||||
|
|
||||||
|
if (orgEntity.getJoinType() == 0) {
|
||||||
|
orgUser.setStatus(1);
|
||||||
|
orgUser.setJoinTime(new java.util.Date());
|
||||||
|
} else {
|
||||||
|
orgUser.setStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
orgUser.setId(existing.getId());
|
||||||
|
this.update(orgUser);
|
||||||
|
} else {
|
||||||
|
this.add(orgUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void quitOrg(Long userId, Long orgId) {
|
||||||
|
AppOrgUserEntity orgUser = getOne(QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getOrgId, orgId)
|
||||||
|
.eq(AppOrgUserEntity::getUserId, userId)
|
||||||
|
.eq(AppOrgUserEntity::getStatus, 1));
|
||||||
|
CoolPreconditions.checkEmpty(orgUser, "未加入该组织");
|
||||||
|
|
||||||
|
orgUser.setStatus(3);
|
||||||
|
this.update(orgUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void approve(Long adminUserId, Long orgId, Long targetUserId, boolean approved) {
|
||||||
|
CoolPreconditions.check(!isOrgAdmin(adminUserId, orgId), "无审批权限");
|
||||||
|
|
||||||
|
AppOrgUserEntity orgUser = getOne(QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getOrgId, orgId)
|
||||||
|
.eq(AppOrgUserEntity::getUserId, targetUserId)
|
||||||
|
.eq(AppOrgUserEntity::getStatus, 0));
|
||||||
|
CoolPreconditions.checkEmpty(orgUser, "无待审批记录");
|
||||||
|
|
||||||
|
orgUser.setStatus(approved ? 1 : 2);
|
||||||
|
if (approved) {
|
||||||
|
orgUser.setJoinTime(new java.util.Date());
|
||||||
|
}
|
||||||
|
this.update(orgUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getOrgListByUserId(Long userId) {
|
||||||
|
List<AppOrgUserEntity> orgUsers = list(QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getUserId, userId)
|
||||||
|
.eq(AppOrgUserEntity::getStatus, 1));
|
||||||
|
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
for (AppOrgUserEntity ou : orgUsers) {
|
||||||
|
Map<String, Object> item = new HashMap<>();
|
||||||
|
item.put("orgId", ou.getOrgId());
|
||||||
|
item.put("role", ou.getRole());
|
||||||
|
item.put("joinTime", ou.getJoinTime());
|
||||||
|
|
||||||
|
AppOrgEntity org = appOrgMapper.selectOneById(ou.getOrgId());
|
||||||
|
if (org != null) {
|
||||||
|
item.put("name", org.getName());
|
||||||
|
item.put("icon", org.getIcon());
|
||||||
|
item.put("type", org.getType());
|
||||||
|
item.put("status", org.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get modules
|
||||||
|
List<String> moduleKeys = appOrgModuleService.getModuleKeysByOrgId(ou.getOrgId());
|
||||||
|
item.put("modules", moduleKeys);
|
||||||
|
|
||||||
|
result.add(item);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getMemberList(Long orgId, Integer page, Integer size) {
|
||||||
|
return getMemberList(orgId, null, page, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getMemberList(Long orgId, String orgName, Integer page, Integer size) {
|
||||||
|
int pageNum = (page != null && page > 0) ? page : 1;
|
||||||
|
int pageSize = (size != null && size > 0) ? size : 10;
|
||||||
|
|
||||||
|
QueryWrapper qw = QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getStatus, 1);
|
||||||
|
|
||||||
|
if (orgId != null) {
|
||||||
|
qw.eq(AppOrgUserEntity::getOrgId, orgId);
|
||||||
|
} else if (StrUtil.isNotBlank(orgName)) {
|
||||||
|
List<AppOrgEntity> orgs = appOrgMapper.selectListByQuery(
|
||||||
|
QueryWrapper.create().like(AppOrgEntity::getName, orgName)
|
||||||
|
);
|
||||||
|
if (!orgs.isEmpty()) {
|
||||||
|
List<Long> orgIds = orgs.stream().map(AppOrgEntity::getId).toList();
|
||||||
|
qw.in(AppOrgUserEntity::getOrgId, orgIds);
|
||||||
|
} else {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("list", new ArrayList<>());
|
||||||
|
result.put("pagination", Map.of("total", 0, "page", pageNum, "size", pageSize));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qw.orderBy(AppOrgUserEntity::getJoinTime, false);
|
||||||
|
|
||||||
|
com.mybatisflex.core.paginate.Page<AppOrgUserEntity> pg = page(
|
||||||
|
com.mybatisflex.core.paginate.Page.of(pageNum, pageSize), qw);
|
||||||
|
|
||||||
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
|
for (AppOrgUserEntity ou : pg.getRecords()) {
|
||||||
|
Map<String, Object> item = new HashMap<>();
|
||||||
|
item.put("id", ou.getId());
|
||||||
|
item.put("userId", ou.getUserId());
|
||||||
|
item.put("orgId", ou.getOrgId());
|
||||||
|
item.put("role", ou.getRole());
|
||||||
|
item.put("joinTime", ou.getJoinTime());
|
||||||
|
|
||||||
|
AppOrgEntity org = appOrgMapper.selectOneById(ou.getOrgId());
|
||||||
|
if (org != null) {
|
||||||
|
item.put("orgName", org.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInfoEntity user = userInfoMapper.selectOneById(ou.getUserId());
|
||||||
|
if (user != null) {
|
||||||
|
item.put("nickName", user.getNickName());
|
||||||
|
item.put("avatarUrl", user.getAvatarUrl());
|
||||||
|
item.put("phone", user.getPhone());
|
||||||
|
}
|
||||||
|
list.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("list", list);
|
||||||
|
result.put("pagination", Map.of("total", pg.getTotalRow(), "page", pageNum, "size", pageSize));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOrgAdmin(Long userId, Long orgId) {
|
||||||
|
AppOrgUserEntity orgUser = getOne(QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getOrgId, orgId)
|
||||||
|
.eq(AppOrgUserEntity::getUserId, userId)
|
||||||
|
.eq(AppOrgUserEntity::getStatus, 1)
|
||||||
|
.eq(AppOrgUserEntity::getRole, "admin"));
|
||||||
|
return orgUser != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOrgMember(Long userId, Long orgId) {
|
||||||
|
AppOrgUserEntity orgUser = getOne(QueryWrapper.create()
|
||||||
|
.eq(AppOrgUserEntity::getOrgId, orgId)
|
||||||
|
.eq(AppOrgUserEntity::getUserId, userId)
|
||||||
|
.eq(AppOrgUserEntity::getStatus, 1));
|
||||||
|
return orgUser != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.cool.modules.product.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品行为处理器接口
|
||||||
|
*/
|
||||||
|
public interface ActionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取行为编码
|
||||||
|
*/
|
||||||
|
String getCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取行为名称
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取行为描述
|
||||||
|
*/
|
||||||
|
String getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买时校验
|
||||||
|
*
|
||||||
|
* @param attrCode 属性编码
|
||||||
|
* @param attrValue 属性值
|
||||||
|
* @param quantity 购买数量
|
||||||
|
*/
|
||||||
|
void validate(String attrCode, String attrValue, int quantity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买成功后执行(如扣减库存)
|
||||||
|
*
|
||||||
|
* @param attrCode 属性编码
|
||||||
|
* @param attrValue 属性值
|
||||||
|
* @param quantity 购买数量
|
||||||
|
* @return 更新后的属性值
|
||||||
|
*/
|
||||||
|
default String afterPurchase(String attrCode, String attrValue, int quantity) {
|
||||||
|
return attrValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.cool.modules.product.action;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行为处理器注册中心
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ActionHandlerRegistry {
|
||||||
|
|
||||||
|
private final List<ActionHandler> handlers;
|
||||||
|
|
||||||
|
private Map<String, ActionHandler> handlerMap;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
handlerMap = handlers.stream()
|
||||||
|
.collect(Collectors.toMap(ActionHandler::getCode, Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionHandler getHandler(String actionCode) {
|
||||||
|
return handlerMap.get(actionCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasHandler(String actionCode) {
|
||||||
|
return handlerMap.containsKey(actionCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ActionHandler> getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.cool.modules.product.action;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期选择处理器(服务类商品预约时间)
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class DatePickHandler implements ActionHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCode() {
|
||||||
|
return "date_pick";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "日期选择";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "服务类商品购买时必须选择服务日期";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(String attrCode, String attrValue, int quantity) {
|
||||||
|
if (attrValue == null || attrValue.isEmpty()) {
|
||||||
|
throw new RuntimeException("请选择服务时间");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.cool.modules.product.action;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发货路由处理器(判断物流/线上交付)
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class DeliveryRouteHandler implements ActionHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCode() {
|
||||||
|
return "delivery_route";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "发货路由";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "购买时校验发货方式,决定走物流配送还是线上交付";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(String attrCode, String attrValue, int quantity) {
|
||||||
|
if (attrValue == null || attrValue.isEmpty()) {
|
||||||
|
throw new RuntimeException("请选择发货方式");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.cool.modules.product.action;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 库存校验处理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class StockCheckHandler implements ActionHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCode() {
|
||||||
|
return "stock_check";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "库存校验";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "购买时校验库存是否充足,购买后自动扣减库存";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate(String attrCode, String attrValue, int quantity) {
|
||||||
|
if (attrValue == null || attrValue.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int stock = Integer.parseInt(attrValue);
|
||||||
|
if (stock < quantity) {
|
||||||
|
throw new RuntimeException("库存不足,当前库存:" + stock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String afterPurchase(String attrCode, String attrValue, int quantity) {
|
||||||
|
if (attrValue == null || attrValue.isEmpty()) {
|
||||||
|
return attrValue;
|
||||||
|
}
|
||||||
|
int stock = Integer.parseInt(attrValue);
|
||||||
|
return String.valueOf(stock - quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
package com.cool.modules.product.controller.admin;
|
||||||
|
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.product.action.ActionHandler;
|
||||||
|
import com.cool.modules.product.action.ActionHandlerRegistry;
|
||||||
|
import com.cool.modules.product.entity.ProductActionEntity;
|
||||||
|
import com.cool.modules.product.service.ProductActionService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "商品行为管理", description = "商品行为管理")
|
||||||
|
@CoolRestController(api = {"list", "toggle"})
|
||||||
|
public class AdminProductActionController {
|
||||||
|
|
||||||
|
private final ActionHandlerRegistry actionHandlerRegistry;
|
||||||
|
|
||||||
|
private final ProductActionService productActionService;
|
||||||
|
|
||||||
|
@Operation(summary = "行为列表(自动从handler生成)")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public R list() {
|
||||||
|
List<ActionHandler> handlers = actionHandlerRegistry.getHandlers();
|
||||||
|
Set<String> disabledCodes = productActionService.list(
|
||||||
|
QueryWrapper.create().eq(ProductActionEntity::getStatus, 0)
|
||||||
|
).stream().map(ProductActionEntity::getCode).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
for (ActionHandler handler : handlers) {
|
||||||
|
Map<String, Object> item = new HashMap<>();
|
||||||
|
item.put("code", handler.getCode());
|
||||||
|
item.put("name", handler.getName());
|
||||||
|
item.put("description", handler.getDescription());
|
||||||
|
item.put("status", disabledCodes.contains(handler.getCode()) ? 0 : 1);
|
||||||
|
result.add(item);
|
||||||
|
}
|
||||||
|
return R.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "启用/禁用行为")
|
||||||
|
@PostMapping("/toggle")
|
||||||
|
public R toggle(@RequestBody Map<String, Object> body) {
|
||||||
|
String code = (String) body.get("code");
|
||||||
|
Integer status = (Integer) body.get("status");
|
||||||
|
|
||||||
|
ProductActionEntity existing = productActionService.getOne(
|
||||||
|
QueryWrapper.create().eq(ProductActionEntity::getCode, code)
|
||||||
|
);
|
||||||
|
if (status == 0) {
|
||||||
|
if (existing == null) {
|
||||||
|
ProductActionEntity entity = new ProductActionEntity();
|
||||||
|
entity.setCode(code);
|
||||||
|
entity.setName(code);
|
||||||
|
entity.setStatus(0);
|
||||||
|
productActionService.save(entity);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existing.setStatus(0);
|
||||||
|
productActionService.update(existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (existing != null) {
|
||||||
|
productActionService.removeById(existing.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.cool.modules.product.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.modules.product.entity.ProductAttributeEntity;
|
||||||
|
import com.cool.modules.product.service.ProductAttributeService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "商品属性管理", description = "商品属性管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"})
|
||||||
|
public class AdminProductAttributeController extends BaseController<ProductAttributeService, ProductAttributeEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.cool.modules.product.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.modules.product.entity.ProductGoodsEntity;
|
||||||
|
import com.cool.modules.product.service.ProductGoodsService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "商品管理", description = "商品管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"})
|
||||||
|
public class AdminProductGoodsController extends BaseController<ProductGoodsService, ProductGoodsEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.cool.modules.product.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.base.BaseController;
|
||||||
|
import com.cool.modules.product.entity.ProductGoodsSkuEntity;
|
||||||
|
import com.cool.modules.product.service.ProductGoodsSkuService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "商品SKU管理", description = "商品SKU管理")
|
||||||
|
@CoolRestController(api = {"add", "delete", "update", "page", "info"})
|
||||||
|
public class AdminProductGoodsSkuController extends BaseController<ProductGoodsSkuService, ProductGoodsSkuEntity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init(HttpServletRequest request, JSONObject requestParams) {
|
||||||
|
setPageOption(createOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cool.modules.product.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.product.entity.ProductActionEntity;
|
||||||
|
import com.cool.modules.product.service.ProductActionService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "商品行为", description = "App端商品行为")
|
||||||
|
@CoolRestController
|
||||||
|
public class AppProductActionController {
|
||||||
|
|
||||||
|
private final ProductActionService productActionService;
|
||||||
|
|
||||||
|
@Operation(summary = "行为列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public R list(@RequestAttribute JSONObject requestParams) {
|
||||||
|
return R.ok(productActionService.list(requestParams, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cool.modules.product.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.product.entity.ProductAttributeEntity;
|
||||||
|
import com.cool.modules.product.service.ProductAttributeService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "商品属性", description = "App端商品属性")
|
||||||
|
@CoolRestController
|
||||||
|
public class AppProductAttributeController {
|
||||||
|
|
||||||
|
private final ProductAttributeService productAttributeService;
|
||||||
|
|
||||||
|
@Operation(summary = "属性列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public R list(@RequestAttribute JSONObject requestParams) {
|
||||||
|
return R.ok(productAttributeService.list(requestParams, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.cool.modules.product.controller.app;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.cool.core.annotation.CoolRestController;
|
||||||
|
import com.cool.core.request.R;
|
||||||
|
import com.cool.modules.product.entity.ProductGoodsEntity;
|
||||||
|
import com.cool.modules.product.service.ProductGoodsService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "商品", description = "App端商品")
|
||||||
|
@CoolRestController
|
||||||
|
public class AppProductGoodsController {
|
||||||
|
|
||||||
|
private final ProductGoodsService productGoodsService;
|
||||||
|
|
||||||
|
@Operation(summary = "商品列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public R list(@RequestAttribute JSONObject requestParams) {
|
||||||
|
return R.ok(productGoodsService.list(requestParams, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "商品详情")
|
||||||
|
@GetMapping("/detail")
|
||||||
|
public R detail(@RequestAttribute JSONObject requestParams) {
|
||||||
|
Long id = requestParams.getLong("id");
|
||||||
|
return R.ok(productGoodsService.info(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.cool.modules.product.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "product_action", comment = "商品行为表")
|
||||||
|
public class ProductActionEntity extends TenantEntity<ProductActionEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "行为名称", notNull = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "行为编码", notNull = true)
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "说明", type = "text")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.cool.modules.product.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "product_attribute", comment = "商品属性表")
|
||||||
|
public class ProductAttributeEntity extends TenantEntity<ProductAttributeEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "属性名称", notNull = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "属性编码", notNull = true)
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "值类型 0:文本 1:数字 2:选择 3:日期", defaultValue = "0")
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "选项值(type=2时存JSON)", type = "text")
|
||||||
|
private String options;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "关联行为编码")
|
||||||
|
private String action;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "是否购买时填写 0:否 1:是", defaultValue = "0")
|
||||||
|
private Integer fillOnPurchase;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.cool.modules.product.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "product_goods", comment = "商品表")
|
||||||
|
public class ProductGoodsEntity extends TenantEntity<ProductGoodsEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "商品名称", notNull = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "图片")
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "描述", type = "text")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "商品类型 0:实物商品 1:虚拟商品", defaultValue = "0")
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "扩展属性", type = "text")
|
||||||
|
private String extra;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:下架 1:上架", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.cool.modules.product.entity;
|
||||||
|
|
||||||
|
import com.cool.core.base.TenantEntity;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import com.cool.core.annotation.ColumnDefine;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Table(value = "product_goods_sku", comment = "商品SKU表")
|
||||||
|
public class ProductGoodsSkuEntity extends TenantEntity<ProductGoodsSkuEntity> {
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "商品ID", type = "bigint")
|
||||||
|
private Long goodsId;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "SKU编码")
|
||||||
|
private String skuCode;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "规格组合", type = "text")
|
||||||
|
private String attrs;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "价格")
|
||||||
|
private Double price;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "库存")
|
||||||
|
private Integer stock;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "是否显示库存 0:否 1:是", defaultValue = "0")
|
||||||
|
private Integer showStock;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "规格图")
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1")
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user