diff --git a/jeecg-boot/jeecg-boot-base-core/pom.xml b/jeecg-boot/jeecg-boot-base-core/pom.xml index 9ad9b1ee..9edcc854 100644 --- a/jeecg-boot/jeecg-boot-base-core/pom.xml +++ b/jeecg-boot/jeecg-boot-base-core/pom.xml @@ -111,6 +111,11 @@ mybatis-plus-boot-starter ${mybatis-plus.version} + + + org.jeecgframework + minidao-spring-boot-starter + @@ -314,10 +319,5 @@ org.jeecgframework.boot jeecg-boot-starter-chatgpt - - - org.jeecgframework - minidao-spring-boot-starter - \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java index 2db1edc2..902c6674 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java @@ -1,6 +1,7 @@ package org.jeecg.common.api.vo; import com.fasterxml.jackson.annotation.JsonIgnore; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.jeecg.common.constant.CommonConstant; diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DySmsEnum.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DySmsEnum.java index c1e6f34a..d39b43c1 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DySmsEnum.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/DySmsEnum.java @@ -9,14 +9,14 @@ import org.apache.commons.lang3.StringUtils; public enum DySmsEnum { /**登录短信模板编码*/ - LOGIN_TEMPLATE_CODE("SMS_175435174","敲敲云","code"), + LOGIN_TEMPLATE_CODE("SMS_175435174","敲敲云","code"), /**忘记密码短信模板编码*/ - FORGET_PASSWORD_TEMPLATE_CODE("SMS_175435174","敲敲云","code"), - /**修改密码短信模板编码*/ - CHANGE_PASSWORD_TEMPLATE_CODE("SMS_465391221","敲敲云","code"), - /**注册账号短信模板编码*/ - REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","code"); - + FORGET_PASSWORD_TEMPLATE_CODE("SMS_175435174","敲敲云","code"), + /**修改密码短信模板编码*/ + CHANGE_PASSWORD_TEMPLATE_CODE("SMS_465391221","敲敲云","code"), + /**注册账号短信模板编码*/ + REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","code"); + /** * 短信模板编码 */ diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java index 18965999..d13f58b8 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java @@ -1,6 +1,7 @@ package org.jeecg.common.exception; import cn.hutool.core.util.ObjectUtil; +import io.undertow.server.RequestTooBigException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.shiro.SecurityUtils; @@ -30,6 +31,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.NoHandlerFoundException; import javax.annotation.Resource; @@ -56,7 +58,7 @@ public class JeecgBootExceptionHandler { addSysLog(e); return Result.error("校验失败!" + e.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","))); } - + /** * 处理自定义异常 */ @@ -166,6 +168,27 @@ public class JeecgBootExceptionHandler { return Result.error("文件大小超出10MB限制, 请压缩或降低文件质量! "); } + /** + * 处理文件过大异常. + * jdk17中的MultipartException异常类已经被拆分成了MultipartException和MaxUploadSizeExceededException + * for [QQYUN-11716]上传大图片失败没有精确提示 + * @param e + * @return + * @author chenrui + * @date 2025/4/8 16:13 + */ + @ExceptionHandler(MultipartException.class) + public Result handleMaxUploadSizeExceededException(MultipartException e) { + Throwable cause = e.getCause(); + if (cause instanceof IllegalStateException && cause.getCause() instanceof RequestTooBigException) { + log.error("文件大小超出限制: {}", cause.getMessage(), e); + addSysLog(e); + return Result.error("文件大小超出限制, 请压缩或降低文件质量!"); + } else { + return handleException(e); + } + } + @ExceptionHandler(DataIntegrityViolationException.class) public Result handleDataIntegrityViolationException(DataIntegrityViolationException e) { log.error(e.getMessage(), e); @@ -221,11 +244,16 @@ public class JeecgBootExceptionHandler { } catch (NullPointerException | BeansException ignored) { } if (null != request) { + //update-begin---author:chenrui ---date:20250408 for:[QQYUN-11716]上传大图片失败没有精确提示------------ //请求的参数 - Map parameterMap = request.getParameterMap(); - if(!CollectionUtils.isEmpty(parameterMap)){ - log.setMethod(oConvertUtils.mapToString(request.getParameterMap())); + if (!isTooBigException(e)) { + // 文件上传过大异常时不能获取参数,否则会报错 + Map parameterMap = request.getParameterMap(); + if(!CollectionUtils.isEmpty(parameterMap)) { + log.setMethod(oConvertUtils.mapToString(request.getParameterMap())); + } } + //update-end---author:chenrui ---date:20250408 for:[QQYUN-11716]上传大图片失败没有精确提示------------ // 请求地址 log.setRequestUrl(request.getRequestURI()); //设置IP地址 @@ -251,4 +279,26 @@ public class JeecgBootExceptionHandler { } //update-end---author:chenrui ---date:20240423 for:[QQYUN-8732]把错误的日志都抓取了 方便后续处理,单独弄个日志类型------------ + /** + * 是否文件过大异常 + * for [QQYUN-11716]上传大图片失败没有精确提示 + * @param e + * @return + * @author chenrui + * @date 2025/4/8 20:21 + */ + private static boolean isTooBigException(Throwable e) { + boolean isTooBigException = false; + if(e instanceof MultipartException){ + Throwable cause = e.getCause(); + if (cause instanceof IllegalStateException && cause.getCause() instanceof RequestTooBigException){ + isTooBigException = true; + } + } + if(e instanceof MaxUploadSizeExceededException){ + isTooBigException = true; + } + return isTooBigException; + } + } diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/entity/JeecgEntity.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/entity/JeecgEntity.java index 4d49cf7d..c4e6603a 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/entity/JeecgEntity.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/entity/JeecgEntity.java @@ -2,7 +2,6 @@ package org.jeecg.common.system.base.entity; import java.io.Serializable; -import io.swagger.v3.oas.annotations.media.Schema; import org.jeecgframework.poi.excel.annotation.Excel; import org.springframework.format.annotation.DateTimeFormat; @@ -10,6 +9,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java index 91f83390..f045c7da 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java @@ -36,6 +36,7 @@ public class RestUtil { } return domain; } + private static String getPath() { if (path == null) { path = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("server.servlet.context-path"); diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java index 853551c2..673fe734 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java @@ -5,7 +5,6 @@ import lombok.extern.slf4j.Slf4j; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.SymbolConstant; import org.jeecg.common.exception.JeecgSqlInjectionException; - import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java index 96a0a085..20aa47bc 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java @@ -68,6 +68,13 @@ public class DbTypeUtils { return dbTypeIf(dbType, DbType.ORACLE, DbType.ORACLE_12C, DbType.DM); } + /** + * 是否是达梦 + */ + public static boolean dbTypeIsDm(DbType dbType) { + return dbTypeIf(dbType, DbType.DM); + } + public static boolean dbTypeIsSqlServer(DbType dbType) { return dbTypeIf(dbType, DbType.SQL_SERVER, DbType.SQL_SERVER2005); } diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java index 11f16b7b..33e6fda0 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java @@ -7,6 +7,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.SymbolConstant; +import org.jeecg.config.mybatis.MybatisPlusSaasConfig; import org.springframework.beans.BeanUtils; import javax.servlet.http.HttpServletRequest; @@ -1133,5 +1134,14 @@ public class oConvertUtils { public static boolean isIn(T obj, T... objs) { return isIn(obj, objs); } + + /** + * 判断租户ID是否有效 + * @param tenantId + * @return + */ + public static boolean isEffectiveTenant(String tenantId) { + return MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && isNotEmpty(tenantId) && !("0").equals(tenantId); + } } diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java index 484624b9..59daba8f 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java @@ -1,8 +1,9 @@ //package org.jeecg.config; // // -//import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; +//import io.swagger.v3.oas.annotations.Operation; //import org.jeecg.common.constant.CommonConstant; +//import org.jeecg.config.mybatis.MybatisPlusSaasConfig; //import org.springframework.beans.BeansException; //import org.springframework.beans.factory.config.BeanPostProcessor; //import org.springframework.context.annotation.Bean; @@ -18,15 +19,13 @@ //import springfox.documentation.builders.ParameterBuilder; //import springfox.documentation.builders.PathSelectors; //import springfox.documentation.builders.RequestHandlerSelectors; -//import springfox.documentation.oas.annotations.EnableOpenApi; //import springfox.documentation.schema.ModelRef; //import springfox.documentation.service.*; //import springfox.documentation.spi.DocumentationType; //import springfox.documentation.spi.service.contexts.SecurityContext; //import springfox.documentation.spring.web.plugins.Docket; -//import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider; //import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; -//import springfox.documentation.swagger2.annotations.EnableSwagger2; +//import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; // //import java.lang.reflect.Field; //import java.util.ArrayList; @@ -38,8 +37,7 @@ // * @Author scott // */ //@Configuration -//@EnableSwagger2 //开启 Swagger2 -//@EnableKnife4j //开启 knife4j,可以不写 +//@EnableSwagger2WebMvc //@Import(BeanValidatorPluginsConfiguration.class) //public class Swagger2Config implements WebMvcConfigurer { // @@ -97,6 +95,14 @@ // List pars = new ArrayList<>(); // tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); // pars.add(tokenPar.build()); +// //update-begin-author:liusq---date:2024-08-15--for: 开启多租户时,全局参数增加租户id +// if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){ +// ParameterBuilder tenantPar = new ParameterBuilder(); +// tenantPar.name(CommonConstant.TENANT_ID).description("租户ID").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); +// pars.add(tenantPar.build()); +// } +// //update-end-author:liusq---date:2024-08-15--for: 开启多租户时,全局参数增加租户id +// // return pars; // } // @@ -151,7 +157,7 @@ // // @Override // public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { -// if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) { +// if (bean instanceof WebMvcRequestHandlerProvider) { // customizeSpringfoxHandlerMappings(getHandlerMappings(bean)); // } // return bean; diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java index 9bdcbd64..bb207d65 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java @@ -6,12 +6,15 @@ import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.CommonAPI; import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.CommonConstant; +import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.CommonUtils; import org.jeecg.common.util.SpringContextUtils; import org.jeecg.config.JeecgBaseConfig; +import org.jeecg.config.firewall.interceptor.enums.LowCodeUrlsEnum; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.AntPathMatcher; import org.springframework.web.servlet.HandlerInterceptor; import javax.annotation.Resource; diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java index e2a68a96..ba9a0dbf 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java @@ -221,6 +221,7 @@ public class ShiroConfig { registration.addUrlPatterns("/airag/flow/debug"); registration.addUrlPatterns("/airag/chat/send"); registration.addUrlPatterns("/airag/app/debug"); + registration.addUrlPatterns("/airag/app/prompt/generate"); //支持异步 registration.setAsyncSupported(true); registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC); @@ -320,7 +321,7 @@ public class ShiroConfig { return sentinelManager; } - + // redis 单机支持,在集群为空,或者集群无机器时候使用 add by jzyadmin@163.com if (lettuceConnectionFactory.getClusterConfiguration() == null || lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().isEmpty()) { RedisManager redisManager = new RedisManager(); diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/pom.xml b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/pom.xml index c2c1ed9b..bce5b662 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/pom.xml +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/pom.xml @@ -53,13 +53,29 @@ jeecg-system-cloud-api --> + - org.jeecgframework.boot - jeecg-aiflow - 1.0.4 + org.jeecgframework + ai-flow + 1.1.0 + + + + com.yomahub + liteflow-spring-boot-starter + ${liteflow.version} + + + commons-lang + commons-lang + + + + + com.yomahub + liteflow-rule-sql + ${liteflow.version} - - com.yomahub liteflow-script-graaljs @@ -84,6 +100,11 @@ runtime + + org.jetbrains.kotlin + kotlin-scripting-jsr223 + ${kotlin.version} + com.yomahub liteflow-script-aviator diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/consts/AiAppConsts.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/consts/AiAppConsts.java index c38ee0e2..b8626942 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/consts/AiAppConsts.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/consts/AiAppConsts.java @@ -16,6 +16,10 @@ public class AiAppConsts { * 状态:禁用 */ public static final String STATUS_DISABLE = "disable"; + /** + * 状态:发布 + */ + public static final String STATUS_RELEASE = "release"; /** diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragAppController.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragAppController.java index 6a81852f..e13f13e9 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragAppController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragAppController.java @@ -4,10 +4,13 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.authz.annotation.RequiresPermissions; import org.jeecg.common.api.vo.Result; import org.jeecg.common.system.base.controller.JeecgController; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.util.AssertUtils; +import org.jeecg.common.util.TokenUtils; +import org.jeecg.config.mybatis.MybatisPlusSaasConfig; import org.jeecg.config.shiro.IgnoreAuth; import org.jeecg.modules.airag.app.consts.AiAppConsts; import org.jeecg.modules.airag.app.entity.AiragApp; @@ -19,7 +22,6 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import javax.servlet.http.HttpServletRequest; -import java.util.Arrays; /** * @Description: AI应用 @@ -64,6 +66,7 @@ public class AiragAppController extends JeecgController edit(@RequestBody AiragApp airagApp) { AssertUtils.assertNotEmpty("参数异常", airagApp); AssertUtils.assertNotEmpty("请输入应用名称", airagApp.getName()); @@ -73,6 +76,28 @@ public class AiragAppController extends JeecgController release(@RequestParam(name = "id") String id, @RequestParam(name = "release") Boolean release) { + AssertUtils.assertNotEmpty("id必须填写", id); + if (release == null) { + release = true; + } + AiragApp airagApp = new AiragApp(); + airagApp.setId(id); + if (release) { + airagApp.setStatus(AiAppConsts.STATUS_RELEASE); + } else { + airagApp.setStatus(AiAppConsts.STATUS_ENABLE); + } + airagAppService.updateById(airagApp); + return Result.OK(release ? "发布成功" : "取消发布成功"); + } + /** * 通过id删除 * @@ -80,23 +105,23 @@ public class AiragAppController extends JeecgController delete(@RequestParam(name = "id", required = true) String id) { + @RequiresPermissions("airag:app:delete") + public Result delete(HttpServletRequest request,@RequestParam(name = "id", required = true) String id) { + //update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ + //如果是saas隔离的情况下,判断当前租户id是否是当前租户下的 + if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + AiragApp app = airagAppService.getById(id); + //获取当前租户 + String currentTenantId = TokenUtils.getTenantIdByRequest(request); + if (null == app || !app.getTenantId().equals(currentTenantId)) { + return Result.error("删除AI应用失败,不能删除其他租户的AI应用!"); + } + } + //update-end---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ airagAppService.removeById(id); return Result.OK("删除成功!"); } - /** - * 批量删除 - * - * @param ids - * @return - */ - @DeleteMapping(value = "/deleteBatch") - public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { - this.airagAppService.removeByIds(Arrays.asList(ids.split(","))); - return Result.OK("批量删除成功!"); - } - /** * 通过id查询 * diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragChatController.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragChatController.java index 1c1aebb4..62fec9a3 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragChatController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/controller/AiragChatController.java @@ -2,14 +2,22 @@ package org.jeecg.modules.airag.app.controller; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.common.util.CommonUtils; import org.jeecg.config.shiro.IgnoreAuth; import org.jeecg.modules.airag.app.service.IAiragChatService; import org.jeecg.modules.airag.app.vo.ChatConversation; import org.jeecg.modules.airag.app.vo.ChatSendParams; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /** * airag应用-chat @@ -25,6 +33,15 @@ public class AiragChatController { @Autowired IAiragChatService chatService; + @Value(value = "${jeecg.path.upload}") + private String uploadpath; + + /** + * 本地:local minio:minio 阿里:alioss + */ + @Value(value="${jeecg.uploadType}") + private String uploadType; + /** * 发送消息 @@ -59,6 +76,19 @@ public class AiragChatController { return chatService.send(chatSendParams); } + /** + * 获取所有对话 + * + * @return 返回一个Result对象,包含所有对话的信息 + * @author chenrui + * @date 2025/2/25 11:42 + */ + @IgnoreAuth + @GetMapping(value = "/init") + public Result initChat(@RequestParam(name = "id", required = true) String id) { + return chatService.initChat(id); + } + /** * 获取所有对话 * @@ -141,4 +171,36 @@ public class AiragChatController { return chatService.stop(requestId); } + + /** + * 上传文件 + * for [QQYUN-12135]AI聊天,上传图片提示非法token + * + * @param request + * @param response + * @return + * @throws Exception + * @author chenrui + * @date 2025/4/25 11:04 + */ + @IgnoreAuth + @PostMapping(value = "/upload") + public Result upload(HttpServletRequest request, HttpServletResponse response) throws Exception { + String bizPath = "airag"; + + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + // 获取上传文件对象 + MultipartFile file = multipartRequest.getFile("file"); + String savePath; + if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) { + savePath = CommonUtils.uploadLocal(file, bizPath, uploadpath); + } else { + savePath = CommonUtils.upload(file, bizPath, uploadType); + } + Result result = new Result<>(); + result.setMessage(savePath); + result.setSuccess(true); + return result; + } + } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/entity/AiragApp.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/entity/AiragApp.java index e5204b5a..0659c877 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/entity/AiragApp.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/entity/AiragApp.java @@ -39,12 +39,13 @@ public class AiragApp implements Serializable { */ @TableId(type = IdType.ASSIGN_ID) @Schema(description = "主键") - private String id; + private java.lang.String id; /** * 创建人 */ @Schema(description = "创建人") - private String createBy; + @Dict(dictTable = "sys_user",dicCode = "username",dicText = "realname") + private java.lang.String createBy; /** * 创建日期 */ @@ -56,7 +57,7 @@ public class AiragApp implements Serializable { * 更新人 */ @Schema(description = "更新人") - private String updateBy; + private java.lang.String updateBy; /** * 更新日期 */ @@ -68,95 +69,95 @@ public class AiragApp implements Serializable { * 所属部门 */ @Schema(description = "所属部门") - private String sysOrgCode; + private java.lang.String sysOrgCode; /** * 租户id */ @Excel(name = "租户id", width = 15) @Schema(description = "租户id") - private String tenantId; + private java.lang.String tenantId; /** * 应用名称 */ @Excel(name = "应用名称", width = 15) @Schema(description = "应用名称") - private String name; + private java.lang.String name; /** * 应用描述 */ @Excel(name = "应用描述", width = 15) @Schema(description = "应用描述") - private String descr; + private java.lang.String descr; /** * 应用图标 */ @Excel(name = "应用图标", width = 15) @Schema(description = "应用图标") - private String icon; + private java.lang.String icon; /** * 应用类型 */ @Excel(name = "应用类型", width = 15, dicCode = "ai_app_type") @Dict(dicCode = "ai_app_type") @Schema(description = "应用类型") - private String type; + private java.lang.String type; /** * 开场白 */ @Excel(name = "开场白", width = 15) @Schema(description = "开场白") - private String prologue; + private java.lang.String prologue; /** * 预设问题 */ @Excel(name = "预设问题", width = 15) @Schema(description = "预设问题") - private String presetQuestion; + private java.lang.String presetQuestion; /** * 提示词 */ @Excel(name = "提示词", width = 15) @Schema(description = "提示词") - private String prompt; + private java.lang.String prompt; /** * 模型配置 */ @Excel(name = "模型配置", width = 15, dictTable = "airag_model where model_type = 'LLM' ", dicText = "name", dicCode = "id") @Dict(dictTable = "airag_model where model_type = 'LLM' ", dicText = "name", dicCode = "id") @Schema(description = "模型配置") - private String modelId; + private java.lang.String modelId; /** * 历史消息数 */ @Excel(name = "历史消息数", width = 15) @Schema(description = "历史消息数") - private Integer msgNum; + private java.lang.Integer msgNum; /** * 知识库 */ @Excel(name = "知识库", width = 15, dictTable = "airag_knowledge where status = 'enable'", dicText = "name", dicCode = "id") @Dict(dictTable = "airag_knowledge where status = 'enable'", dicText = "name", dicCode = "id") @Schema(description = "知识库") - private String knowledgeIds; + private java.lang.String knowledgeIds; /** * 流程 */ @Excel(name = "流程", width = 15, dictTable = "airag_flow where status = 'enable' ", dicText = "name", dicCode = "id") @Dict(dictTable = "airag_flow where status = 'enable' ", dicText = "name", dicCode = "id") @Schema(description = "流程") - private String flowId; + private java.lang.String flowId; /** * 快捷指令 */ @Excel(name = "快捷指令", width = 15) @Schema(description = "快捷指令") - private String quickCommand; + private java.lang.String quickCommand; /** - * 状态 + * 状态(enable=启用、disable=禁用、release=发布) */ @Excel(name = "状态", width = 15) @Schema(description = "状态") - private String status; + private java.lang.String status; /** @@ -164,7 +165,7 @@ public class AiragApp implements Serializable { */ @Excel(name = "元数据", width = 15) @Schema(description = "元数据") - private String metadata; + private java.lang.String metadata; /** * 知识库ids diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/AiragAppMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/AiragAppMapper.java index 05e870d8..718c016e 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/AiragAppMapper.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/AiragAppMapper.java @@ -1,5 +1,6 @@ package org.jeecg.modules.airag.app.mapper; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.jeecg.modules.airag.app.entity.AiragApp; @@ -11,4 +12,14 @@ import org.jeecg.modules.airag.app.entity.AiragApp; */ public interface AiragAppMapper extends BaseMapper { + /** + * 根据ID查询app信息(忽略租户) + * @param id + * @return + * @author chenrui + * @date 2025/4/21 16:03 + */ + @InterceptorIgnore(tenantLine = "true") + AiragApp getByIdIgnoreTenant(String id); + } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/xml/AiragAppMapper.xml b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/xml/AiragAppMapper.xml index 2dce98bf..f3f9da6f 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/xml/AiragAppMapper.xml +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/mapper/xml/AiragAppMapper.xml @@ -2,4 +2,8 @@ + + \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/IAiragChatService.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/IAiragChatService.java index 916c9ed1..fc8e197a 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/IAiragChatService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/IAiragChatService.java @@ -92,4 +92,14 @@ public interface IAiragChatService { * @date 2025/3/3 19:49 */ Result clearMessage(String conversationId); + + /** + * 初始化聊天(忽略租户) + * [QQYUN-12113]分享之后的聊天,应用、模型、知识库不根据租户查询 + * @param appId + * @return + * @author chenrui + * @date 2025/4/21 14:17 + */ + Result initChat(String appId); } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragChatServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragChatServiceImpl.java index c198b215..9bfbd423 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragChatServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragChatServiceImpl.java @@ -13,6 +13,7 @@ import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.util.*; import org.jeecg.modules.airag.app.consts.AiAppConsts; import org.jeecg.modules.airag.app.entity.AiragApp; +import org.jeecg.modules.airag.app.mapper.AiragAppMapper; import org.jeecg.modules.airag.app.service.IAiragAppService; import org.jeecg.modules.airag.app.service.IAiragChatService; import org.jeecg.modules.airag.app.vo.AppDebugParams; @@ -63,7 +64,7 @@ public class AiragChatServiceImpl implements IAiragChatService { RedisTemplate redisTemplate; @Autowired - IAiragAppService airagAppService; + AiragAppMapper airagAppMapper; @Autowired IAiragFlowService airagFlowService; @@ -85,7 +86,7 @@ public class AiragChatServiceImpl implements IAiragChatService { // 获取app信息 AiragApp app = null; if (oConvertUtils.isNotEmpty(chatSendParams.getAppId())) { - app = airagAppService.getById(chatSendParams.getAppId()); + app = airagAppMapper.getByIdIgnoreTenant(chatSendParams.getAppId()); } ChatConversation chatConversation = getOrCreateChatConversation(app, conversationId); // 更新标题 @@ -146,13 +147,19 @@ public class AiragChatServiceImpl implements IAiragChatService { try { // 发送完成事件 emitter.send(SseEmitter.event().data(eventData)); - } catch (IOException e) { + } catch (Exception e) { log.error("终止会话时发生错误", e); + try { + // 防止异常冒泡 + emitter.completeWithError(e); + } catch (Exception ignore) {} } finally { // 从缓存中移除emitter AiragLocalCache.remove(AiragConsts.CACHE_TYPE_SSE, eventData.getRequestId()); // 关闭emitter - emitter.complete(); + try { + emitter.complete(); + } catch (Exception ignore) {} } } @@ -237,6 +244,12 @@ public class AiragChatServiceImpl implements IAiragChatService { return Result.ok(); } + @Override + public Result initChat(String appId) { + AiragApp app = airagAppMapper.getByIdIgnoreTenant(appId); + return Result.ok(app); + } + @Override public Result deleteConversation(String conversationId) { AssertUtils.assertNotEmpty("请选择要删除的会话", conversationId); @@ -278,7 +291,7 @@ public class AiragChatServiceImpl implements IAiragChatService { * @author chenrui * @date 2025/2/25 19:27 */ - private String getConversationCacheKey(String conversationId,HttpServletRequest httpRequest) { + private String getConversationCacheKey(String conversationId, HttpServletRequest httpRequest) { if (oConvertUtils.isEmpty(conversationId)) { return null; } @@ -376,7 +389,7 @@ public class AiragChatServiceImpl implements IAiragChatService { * @author chenrui * @date 2025/2/25 19:27 */ - private void saveChatConversation(ChatConversation chatConversation, boolean temp,HttpServletRequest httpRequest) { + private void saveChatConversation(ChatConversation chatConversation, boolean temp, HttpServletRequest httpRequest) { if (null == chatConversation) { return; } @@ -414,8 +427,7 @@ public class AiragChatServiceImpl implements IAiragChatService { case AiragConsts.MESSAGE_ROLE_USER: List contents = new ArrayList<>(); List images = history.getImages(); - if (oConvertUtils.isObjectNotEmpty(images) - && !images.isEmpty()) { + if (oConvertUtils.isObjectNotEmpty(images) && !images.isEmpty()) { contents.addAll(images.stream().map(imageHistory -> { if (oConvertUtils.isNotEmpty(imageHistory.getUrl())) { return ImageContent.from(imageHistory.getUrl()); @@ -452,8 +464,7 @@ public class AiragChatServiceImpl implements IAiragChatService { * @author chenrui * @date 2025/2/25 19:05 */ - private void appendMessage(List messages, ChatMessage message, ChatConversation - chatConversation, String topicId) { + private void appendMessage(List messages, ChatMessage message, ChatConversation chatConversation, String topicId) { if (message.type().equals(ChatMessageType.SYSTEM)) { // 系统消息,放到消息列表最前面,并且不记录历史 @@ -467,11 +478,7 @@ public class AiragChatServiceImpl implements IAiragChatService { histories = new ArrayList<>(); } // 消息记录 - MessageHistory historyMessage = MessageHistory.builder() - .conversationId(chatConversation.getId()) - .topicId(topicId) - .datetime(DateUtils.now()) - .build(); + MessageHistory historyMessage = MessageHistory.builder().conversationId(chatConversation.getId()).topicId(topicId).datetime(DateUtils.now()).build(); if (message.type().equals(ChatMessageType.USER)) { historyMessage.setRole(AiragConsts.MESSAGE_ROLE_USER); StringBuilder textContent = new StringBuilder(); @@ -516,8 +523,21 @@ public class AiragChatServiceImpl implements IAiragChatService { // 每次会话都生成一个新的,用来缓存emitter String requestId = UUIDGenerator.generate(); SseEmitter emitter = new SseEmitter(-0L); + emitter.onError(throwable -> { + log.warn("SEE向客户端发送消息失败: {}", throwable.getMessage()); + AiragLocalCache.remove(AiragConsts.CACHE_TYPE_SSE, requestId); + try { + emitter.complete(); + } catch (Exception ignore) {} + }); + EventData eventRequestId = new EventData(requestId, null, EventData.EVENT_INIT_REQUEST_ID, chatConversation.getId(), topicId); + eventRequestId.setData(EventMessageData.builder().message("").build()); + sendMessage2Client(emitter, eventRequestId); // 缓存emitter AiragLocalCache.put(AiragConsts.CACHE_TYPE_SSE, requestId, emitter); + // 缓存开始发送时间 + log.info("[AI-CHAT]开始发送消息,requestId:{}", requestId); + AiragLocalCache.put(AiragConsts.CACHE_TYPE_SSE_SEND_TIME, requestId, System.currentTimeMillis()); try { // 组装用户消息 UserMessage userMessage = aiChatHandler.buildUserMessage(sendParams.getContent(), sendParams.getImages()); @@ -589,36 +609,51 @@ public class AiragChatServiceImpl implements IAiragChatService { SseEmitter emitter = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE, requestId); flowRunParams.setEventCallback(eventData -> { if (EventData.EVENT_FLOW_FINISHED.equals(eventData.getEvent())) { + // 打印耗时日志 + printChatDuration(requestId, "流程执行完毕"); + // 已经执行完了,删除时间缓存 + AiragLocalCache.remove(AiragConsts.CACHE_TYPE_SSE_SEND_TIME, requestId); EventFlowData data = (EventFlowData) eventData.getData(); - Object outputs = data.getOutputs(); - if (oConvertUtils.isObjectNotEmpty(outputs)) { - AiMessage aiMessage; - if (outputs instanceof String) { - // 兼容推理模型 - String messageText = String.valueOf(outputs); - messageText = messageText.replaceAll("([\\s\\S]*?)", "> $1"); - aiMessage = new AiMessage(messageText); - } else { - aiMessage = new AiMessage(JSONObject.toJSONString(outputs)); + if(data.isSuccess()) { + Object outputs = data.getOutputs(); + if (oConvertUtils.isObjectNotEmpty(outputs)) { + AiMessage aiMessage; + if (outputs instanceof String) { + // 兼容推理模型 + String messageText = String.valueOf(outputs); + messageText = messageText.replaceAll("([\\s\\S]*?)", "> $1"); + aiMessage = new AiMessage(messageText); + } else { + aiMessage = new AiMessage(JSONObject.toJSONString(outputs)); + } + EventData msgEventData = new EventData(requestId, null, EventData.EVENT_MESSAGE, chatConversation.getId(), topicId); + EventMessageData messageEventData = EventMessageData.builder().message(aiMessage.text()).build(); + msgEventData.setData(messageEventData); + msgEventData.setRequestId(requestId); + sendMessage2Client(emitter, msgEventData); + appendMessage(messages, aiMessage, chatConversation, topicId); + // 保存会话 + saveChatConversation(chatConversation, false, httpRequest); } - EventData msgEventData = new EventData(requestId, null, EventData.EVENT_MESSAGE, chatConversation.getId(), topicId); - EventMessageData messageEventData = EventMessageData.builder() - .message(aiMessage.text()) - .build(); - msgEventData.setData(messageEventData); - try { - String eventStr = JSONObject.toJSONString(msgEventData); - log.debug("[AI应用]接收FLOW返回消息:{}", eventStr); - emitter.send(SseEmitter.event().data(eventStr)); - } catch (IOException e) { - throw new RuntimeException(e); + }else{ + //update-begin---author:chenrui ---date:20250425 for:[QQYUN-12203]AI 聊天,超时或者服务器报错,给个友好提示------------ + // 失败 + String message = data.getMessage(); + if (message != null && message.contains(FlowConsts.FLOW_ERROR_MSG_LLM_TIMEOUT)) { + message = "当前用户较多,排队中,请稍后再试!"; + EventData errEventData = new EventData(requestId, null, EventData.EVENT_MESSAGE, chatConversation.getId(), topicId); + errEventData.setData(EventMessageData.builder().message("\n" + message).build()); + sendMessage2Client(emitter, errEventData); + errEventData = new EventData(requestId, null, EventData.EVENT_MESSAGE_END, chatConversation.getId(), topicId); + // 如果是超时,主动关闭SSE,防止流程切面中返回异常消息导致前端不能正常展示上面的{普通消息}. + closeSSE(emitter, errEventData); } - appendMessage(messages, aiMessage, chatConversation, topicId); - // 保存会话 - saveChatConversation(chatConversation, false, httpRequest); + //update-end---author:chenrui ---date:20250425 for:[QQYUN-12203]AI 聊天,超时或者服务器报错,给个友好提示------------ } } }); + // 打印流程耗时日志 + printChatDuration(requestId, "开始执行流程"); airagFlowService.runFlow(flowRunParams); } @@ -649,24 +684,26 @@ public class AiragChatServiceImpl implements IAiragChatService { String metadataStr = aiApp.getMetadata(); if (oConvertUtils.isNotEmpty(metadataStr)) { JSONObject metadata = JSONObject.parseObject(metadataStr); - if(oConvertUtils.isNotEmpty(metadata)){ + if (oConvertUtils.isNotEmpty(metadata)) { if (metadata.containsKey("temperature")) { aiChatParams.setTemperature(metadata.getDouble("temperature")); } if (metadata.containsKey("topP")) { - aiChatParams.setTopP(metadata.getDouble("temperature")); + aiChatParams.setTopP(metadata.getDouble("topP")); } if (metadata.containsKey("presencePenalty")) { - aiChatParams.setPresencePenalty(metadata.getDouble("temperature")); + aiChatParams.setPresencePenalty(metadata.getDouble("presencePenalty")); } if (metadata.containsKey("frequencyPenalty")) { - aiChatParams.setFrequencyPenalty(metadata.getDouble("temperature")); + aiChatParams.setFrequencyPenalty(metadata.getDouble("frequencyPenalty")); } if (metadata.containsKey("maxTokens")) { - aiChatParams.setMaxTokens(metadata.getInteger("temperature")); + aiChatParams.setMaxTokens(metadata.getInteger("maxTokens")); } } } + // 打印流程耗时日志 + printChatDuration(requestId, "构造应用自定义参数完成"); // 发消息 sendWithDefault(requestId, chatConversation, topicId, modelId, messages, aiChatParams); } @@ -683,10 +720,9 @@ public class AiragChatServiceImpl implements IAiragChatService { * @author chenrui * @date 2025/2/25 19:24 */ - private void sendWithDefault(String requestId, ChatConversation chatConversation, String topicId, String modelId, - List messages,AIChatParams aiChatParams) { + private void sendWithDefault(String requestId, ChatConversation chatConversation, String topicId, String modelId, List messages, AIChatParams aiChatParams) { // 调用ai聊天 - if(null == aiChatParams){ + if (null == aiChatParams) { aiChatParams = new AIChatParams(); } aiChatParams.setKnowIds(chatConversation.getApp().getKnowIds()); @@ -694,13 +730,15 @@ public class AiragChatServiceImpl implements IAiragChatService { HttpServletRequest httpRequest = SpringContextUtils.getHttpServletRequest(); TokenStream chatStream; try { + // 打印流程耗时日志 + printChatDuration(requestId, "开始向LLM发送消息"); if (oConvertUtils.isNotEmpty(modelId)) { chatStream = aiChatHandler.chat(modelId, messages, aiChatParams); } else { chatStream = aiChatHandler.chatByDefaultModel(messages, aiChatParams); } } catch (Exception e) { - log.error(e.getMessage(),e); + log.error(e.getMessage(), e); throw new JeecgBootBizTipException("调用大模型接口失败:" + e.getMessage()); } /** @@ -709,91 +747,120 @@ public class AiragChatServiceImpl implements IAiragChatService { AtomicBoolean isThinking = new AtomicBoolean(false); // ai聊天响应逻辑 chatStream.onNext((String resMessage) -> { - // 兼容推理模型 - if ("".equals(resMessage)) { - isThinking.set(true); - resMessage = "> "; - } - if ("".equals(resMessage)) { - isThinking.set(false); - resMessage = "\n\n"; - } - if (isThinking.get()) { - if (null != resMessage && resMessage.contains("\n")) { - resMessage = "\n> "; - } - } - EventData eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE, chatConversation.getId(), topicId); - EventMessageData messageEventData = EventMessageData.builder() - .message(resMessage) - .build(); - eventData.setData(messageEventData); - // sse - SseEmitter emitter = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE, requestId); - if (null == emitter) { - log.warn("[AI应用]接收LLM返回会话已关闭"); - return; - } - try { - String eventStr = JSONObject.toJSONString(eventData); - log.debug("[AI应用]接收LLM返回消息:{}", eventStr); - emitter.send(SseEmitter.event().data(eventStr)); - } catch (IOException e) { - throw new RuntimeException(e); - } - }) - .onComplete((responseMessage) -> { - // 记录ai的回复 - AiMessage aiMessage = responseMessage.content(); - FinishReason finishReason = responseMessage.finishReason(); - String respText = aiMessage.text(); - // sse - SseEmitter emitter = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE, requestId); - if (null == emitter) { - log.warn("[AI应用]接收LLM返回会话已关闭"); - return; - } - if (FinishReason.STOP.equals(finishReason) || null == finishReason) { - // 正常结束 - EventData eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE_END, chatConversation.getId(), topicId); - try { - log.debug("[AI应用]接收LLM返回消息完成:{}", respText); - emitter.send(SseEmitter.event().data(eventData)); - } catch (IOException e) { - throw new RuntimeException(e); - } - appendMessage(messages, aiMessage, chatConversation, topicId); - // 保存会话 - saveChatConversation(chatConversation,false,httpRequest); - closeSSE(emitter, eventData); - } else if (FinishReason.TOOL_EXECUTION.equals(finishReason)) { - // 需要执行工具 - // TODO author: chenrui for: date:2025/3/7 - } else { - // 异常结束 - log.error("调用模型异常:" + respText); - if (respText.contains("insufficient Balance")) { - respText = "大预言模型账号余额不足!"; - } - EventData eventData = new EventData(requestId, null, EventData.EVENT_FLOW_ERROR, chatConversation.getId(), topicId); - eventData.setData(EventFlowData.builder().success(false).message(respText).build()); - closeSSE(emitter, eventData); - } - }) - .onError((Throwable error) -> { - // sse - SseEmitter emitter = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE, requestId); - if (null == emitter) { - log.warn("[AI应用]接收LLM返回会话已关闭"); - return; - } - String errMsg = "调用大模型接口失败:" + error.getMessage(); - log.error(errMsg, error); - EventData eventData = new EventData(requestId, null, EventData.EVENT_FLOW_ERROR, chatConversation.getId(), topicId); - eventData.setData(EventFlowData.builder().success(false).message(errMsg).build()); - closeSSE(emitter, eventData); - }) - .start(); + // 兼容推理模型 + if ("".equals(resMessage)) { + isThinking.set(true); + resMessage = "> "; + } + if ("".equals(resMessage)) { + isThinking.set(false); + resMessage = "\n\n"; + } + if (isThinking.get()) { + if (null != resMessage && resMessage.contains("\n")) { + resMessage = "\n> "; + } + } + EventData eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE, chatConversation.getId(), topicId); + EventMessageData messageEventData = EventMessageData.builder().message(resMessage).build(); + eventData.setData(messageEventData); + eventData.setRequestId(requestId); + // sse + SseEmitter emitter = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE, requestId); + if (null == emitter) { + log.warn("[AI应用]接收LLM返回会话已关闭"); + return; + } + sendMessage2Client(emitter, eventData); + }).onComplete((responseMessage) -> { + // 打印流程耗时日志 + printChatDuration(requestId, "LLM输出消息完成"); + AiragLocalCache.remove(AiragConsts.CACHE_TYPE_SSE_SEND_TIME, requestId); + // 记录ai的回复 + AiMessage aiMessage = responseMessage.content(); + FinishReason finishReason = responseMessage.finishReason(); + String respText = aiMessage.text(); + // sse + SseEmitter emitter = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE, requestId); + if (null == emitter) { + log.warn("[AI应用]接收LLM返回会话已关闭"); + return; + } + if (FinishReason.STOP.equals(finishReason) || null == finishReason) { + // 正常结束 + EventData eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE_END, chatConversation.getId(), topicId); + appendMessage(messages, aiMessage, chatConversation, topicId); + // 保存会话 + saveChatConversation(chatConversation, false, httpRequest); + closeSSE(emitter, eventData); + } else if (FinishReason.TOOL_EXECUTION.equals(finishReason)) { + // 需要执行工具 + // TODO author: chenrui for: date:2025/3/7 + } else if (FinishReason.LENGTH.equals(finishReason)) { + // 上下文长度超过限制 + log.error("调用模型异常:上下文长度超过限制:{}", responseMessage.tokenUsage()); + EventData eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE, chatConversation.getId(), topicId); + eventData.setData(EventMessageData.builder().message("\n上下文长度超过限制,请调整模型最大Tokens").build()); + sendMessage2Client(emitter, eventData); + eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE_END, chatConversation.getId(), topicId); + closeSSE(emitter, eventData); + } else { + // 异常结束 + log.error("调用模型异常:" + respText); + if (respText.contains("insufficient Balance")) { + respText = "大预言模型账号余额不足!"; + } + EventData eventData = new EventData(requestId, null, EventData.EVENT_FLOW_ERROR, chatConversation.getId(), topicId); + eventData.setData(EventFlowData.builder().success(false).message(respText).build()); + closeSSE(emitter, eventData); + } + }).onError((Throwable error) -> { + // 打印流程耗时日志 + printChatDuration(requestId, "LLM输出消息异常"); + AiragLocalCache.remove(AiragConsts.CACHE_TYPE_SSE_SEND_TIME, requestId); + // sse + SseEmitter emitter = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE, requestId); + if (null == emitter) { + log.warn("[AI应用]接收LLM返回会话已关闭{}", requestId); + return; + } + log.error(error.getMessage(), error); + String errMsg = error.getMessage(); + if (errMsg != null && errMsg.contains("timeout")) { + //update-begin---author:chenrui ---date:20250425 for:[QQYUN-12203]AI 聊天,超时或者服务器报错,给个友好提示------------ + errMsg = "当前用户较多,排队中,请稍后再试!"; + EventData eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE, chatConversation.getId(), topicId); + eventData.setData(EventMessageData.builder().message("\n" + errMsg).build()); + sendMessage2Client(emitter, eventData); + eventData = new EventData(requestId, null, EventData.EVENT_MESSAGE_END, chatConversation.getId(), topicId); + closeSSE(emitter, eventData); + //update-end---author:chenrui ---date:20250425 for:[QQYUN-12203]AI 聊天,超时或者服务器报错,给个友好提示------------ + } else { + errMsg = "调用大模型接口失败:" + errMsg; + EventData eventData = new EventData(requestId, null, EventData.EVENT_FLOW_ERROR, chatConversation.getId(), topicId); + eventData.setData(EventFlowData.builder().success(false).message(errMsg).build()); + closeSSE(emitter, eventData); + } + }).start(); + } + + /** + * 发送消息到客户端 + * + * @param emitter + * @param eventData + * @author chenrui + * @date 2025/4/22 19:58 + */ + private static void sendMessage2Client(SseEmitter emitter, EventData eventData) { + try { + log.info("发送消息:{}", eventData.getRequestId()); + String eventStr = JSONObject.toJSONString(eventData); + log.debug("[AI应用]接收LLM返回消息:{}", eventStr); + emitter.send(SseEmitter.event().data(eventStr)); + } catch (IOException e) { + log.error("发送消息失败", e); + } } /** @@ -837,12 +904,7 @@ public class AiragChatServiceImpl implements IAiragChatService { } CompletableFuture.runAsync(() -> { List messages = new LinkedList<>(); - String systemMsgStr = "根据用户的问题,总结会话标题.\n" + - "要求如下:\n" + - "1. 使用中文回答.\n" + - "2. 标题长度控制在5个汉字10个英文字符以内\n" + - "3. 直接回复会话标题,不要有其他任何无关描述\n" + - "4. 如果无法总结,回复不知道\n"; + String systemMsgStr = "根据用户的问题,总结会话标题.\n" + "要求如下:\n" + "1. 使用中文回答.\n" + "2. 标题长度控制在5个汉字10个英文字符以内\n" + "3. 直接回复会话标题,不要有其他任何无关描述\n" + "4. 如果无法总结,回复不知道\n"; messages.add(new SystemMessage(systemMsgStr)); messages.add(new UserMessage(question)); String summaryTitle; @@ -876,6 +938,7 @@ public class AiragChatServiceImpl implements IAiragChatService { /** * 获取用户名 + * * @param httpRequest * @return * @author chenrui @@ -885,9 +948,9 @@ public class AiragChatServiceImpl implements IAiragChatService { try { TokenUtils.getTokenByRequest(); String token; - if(null != httpRequest){ + if (null != httpRequest) { token = TokenUtils.getTokenByRequest(httpRequest); - }else{ + } else { token = TokenUtils.getTokenByRequest(); } if (TokenUtils.verifyToken(token, sysBaseApi, redisUtil)) { @@ -898,4 +961,19 @@ public class AiragChatServiceImpl implements IAiragChatService { } return null; } + + + /** + * 打印耗时 + * @param requestId + * @param message + * @author chenrui + * @date 2025/4/28 15:15 + */ + private static void printChatDuration(String requestId,String message) { + Long beginTime = AiragLocalCache.get(AiragConsts.CACHE_TYPE_SSE_SEND_TIME, requestId); + if (null != beginTime) { + log.info("[AI-CHAT]{},requestId:{},耗时:{}s", message, requestId, (System.currentTimeMillis() - beginTime) / 1000); + } + } } \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/demo/JimuDataReader.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/demo/JimuDataReader.java new file mode 100644 index 00000000..12355f82 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/demo/JimuDataReader.java @@ -0,0 +1,83 @@ +package org.jeecg.modules.airag.demo; + +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.exception.JeecgBootBizTipException; +import org.jeecg.modules.airag.flow.component.enhance.IAiRagEnhanceJava; +import org.jeecgframework.poi.excel.ExcelImportUtil; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Java增强Demo: Excel数据读取器 + * for [QQYUN-11718]【AI】积木报表对接AI流程编排接口展示报表 + * @Author: chenrui + * @Date: 2025/4/29 16:51 + */ +@Component("jimuDataReader") +@Slf4j +public class JimuDataReader implements IAiRagEnhanceJava { + + + @Override + public Map process(Map inputParams) { + // inputParams: {"bizData":"/xxxx/xxxx/xxxx/xxxx.xls"} + try { + String filePath = (String) inputParams.get("bizData"); + if (filePath == null || filePath.isEmpty()) { + throw new IllegalArgumentException("File path is empty"); + } + + File excelFile = new File(filePath); + if (!excelFile.exists() || !excelFile.isFile()) { + throw new IllegalArgumentException("File not found: " + filePath); + } + + // Since we don't know the target entity class, we'll read the Excel generically + return readExcelData(excelFile); + } catch (Exception e) { + log.error("Error processing Excel file", e); + throw new JeecgBootBizTipException("调用java增强失败", e); + } + } + + /** + * Excel导入工具方法,基于ExcelImportUtil + * + * @param file Excel文件 + * @return Excel读取结果,包含字段和数据 + * @throws Exception 导入过程中的异常 + */ + public static Map readExcelData(File file) throws Exception { + Map result = new HashMap<>(); + + // 设置导入参数 + ImportParams params = new ImportParams(); + params.setTitleRows(0); // 没有标题 + params.setHeadRows(1); // 第一行是表头 + + // 读取Excel数据 + List> dataList = ExcelImportUtil.importExcel(file, Map.class, params); + + // 如果没有数据,返回空结果 + if (dataList == null || dataList.isEmpty()) { + result.put("fields", new ArrayList<>()); + result.put("datas", new ArrayList<>()); + return result; + } + + // 从第一行数据中获取字段名 + List fieldNames = new ArrayList<>(dataList.get(0).keySet()); + + result.put("fields", fieldNames); + result.put("datas", dataList); + + return result; + } + +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/demo/TestAiragEnhance.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/demo/TestAiragEnhance.java new file mode 100644 index 00000000..0cbd7020 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/demo/TestAiragEnhance.java @@ -0,0 +1,22 @@ +package org.jeecg.modules.airag.demo; + +import org.jeecg.modules.airag.flow.component.enhance.IAiRagEnhanceJava; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.Map; + +/** + * @Description: Java增强节点示例类 + * @Author: chenrui + * @Date: 2025/3/6 11:42 + */ +@Component("testAiragEnhance") +public class TestAiragEnhance implements IAiRagEnhanceJava { + @Override + public Map process(Map inputParams) { + Object arg1 = inputParams.get("arg1"); + Object arg2 = inputParams.get("arg2"); + return Collections.singletonMap("result",arg1.toString()+"java拼接"+arg2.toString()); + } +} \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/consts/LLMConsts.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/consts/LLMConsts.java index 7e5c8285..ef3f3933 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/consts/LLMConsts.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/consts/LLMConsts.java @@ -35,6 +35,11 @@ public class LLMConsts { */ public static final String MODEL_TYPE_LLM = "LLM"; + /** + * 向量模型:默认维度 + */ + public static final Integer EMBED_MODEL_DEFAULT_DIMENSION = 1536; + /** * 知识库:文档状态:草稿 */ @@ -47,7 +52,10 @@ public class LLMConsts { * 知识库:文档状态:构建完成 */ public static final String KNOWLEDGE_DOC_STATUS_COMPLETE = "complete"; - + /** + * 知识库:文档状态:构建失败 + */ + public static final String KNOWLEDGE_DOC_STATUS_FAILED = "failed"; /** * 知识库:文档类型:文本 diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragKnowledgeController.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragKnowledgeController.java index 2abf2b36..7924baed 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragKnowledgeController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragKnowledgeController.java @@ -4,9 +4,12 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.authz.annotation.RequiresPermissions; import org.jeecg.common.api.vo.Result; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.util.AssertUtils; +import org.jeecg.common.util.TokenUtils; +import org.jeecg.config.mybatis.MybatisPlusSaasConfig; import org.jeecg.modules.airag.common.vo.knowledge.KnowledgeSearchResult; import org.jeecg.modules.airag.llm.consts.LLMConsts; import org.jeecg.modules.airag.llm.entity.AiragKnowledge; @@ -74,6 +77,7 @@ public class AiragKnowledgeController { * @date 2025/2/18 17:09 */ @PostMapping(value = "/add") + @RequiresPermissions("airag:knowledge:add") public Result add(@RequestBody AiragKnowledge airagKnowledge) { airagKnowledge.setStatus(LLMConsts.STATUS_ENABLE); airagKnowledgeService.save(airagKnowledge); @@ -90,6 +94,7 @@ public class AiragKnowledgeController { */ @Transactional(rollbackFor = Exception.class) @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST}) + @RequiresPermissions("airag:knowledge:edit") public Result edit(@RequestBody AiragKnowledge airagKnowledge) { AiragKnowledge airagKnowledgeEntity = airagKnowledgeService.getById(airagKnowledge.getId()); if (airagKnowledgeEntity == null) { @@ -113,6 +118,7 @@ public class AiragKnowledgeController { * @date 2025/3/12 17:05 */ @PutMapping(value = "/rebuild") + @RequiresPermissions("airag:knowledge:rebuild") public Result rebuild(@RequestParam("knowIds") String knowIds) { String[] knowIdArr = knowIds.split(","); for (String knowId : knowIdArr) { @@ -131,29 +137,24 @@ public class AiragKnowledgeController { */ @Transactional(rollbackFor = Exception.class) @DeleteMapping(value = "/delete") - public Result delete(@RequestParam(name = "id", required = true) String id) { + @RequiresPermissions("airag:knowledge:delete") + public Result delete(HttpServletRequest request, @RequestParam(name = "id", required = true) String id) { + //update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ + //如果是saas隔离的情况下,判断当前租户id是否是当前租户下的 + if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + AiragKnowledge know = airagKnowledgeService.getById(id); + //获取当前租户 + String currentTenantId = TokenUtils.getTenantIdByRequest(request); + if (null == know || !know.getTenantId().equals(currentTenantId)) { + return Result.error("删除AI知识库失败,不能删除其他租户的AI知识库!"); + } + } + //update-end---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ airagKnowledgeDocService.removeByKnowIds(Collections.singletonList(id)); airagKnowledgeService.removeById(id); return Result.OK("删除成功!"); } - /** - * 批量删除知识库 - * - * @param ids - * @return - * @author chenrui - * @date 2025/2/18 17:09 - */ - @Transactional(rollbackFor = Exception.class) - @DeleteMapping(value = "/deleteBatch") - public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { - List idsList = Arrays.asList(ids.split(",")); - airagKnowledgeDocService.removeByKnowIds(idsList); - airagKnowledgeService.removeByIds(idsList); - return Result.OK("批量删除成功!"); - } - /** * 通过id查询知识库 * @@ -203,6 +204,7 @@ public class AiragKnowledgeController { * @date 2025/2/18 15:47 */ @PostMapping(value = "/doc/edit") + @RequiresPermissions("airag:knowledge:doc:edit") public Result addDocument(@RequestBody AiragKnowledgeDoc airagKnowledgeDoc) { return airagKnowledgeDocService.editDocument(airagKnowledgeDoc); } @@ -215,6 +217,7 @@ public class AiragKnowledgeController { * @date 2025/3/20 11:29 */ @PostMapping(value = "/doc/import/zip") + @RequiresPermissions("airag:knowledge:doc:zip") public Result importDocumentFromZip(@RequestParam(name = "knowId", required = true) String knowId, @RequestParam(name = "file", required = true) MultipartFile file) { return airagKnowledgeDocService.importDocumentFromZip(knowId,file); @@ -241,6 +244,7 @@ public class AiragKnowledgeController { * @date 2025/2/18 15:47 */ @PutMapping(value = "/doc/rebuild") + @RequiresPermissions("airag:knowledge:doc:rebuild") public Result rebuildDocument(@RequestParam("docIds") String docIds) { return airagKnowledgeDocService.rebuildDocument(docIds); } @@ -255,12 +259,49 @@ public class AiragKnowledgeController { */ @Transactional(rollbackFor = Exception.class) @DeleteMapping(value = "/doc/deleteBatch") - public Result deleteDocumentBatch(@RequestParam(name = "ids", required = true) String ids) { + @RequiresPermissions("airag:knowledge:doc:deleteBatch") + public Result deleteDocumentBatch(HttpServletRequest request, @RequestParam(name = "ids", required = true) String ids) { List idsList = Arrays.asList(ids.split(",")); + //update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ + //如果是saas隔离的情况下,判断当前租户id是否是当前租户下的 + if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + List docList = airagKnowledgeDocService.listByIds(idsList); + //获取当前租户 + String currentTenantId = TokenUtils.getTenantIdByRequest(request); + docList.forEach(airagKnowledgeDoc -> { + if (null == airagKnowledgeDoc || !airagKnowledgeDoc.getTenantId().equals(currentTenantId)) { + throw new IllegalArgumentException("删除AI知识库文档失败,不能删除其他租户的AI知识库文档!"); + } + }); + } + //update-end---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ airagKnowledgeDocService.removeDocByIds(idsList); return Result.OK("批量删除成功!"); } + /** + * 清空知识库文档 + * + * @param + * @return + */ + @Transactional(rollbackFor = Exception.class) + @DeleteMapping(value = "/doc/deleteAll") + @RequiresPermissions("airag:knowledge:doc:deleteAll") + public Result deleteDocumentAll(HttpServletRequest request, @RequestParam(name = "knowId") String knowId) { + //update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ + //如果是saas隔离的情况下,判断当前租户id是否是当前租户下的 + if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + AiragKnowledge know = airagKnowledgeService.getById(knowId); + //获取当前租户 + String currentTenantId = TokenUtils.getTenantIdByRequest(request); + if (null == know || !know.getTenantId().equals(currentTenantId)) { + return Result.error("删除AI知识库失败,不能删除其他租户的AI知识库!"); + } + } + //update-end---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ + return airagKnowledgeDocService.deleteAllByKnowId(knowId); + } /** * 命中测试 diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragModelController.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragModelController.java index e13841e0..990d360a 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragModelController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/controller/AiragModelController.java @@ -3,12 +3,23 @@ package org.jeecg.modules.airag.llm.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.embedding.EmbeddingModel; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.jeecg.ai.factory.AiModelFactory; +import org.jeecg.ai.factory.AiModelOptions; import org.jeecg.common.api.vo.Result; import org.jeecg.common.system.base.controller.JeecgController; import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.util.AssertUtils; +import org.jeecg.common.util.TokenUtils; +import org.jeecg.config.mybatis.MybatisPlusSaasConfig; +import org.jeecg.modules.airag.llm.consts.LLMConsts; import org.jeecg.modules.airag.llm.entity.AiragModel; +import org.jeecg.modules.airag.llm.handler.AIChatHandler; +import org.jeecg.modules.airag.llm.handler.EmbeddingHandler; import org.jeecg.modules.airag.llm.service.IAiragModelService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -17,6 +28,7 @@ import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; +import java.util.Collections; /** * @Description: AiRag模型配置 @@ -32,6 +44,8 @@ public class AiragModelController extends JeecgController add(@RequestBody AiragModel airagModel) { + // 验证 模型名称/模型类型/基础模型 + AssertUtils.assertNotEmpty("模型名称不能为空", airagModel.getName()); + AssertUtils.assertNotEmpty("模型类型不能为空", airagModel.getModelType()); + AssertUtils.assertNotEmpty("基础模型不能为空", airagModel.getModelName()); airagModelService.save(airagModel); return Result.OK("添加成功!"); } @@ -69,6 +88,7 @@ public class AiragModelController extends JeecgController edit(@RequestBody AiragModel airagModel) { airagModelService.updateById(airagModel); return Result.OK("编辑成功!"); @@ -81,23 +101,23 @@ public class AiragModelController extends JeecgController delete(@RequestParam(name = "id", required = true) String id) { + @RequiresPermissions("airag:model:delete") + public Result delete(HttpServletRequest request, @RequestParam(name = "id", required = true) String id) { + //update-begin---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ + //如果是saas隔离的情况下,判断当前租户id是否是当前租户下的 + if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + AiragModel model = airagModelService.getById(id); + //获取当前租户 + String currentTenantId = TokenUtils.getTenantIdByRequest(request); + if (null == model || !model.getTenantId().equals(currentTenantId)) { + return Result.error("删除AI模型失败,不能删除其他租户的AI模型!"); + } + } + //update-end---author:chenrui ---date:20250606 for:[issues/8337]关于ai工作列表的数据权限问题 #8337------------ airagModelService.removeById(id); return Result.OK("删除成功!"); } - /** - * 批量删除 - * - * @param ids - * @return - */ - @DeleteMapping(value = "/deleteBatch") - public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) { - this.airagModelService.removeByIds(Arrays.asList(ids.split(","))); - return Result.OK("批量删除成功!"); - } - /** * 通过id查询 * @@ -136,4 +156,25 @@ public class AiragModelController extends JeecgController test(@RequestBody AiragModel airagModel) { + // 验证 模型名称/模型类型/基础模型 + AssertUtils.assertNotEmpty("模型名称不能为空", airagModel.getName()); + AssertUtils.assertNotEmpty("模型类型不能为空", airagModel.getModelType()); + AssertUtils.assertNotEmpty("基础模型不能为空", airagModel.getModelName()); + try { + if(LLMConsts.MODEL_TYPE_LLM.equals(airagModel.getModelType())){ + aiChatHandler.completions(airagModel, Collections.singletonList(UserMessage.from("test connection")), null); + }else{ + AiModelOptions aiModelOptions = EmbeddingHandler.buildModelOptions(airagModel); + EmbeddingModel embeddingModel = AiModelFactory.createEmbeddingModel(aiModelOptions); + embeddingModel.embed("test text"); + } + }catch (Exception e){ + log.error("测试模型连接失败", e); + return Result.error("测试模型连接失败" + e.getMessage()); + } + return Result.OK("测试模型连接成功"); + } + } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledge.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledge.java index eb61ed3a..590de96d 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledge.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledge.java @@ -30,13 +30,14 @@ public class AiragKnowledge implements Serializable { */ @TableId(type = IdType.ASSIGN_ID) @Schema(description = "主键") - private String id; + private java.lang.String id; /** * 创建人 */ @Schema(description = "创建人") - private String createBy; + @Dict(dictTable = "sys_user",dicCode = "username",dicText = "realname") + private java.lang.String createBy; /** * 创建日期 @@ -50,7 +51,7 @@ public class AiragKnowledge implements Serializable { * 更新人 */ @Schema(description = "更新人") - private String updateBy; + private java.lang.String updateBy; /** * 更新日期 @@ -64,21 +65,21 @@ public class AiragKnowledge implements Serializable { * 所属部门 */ @Schema(description = "所属部门") - private String sysOrgCode; + private java.lang.String sysOrgCode; /** * 租户id */ @Excel(name = "租户id", width = 15) @Schema(description = "租户id") - private String tenantId; + private java.lang.String tenantId; /** * 知识库名称 */ @Excel(name = "知识库名称", width = 15) @Schema(description = "知识库名称") - private String name; + private java.lang.String name; /** * 向量模型id @@ -86,19 +87,19 @@ public class AiragKnowledge implements Serializable { @Excel(name = "向量模型id", width = 15, dictTable = "airag_model where model_type = 'EMBED'", dicText = "name", dicCode = "id") @Dict(dictTable = "airag_model where model_type = 'EMBED'", dicText = "name", dicCode = "id") @Schema(description = "向量模型id") - private String embedId; + private java.lang.String embedId; /** * 描述 */ @Excel(name = "描述", width = 15) @Schema(description = "描述") - private String descr; + private java.lang.String descr; /** * 状态 */ @Excel(name = "状态", width = 15) @Schema(description = "状态") - private String status; + private java.lang.String status; } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledgeDoc.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledgeDoc.java index 8a23716d..9f6d7f18 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledgeDoc.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragKnowledgeDoc.java @@ -3,6 +3,7 @@ package org.jeecg.modules.airag.llm.entity; import java.io.Serializable; import com.baomidou.mybatisplus.annotation.*; +import org.jeecg.common.aspect.annotation.Dict; import org.jeecg.common.constant.ProvinceCityArea; import org.jeecg.common.util.SpringContextUtils; import lombok.Data; @@ -40,6 +41,7 @@ public class AiragKnowledgeDoc implements Serializable { * 创建人 */ @Schema(description = "创建人") + @Dict(dictTable = "sys_user",dicCode = "username",dicText = "realname") private String createBy; /** @@ -119,9 +121,4 @@ public class AiragKnowledgeDoc implements Serializable { @Schema(description = "状态") private String status; - /** - * 服务器基础路径 - */ - @TableField(exist = false) - private String baseUrl; } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragModel.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragModel.java index c79892c3..f456224e 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragModel.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/entity/AiragModel.java @@ -45,6 +45,7 @@ public class AiragModel implements Serializable { * 创建人 */ @Schema(description = "创建人") + @Dict(dictTable = "sys_user",dicCode = "username",dicText = "realname") private String createBy; /** * 创建日期 diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/AIChatHandler.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/AIChatHandler.java index 14b42227..6d0e70c1 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/AIChatHandler.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/AIChatHandler.java @@ -12,7 +12,7 @@ import org.jeecg.modules.airag.common.handler.AIChatParams; import org.jeecg.modules.airag.common.handler.IAIChatHandler; import org.jeecg.modules.airag.llm.consts.LLMConsts; import org.jeecg.modules.airag.llm.entity.AiragModel; -import org.jeecg.modules.airag.llm.service.IAiragModelService; +import org.jeecg.modules.airag.llm.mapper.AiragModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -38,7 +38,7 @@ import java.util.regex.Matcher; public class AIChatHandler implements IAIChatHandler { @Autowired - IAiragModelService airagModelService; + AiragModelMapper airagModelMapper; @Autowired EmbeddingHandler embeddingHandler; @@ -82,7 +82,7 @@ public class AIChatHandler implements IAIChatHandler { AssertUtils.assertNotEmpty("至少发送一条消息", messages); AssertUtils.assertNotEmpty("请选择模型", modelId); - AiragModel airagModel = airagModelService.getById(modelId); + AiragModel airagModel = airagModelMapper.getByIdIgnoreTenant(modelId); return completions(airagModel, messages, params); } @@ -96,7 +96,7 @@ public class AIChatHandler implements IAIChatHandler { * @author chenrui * @date 2025/2/24 17:30 */ - private String completions(AiragModel airagModel, List messages, AIChatParams params) { + public String completions(AiragModel airagModel, List messages, AIChatParams params) { params = mergeParams(airagModel, params); String resp = llmHandler.completions(messages, params); if (resp.contains("") @@ -150,7 +150,7 @@ public class AIChatHandler implements IAIChatHandler { AssertUtils.assertNotEmpty("至少发送一条消息", messages); AssertUtils.assertNotEmpty("请选择模型", modelId); - AiragModel airagModel = airagModelService.getById(modelId); + AiragModel airagModel = airagModelMapper.getByIdIgnoreTenant(modelId); return chat(airagModel, messages, params); } @@ -226,7 +226,7 @@ public class AIChatHandler implements IAIChatHandler { params.setMaxTokens(modelParams.getInteger("maxTokens")); } if (oConvertUtils.isObjectEmpty(params.getTimeout())) { - params.setMaxTokens(modelParams.getInteger("timeout")); + params.setTimeout(modelParams.getInteger("timeout")); } } @@ -237,6 +237,16 @@ public class AIChatHandler implements IAIChatHandler { params.setQueryRouter(queryRouter); } + // 设置确保maxTokens值正确 + if (oConvertUtils.isObjectNotEmpty(params.getMaxTokens()) && params.getMaxTokens() <= 0) { + params.setMaxTokens(null); + } + + // 默认超时时间 + if(oConvertUtils.isObjectEmpty(params.getTimeout())){ + params.setTimeout(60); + } + return params; } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/EmbeddingHandler.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/EmbeddingHandler.java index ca814e25..8ca4d457 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/EmbeddingHandler.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/EmbeddingHandler.java @@ -35,8 +35,9 @@ import org.jeecg.modules.airag.llm.document.TikaDocumentParser; import org.jeecg.modules.airag.llm.entity.AiragKnowledge; import org.jeecg.modules.airag.llm.entity.AiragKnowledgeDoc; import org.jeecg.modules.airag.llm.entity.AiragModel; +import org.jeecg.modules.airag.llm.mapper.AiragKnowledgeMapper; +import org.jeecg.modules.airag.llm.mapper.AiragModelMapper; import org.jeecg.modules.airag.llm.service.IAiragKnowledgeService; -import org.jeecg.modules.airag.llm.service.IAiragModelService; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -69,13 +70,15 @@ public class EmbeddingHandler implements IEmbeddingHandler { EmbedStoreConfigBean embedStoreConfigBean; @Autowired - @Lazy - private IAiragModelService airagModelService; + private AiragModelMapper airagModelMapper; @Autowired @Lazy private IAiragKnowledgeService airagKnowledgeService; + @Autowired + private AiragKnowledgeMapper airagKnowledgeMapper; + @Value(value = "${jeecg.path.upload:}") private String uploadpath; @@ -112,6 +115,13 @@ public class EmbeddingHandler implements IEmbeddingHandler { */ private static final ConcurrentHashMap> EMBED_STORE_CACHE = new ConcurrentHashMap<>(); + + /** + * 正则匹配: md图片 + * "!\\[(.*?)]\\((.*?)(\\s*=\\d+)?\\)" + */ + private static final Pattern PATTERN_MD_IMAGE = Pattern.compile("!\\[(.*?)]\\((.*?)\\)"); + /** * 向量化文档 * @@ -183,6 +193,7 @@ public class EmbeddingHandler implements IEmbeddingHandler { * @author chenrui * @date 2025/2/18 16:52 */ + @Override public KnowledgeSearchResult embeddingSearch(List knowIds, String queryText, Integer topNumber, Double similarity) { AssertUtils.assertNotEmpty("请选择知识库", knowIds); AssertUtils.assertNotEmpty("请填写查询内容", queryText); @@ -223,7 +234,7 @@ public class EmbeddingHandler implements IEmbeddingHandler { */ public List> searchEmbedding(String knowId, String queryText, Integer topNumber, Double similarity) { AssertUtils.assertNotEmpty("请选择知识库", knowId); - AiragKnowledge knowledge = airagKnowledgeService.getById(knowId); + AiragKnowledge knowledge = airagKnowledgeMapper.getByIdIgnoreTenant(knowId); AssertUtils.assertNotEmpty("知识库不存在", knowledge); AssertUtils.assertNotEmpty("请填写查询内容", queryText); AiragModel model = getEmbedModelData(knowledge.getEmbedId()); @@ -268,6 +279,7 @@ public class EmbeddingHandler implements IEmbeddingHandler { * @author chenrui * @date 2025/2/20 21:03 */ + @Override public QueryRouter getQueryRouter(List knowIds, Integer topNumber, Double similarity) { AssertUtils.assertNotEmpty("请选择知识库", knowIds); List retrievers = Lists.newArrayList(); @@ -275,7 +287,7 @@ public class EmbeddingHandler implements IEmbeddingHandler { if (oConvertUtils.isEmpty(knowId)) { continue; } - AiragKnowledge knowledge = airagKnowledgeService.getById(knowId); + AiragKnowledge knowledge = airagKnowledgeMapper.getByIdIgnoreTenant(knowId); AssertUtils.assertNotEmpty("知识库不存在", knowledge); AiragModel model = getEmbedModelData(knowledge.getEmbedId()); AiModelOptions modelOptions = buildModelOptions(model); @@ -345,7 +357,7 @@ public class EmbeddingHandler implements IEmbeddingHandler { */ private AiragModel getEmbedModelData(String modelId) { AssertUtils.assertNotEmpty("向量模型不能为空", modelId); - AiragModel model = airagModelService.getById(modelId); + AiragModel model = airagModelMapper.getByIdIgnoreTenant(modelId); AssertUtils.assertNotEmpty("向量模型不存在", model); AssertUtils.assertEquals("仅支持向量模型", LLMConsts.MODEL_TYPE_EMBED, model.getModelType()); return model; @@ -371,6 +383,18 @@ public class EmbeddingHandler implements IEmbeddingHandler { AiModelOptions modelOp = buildModelOptions(model); EmbeddingModel embeddingModel = AiModelFactory.createEmbeddingModel(modelOp); + + String tableName = embedStoreConfigBean.getTable(); + + // update-begin---author:sunjianlei ---date:20250509 for:【QQYUN-12345】向量模型维度不一致问题 + // 如果该模型不是默认的向量维度 + int dimension = embeddingModel.dimension(); + if (!LLMConsts.EMBED_MODEL_DEFAULT_DIMENSION.equals(dimension)) { + // 就加上维度后缀,防止因维度不一致导致保存失败 + tableName += ("_" + dimension); + } + // update-end-----author:sunjianlei ---date:20250509 for:【QQYUN-12345】向量模型维度不一致问题 + EmbeddingStore embeddingStore = PgVectorEmbeddingStore.builder() // Connection and table parameters .host(embedStoreConfigBean.getHost()) @@ -378,7 +402,7 @@ public class EmbeddingHandler implements IEmbeddingHandler { .database(embedStoreConfigBean.getDatabase()) .user(embedStoreConfigBean.getUser()) .password(embedStoreConfigBean.getPassword()) - .table(embedStoreConfigBean.getTable()) + .table(tableName) // Embedding dimension // Required: Must match the embedding model’s output dimension .dimension(embeddingModel.dimension()) @@ -449,16 +473,20 @@ public class EmbeddingHandler implements IEmbeddingHandler { String fileType = FilenameUtils.getExtension(docFile.getName()); if ("md".contains(fileType)) { // 如果是md文件,查找所有图片语法,如果是本地图片,替换成网络图片 - String baseUrl = doc.getBaseUrl() + "/sys/common/static/"; + String baseUrl = "#{domainURL}/sys/common/static/"; String sourcePath = metadataJson.getString(LLMConsts.KNOWLEDGE_DOC_METADATA_SOURCES_PATH); if(oConvertUtils.isNotEmpty(sourcePath)) { String escapedPath = uploadpath; - if (File.separator.equals("\\")){ + //update-begin---author:wangshuai---date:2025-06-03---for:【QQYUN-12636】【AI知识库】文档库上传 本地local 文档中的图片不展示--- + /*if (File.separator.equals("\\")){ escapedPath = uploadpath.replace("//", "\\\\"); - } + }*/ + //update-end---author:wangshuai---date:2025-06-03---for:【QQYUN-12636】【AI知识库】文档库上传 本地local 文档中的图片不展示--- sourcePath = sourcePath.replaceFirst("^" + escapedPath, "").replace("\\", "/"); - baseUrl = baseUrl + sourcePath + "/"; - StringBuffer sb = replaceImageUrl(content, baseUrl); + String docFilePath = metadataJson.getString(LLMConsts.KNOWLEDGE_DOC_METADATA_FILEPATH); + docFilePath = FilenameUtils.getPath(docFilePath); + docFilePath = docFilePath.replace("\\", "/"); + StringBuffer sb = replaceImageUrl(content, baseUrl + sourcePath + "/", baseUrl + docFilePath); content = sb.toString(); } } @@ -469,11 +497,9 @@ public class EmbeddingHandler implements IEmbeddingHandler { } @NotNull - private static StringBuffer replaceImageUrl(String content, String baseUrl) { + private static StringBuffer replaceImageUrl(String content, String abstractBaseUrl, String relativeBaseUrl) { // 正则表达式匹配md文件中的图片语法 ![alt text](image url) - String mdImagePattern = "!\\[(.*?)]\\((.*?)(\\s*=\\d+)?\\)"; - Pattern pattern = Pattern.compile(mdImagePattern); - Matcher matcher = pattern.matcher(content); + Matcher matcher = PATTERN_MD_IMAGE.matcher(content); StringBuffer sb = new StringBuffer(); while (matcher.find()) { @@ -481,7 +507,16 @@ public class EmbeddingHandler implements IEmbeddingHandler { // 检查是否是本地图片路径 if (!imageUrl.startsWith("http")) { // 替换成网络图片路径 - String networkImageUrl = baseUrl + imageUrl; + String networkImageUrl = abstractBaseUrl + imageUrl; + if(imageUrl.startsWith("/")) { + // 绝对路径 + networkImageUrl = abstractBaseUrl + imageUrl; + }else{ + // 相对路径 + networkImageUrl = relativeBaseUrl + imageUrl; + } + // 修改图片路径中//->/,但保留http://和https:// + networkImageUrl = networkImageUrl.replaceAll("(? { + /** + * 根据ID查询知识库信息(忽略租户) + * for [QQYUN-12113]分享之后的聊天,应用、模型、知识库不根据租户查询 + * @param id + * @return + * @author chenrui + * @date 2025/4/21 15:24 + */ + @InterceptorIgnore(tenantLine = "true") + AiragKnowledge getByIdIgnoreTenant(String id); } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/AiragModelMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/AiragModelMapper.java index f640d682..61dc87d9 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/AiragModelMapper.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/AiragModelMapper.java @@ -1,5 +1,6 @@ package org.jeecg.modules.airag.llm.mapper; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.jeecg.modules.airag.llm.entity.AiragModel; @@ -11,4 +12,14 @@ import org.jeecg.modules.airag.llm.entity.AiragModel; */ public interface AiragModelMapper extends BaseMapper { + /** + * 根据ID查询模型信息(忽略租户) + * for [QQYUN-12113]分享之后的聊天,应用、模型、知识库不根据租户查询 + * @param id + * @return + * @author chenrui + * @date 2025/4/21 15:24 + */ + @InterceptorIgnore(tenantLine = "true") + AiragModel getByIdIgnoreTenant(String id); } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragKnowledgeMapper.xml b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragKnowledgeMapper.xml index c433f4e8..7dfded2f 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragKnowledgeMapper.xml +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragKnowledgeMapper.xml @@ -2,4 +2,8 @@ + + \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragModelMapper.xml b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragModelMapper.xml index 60683f67..f89dde53 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragModelMapper.xml +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/mapper/xml/AiragModelMapper.xml @@ -2,4 +2,8 @@ + + \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/IAiragKnowledgeDocService.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/IAiragKnowledgeDocService.java index df0a534f..f082a8f2 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/IAiragKnowledgeDocService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/IAiragKnowledgeDocService.java @@ -67,6 +67,14 @@ public interface IAiragKnowledgeDocService extends IService { */ Result removeDocByIds(List docIds); + /** + * 通过知识库id删除所以文档 + * + * @param knowId + * @return + */ + Result deleteAllByKnowId(String knowId); + /** * 从zip包导入文档 * @param knowId diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java index 0256a916..121595a5 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java @@ -1,9 +1,12 @@ package org.jeecg.modules.airag.llm.service.impl; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.io.FilenameUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.config.TenantContext; @@ -26,9 +29,12 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; @@ -36,8 +42,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import static org.jeecg.modules.airag.llm.consts.LLMConsts.*; @@ -79,6 +83,12 @@ public class AiragKnowledgeDocServiceImpl extends ServiceImpl knowledgeDocs = docList.stream() .filter(doc -> { @@ -143,7 +152,6 @@ public class AiragKnowledgeDocServiceImpl extends ServiceImpl { doc.setStatus(KNOWLEDGE_DOC_STATUS_BUILDING); - doc.setBaseUrl(baseUrl); }) .collect(Collectors.toList()); if (oConvertUtils.isObjectEmpty(knowledgeDocs)) { @@ -174,13 +182,11 @@ public class AiragKnowledgeDocServiceImpl extends ServiceImpl removeByKnowIds(List knowIds) { @@ -198,8 +222,16 @@ public class AiragKnowledgeDocServiceImpl extends ServiceImpl { + try { + embeddingHandler.deleteEmbedDocsByKnowId(finalKnowId, embedId); + } catch (Throwable ignore) { + } + }); // 删除数据 - embeddingHandler.deleteEmbedDocsByKnowId(knowId, airagKnowledge.getEmbedId()); airagKnowledgeDocMapper.deleteByMainId(knowId); } return Result.OK(); @@ -223,13 +255,39 @@ public class AiragKnowledgeDocServiceImpl extends ServiceImpl docIdsToDelete = new ArrayList<>(groupedDocIds); + CompletableFuture.runAsync(() -> { + try { + embeddingHandler.deleteEmbedDocsByDocIds(docIdsToDelete, embedId); + } catch (Throwable ignore) { + } + }); // 删除数据 - embeddingHandler.deleteEmbedDocsByDocIds(groupedDocIds, airagKnowledge.getEmbedId()); airagKnowledgeDocMapper.deleteBatchIds(groupedDocIds); }); return Result.ok("success"); } + @Override + public Result deleteAllByKnowId(String knowId) { + if (oConvertUtils.isEmpty(knowId)) { + return Result.error("知识库id不能为空"); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AiragKnowledgeDoc::getKnowledgeId, knowId); + //noinspection unchecked + wrapper.select(AiragKnowledgeDoc::getId); + List docList = airagKnowledgeDocMapper.selectList(wrapper); + if (docList.isEmpty()) { + return Result.ok("暂无文档"); + } + List docIds = docList.stream().map(AiragKnowledgeDoc::getId).collect(Collectors.toList()); + this.removeDocByIds(docIds); + return Result.ok("清空完成"); + } + @Transactional(rollbackFor = {java.lang.Exception.class}) @Override public Result importDocumentFromZip(String knowId, MultipartFile zipFile) { @@ -283,6 +341,7 @@ public class AiragKnowledgeDocServiceImpl extends ServiceImpl afterExtract) throws - IOException { - // 创建目标目录 - File dir = new File(destDir); - if (!dir.exists()) { - dir.mkdirs(); + public static void unzipFile(String zipFilePath, String destDir, Consumer afterExtract) throws IOException { + unzipFile(Paths.get(zipFilePath), Paths.get(destDir), afterExtract); + } + + + /** + * 解压缩文件 + * + * @param zipFilePath 压缩文件路径 + * @param targetDir 目标文件夹 + * @param afterExtract 解压完成后回调 + * @throws IOException + * @author chenrui + * @date 2025/4/28 17:02 + */ + private static void unzipFile(Path zipFilePath, Path targetDir, Consumer afterExtract) throws IOException { + long totalUnzippedSize = 0; + int entryCount = 0; + + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); } - try (ZipFile zipFile = new ZipFile(zipFilePath)) { - Enumeration entries = zipFile.entries(); - byte[] buffer = new byte[1024]; + try (ZipFile zipFile = new ZipFile(zipFilePath.toFile())) { + Enumeration entries = zipFile.getEntries(); while (entries.hasMoreElements()) { - ZipEntry ze = entries.nextElement(); - File newFile = new File(destDir, ze.getName()); - - // 预防 ZIP 路径穿越攻击 - String canonicalDestDirPath = dir.getCanonicalPath(); - String canonicalFilePath = newFile.getCanonicalPath(); - if (!canonicalFilePath.startsWith(canonicalDestDirPath + File.separator)) { - throw new IOException("ZIP 路径穿越攻击被阻止: " + ze.getName()); + ZipArchiveEntry entry = entries.nextElement(); + entryCount++; + if (entryCount > MAX_ENTRY_COUNT) { + throw new IOException("解压文件数量超限,可能是zip bomb攻击"); } - if (ze.isDirectory()) { - newFile.mkdirs(); - } else { - // 创建父目录 - new File(newFile.getParent()).mkdirs(); + Path newPath = safeResolve(targetDir, entry.getName()); - // 读取 ZIP 文件并写入新文件 - try (InputStream zis = zipFile.getInputStream(ze); - FileOutputStream fos = new FileOutputStream(newFile)) { - int len; - while ((len = zis.read(buffer)) > 0) { - fos.write(buffer, 0, len); + if (entry.isDirectory()) { + Files.createDirectories(newPath); + } else { + Files.createDirectories(newPath.getParent()); + try (InputStream is = zipFile.getInputStream(entry); + OutputStream os = Files.newOutputStream(newPath)) { + + long bytesCopied = copyLimited(is, os, MAX_FILE_SIZE); + totalUnzippedSize += bytesCopied; + + if (totalUnzippedSize > MAX_TOTAL_SIZE) { + throw new IOException("解压总大小超限,可能是zip bomb攻击"); } } + // 解压完成后回调 if (afterExtract != null) { - afterExtract.accept(newFile); + afterExtract.accept(newPath.toFile()); } } } } } + /** + * 安全解析路径,防止Zip Slip攻击 + * + * @param targetDir + * @param entryName + * @return + * @throws IOException + * @author chenrui + * @date 2025/4/28 16:46 + */ + private static Path safeResolve(Path targetDir, String entryName) throws IOException { + Path resolvedPath = targetDir.resolve(entryName).normalize(); + if (!resolvedPath.startsWith(targetDir)) { + throw new IOException("ZIP 路径穿越攻击被阻止:" + entryName); + } + return resolvedPath; + } + + /** + * 复制输入流到输出流,并限制最大字节数 + * + * @param in + * @param out + * @param maxBytes + * @return + * @throws IOException + * @author chenrui + * @date 2025/4/28 17:03 + */ + private static long copyLimited(InputStream in, OutputStream out, long maxBytes) throws IOException { + byte[] buffer = new byte[8192]; + long totalCopied = 0; + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) { + totalCopied += bytesRead; + if (totalCopied > maxBytes) { + throw new IOException("单个文件解压超限,可能是zip bomb攻击"); + } + out.write(buffer, 0, bytesRead); + } + return totalCopied; + } + } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/vo/KnowledgeSearchResult.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/vo/KnowledgeSearchResult.java deleted file mode 100644 index 443cc47a..00000000 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/vo/KnowledgeSearchResult.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.jeecg.modules.airag.llm.vo; - -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - -/** - * 知识库查询返回结果 - * - * @Author: chenrui - * @Date: 2025/2/18 17:53 - */ -@Data -@NoArgsConstructor -public class KnowledgeSearchResult { - - /** - * 命中的文档内容 - */ - String data; - - /** - * 命中的文档列表 - */ - List> documents; - - public KnowledgeSearchResult(String data, List> documents) { - this.data = data; - this.documents = documents; - } -} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/ocr/controller/AiOcrController.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/ocr/controller/AiOcrController.java new file mode 100644 index 00000000..4568885f --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/ocr/controller/AiOcrController.java @@ -0,0 +1,94 @@ +package org.jeecg.modules.airag.ocr.controller; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections.CollectionUtils; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.util.RedisUtil; +import org.jeecg.modules.airag.ocr.entity.AiOcr; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/airag/ocr") +public class AiOcrController { + + @Autowired + private RedisUtil redisUtil; + + private static final String AI_OCR_REDIS_KEY = "airag:ocr"; + + @GetMapping("/list") + public Result list(){ + Object aiOcr = redisUtil.get(AI_OCR_REDIS_KEY); + IPage page = new Page<>(1,10); + if(null != aiOcr){ + List aiOcrList = JSONObject.parseArray(aiOcr.toString(), AiOcr.class); + page.setRecords(aiOcrList); + page.setTotal(aiOcrList.size()); + page.setPages(aiOcrList.size()); + } + return Result.OK(page); + } + + @PostMapping("/add") + public Result add(@RequestBody AiOcr aiOcr){ + Object aiOcrList = redisUtil.get(AI_OCR_REDIS_KEY); + aiOcr.setId(UUID.randomUUID().toString().replace("-","")); + if(null == aiOcrList){ + List list = new ArrayList<>(); + list.add(aiOcr); + redisUtil.set(AI_OCR_REDIS_KEY, JSONObject.toJSONString(list)); + }else{ + List aiOcrs = JSONObject.parseArray(aiOcrList.toString(), AiOcr.class); + aiOcrs.add(aiOcr); + redisUtil.set(AI_OCR_REDIS_KEY,JSONObject.toJSONString(aiOcrs)); + } + return Result.OK("添加成功"); + } + + @PutMapping("/edit") + public Result updateById(@RequestBody AiOcr aiOcr){ + Object aiOcrList = redisUtil.get(AI_OCR_REDIS_KEY); + if(null != aiOcrList){ + List aiOcrs = JSONObject.parseArray(aiOcrList.toString(), AiOcr.class); + aiOcrs.forEach(item->{ + if(item.getId().equals(aiOcr.getId())){ + BeanUtils.copyProperties(aiOcr,item); + } + }); + redisUtil.set(AI_OCR_REDIS_KEY,JSONObject.toJSONString(aiOcrs)); + }else{ + return Result.OK("编辑失败,未找到该数据"); + } + return Result.OK("编辑成功"); + } + + @DeleteMapping("/deleteById") + public Result deleteById(@RequestBody AiOcr aiOcr){ + Object aiOcrObj = redisUtil.get(AI_OCR_REDIS_KEY); + if(null != aiOcrObj){ + List aiOcrs = JSONObject.parseArray(aiOcrObj.toString(), AiOcr.class); + List aiOcrList = new ArrayList<>(); + for(AiOcr ocr: aiOcrs){ + if(!ocr.getId().equals(aiOcr.getId())){ + aiOcrList.add(ocr); + } + } + if(CollectionUtils.isNotEmpty(aiOcrList)){ + redisUtil.set(AI_OCR_REDIS_KEY,JSONObject.toJSONString(aiOcrList)); + }else{ + redisUtil.removeAll(AI_OCR_REDIS_KEY); + } + }else{ + return Result.OK("删除失败,未找到该数据"); + } + return Result.OK("删除成功"); + } +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/ocr/entity/AiOcr.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/ocr/entity/AiOcr.java new file mode 100644 index 00000000..944747d1 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/ocr/entity/AiOcr.java @@ -0,0 +1,29 @@ +package org.jeecg.modules.airag.ocr.entity; + +import lombok.Data; + +/** +* @Description: OCR识别实体类 +* +* @author: wangshuai +* @date: 2025/4/16 17:01 +*/ +@Data +public class AiOcr { + + /** + * 编号 + */ + private String id; + + /** + * 标题 + */ + private String title; + + /** + * 提示词 + */ + private String prompt; + +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/resources/logback-spring.xml b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/resources/logback-spring.xml deleted file mode 100644 index e07d788f..00000000 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}:%L) - %msg%n - - - - - - - - ${LOG_HOME}/jeecgboot-%d{yyyy-MM-dd}.%i.log - - 30 - 10MB - - - - %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n - - - - - - - - ERROR - - - - %p%d%msg%M%F{32}%L - - - ${LOG_HOME}/error-log.html - - - - - - - - ${LOG_HOME}/jeecgboot-%d{yyyy-MM-dd}.%i.html - - 30 - 10MB - - - - %p%d%msg%M%F{32}%L - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/java/org/jeecg/modules/airag/test/TestLLM.java b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/java/org/jeecg/modules/airag/test/TestLLM.java index 74c47629..7c0eba5d 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/java/org/jeecg/modules/airag/test/TestLLM.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/java/org/jeecg/modules/airag/test/TestLLM.java @@ -1,7 +1,10 @@ //package org.jeecg.modules.airag.test; // +//import dev.langchain4j.agent.tool.ToolParameters; +//import dev.langchain4j.agent.tool.ToolSpecification; //import dev.langchain4j.data.message.*; //import dev.langchain4j.model.chat.ChatLanguageModel; +//import dev.langchain4j.model.chat.request.json.JsonObjectSchema; //import dev.langchain4j.model.openai.OpenAiChatModel; //import dev.langchain4j.model.output.Response; //import dev.langchain4j.service.AiServices; @@ -12,15 +15,13 @@ //import org.jeecg.ai.factory.AiModelOptions; //import org.jeecg.ai.handler.AIParams; //import org.jeecg.ai.handler.LLMHandler; -//import org.jeecg.modules.airag.llm.handler.AIChatParams; -//import org.junit.Test; +//import org.junit.jupiter.api.Test; // //import java.io.IOException; +//import java.io.Serial; //import java.nio.file.Files; //import java.nio.file.Paths; -//import java.util.ArrayList; -//import java.util.Base64; -//import java.util.Collections; +//import java.util.*; //import java.util.concurrent.ConcurrentHashMap; //import java.util.concurrent.CountDownLatch; // @@ -174,4 +175,51 @@ // } // // +// @Test +// public void testFuncCalling() { +// String apiKey = "sk-"; +// String baseUrl = "https://api.v3.cm/v1"; +// String modelName = "gpt-4o-mini"; +// double temperature = 0.7; +// ChatLanguageModel llmModel = OpenAiChatModel.builder() +// .apiKey(apiKey) +// .baseUrl(baseUrl) +// .modelName(modelName) +// .temperature(temperature) +// .build(); +// +// List toolSpecifications = new ArrayList<>(); +// Map> properties = new ConcurrentHashMap<>(); +// +// properties.put("location", new HashMap<>() { +// @Serial +// private static final long serialVersionUID = -8440944665582258534L; +// { +// put("type", "string"); +// put("description", "The city and state, e.g. San Francisco, CA"); +// } +// }); +// ToolSpecification toolSpecification = ToolSpecification.builder() +// .name("get_current_weather") +// .description("Get the current weather in a given location") +// .parameters(ToolParameters.builder() +// .properties(properties) +// .required(List.of("location")) +// .type("string") +// .build()) +// .build(); +// toolSpecifications.add(toolSpecification); +// +// List messages = new ArrayList<>(); +// messages.add(UserMessage.from("How is the weather in Beijing today?")); +// +// Response resp = llmModel.generate(messages, toolSpecifications); +// System.out.println(resp); +// +// /*Response { content = AiMessage { text = null +// toolExecutionRequests = [ToolExecutionRequest { id = "call_hjPaRh9WAHv6Ib7KpgHpp8Tl", name = "get_current_weather", arguments = "{"location":"Beijing, China"}" }] }, +// tokenUsage = TokenUsage { inputTokenCount = 69, outputTokenCount = 19, totalTokenCount = 88 }, finishReason = TOOL_EXECUTION, metadata = {} }*/ +// } +// +// //} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.doc b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.doc deleted file mode 100644 index 79122b4f..00000000 Binary files a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.doc and /dev/null differ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.docx b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.docx deleted file mode 100644 index 18a7acb2..00000000 Binary files a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.docx and /dev/null differ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.pdf b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.pdf deleted file mode 100644 index 06b1c1c7..00000000 Binary files a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.pdf and /dev/null differ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.ppt b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.ppt deleted file mode 100644 index 02a35da1..00000000 Binary files a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.ppt and /dev/null differ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.pptx b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.pptx deleted file mode 100644 index a1fbf3e4..00000000 Binary files a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.pptx and /dev/null differ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.txt b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.txt deleted file mode 100644 index f948c9d3..00000000 --- a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.txt +++ /dev/null @@ -1,97 +0,0 @@ -常见问题 -1.pnpm安装依赖报错 -错误: node\_modules\\vite\\node\_modules\\esbuild\\esbuild.exe ENOENT -解决方案:https://blog.csdn.net/weixin_41760500/article/details/119885574
命令:node ./node_modules/esbuild/install.js -2.pnpm安装后,访问提示缺少依赖 -
解决方案: https://stackoverflow.com/questions/70597494/pnpm-does-not-resolve-dependencies -3.pnpm install出现错误 -错误:ERR\_PNPM\_PEER\_DEP\_ISSUES Unmet peer dependencies -http://ms521.cn/index.php/Home/Index/article/aid/271 -4.项目安装依赖无问题,访问页面报错 -前端部分报错: -[plugin:vite:vue-jsx] Cannot find package 'C:\Users\123\Desktop\JeecgBoot-master\pincone_system\jeecgboot-vue3\node_modules\.pnpm\@vitejs+plugin-vue-jsx@3.1.0_vite@5.4.9_@types+node@20.16.13_less@4.2.0_terser@5.36.0__vue@3.5.12_typescript@4.9.5_\node_modules\@babel\plugin-transform-typescript\lib\index.js' imported from C:\Users\123\Desktop\JeecgBoot-master\pincone_system\jeecgboot-vue3\node_modules\.pnpm\@vitejs+plugin-vue-jsx@3.1.0_vite@5.4.9_@types+node@20.16.13_less@4.2.0_terser@5.36.0__vue@3.5.12_typescript@4.9.5_\node_modules\@vitejs\plugin-vue-jsx\dist\index.cjs Did you mean to import "@babel/plugin-transform-typescript/lib/index.js"? #7396 -回答: 是因为项目的路径太长导致 ,相关问题Issues,查看相关博客 - • https://blog.csdn.net/weixin_43235500/article/details/142144989 - • https://blog.csdn.net/qq_25996219/article/details/140328092 -5. 通过npm install启动报错 -建议:请使用pnpm i 可以避免更多问题 -错误情况: -
解决:进入提示的路径 \node_modules\vite-plugin-mock\node_modules\esbuild\
执行命令: node install.js
再启动就好了 -6. 前端刷新进不了登录页面 -报错props.ts:15 Uncaught (in promise) SyntaxError: Unexpected token '='
错误截图: -原因:谷歌浏览器版本过低,升级浏览器
比如这边版本就过低了 - -7.表单如何全部禁用 -加上这个属性就可以了
 -效果
 -8.table列表如何自定义排序 - defSort: { - column: 'id', - order: 'desc', - }, -参考示例: - -9.idea编写js时爆红,提示statement expected -https://blog.csdn.net/mlsama/article/details/80633009 -10.抽屉的setDrawerProps不好使(值会还原) - -11. 如何删除不需要的demo,制作一个精简版本 -精简项目,删除demo等非必须功能 -12.vue3 暗黑模式下显示不完整 -错误示例: - -解决方案: -在样式中的字体颜色和背景颜色使用@变量名称来代替 -color: @text-color; -background-color: @component-background; - -[info] 通用样式变量名称可以在在目录bulid->vite->plugin->themes.ts中找到,darkModifyVars是重写antd中的样式 - -[info]更多样式变量名称请参考目录node_modules/es/style/themes/default.less -
改造完成之后的效果 - -13.操作列“删除按钮”界面布局异常 -相关issue -https://github.com/jeecgboot/jeecgboot-vue3/issues/458 -问题截图: - -解决方案:找到popConfirm填写属性placement: 'left' -placement: 'left', - -效果截图 - -14.在centos7中下载依赖pnpm i时 mozjpeg依赖下载不下来 -https://github.com/jeecgboot/jeecgboot-vue3/issues/433#issuecomment-1510470534 -15.日期遮挡问题 -问题截图:
下拉显示组件,页面滚动时,页面出现错位遮挡问题 - -解决方案:将组件挂载到父节点上 -getPopupContainer: (node) => node.parentNode, -效果截图 - -16.nextTick作用 -在 Vue 3 中,nextTick 方法用于在 DOM 更新之后执行回调函数。它的作用是在下次 DOM 更新循环结束后执行一些操作,以确保你在操作更新的 DOM 元素时能够获取到最新的结果。
nextTick 方法可以用于以下情况: - 1 在更新数据后立即操作 DOM 元素。 - 2 在更新组件后执行某些逻辑或触发一些副作用。 - 3 在更新后获取更新后的 DOM 元素的尺寸或位置等信息。 -使用nextTick 方法有两种方式:
1.使用回调函数: -nextTick(()=> -//在DOM更新后执行的操作 -}): -2.使用Promise: -nextTick().then(()=> -//在DOM更新后执行的操作 -}) -无论使用哪种方式,传入的回调函数或Promisel回调都会在下一次DOM更新周期之后被调用。这样可以确保在数据变化后,Vue已经完成了相应的DOM更新。 -需要注意的是,nextTick 方法是异步执行的,因此不能保证回调函数会立即执行。如果需要等待nextTick执行完成,可以使用await关键字或者. then()方法来等待Promise的完成。 -17. 一个页面多个表格,列的展示会互相影响 -[info] 相关issue -https://github.com/jeecgboot/jeecgboot-vue3/issues/1064 -[info]问题截图 - -[info] 解决方案:在不同的tableProps下设置不同的checkKey即可解决 - -tableSetting: { cacheKey: 'depart_user_departInfo' }, -18. 通过npm install启动报错 -
可以使用这个命令: -npm install --ignore-scripts diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.xls b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.xls deleted file mode 100644 index 3bdc599f..00000000 Binary files a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.xls and /dev/null differ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.xlsx b/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.xlsx deleted file mode 100644 index 1a1519b7..00000000 Binary files a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/test/resources/test.xlsx and /dev/null differ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/cloud/controller/JcloudDemoFeignController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/cloud/controller/JcloudDemoFeignController.java index 100f87e9..26968540 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/cloud/controller/JcloudDemoFeignController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/cloud/controller/JcloudDemoFeignController.java @@ -1,8 +1,8 @@ //package org.jeecg.modules.demo.cloud.controller; // //import com.alibaba.csp.sentinel.annotation.SentinelResource; -//import io.swagger.annotations.Api; -//import io.swagger.annotations.ApiOperation; +//import io.swagger.v3.oas.annotations.tags.Tag; +//import io.swagger.v3.oas.annotations.Operation; //import lombok.extern.slf4j.Slf4j; //import org.jeecg.common.api.vo.Result; //import org.jeecg.common.system.api.ISysBaseAPI; @@ -18,7 +18,7 @@ // * // */ //@Slf4j -//@Api(tags = "【微服务】单元测试") +//@Tag(name = "【微服务】单元测试") //@RestController //@RequestMapping("/test") //public class JcloudDemoFeignController { @@ -34,7 +34,7 @@ // */ // @GetMapping("/callSystem") // //@SentinelResource(value = "remoteDict",fallback = "getDefaultHandler") -// @ApiOperation(value = "通过feign调用system服务", notes = "测试jeecg-demo服务,是否通过fegin调用system服务接口") +// @Operation(summary = "通过feign调用system服务") // public Result getRemoteDict() { // List list = sysBaseApi.queryAllDict(); // return Result.OK(list); @@ -48,7 +48,7 @@ //// * @return //// */ //// @GetMapping("/callErp") -//// @ApiOperation(value = "测试feign erp", notes = "测试feign erp") +//// @Operation(summary = "测试feign erp") //// public Result callErp() { //// log.info("call erp 服务"); //// String res = erpHelloApi.callHello(); diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/controller/AiController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/controller/AiController.java deleted file mode 100644 index ec35dd13..00000000 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/controller/AiController.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.jeecg.modules.demo.gpt.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.extern.slf4j.Slf4j; -import org.jeecg.chatgpt.service.AiChatService; -import org.jeecg.common.api.vo.Result; -import org.jeecg.common.aspect.annotation.AutoLog; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -//update-begin---author:chenrui ---date:20240110 for:[QQYUN-5509]AI生成表结构和软文------------ - -/** - * @Description: chatGpt接口 - * @Author: chenrui - * @Date: 2024/1/9 16:30 - */ -@Tag(name = "AI接口") -@RestController -@RequestMapping("/test/ai") -@Slf4j -public class AiController { - - private static final String CACHE_PREFIX = "ai:resp:"; - - @Autowired - AiChatService aiChatService; - - - /** - * 通过AI生成模块表设计 - * @param descr 描述 - * @return - * @author chenrui - * @date 2024/1/9 20:12 - */ - @AutoLog(value = "通过AI生成模块表设计") - @PostMapping(value = "/gen/schema/modules") - @Operation(summary = "通过AI生成模块表设计") - public Result genSchemaModules(@RequestParam(name = "prompt", required = true) String prompt) { - String result = aiChatService.genSchemaModules(prompt); - return Result.ok(result); - } - - /** - * 通过AI生成软文 - * @param descr 描述 - * @return - * @author chenrui - * @date 2024/1/9 20:12 - */ - @AutoLog(value = "通过AI生成软文") - @PostMapping(value = "/gen/article") - @Operation(summary = "通过AI生成软文") - public Result genArticle(@RequestParam(name = "prompt", required = true) String prompt) { - String result = aiChatService.genArticleWithMd(prompt); - return Result.ok(result); - } - - /** - * 向AI提问 - * @param message - * @return - * @author chenrui - * @date 2024/1/15 19:11 - */ - @AutoLog(value = "向AI提问") - @PostMapping(value = "/completions") - @Operation(summary = "向AI提问") - public Result completions(@RequestParam(name = "message", required = true) String message) { - String result = aiChatService.completions(message); - return Result.ok(result); - } - - /** - * 让AI生成图片 - * @param prompt - * @return - * @author chenrui - * @date 2024/1/15 19:11 - */ - @AutoLog(value = "让AI生成图片") - @PostMapping(value = "/gen/image") - @Operation(summary = "让AI生成图片") - public Result genImage(@RequestParam(name = "prompt", required = true) String prompt) { - String result = aiChatService.imageGenerate(prompt); - return Result.ok(result); - } - -} -//update-end---author:chenrui ---date:20240110 for://update-begin---author:chenrui ---date:20240110 for:[QQYUN-5509]AI生成表结构和软文------------------------ diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java index 113e6a48..d81b126d 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java @@ -4,8 +4,6 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; @@ -64,7 +62,7 @@ public class JeecgDemoController extends JeecgController list(JeecgDemo jeecgDemo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @@ -477,7 +475,6 @@ public class JeecgDemoController extends JeecgController test() { //解决shiro报错No SecurityManager accessible to the calling code, either bound to the org.apache.shiro diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDynamicDataController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDynamicDataController.java index b6a61ff9..530149b1 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDynamicDataController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDynamicDataController.java @@ -1,7 +1,7 @@ package org.jeecg.modules.demo.test.controller; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java index 721a2259..1b3a1c47 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/test/entity/JeecgDemo.java @@ -3,7 +3,6 @@ package org.jeecg.modules.demo.test.entity; import java.io.Serializable; import com.baomidou.mybatisplus.annotation.Version; -import io.swagger.v3.oas.annotations.media.Schema; import org.jeecg.common.system.base.entity.JeecgEntity; import org.jeecgframework.poi.excel.annotation.Excel; import org.springframework.format.annotation.DateTimeFormat; @@ -11,6 +10,8 @@ import org.springframework.format.annotation.DateTimeFormat; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java index 461705a6..eaa3c7a9 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/handle/impl/EmailSendMsgHandle.java @@ -27,6 +27,10 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.List; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * @Description: 邮箱发送信息 @@ -54,32 +58,37 @@ public class EmailSendMsgHandle implements ISendMsgHandle { * 真实姓名变量 */ private static final String realNameExp = "{REALNAME}"; - + /** + * 线程池用于异步发送消息 + */ + public static ExecutorService cachedThreadPool = new ThreadPoolExecutor(0, 1024, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); @Override public void sendMsg(String esReceiver, String esTitle, String esContent) { JavaMailSender mailSender = (JavaMailSender) SpringContextUtils.getBean("mailSender"); MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = null; //update-begin-author:taoyan date:20200811 for:配置类数据获取 if(oConvertUtils.isEmpty(emailFrom)){ StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class); setEmailFrom(staticConfig.getEmailFrom()); } //update-end-author:taoyan date:20200811 for:配置类数据获取 - try { - helper = new MimeMessageHelper(message, true); - // 设置发送方邮箱地址 - helper.setFrom(emailFrom); - helper.setTo(esReceiver); - helper.setSubject(esTitle); - helper.setText(esContent, true); - mailSender.send(message); - } catch (MessagingException e) { - e.printStackTrace(); - } - + cachedThreadPool.execute(()->{ + try { + log.info("============> 开始邮件发送,接收人:"+esReceiver); + MimeMessageHelper helper = new MimeMessageHelper(message, true); + // 设置发送方邮箱地址 + helper.setFrom(emailFrom); + helper.setTo(esReceiver); + helper.setSubject(esTitle); + helper.setText(esContent, true); + mailSender.send(message); + log.info("============> 邮件发送成功,接收人:"+esReceiver); + } catch (MessagingException e) { + log.error("============> 邮件发送失败,接收人:"+esReceiver, e.getMessage()); + } + }); } @Override @@ -180,24 +189,26 @@ public class EmailSendMsgHandle implements ISendMsgHandle { private void sendEmail(String email, String content, String title){ JavaMailSender mailSender = (JavaMailSender) SpringContextUtils.getBean("mailSender"); MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = null; if (oConvertUtils.isEmpty(emailFrom)) { StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class); setEmailFrom(staticConfig.getEmailFrom()); } - try { - helper = new MimeMessageHelper(message, true); - // 设置发送方邮箱地址 - helper.setFrom(emailFrom); - helper.setTo(email); - //设置抄送人 - helper.setCc(email); - helper.setSubject(title); - helper.setText(content, true); - mailSender.send(message); - } catch (MessagingException e) { - e.printStackTrace(); - } + cachedThreadPool.execute(()->{ + try { + MimeMessageHelper helper = new MimeMessageHelper(message, true); + // 设置发送方邮箱地址 + helper.setFrom(emailFrom); + helper.setTo(email); + //设置抄送人 + helper.setCc(email); + helper.setSubject(title); + helper.setText(content, true); + mailSender.send(message); + log.info("============> 邮件发送成功,接收人:"+email); + } catch (MessagingException e) { + log.warn("============> 邮件发送失败,接收人:"+email, e.getMessage()); + } + }); } //update-end-author:taoyan date:2023-6-20 for: QQYUN-5557【简流】通知节点 发送邮箱 表单上有一个邮箱字段,流程中,邮件发送节点,邮件接收人 不可选择邮箱 diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java index 741f5ab4..b7a1811f 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java @@ -3,8 +3,8 @@ package org.jeecg.modules.quartz.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/CommonController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/CommonController.java index c4abb884..d975bf01 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/CommonController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/CommonController.java @@ -229,7 +229,7 @@ public class CommonController { File file = new File(filePath); if(!file.exists()){ response.setStatus(404); - log.error("文件["+imgPath+"]不存在.."); + log.warn("文件["+imgPath+"]不存在.."); return; //throw new RuntimeException(); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java index 84bc35b2..ab5ce079 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java @@ -1,7 +1,7 @@ package org.jeecg.modules.system.controller; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.jeecg.common.api.vo.Result; @@ -36,7 +36,7 @@ public class DuplicateCheckController { * @return */ @RequestMapping(value = "/check", method = RequestMethod.GET) - @Operation(summary ="重复校验接口") + @Operation(summary="重复校验接口") public Result doDuplicateCheck(DuplicateCheckVo duplicateCheckVo, HttpServletRequest request) { log.debug("----duplicate check------:"+ duplicateCheckVo.toString()); diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java index 6085346e..c9271a4a 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java @@ -5,8 +5,8 @@ import com.alibaba.fastjson.JSONObject; import com.aliyuncs.exceptions.ClientException; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.annotation.RequiresRoles; @@ -70,7 +70,7 @@ public class LoginController { private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890"; - @Operation(summary = "登录接口") + @Operation(summary="登录接口") @RequestMapping(value = "/login", method = RequestMethod.POST) public Result login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request){ Result result = new Result(); @@ -404,7 +404,7 @@ public class LoginController { * @param jsonObject * @return */ - @Operation(summary = "手机号登录接口") + @Operation(summary="手机号登录接口") @PostMapping("/phoneLogin") public Result phoneLogin(@RequestBody JSONObject jsonObject, HttpServletRequest request) { Result result = new Result(); @@ -523,7 +523,7 @@ public class LoginController { * @param response * @param key */ - @Operation(summary = "获取验证码") + @Operation(summary="获取验证码") @GetMapping(value = "/randomImage/{key}") public Result randomImage(HttpServletResponse response,@PathVariable("key") String key){ Result res = new Result(); diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java index aa07a9ff..bcb93489 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java @@ -534,6 +534,7 @@ public class SysAnnouncementController { */ @RequestMapping(value = "/vue3List", method = RequestMethod.GET) public Result> vue3List(@RequestParam(name="fromUser", required = false) String fromUser, + @RequestParam(name="busType", required = false) String busType, @RequestParam(name="starFlag", required = false) String starFlag, @RequestParam(name="rangeDateKey", required = false) String rangeDateKey, @RequestParam(name="beginDate", required = false) String beginDate, @@ -562,7 +563,7 @@ public class SysAnnouncementController { } // 2、根据条件查询用户的通知消息 - List ls = this.sysAnnouncementService.querySysMessageList(pageSize, pageNo, fromUser, starFlag, beginTime, endTime); + List ls = this.sysAnnouncementService.querySysMessageList(pageSize, pageNo, fromUser, starFlag,busType, beginTime, endTime); // 3、设置当前页的消息为已读 if (!CollectionUtils.isEmpty(ls)) { diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java index 2f1156e9..2f8e38f4 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java @@ -4,8 +4,8 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCommentController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCommentController.java index e08e6259..9bcddbc1 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCommentController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCommentController.java @@ -3,8 +3,8 @@ package org.jeecg.modules.system.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.dto.DataLogDTO; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java index b670fee6..9ca69bff 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java @@ -7,8 +7,8 @@ import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java index 3fad7e34..e6f3c89e 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java @@ -8,8 +8,6 @@ import javax.servlet.http.HttpServletResponse; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.CommonConstant; @@ -36,6 +34,8 @@ import org.jeecg.modules.system.service.ISysPermissionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; /** * @Description: 部门权限表 @@ -72,7 +72,7 @@ public class SysDepartPermissionController extends JeecgController queryPageList(SysDepartPermission sysDepartPermission, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @@ -90,7 +90,7 @@ public class SysDepartPermissionController extends JeecgController add(@RequestBody SysDepartPermission sysDepartPermission) { sysDepartPermissionService.save(sysDepartPermission); @@ -103,7 +103,7 @@ public class SysDepartPermissionController extends JeecgController edit(@RequestBody SysDepartPermission sysDepartPermission) { sysDepartPermissionService.updateById(sysDepartPermission); @@ -116,7 +116,7 @@ public class SysDepartPermissionController extends JeecgController delete(@RequestParam(name="id",required=true) String id) { sysDepartPermissionService.removeById(id); @@ -129,7 +129,7 @@ public class SysDepartPermissionController extends JeecgController deleteBatch(@RequestParam(name="ids",required=true) String ids) { this.sysDepartPermissionService.removeByIds(Arrays.asList(ids.split(","))); @@ -142,7 +142,7 @@ public class SysDepartPermissionController extends JeecgController queryById(@RequestParam(name="id",required=true) String id) { SysDepartPermission sysDepartPermission = sysDepartPermissionService.getById(id); diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java index 938df5c3..38a218e9 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java @@ -8,8 +8,6 @@ import javax.servlet.http.HttpServletResponse; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; @@ -31,6 +29,8 @@ import org.jeecg.common.system.base.controller.JeecgController; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; /** * @Description: 部门角色 @@ -70,7 +70,7 @@ public class SysDepartRoleController extends JeecgController queryPageList(SysDepartRole sysDepartRole, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @@ -111,7 +111,7 @@ public class SysDepartRoleController extends JeecgController add(@RequestBody SysDepartRole sysDepartRole) { sysDepartRoleService.save(sysDepartRole); @@ -124,7 +124,7 @@ public class SysDepartRoleController extends JeecgController edit(@RequestBody SysDepartRole sysDepartRole) { @@ -139,7 +139,7 @@ public class SysDepartRoleController extends JeecgController delete(@RequestParam(name="id",required=true) String id) { @@ -154,7 +154,7 @@ public class SysDepartRoleController extends JeecgController deleteBatch(@RequestParam(name="ids",required=true) String ids) { @@ -169,7 +169,7 @@ public class SysDepartRoleController extends JeecgController queryById(@RequestParam(name="id",required=true) String id) { SysDepartRole sysDepartRole = sysDepartRoleService.getById(id); diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java index e1b1893a..69995eca 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDictItemController.java @@ -7,8 +7,8 @@ import java.util.Date; import javax.servlet.http.HttpServletRequest; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import org.apache.commons.lang.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; @@ -162,7 +162,7 @@ public class SysDictItemController { * @return */ @RequestMapping(value = "/dictItemCheck", method = RequestMethod.GET) - @Operation(summary ="字典重复校验接口") + @Operation(summary="字典重复校验接口") public Result doDictItemCheck(SysDictItem sysDictItem, HttpServletRequest request) { Long num = Long.valueOf(0); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java index 7a96fff8..9ddb41ba 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java @@ -5,8 +5,8 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFormFileController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFormFileController.java index 2d6db07d..71c5ad66 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFormFileController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysFormFileController.java @@ -3,8 +3,8 @@ package org.jeecg.modules.system.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java index 5f3de909..31a7a82d 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java @@ -5,8 +5,8 @@ import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java index e48a8a57..9f862293 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleIndexController.java @@ -4,8 +4,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.jeecg.common.api.vo.Result; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTableWhiteListController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTableWhiteListController.java index 2f09102a..994b2640 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTableWhiteListController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTableWhiteListController.java @@ -3,8 +3,8 @@ package org.jeecg.modules.system.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java index 5f630cf6..2bde5fdd 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java @@ -986,4 +986,16 @@ public class SysTenantController { } return result; } + + /** + * 目前只给敲敲云人员与部门下的用户删除使用 + * + * 删除用户 + */ + @DeleteMapping("/deleteUser") + public Result deleteUser(@RequestBody SysUser sysUser,HttpServletRequest request){ + Integer tenantId = oConvertUtils.getInteger(TokenUtils.getTenantIdByRequest(request), null); + sysTenantService.deleteUser(sysUser, tenantId); + return Result.ok("删除用户成功"); + } } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java index 2bd0a8e8..899deab4 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java @@ -1727,7 +1727,7 @@ public class SysUserController { } return result; } - + /** * 根据关键词搜索部门和用户【low-app】 * @param keyword @@ -1847,7 +1847,7 @@ public class SysUserController { public Result importAppUser(HttpServletRequest request, HttpServletResponse response)throws IOException { return sysUserService.importAppUser(request); } - + /** * 更改手机号(敲敲云个人设置专用) * diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java index 66abfe6f..3dee0480 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java @@ -45,7 +45,6 @@ public class SysUserOnlineController { public ISysUserService userService; @Autowired private SysBaseApiImpl sysBaseApi; - @Resource private BaseCommonService baseCommonService; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java index 59260b14..def8b6d1 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/ThirdLoginController.java @@ -283,7 +283,7 @@ public class ThirdLoginController { * @param jsonObject * @return */ - @Operation(summary ="手机号登录接口") + @Operation(summary="手机号登录接口") @PostMapping("/bindingThirdPhone") @ResponseBody public Result bindingThirdPhone(@RequestBody JSONObject jsonObject) { diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCheckRule.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCheckRule.java index 96d681ae..6de3e08a 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCheckRule.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCheckRule.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -23,7 +24,7 @@ import java.util.Date; @TableName("sys_check_rule") @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) -@Schema(description = "编码校验规则") +@Schema(description="编码校验规则") public class SysCheckRule { /** diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysComment.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysComment.java index 2f35e902..17e828cc 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysComment.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysComment.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDataSource.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDataSource.java index 6ae74443..be5b0b6f 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDataSource.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDataSource.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -22,7 +23,7 @@ import org.springframework.format.annotation.DateTimeFormat; @TableName("sys_data_source") @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) -@Schema(description = "多数据源管理") +@Schema(description="多数据源管理") public class SysDataSource { /** diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartPermission.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartPermission.java index db48e453..9bfe4e57 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartPermission.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartPermission.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableField; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRole.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRole.java index 8314a761..9bc675cb 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRole.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRole.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableField; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRolePermission.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRolePermission.java index e34ab423..ff0590eb 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRolePermission.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRolePermission.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableField; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -24,7 +25,7 @@ import org.jeecgframework.poi.excel.annotation.Excel; @TableName("sys_depart_role_permission") @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) -@Schema( description="部门角色权限") +@Schema(description="部门角色权限") public class SysDepartRolePermission { /**id*/ diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRoleUser.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRoleUser.java index 1e8af5c1..0b8c80ca 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRoleUser.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysDepartRoleUser.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableField; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFillRule.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFillRule.java index 9ead1cf0..a8a0c24e 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFillRule.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFillRule.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -21,7 +22,7 @@ import org.springframework.format.annotation.DateTimeFormat; @TableName("sys_fill_rule") @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) -@Schema(description = "填值规则") +@Schema(description="填值规则") public class SysFillRule { /** diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFormFile.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFormFile.java index 5cb736fb..7023ccdb 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFormFile.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysFormFile.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysGatewayRoute.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysGatewayRoute.java index 2cb46f21..afb4cb98 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysGatewayRoute.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysGatewayRoute.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPackPermission.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPackPermission.java index 6664ed76..96b6b25b 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPackPermission.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPackPermission.java @@ -5,11 +5,12 @@ import java.util.Date; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import com.fasterxml.jackson.annotation.JsonFormat; import org.springframework.format.annotation.DateTimeFormat; import org.jeecgframework.poi.excel.annotation.Excel; + +import io.swagger.v3.oas.annotations.media.Schema; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPosition.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPosition.java index 480982de..1db498a9 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPosition.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysPosition.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -22,7 +23,7 @@ import org.springframework.format.annotation.DateTimeFormat; @TableName("sys_position") @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) -@Schema(description = "职务表") +@Schema(description="职务表") public class SysPosition { /** diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java index 20439289..471cd064 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysRoleIndex.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableField; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTableWhiteList.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTableWhiteList.java index 7a1bed8f..771bcde3 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTableWhiteList.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTableWhiteList.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -21,7 +22,7 @@ import org.springframework.format.annotation.DateTimeFormat; @TableName("sys_table_white_list") @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) -@Schema(description = "系统表白名单") +@Schema(description="系统表白名单") public class SysTableWhiteList { /** diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPack.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPack.java index 7e456d25..fa13ff99 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPack.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPack.java @@ -4,11 +4,12 @@ import java.io.Serializable; import java.util.Date; import com.baomidou.mybatisplus.annotation.*; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import com.fasterxml.jackson.annotation.JsonFormat; import org.springframework.format.annotation.DateTimeFormat; import org.jeecgframework.poi.excel.annotation.Excel; + +import io.swagger.v3.oas.annotations.media.Schema; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPackUser.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPackUser.java index ade5cfd4..7b8e4a9e 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPackUser.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysTenantPackUser.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java index a08e325e..11a2c569 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAppConfig.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAppConfig.java index fe040570..dcc1ae02 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAppConfig.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysThirdAppConfig.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserDepart.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserDepart.java index d370ddde..e3d595b9 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserDepart.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserDepart.java @@ -31,8 +31,8 @@ public class SysUserDepart implements Serializable { this.depId = depId; } - public SysUserDepart(String id, String departId) { - this.userId = id; + public SysUserDepart(String userId, String departId) { + this.userId = userId; this.depId = departId; } } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserPosition.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserPosition.java index 027f2b42..fc7d0d4c 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserPosition.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserPosition.java @@ -4,13 +4,14 @@ import java.io.Serializable; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import com.fasterxml.jackson.annotation.JsonFormat; import org.springframework.format.annotation.DateTimeFormat; import org.jeecgframework.poi.excel.annotation.Excel; import java.util.Date; +import io.swagger.v3.oas.annotations.media.Schema; + /** * @Description: 用户职位关系表 * @Author: jeecg-boot diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserTenant.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserTenant.java index 03f67360..ce073fd0 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserTenant.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserTenant.java @@ -5,11 +5,12 @@ import java.util.Date; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import com.fasterxml.jackson.annotation.JsonFormat; import org.springframework.format.annotation.DateTimeFormat; import org.jeecgframework.poi.excel.annotation.Excel; + +import io.swagger.v3.oas.annotations.media.Schema; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysAnnouncementMapper.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysAnnouncementMapper.java index 4df93c7c..e968f85e 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysAnnouncementMapper.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysAnnouncementMapper.java @@ -46,7 +46,7 @@ public interface SysAnnouncementMapper extends BaseMapper { * @param endDate * @return */ - List queryAllMessageList(Page page, @Param("userId")String userId, @Param("fromUser")String fromUser, @Param("starFlag")String starFlag, @Param("beginDate")Date beginDate, @Param("endDate")Date endDate); + List queryAllMessageList(Page page, @Param("userId")String userId, @Param("fromUser")String fromUser, @Param("starFlag")String starFlag, @Param("busType")String busType, @Param("beginDate")Date beginDate, @Param("endDate")Date endDate); /** * 查询用户未阅读的通知公告 diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java index 3bf81943..b1291586 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDepartMapper.java @@ -178,4 +178,21 @@ public interface SysDepartMapper extends BaseMapper { * @return */ List getSysDepartList(@Param("parentId") String parentId,@Param("tenantId") Integer tenantId, List idList); + + /** + * 根据多个部门id获取部门数据 + * + * @param departIds + * @return + */ + List getDepartByIds(List departIds); + + /** + * 根据用户id获取部门数据 + * + * @param userList + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List getUserDepartByUserId(@Param("userList")List userList); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java index 7fefb3b3..417ac4d1 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java @@ -8,6 +8,8 @@ import org.apache.ibatis.annotations.Select; import org.jeecg.modules.system.entity.SysRole; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.system.entity.SysUser; +import org.jeecg.modules.system.vo.SysUserPositionVo; import java.util.List; @@ -73,4 +75,12 @@ public interface SysRoleMapper extends BaseMapper { */ @Select("select count(*) from sys_role where id=#{id} and tenant_id=#{tenantId}") Long getRoleCountByTenantId(@Param("id") String id, @Param("tenantId") Integer tenantId); + + /** + * 根据用户id获取角色信息 + * + * @param userList + * @return + */ + List getUserRoleByUserId(@Param("userList") List userList); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysAnnouncementMapper.xml b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysAnnouncementMapper.xml index 9f4eabe9..d43c20d9 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysAnnouncementMapper.xml +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysAnnouncementMapper.xml @@ -92,6 +92,9 @@ and b.star_flag = #{starFlag} + + and a.bus_type = #{busType} + order by b.read_flag ASC, a.create_time DESC diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml index 8d7df92f..853e5441 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDepartMapper.xml @@ -193,4 +193,29 @@ ORDER BY depart_order DESC + + + + + + \ No newline at end of file diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml index b467375a..e046cff1 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml @@ -54,5 +54,14 @@ AND tenant_id = #{tenantId} - + + + \ No newline at end of file diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserPositionMapper.xml b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserPositionMapper.xml index a398fc86..77b3f689 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserPositionMapper.xml +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserPositionMapper.xml @@ -29,6 +29,7 @@ AND sp.tenant_id = #{tenantId} + order by sup.create_time desc diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysAnnouncementService.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysAnnouncementService.java index 61240453..36605972 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysAnnouncementService.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysAnnouncementService.java @@ -72,7 +72,7 @@ public interface ISysAnnouncementService extends IService { /** * 分页查询当前登录用户的消息, 并且标记哪些是未读消息 */ - List querySysMessageList(int pageSize, int pageNo, String fromUser, String starFlag, Date beginDate, Date endDate); + List querySysMessageList(int pageSize, int pageNo, String fromUser, String starFlag, String busType, Date beginDate, Date endDate); /** * 修改为已读消息 diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java index 035c69fc..f4c79aaa 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java @@ -232,4 +232,11 @@ public interface ISysTenantService extends IService { * @return */ List getTenantListByUserId(String userId); + + /** + * 删除用户 + * @param sysUser + * @param tenantId + */ + void deleteUser(SysUser sysUser, Integer tenantId); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysThirdAppConfigService.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysThirdAppConfigService.java index b35a18aa..1c9c45cd 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysThirdAppConfigService.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysThirdAppConfigService.java @@ -1,6 +1,7 @@ package org.jeecg.modules.system.service; import com.baomidou.mybatisplus.extension.service.IService; + import org.jeecg.modules.system.entity.SysThirdAppConfig; import java.util.List; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysUserService.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysUserService.java index 2b33a84d..37f8453f 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysUserService.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysUserService.java @@ -12,12 +12,14 @@ import org.jeecg.common.system.vo.SysUserCacheInfo; import org.jeecg.modules.system.entity.SysRoleIndex; import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.model.SysUserSysDepartModel; +import org.jeecg.modules.system.vo.SysUserExportVo; import org.jeecg.modules.system.vo.lowapp.DepartAndUserInfo; import org.jeecg.modules.system.vo.lowapp.UpdateDepartInfo; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; +import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; @@ -458,4 +460,26 @@ public interface ISysUserService extends IService { * @param username */ void userLogOff(JSONObject jsonObject, String username); + + /** + * 获取部门和用户关系的导出信息 + * @param pageList + */ + List getDepartAndRoleExportMsg(List pageList); + + /** + * 导入用户 + * + * @param request + */ + Result importSysUser(HttpServletRequest request); + + /** + * 没有绑定手机号 直接修改密码 + * + * @param oldPassword + * @param password + * @param username + */ + void updatePasswordNotBindPhone(String oldPassword, String password, String username); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysAnnouncementServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysAnnouncementServiceImpl.java index 4127474b..bf1d91ac 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysAnnouncementServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysAnnouncementServiceImpl.java @@ -199,7 +199,7 @@ public class SysAnnouncementServiceImpl extends ServiceImpl querySysMessageList(int pageSize, int pageNo, String fromUser, String starFlag, Date beginDate, Date endDate) { + public List querySysMessageList(int pageSize, int pageNo, String fromUser, String starFlag, String busType, Date beginDate, Date endDate) { // //1. 补全send表的数据 // completeNoteThreadPool.execute(()->{ // completeAnnouncementSendInfo(); @@ -208,7 +208,7 @@ public class SysAnnouncementServiceImpl extends ServiceImpl page = new Page(pageNo,pageSize); - List list = baseMapper.queryAllMessageList(page, sysUser.getId(), fromUser, starFlag, beginDate, endDate); + List list = baseMapper.queryAllMessageList(page, sysUser.getId(), fromUser, starFlag, busType, beginDate, endDate); return list; } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java index 3c8ed8eb..4372bfc4 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java @@ -1199,6 +1199,23 @@ public class SysBaseApiImpl implements ISysBaseAPI { int count = sysPermissionMapper.queryCountByUsername(username, p); has = has || (count>0); } + if (!has) { + //没有配置菜单 找online表单菜单地址 + SysPermission sysPermission = new SysPermission(); + sysPermission.setUrl(onlineFormUrl); + int count = sysPermissionMapper.queryCountByUsername(username, sysPermission); + if (count <= 0) { + //update-begin---author:chenrui ---date:20240123 for:[QQYUN-7992]【online】工单申请下的online表单,未配置online表单开发菜单,操作报错无权限------------ + sysPermission.setUrl(onlineAuthDTO.getOnlineWorkOrderUrl()); + count = sysPermissionMapper.queryCountByUsername(username, sysPermission); + if (count > 0) { + has = true; + } + //update-end---author:chenrui ---date:20240123 for:[QQYUN-7992]【online】工单申请下的online表单,未配置online表单开发菜单,操作报错无权限------------ + } else { + has = true; + } + } return has; } return true; @@ -1408,7 +1425,7 @@ public class SysBaseApiImpl implements ISysBaseAPI { e.printStackTrace(); } - log.info("Email Html Text:{}", htmlText); + log.debug("Email Html Text:{}", htmlText); emailHandle.sendMsg(email, title, htmlText); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java index 7ce35577..4b7d4759 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java @@ -889,25 +889,76 @@ public class SysTenantServiceImpl extends ServiceImpl getTenantListByUserId(String userId) { return tenantMapper.getTenantListByUserId(userId); } + @Override + public void deleteUser(SysUser sysUser, Integer tenantId) { + //被删除人的用户id + String userId = sysUser.getId(); + //被删除人的密码 + String password = sysUser.getPassword(); + //当前登录用户 + LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); + //step1 判断当前用户是否为当前租户的创建者才可以删除 + SysTenant sysTenant = this.getById(tenantId); + if(null == sysTenant || !user.getUsername().equals(sysTenant.getCreateBy())){ + throw new JeecgBootException("您不是当前组织的创建者,无法删除用户!"); + } + //step2 判断除了当前组织之外是否还有加入了其他组织 + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(SysUserTenant::getUserId,userId); + query.ne(SysUserTenant::getTenantId,tenantId); + List sysUserTenants = userTenantMapper.selectList(query); + if(CollectionUtils.isNotEmpty(sysUserTenants)){ + throw new JeecgBootException("该用户还存在于其它组织中,无法删除用户!"); + } + //step3 验证创建时间和密码 + SysUser sysUserData = userService.getById(userId); + this.verifyCreateTimeAndPassword(sysUserData,password); + //step4 真实删除用户 + userService.deleteUser(userId); + userService.removeLogicDeleted(Collections.singletonList(userId)); + } + } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java index f2f656be..40c986f2 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java @@ -28,12 +28,14 @@ import org.jeecg.common.constant.enums.MessageTypeEnum; import org.jeecg.common.constant.enums.RoleIndexConfigEnum; import org.jeecg.common.constant.enums.SysAnnmentTypeEnum; import org.jeecg.common.desensitization.annotation.SensitiveEncode; +import org.jeecg.common.exception.JeecgBootBizTipException; import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.SysUserCacheInfo; import org.jeecg.common.util.*; import org.jeecg.config.mybatis.MybatisPlusSaasConfig; import org.jeecg.modules.base.service.BaseCommonService; +import org.jeecg.modules.jmreport.common.util.OkConvertUtils; import org.jeecg.modules.message.handle.impl.SystemSendMsgHandle; import org.jeecg.modules.system.entity.*; import org.jeecg.modules.system.mapper.*; @@ -42,6 +44,7 @@ import org.jeecg.modules.system.service.ISysRoleIndexService; import org.jeecg.modules.system.service.ISysThirdAccountService; import org.jeecg.modules.system.service.ISysUserService; import org.jeecg.modules.system.vo.SysUserDepVo; +import org.jeecg.modules.system.vo.SysUserExportVo; import org.jeecg.modules.system.vo.SysUserPositionVo; import org.jeecg.modules.system.vo.UserAvatar; import org.jeecg.modules.system.vo.lowapp.AppExportUserVo; @@ -59,6 +62,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -121,6 +125,7 @@ public class SysUserServiceImpl extends ServiceImpl impl private SysPositionMapper sysPositionMapper; @Autowired private SystemSendMsgHandle systemSendMsgHandle; + @Autowired private ISysThirdAccountService sysThirdAccountService; @Autowired @@ -1550,8 +1555,11 @@ public class SysUserServiceImpl extends ServiceImpl impl } //查询用户数据 List userList = userMapper.getUserByDepartsTenantId(list, tenantId); - //获取部门名称 - List userDepVos = sysDepartMapper.getUserDepartByTenantUserId(userList, tenantId); + //获取部门名称 + List userDepVos = new ArrayList<>(); + if(CollectionUtil.isNotEmpty(userList)){ + userDepVos = sysDepartMapper.getUserDepartByTenantUserId(userList, tenantId); + } //获取职位 List positionVos = sysUserPositionMapper.getPositionIdByUsersTenantId(userList, tenantId); // step2 根据用户id进行分类 @@ -1560,9 +1568,10 @@ public class SysUserServiceImpl extends ServiceImpl impl for (SysUser sysUser : userList) { AppExportUserVo exportUserVo = new AppExportUserVo(); BeanUtils.copyProperties(sysUser, exportUserVo); - String departNames = userDepVos.stream().filter(item -> item.getUserId().equals(sysUser.getId())) - .map(SysUserDepVo::getDepartName).collect(Collectors.joining(SymbolConstant.SEMICOLON)); - exportUserVo.setDepart(departNames); + //update-begin---author:wangshuai---date:2025-01-17---for:【QQYUN-10926】组织管理——用户导出时,部门没有导出上下级关系--- + StringBuilder departNames = this.getDepartNames(userDepVos,sysUser); + exportUserVo.setDepart(departNames.toString()); + //update-end---author:wangshuai---date:2025-01-17---for:【QQYUN-10926】组织管理——用户导出时,部门没有导出上下级关系--- String posNames = positionVos.stream().filter(item -> item.getUserId().equals(sysUser.getId())).map(SysUserPositionVo::getName).collect(Collectors.joining(SymbolConstant.SEMICOLON)); exportUserVo.setPosition(posNames); exportUserVoList.add(exportUserVo); @@ -1582,7 +1591,65 @@ public class SysUserServiceImpl extends ServiceImpl impl return mv; } - //======================================= end 用户与部门 用户列表导出 ========================================= + /** + * 获取部门名称 + * for:【QQYUN-10926】组织管理——用户导出时,部门没有导出上下级关系 + * + * @param userDepVos + * @param sysUser + * @return + */ + private StringBuilder getDepartNames(List userDepVos, SysUser sysUser) { + List SysUserDepVoList = userDepVos.stream().filter(item -> item.getUserId().equals(sysUser.getId())) + .map(item -> { + SysUserDepVo userDepVo = new SysUserDepVo(); + userDepVo.setUserId(item.getUserId()); + userDepVo.setDeptId(item.getDeptId()); + userDepVo.setDepartName(item.getDepartName()); + userDepVo.setParentId(item.getParentId()); + return userDepVo; + }).collect(Collectors.toList()); + //循环SysUserDepVoList,如果存在父级id的情况下,需要将父级id的部门名称查询出来 + StringBuilder departNames = new StringBuilder(); + for (SysUserDepVo sysUserDepVo : SysUserDepVoList) { + if(oConvertUtils.isEmpty(sysUserDepVo.getDepartName())){ + continue; + } + //用于查询父级的部门名称 + List departNameList = new LinkedList<>(); + departNameList.add(sysUserDepVo.getDepartName()); + if (StringUtils.isNotEmpty(sysUserDepVo.getParentId())) { + //递归查询部门名称 + this.getDepartNameByParentId(sysUserDepVo.getParentId(), departNameList); + } + Collections.reverse(departNameList); + String departName = departNameList.stream().collect(Collectors.joining(SymbolConstant.SINGLE_SLASH)); + if (StringUtils.isNotEmpty(departNames.toString())) { + departNames.append(SymbolConstant.SEMICOLON); + } + departNames.append(departName); + } + return departNames; + } + + /** + * 根据父级id查询父级的部门名称 + * for:【QQYUN-10926】组织管理——用户导出时,部门没有导出上下级关系 + * + * @param parentId + * @param departNameList + */ + private void getDepartNameByParentId(String parentId, List departNameList) { + SysDepart parentDepartId = sysDepartMapper.getDepartById(parentId); + if (null != parentDepartId) { + departNameList.add(parentDepartId.getDepartName()); + if (StringUtils.isNotEmpty(parentDepartId.getParentId())) { + this.getDepartNameByParentId(parentDepartId.getParentId(), departNameList); + } + } + } + + //======================================= end 用户与部门 用户列表导出 ========================================= //======================================= begin 用户与部门 用户列表导入 ========================================= @Override @@ -1804,9 +1871,9 @@ public class SysUserServiceImpl extends ServiceImpl impl String[] departNames = depart.split(SymbolConstant.SEMICOLON); List departNameList = Arrays.asList(departNames); departNameList = departNameList.stream().distinct().collect(Collectors.toList()); - //部门id - String parentId = ""; for (String departName : departNameList) { + //部门id + String parentId = ""; String[] names = departName.split(SymbolConstant.SINGLE_SLASH); //部门名称拼接 String nameStr = ""; @@ -1886,7 +1953,7 @@ public class SysUserServiceImpl extends ServiceImpl impl messageDTO.setTitle(title); Map data = new HashMap<>(); //update-begin---author:wangshuai---date:2024-03-11---for:【QQYUN-8425】用户导入成功后 消息提醒 跳转至同意页面--- - data.put(CommonConstant.NOTICE_MSG_BUS_TYPE, SysAnnmentTypeEnum.TENANT_INVITE.getType()); + data.put(CommonConstant.NOTICE_MSG_BUS_TYPE,SysAnnmentTypeEnum.TENANT_INVITE.getType()); //update-end---author:wangshuai---date:2024-03-11---for:【QQYUN-8425】用户导入成功后 消息提醒 跳转至同意页面--- messageDTO.setData(data); messageDTO.setContent(title); @@ -2040,7 +2107,7 @@ public class SysUserServiceImpl extends ServiceImpl impl log.warn("--------[警告] IP地址:{}, 短信接口请求太多-------", clientIp); throw new JeecgBootException("短信接口请求太多,请稍后再试!", CommonConstant.PHONE_SMS_FAIL_CODE); } - + //随机数 String captcha = RandomUtil.randomNumbers(6); JSONObject obj = new JSONObject(); @@ -2057,4 +2124,236 @@ public class SysUserServiceImpl extends ServiceImpl impl throw new JeecgBootException("短信接口未配置,请联系管理员!"); } } + + //================================================= begin 低代码部门导入导出 ================================================================ + @Override + public List getDepartAndRoleExportMsg(List userList) { + List list = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(userList)) { + //获取部门 + List userDepVos = sysDepartMapper.getUserDepartByUserId(userList); + //获取职位 + List sysRoles = sysRoleMapper.getUserRoleByUserId(userList); + //组装数据并返回 + for (SysUser sysUser : userList) { + SysUserExportVo userExportVo = new SysUserExportVo(); + BeanUtils.copyProperties(sysUser, userExportVo); + StringBuilder departNames = this.getDepartNames(userDepVos, sysUser); + userExportVo.setDepartNames(departNames.toString()); + String departIds = sysUser.getDepartIds(); + if (oConvertUtils.isNotEmpty(departIds)) { + List depVoList = sysDepartMapper.getDepartByIds(Arrays.asList(departIds.split(","))); + StringBuilder names = this.getDepartNames(userDepVos, sysUser); + userExportVo.setDepartIds(names.toString()); + } + String posNames = sysRoles.stream().filter(item -> item.getUserId().equals(sysUser.getId())).map(SysUserPositionVo::getName).collect(Collectors.joining(SymbolConstant.SEMICOLON)); + userExportVo.setRoleNames(posNames); + list.add(userExportVo); + } + } + return list; + } + + @Override + public Result importSysUser(HttpServletRequest request) { + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + Map fileMap = multipartRequest.getFileMap(); + // 错误信息 + List errorMessage = new ArrayList<>(); + int successLines = 0, errorLines = 0; + //存放部门的map;key为名称 value为SysDepart对象。避免多次导入和查询 + Map departMap = new HashMap<>(); + Map positionMap = new HashMap<>(); + String tenantId = TokenUtils.getTenantIdByRequest(request); + for (Map.Entry entity : fileMap.entrySet()) { + MultipartFile file = entity.getValue();// 获取上传文件对象 + ImportParams params = new ImportParams(); + params.setTitleRows(2); + params.setHeadRows(1); + params.setNeedSave(true); + try { + List listSysUsers = ExcelImportUtil.importExcel(file.getInputStream(), SysUserExportVo.class, params); + for (int i = 0; i < listSysUsers.size(); i++) { + SysUserExportVo sysUserExcel = listSysUsers.get(i); + SysUser sysUser = new SysUser(); + BeanUtils.copyProperties(sysUserExcel, sysUser); + if (OkConvertUtils.isEmpty(sysUser.getUsername())) { + errorLines += 1; + int lineNumber = i + 1; + errorMessage.add("第 " + lineNumber + " 行:用户账号为空,忽略导入。"); + continue; + } + try { + String username = sysUser.getUsername(); + //根据用户名程序,为空则添加用户 + SysUser userByName = userMapper.getUserByName(username); + if (null != userByName) { + errorLines += 1; + int lineNumber = i + 1; + errorMessage.add("第 " + lineNumber + " 行:用户名已经存在,忽略导入。"); + continue; + } else { + // 密码默认为 “123456” + sysUser.setPassword("123456"); + // 密码加密加盐 + String salt = oConvertUtils.randomGen(8); + sysUser.setSalt(salt); + String passwordEncode = PasswordUtil.encrypt(sysUserExcel.getUsername(), sysUser.getPassword(), salt); + sysUser.setPassword(passwordEncode); + this.save(sysUser); + } + //添加部门 + String departNames = sysUserExcel.getDepartNames(); + //新增或编辑部门 + Integer tenantIdInt = null; + if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + tenantIdInt = OkConvertUtils.getInt(tenantId, 0); + } + this.addOrEditDepart(sysUser.getId(), departNames, tenantIdInt, departMap); + //新增或编辑角色 + String roleNames = sysUserExcel.getRoleNames(); + this.saveOrEditRole(sysUser.getId(), roleNames, tenantIdInt); + //新增或编辑职位 + String position = sysUserExcel.getPost(); + if (oConvertUtils.isNotEmpty(position)) { + this.addOrEditPosition(sysUser.getId(), position, false, tenantIdInt, positionMap); + } + //添加负责部门 + this.saveChargeDepart(sysUser, sysUserExcel.getDepartIds(), departMap); + successLines++; + } catch (Exception e) { + errorLines++; + String message = e.getMessage().toLowerCase(); + int lineNumber = i + 1; + // 通过索引名判断出错信息 + if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_USERNAME)) { + errorMessage.add("第 " + lineNumber + " 行:用户名已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_WORK_NO)) { + errorMessage.add("第 " + lineNumber + " 行:工号已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_PHONE)) { + errorMessage.add("第 " + lineNumber + " 行:手机号已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_EMAIL)) { + errorMessage.add("第 " + lineNumber + " 行:电子邮件已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER)) { + errorMessage.add("第 " + lineNumber + " 行:违反表唯一性约束。"); + } else { + errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入"); + log.error(e.getMessage(), e); + } + } + } + } catch (Exception e) { + errorMessage.add("发生异常:" + e.getMessage()); + log.error(e.getMessage(), e); + } finally { + try { + file.getInputStream().close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + } + try { + departMap.clear(); + departMap = null; + return ImportExcelUtil.imporReturnRes(errorLines, successLines, errorMessage); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void saveChargeDepart(SysUser sysUser, String departIds, Map departMap) { + //判断那些部门没有,即没有加入到部门,则不能成为负责部门人员 + if (OkConvertUtils.isEmpty(departIds)) { + return; + } + //多个部门用;分隔开 + String[] split = departIds.split(SymbolConstant.SEMICOLON); + //负责部门id + StringBuilder departIdBulider = new StringBuilder(); + for (String name : split) { + if (departMap.containsKey(name)) { + SysDepart sysDepart = departMap.get(name); + departIdBulider.append(sysDepart.getId()).append(","); + } + } + // 检查并删除最后一个逗号 + if (departIdBulider.length() > 0 && departIdBulider.charAt(departIdBulider.length() - 1) == ',') { + departIdBulider.deleteCharAt(departIdBulider.length() - 1); + } + sysUser.setDepartIds(departIdBulider.toString()); + this.updateById(sysUser); + } + + /** + * 保存或编辑角色 + * + * @param userId + * @param roleNames + * @param tenantIdInt + */ + private void saveOrEditRole(String userId, String roleNames, Integer tenantIdInt) { + if (oConvertUtils.isEmpty(roleNames)) { + return; + } + String[] roleNameArray = roleNames.split(SymbolConstant.SEMICOLON); + //删除用户下的角色 + LambdaQueryWrapper deleteQuery = new LambdaQueryWrapper<>(); + deleteQuery.eq(SysUserRole::getUserId, userId); + sysUserRoleMapper.delete(deleteQuery); + //通过名字获取角色 + LambdaQueryWrapper roleQuery = new LambdaQueryWrapper<>(); + roleQuery.orderByDesc(SysRole::getCreateTime); + if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) { + roleQuery.eq(SysRole::getTenantId, tenantIdInt); + } + for (String roleName : roleNameArray) { + roleQuery.eq(SysRole::getRoleName, roleName); + List sysRoles = sysRoleMapper.selectList(roleQuery); + String roleId = ""; + if (CollectionUtil.isNotEmpty(sysRoles)) { + roleId = sysRoles.get(0).getId(); + } else { + SysRole sysRole = new SysRole(); + sysRole.setRoleName(roleName); + sysRole.setRoleCode(RandomUtil.randomString(10)); + sysRoleMapper.insert(sysRole); + roleId = sysRole.getId(); + } + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setUserId(userId); + sysUserRole.setRoleId(roleId); + sysUserRoleMapper.insert(sysUserRole); + } + } + //================================================= end 低代码部门导入导出 ================================================================ + + @Override + public void updatePasswordNotBindPhone(String oldPassword, String password, String username) { + LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal(); + //step1 只能修改自己的密码 + if(!sysUser.getUsername().equals(username)){ + throw new JeecgBootBizTipException("只允许修改自己的密码!"); + } + //step2 用户不存在禁止修改密码 + SysUser user = this.getUserByName(username); + if(null == user){ + throw new JeecgBootBizTipException("用户不存在,无法修改密码!"); + } + //setp3 如果手机号存在需要用手机号修改密码的方式 + if(oConvertUtils.isNotEmpty(user.getPhone())){ + throw new JeecgBootBizTipException("手机号不为空,请根据手机号进行修改密码操作!"); + } + //step4 判断旧密码是否正确 + String passwordEncode = PasswordUtil.encrypt(username, oldPassword, user.getSalt()); + if (!user.getPassword().equals(passwordEncode)) { + throw new JeecgBootBizTipException("旧密码输入错误!"); + } + if (oConvertUtils.isEmpty(password)) { + throw new JeecgBootBizTipException("新密码不允许为空!"); + } + //step5 修改密码 + String newPassWord = PasswordUtil.encrypt(username, password, user.getSalt()); + this.userMapper.update(new SysUser().setPassword(newPassWord), new LambdaQueryWrapper().eq(SysUser::getId, user.getId())); + } } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java index ae9b3e04..d659bb36 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java @@ -32,10 +32,7 @@ import org.jeecg.common.constant.enums.MessageTypeEnum; import org.jeecg.common.exception.JeecgBootBizTipException; import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.system.util.JwtUtil; -import org.jeecg.common.util.PasswordUtil; -import org.jeecg.common.util.RestUtil; -import org.jeecg.common.util.SpringContextUtils; -import org.jeecg.common.util.oConvertUtils; +import org.jeecg.common.util.*; import org.jeecg.config.JeecgBaseConfig; import org.jeecg.config.mybatis.MybatisPlusSaasConfig; import org.jeecg.modules.system.entity.*; diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/ImportOldUserUtil.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/ImportOldUserUtil.java new file mode 100644 index 00000000..7680ce18 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/ImportOldUserUtil.java @@ -0,0 +1,112 @@ +package org.jeecg.modules.system.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.common.util.ImportExcelUtil; +import org.jeecg.common.util.PasswordUtil; +import org.jeecg.common.util.SpringContextUtils; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.system.entity.SysUser; +import org.jeecg.modules.system.entity.SysUserDepart; +import org.jeecg.modules.system.service.ISysUserDepartService; +import org.jeecg.modules.system.service.ISysUserService; +import org.jeecg.modules.system.service.impl.SysUserDepartServiceImpl; +import org.jeecg.modules.system.service.impl.SysUserServiceImpl; +import org.jeecgframework.poi.excel.ExcelImportUtil; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @Description: 旧版导入 + * @author: wangshuai + * @date: 2025/4/2 10:19 + */ +@Slf4j +public class ImportOldUserUtil { + + public static Result importOldSysUser(HttpServletRequest request) throws IOException { + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + Map fileMap = multipartRequest.getFileMap(); + // 错误信息 + List errorMessage = new ArrayList<>(); + int successLines = 0, errorLines = 0; + for (Map.Entry entity : fileMap.entrySet()) { + MultipartFile file = entity.getValue();// 获取上传文件对象 + ImportParams params = new ImportParams(); + params.setTitleRows(2); + params.setHeadRows(1); + params.setNeedSave(true); + try { + List listSysUsers = ExcelImportUtil.importExcel(file.getInputStream(), SysUser.class, params); + for (int i = 0; i < listSysUsers.size(); i++) { + SysUser sysUserExcel = listSysUsers.get(i); + if (StringUtils.isBlank(sysUserExcel.getPassword())) { + // 密码默认为 “123456” + sysUserExcel.setPassword("123456"); + } + // 密码加密加盐 + String salt = oConvertUtils.randomGen(8); + sysUserExcel.setSalt(salt); + String passwordEncode = PasswordUtil.encrypt(sysUserExcel.getUsername(), sysUserExcel.getPassword(), salt); + sysUserExcel.setPassword(passwordEncode); + try { + ISysUserService service = SpringContextUtils.getBean(SysUserServiceImpl.class); + service.save(sysUserExcel); + successLines++; + } catch (Exception e) { + errorLines++; + String message = e.getMessage().toLowerCase(); + int lineNumber = i + 1; + // 通过索引名判断出错信息 + if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_USERNAME)) { + errorMessage.add("第 " + lineNumber + " 行:用户名已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_WORK_NO)) { + errorMessage.add("第 " + lineNumber + " 行:工号已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_PHONE)) { + errorMessage.add("第 " + lineNumber + " 行:手机号已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_EMAIL)) { + errorMessage.add("第 " + lineNumber + " 行:电子邮件已经存在,忽略导入。"); + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER)) { + errorMessage.add("第 " + lineNumber + " 行:违反表唯一性约束。"); + } else { + errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入"); + log.error(e.getMessage(), e); + } + } + // 批量将部门和用户信息建立关联关系 + String departIds = sysUserExcel.getDepartIds(); + if (StringUtils.isNotBlank(departIds)) { + String userId = sysUserExcel.getId(); + String[] departIdArray = departIds.split(","); + List userDepartList = new ArrayList<>(departIdArray.length); + for (String departId : departIdArray) { + userDepartList.add(new SysUserDepart(userId, departId)); + } + ISysUserDepartService service = SpringContextUtils.getBean(SysUserDepartServiceImpl.class); + service.saveBatch(userDepartList); + } + + } + } catch (Exception e) { + errorMessage.add("发生异常:" + e.getMessage()); + log.error(e.getMessage(), e); + } finally { + try { + file.getInputStream().close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + } + return ImportExcelUtil.imporReturnRes(errorLines, successLines, errorMessage); + } +} diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/vo/SysUserExportVo.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/vo/SysUserExportVo.java new file mode 100644 index 00000000..2b9dcb96 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/vo/SysUserExportVo.java @@ -0,0 +1,119 @@ +package org.jeecg.modules.system.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @Description: 低代码用户导出 + * @author: wangshuai + * @date: 2025/3/28 12:01 + */ +@Data +public class SysUserExportVo { + + /** + * 登录账号 + */ + @Excel(name = "登录账号", width = 15) + private String username; + + /** + * 真实姓名 + */ + @Excel(name = "真实姓名", width = 15) + private String realname; + + /** + * 头像 + */ + @Excel(name = "头像", width = 15, type = 2) + private String avatar; + + /** + * 生日 + */ + @Excel(name = "生日", width = 15, format = "yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date birthday; + + /** + * 性别(1:男 2:女) + */ + @Excel(name = "性别", width = 15, dicCode = "sex") + private Integer sex; + + /** + * 电子邮件 + */ + @Excel(name = "电子邮件", width = 15) + private String email; + + /** + * 电话 + */ + @Excel(name = "电话", width = 15) + private String phone; + + /** + * 状态(1:正常 2:冻结 ) + */ + @Excel(name = "状态", width = 15, dicCode = "user_status") + private Integer status; + + /** + * 删除状态(0,正常,1已删除) + */ + @Excel(name = "删除状态", width = 15, dicCode = "del_flag") + private Integer delFlag; + + /** + * 工号,唯一键 + */ + @Excel(name = "工号", width = 15) + private String workNo; + + /** + * 职务,关联职务表 + */ + @Excel(name = "职务", width = 15) + @TableField(exist = false) + private String post; + + /** + * 座机号 + */ + @Excel(name = "座机号", width = 15) + private String telephone; + + + /** + * 身份(0 普通成员 1 上级) + */ + @Excel(name = "(1普通成员 2上级)", width = 15) + private Integer userIdentity; + + /** + * 角色名称 + */ + @Excel(name = "角色", width = 15) + private String roleNames; + + /** + * 部门名称 + */ + @Excel(name = "所属部门", width = 15) + private String departNames; + + /** + * 负责部门 + */ + @Excel(name = "负责部门", width = 15) + private String departIds; + +} diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai index e28c4764..bebb4c2d 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai @@ -48,7 +48,10 @@ import org.apache.shiro.authz.annotation.RequiresPermissions; <#assign has_multi_query_field=true> - +<#assign enhanceJavaList=[]> +<#if tableVo.extendParams?? && tableVo.extendParams.enhanceJavaList??> + <#assign enhanceJavaList = tableVo.extendParams.enhanceJavaList?filter(enhance -> enhance??)> + /** * @Description: ${tableVo.ftlDescription} * @Author: jeecg-boot @@ -79,6 +82,16 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, HttpServletRequest req) { + +<#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='query' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'> + //TODO 查询前触发的方法,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.beforeQuery() + + + + <#if has_multi_query_field> // 自定义查询规则 Map customeRuleMap = new HashMap<>(); @@ -94,6 +107,14 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e Page<${entityName}> page = new Page<${entityName}>(pageNo, pageSize); IPage<${entityName}> pageList = ${entityName?uncap_first}Service.page(page, queryWrapper); +<#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='query' && enhanceJava.event=='end' && enhanceJava.activeStatus=='1'> + //TODO 查询后触发的方法,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.afterQuery() + + + return Result.OK(pageList); } @@ -108,10 +129,27 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e @RequiresPermissions("${entityPackage}:${tableName}:add") @PostMapping(value = "/add") public Result add(@RequestBody ${entityName} ${entityName?uncap_first}) { +<#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='add' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'> + //TODO 新增前的处理方法,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.beforeAdd() + + + <#if bpm_flag> ${entityName?uncap_first}.setBpmStatus("1"); ${entityName?uncap_first}Service.save(${entityName?uncap_first}); + +<#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='add' && enhanceJava.event=='end' && enhanceJava.activeStatus=='1'> + //TODO 新增后的处理方法,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.afterAdd() + + + return Result.OK("添加成功!"); } @@ -126,7 +164,23 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e @RequiresPermissions("${entityPackage}:${tableName}:edit") @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) public Result edit(@RequestBody ${entityName} ${entityName?uncap_first}) { +<#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='edit' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'> + //TODO 编辑前,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.beforeEdit() + + + ${entityName?uncap_first}Service.updateById(${entityName?uncap_first}); +<#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='edit' && enhanceJava.event=='end' && enhanceJava.activeStatus=='1'> + //TODO 编辑后,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.afterEdit() + + + return Result.OK("编辑成功!"); } @@ -186,6 +240,14 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e @RequiresPermissions("${entityPackage}:${tableName}:exportXls") @RequestMapping(value = "/exportXls") public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) { +<#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='export' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'> + //TODO 导出前,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.beforeExport() + + + return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}"); } @@ -199,6 +261,14 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e @RequiresPermissions("${entityPackage}:${tableName}:importExcel") @RequestMapping(value = "/importExcel", method = RequestMethod.POST) public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + <#if enhanceJavaList?size gt 0> + <#list enhanceJavaList as enhanceJava> + <#if enhanceJava.buttonCode=='import' && enhanceJava.event=='start' && enhanceJava.activeStatus=='1'> + //TODO 导入前,代码生成后,请手工实现增强类逻辑; + //${entityName?uncap_first}Service.beforeImport() + + + return super.importExcel(request, response, ${entityName}.class); } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai index 5b9f134f..49cfddc3 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/entity/${entityName}.javai @@ -51,6 +51,8 @@ public class ${entityName} implements Serializable { <#elseif po.classType=='sel_tree'> <#assign list_field_dictCode=', dictTable = "${po.dictTable}", dicText = "${po.dictText?split(",")[2]}", dicCode = "${po.dictText?split(",")[0]}"'> + <#elseif po.classType=='link_table'> + <#assign list_field_dictCode=', dictTable = "${po.dictTable}", dicCode = "${po.dictField}", dicText = "${po.dictText?split(",")[0]}"'> /**${po.filedComment}*/ <#if po.fieldName == primaryKeyField> diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei index b6332ab9..918e65cc 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei @@ -8,8 +8,8 @@ navigationBarTitleText: '${tableVo.ftlDescription}', }, } -