From 276e8bf9ff33cdc3f44bcc774267264e26ccc846 Mon Sep 17 00:00:00 2001 From: Leslie Date: Fri, 29 Aug 2025 00:24:09 +0800 Subject: [PATCH 01/88] =?UTF-8?q?fixed:=20=E4=BF=AE=E5=A4=8D=E5=9B=A0?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E9=A1=BA=E5=BA=8F=E5=BD=B1=E5=93=8D=E5=88=B0?= =?UTF-8?q?=E8=B7=A8=E5=9F=9F=E9=85=8D=E7=BD=AE=E4=B8=8D=E7=94=9F=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/web/config/YudaoWebAutoConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java index 9126c7e8ea..763bab95c7 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -18,6 +18,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; +import org.springframework.core.annotation.Order; import org.springframework.util.AntPathMatcher; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @@ -80,6 +81,7 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { /** * 创建 CorsFilter Bean,解决跨域问题 */ + @Order(value = 0) @Bean public FilterRegistrationBean corsFilterBean() { // 创建 CorsConfiguration 对象 From 8402441a559f58be58f51878a9778be37d33b0d2 Mon Sep 17 00:00:00 2001 From: Leslie Date: Tue, 2 Sep 2025 10:38:17 +0800 Subject: [PATCH 02/88] =?UTF-8?q?refactor:=20=E8=B7=A8=E5=9F=9F=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E9=A1=BA=E5=BA=8F=E4=BD=BF=E7=94=A8=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/web/config/YudaoWebAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java index 763bab95c7..32bc4ace76 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -81,7 +81,7 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { /** * 创建 CorsFilter Bean,解决跨域问题 */ - @Order(value = 0) + @Order(value = WebFilterOrderEnum.CORS_FILTER) @Bean public FilterRegistrationBean corsFilterBean() { // 创建 CorsConfiguration 对象 From bb7eaa214c96a5e9638605fdb11a2cc7f1eeccd0 Mon Sep 17 00:00:00 2001 From: Leslie Date: Tue, 14 Oct 2025 01:45:18 +0800 Subject: [PATCH 03/88] =?UTF-8?q?fixed(pay):=20=E5=85=BC=E5=AE=B9=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98=E5=85=AC=E9=92=A5=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E5=B9=B6=E8=A7=A3=E5=86=B3=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pay/core/client/impl/weixin/AbstractWxPayClient.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java index 4ee904bbb1..1db6bd146a 100644 --- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -72,6 +72,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient Date: Thu, 27 Nov 2025 12:01:55 +0800 Subject: [PATCH 04/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90SocialClient?= =?UTF-8?q?=E3=80=91=20=E6=94=AF=E4=BB=98=E5=AE=9D=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E7=99=BB=E5=BD=95=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 4 +++- sql/kingbase/ruoyi-vue-pro.sql | 4 +++- sql/mysql/ruoyi-vue-pro.sql | 3 ++- sql/opengauss/ruoyi-vue-pro.sql | 4 +++- sql/oracle/ruoyi-vue-pro.sql | 4 +++- sql/postgresql/ruoyi-vue-pro.sql | 4 +++- sql/sqlserver/ruoyi-vue-pro.sql | 10 +++++++++- .../admin/socail/vo/client/SocialClientRespVO.java | 3 +++ .../admin/socail/vo/client/SocialClientSaveReqVO.java | 3 +++ .../system/dal/dataobject/social/SocialClientDO.java | 8 ++++++++ .../module/system/enums/social/SocialTypeEnum.java | 6 ++++++ .../system/service/social/SocialClientServiceImpl.java | 8 ++++++-- yudao-server/src/main/resources/application-dev.yaml | 7 +++++++ yudao-server/src/main/resources/application-local.yaml | 7 +++++++ 14 files changed, 66 insertions(+), 9 deletions(-) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index 3e0dcda2aa..29a4a414f4 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -4179,7 +4179,8 @@ CREATE TABLE system_social_client social_type smallint NOT NULL, user_type smallint NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) DEFAULT NULL NULL, agent_id varchar(255) DEFAULT NULL NULL, status smallint NOT NULL, creator varchar(64) DEFAULT '' NULL, @@ -4195,6 +4196,7 @@ COMMENT ON COLUMN system_social_client.name IS '应用名'; COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; diff --git a/sql/kingbase/ruoyi-vue-pro.sql b/sql/kingbase/ruoyi-vue-pro.sql index 33c41c1c54..b33f3daa02 100644 --- a/sql/kingbase/ruoyi-vue-pro.sql +++ b/sql/kingbase/ruoyi-vue-pro.sql @@ -4461,7 +4461,8 @@ CREATE TABLE system_social_client social_type int2 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) NULL DEFAULT NULL, agent_id varchar(255) NULL DEFAULT NULL, status int2 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4481,6 +4482,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index ff2618c80d..7f0d0b4384 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -3502,7 +3502,8 @@ CREATE TABLE `system_social_client` ( `social_type` tinyint NOT NULL COMMENT '社交平台的类型', `user_type` tinyint NOT NULL COMMENT '用户类型', `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', - `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥', + `client_secret` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥', + `public_key` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT 'publicKey公钥', `agent_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '代理编号', `status` tinyint NOT NULL COMMENT '状态', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', diff --git a/sql/opengauss/ruoyi-vue-pro.sql b/sql/opengauss/ruoyi-vue-pro.sql index 33849b5c68..3f14f05cdb 100644 --- a/sql/opengauss/ruoyi-vue-pro.sql +++ b/sql/opengauss/ruoyi-vue-pro.sql @@ -4461,7 +4461,8 @@ CREATE TABLE system_social_client social_type int2 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) NULL DEFAULT NULL, agent_id varchar(255) NULL DEFAULT NULL, status int2 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4481,6 +4482,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/oracle/ruoyi-vue-pro.sql b/sql/oracle/ruoyi-vue-pro.sql index 4c844b1460..68b89e552c 100644 --- a/sql/oracle/ruoyi-vue-pro.sql +++ b/sql/oracle/ruoyi-vue-pro.sql @@ -4355,7 +4355,8 @@ CREATE TABLE system_social_client social_type smallint NOT NULL, user_type smallint NOT NULL, client_id varchar2(255) NULL, - client_secret varchar2(255) NULL, + client_secret varchar2(2048) NULL, + public_key varchar2(2048) DEFAULT NULL NULL, agent_id varchar2(255) DEFAULT NULL NULL, status smallint NOT NULL, creator varchar2(64) DEFAULT '' NULL, @@ -4375,6 +4376,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index f85884776e..9cf5630f7d 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -4461,7 +4461,8 @@ CREATE TABLE system_social_client social_type int2 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) NULL DEFAULT NULL, agent_id varchar(255) NULL DEFAULT NULL, status int2 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4481,6 +4482,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql index abf63c4e34..e0ba031644 100644 --- a/sql/sqlserver/ruoyi-vue-pro.sql +++ b/sql/sqlserver/ruoyi-vue-pro.sql @@ -10433,7 +10433,8 @@ CREATE TABLE system_social_client social_type tinyint NOT NULL, user_type tinyint NOT NULL, client_id nvarchar(255) NOT NULL, - client_secret nvarchar(255) NOT NULL, + client_secret nvarchar(2048) NOT NULL, + public_key nvarchar(2048) DEFAULT NULL NULL, agent_id nvarchar(255) DEFAULT NULL NULL, status tinyint NOT NULL, creator nvarchar(64) DEFAULT '' NULL, @@ -10487,6 +10488,13 @@ EXEC sp_addextendedproperty 'COLUMN', N'client_secret' GO +EXEC sp_addextendedproperty + 'MS_Description', N'publicKey公钥', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'public_key' +GO + EXEC sp_addextendedproperty 'MS_Description', N'代理编号', 'SCHEMA', N'dbo', diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java index 900f363d1a..375d52beba 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java @@ -27,6 +27,9 @@ public class SocialClientRespVO { @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") private String clientSecret; + @Schema(description = "publicKey公钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") + private String publicKey; + @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") private String agentId; diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java index be89153e87..9b3ceee91e 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java @@ -41,6 +41,9 @@ public class SocialClientSaveReqVO { @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") @NotNull(message = "客户端密钥不能为空") private String clientSecret; + + @Schema(description = "publicKey公钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") + private String publicKey; @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") private String agentId; diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java index 5449106105..1fcc29f1f1 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java @@ -64,6 +64,14 @@ public class SocialClientDO extends TenantBaseDO { * 客户端 Secret */ private String clientSecret; + + /** + * publicKey公钥 + * + * 目前只有部分“社交类型”在使用: + * 1. 支付宝:支付宝公钥 + */ + private String publicKey; /** * 代理编号 diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java index e6c4dc32b5..f84ce535de 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java @@ -53,6 +53,12 @@ public enum SocialTypeEnum implements ArrayValuable { * @see 接入文档 */ WECHAT_MINI_PROGRAM(34, "WECHAT_MINI_PROGRAM"), + /** + * 支付宝小程序 + * + * @see 接入文档 + */ + ALIPAY_MINI_PROGRAM(40, "ALIPAY"), ; public static final Integer[] ARRAYS = Arrays.stream(values()).map(SocialTypeEnum::getType).toArray(Integer[]::new); diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java index e03bd208e1..82282abeb3 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java @@ -11,7 +11,6 @@ import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.ObjUtil; @@ -51,6 +50,7 @@ import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthAlipayRequest; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.utils.AuthStateUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -169,7 +169,7 @@ public class SocialClientServiceImpl implements SocialClientService { public AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state) { // 构建请求 AuthRequest authRequest = buildAuthRequest(socialType, userType); - AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); + AuthCallback authCallback = AuthCallback.builder().code(code).auth_code(code).state(state).build(); // 执行请求 AuthResponse authResponse = authRequest.login(authCallback); log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType, @@ -205,6 +205,10 @@ public class SocialClientServiceImpl implements SocialClientService { if (client.getAgentId() != null) { // 如果有 agentId 则修改 agentId newAuthConfig.setAgentId(client.getAgentId()); } + // 如果是阿里的小程序 + if (SocialTypeEnum.ALIPAY_MINI_PROGRAM.getType().equals(socialType)) { + return new AuthAlipayRequest(newAuthConfig, client.getPublicKey()); + } // 2.3 设置会 request 里,进行后续使用 ReflectUtil.setFieldValue(request, "config", newAuthConfig); } diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 5e0ef1e108..9be9396c78 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -197,6 +197,13 @@ justauth: client-id: ${wx.mp.app-id} client-secret: ${wx.mp.secret} ignore-check-redirect-uri: true + ALIPAY: # 支付宝小程序 + client-id: xx + client-secret: xx + alipay-public-key: xx + ignore-check-redirect-uri: true + redirect-uri: http://yunai.natapp1.cc + ignore-check-state: true cache: type: REDIS prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 4297a17855..1ad0f983d5 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -262,6 +262,13 @@ justauth: client-id: ${wx.mp.app-id} client-secret: ${wx.mp.secret} ignore-check-redirect-uri: true + ALIPAY: # 支付宝小程序 + client-id: xx + client-secret: xx + alipay-public-key: xx + ignore-check-redirect-uri: true + redirect-uri: http://yunai.natapp1.cc + ignore-check-state: true cache: type: REDIS prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: From 3476df84aba771352539a4035b1b532855f70d15 Mon Sep 17 00:00:00 2001 From: yunlongn Date: Thu, 27 Nov 2025 13:43:10 +0800 Subject: [PATCH 05/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90SocialClient?= =?UTF-8?q?=E3=80=91=20=E6=94=AF=E4=BB=98=E5=AE=9D=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E7=99=BB=E5=BD=95=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 1 + sql/kingbase/ruoyi-vue-pro.sql | 1 + sql/mysql/ruoyi-vue-pro.sql | 1 + sql/opengauss/ruoyi-vue-pro.sql | 1 + sql/oracle/ruoyi-vue-pro.sql | 1 + sql/postgresql/ruoyi-vue-pro.sql | 1 + sql/sqlserver/ruoyi-vue-pro.sql | 2 ++ 7 files changed, 8 insertions(+) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index 29a4a414f4..86d5cbf818 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -1240,6 +1240,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; SET IDENTITY_INSERT system_dict_data OFF; -- @formatter:on diff --git a/sql/kingbase/ruoyi-vue-pro.sql b/sql/kingbase/ruoyi-vue-pro.sql index b33f3daa02..9d08ebd0dc 100644 --- a/sql/kingbase/ruoyi-vue-pro.sql +++ b/sql/kingbase/ruoyi-vue-pro.sql @@ -1354,6 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', 40, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 7f0d0b4384..852bf41132 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -1084,6 +1084,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3028, 2, 'Anthropic', 'Anthropic', 'ai_platform', 0, '', '', '', '1', '2025-08-21 22:54:24', '1', '2025-08-21 22:57:58', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3029, 2, '谷歌 Gemini', 'Gemini', 'ai_platform', 0, '', '', '', '1', '2025-08-22 22:39:35', '1', '2025-08-22 22:44:49', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3030, 1, '文件系统', 'filesystem', 'ai_mcp_client_name', 0, '', '', '', '1', '2025-08-28 13:58:43', '1', '2025-08-28 21:19:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', b'0'); COMMIT; -- ---------------------------- diff --git a/sql/opengauss/ruoyi-vue-pro.sql b/sql/opengauss/ruoyi-vue-pro.sql index 3f14f05cdb..97c284e86a 100644 --- a/sql/opengauss/ruoyi-vue-pro.sql +++ b/sql/opengauss/ruoyi-vue-pro.sql @@ -1354,6 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on diff --git a/sql/oracle/ruoyi-vue-pro.sql b/sql/oracle/ruoyi-vue-pro.sql index 68b89e552c..e5cf5d3572 100644 --- a/sql/oracle/ruoyi-vue-pro.sql +++ b/sql/oracle/ruoyi-vue-pro.sql @@ -1306,6 +1306,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', to_date('2025-03-23 12:15:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-03-23 12:15:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', to_date('2025-04-23 21:47:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-05-02 12:01:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', to_date('2025-05-10 08:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-05-10 08:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:07:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); COMMIT; -- @formatter:on diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index 9cf5630f7d..b4c4fd58f8 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -1354,6 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql index e0ba031644..9b84d6e120 100644 --- a/sql/sqlserver/ruoyi-vue-pro.sql +++ b/sql/sqlserver/ruoyi-vue-pro.sql @@ -3299,6 +3299,8 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t GO INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, N'支付宝余额', N'6', N'brokerage_withdraw_type', 0, N'', N'', N'API 打款', N'1', N'2025-05-10 08:24:49', N'1', N'2025-05-10 08:24:49', N'0') GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, N'支付宝小程序', N'40', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:38', N'1', N'2023-11-04 13:07:16', N'0') +GO SET IDENTITY_INSERT system_dict_data OFF GO COMMIT From f6090690fd5bd8b5286a398d12b8bc27012d148b Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 27 Nov 2025 15:42:41 +0800 Subject: [PATCH 06/88] =?UTF-8?q?fix:=20=E3=80=90infra=20=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E8=AE=BE=E6=96=BD=E3=80=91S3FileClient=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=9A=84=20region=20>=20=E4=BB=8E=20endpoint=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E7=9A=84=20region=20>=20=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=80=BC=20us-east-1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../file/core/client/s3/S3FileClient.java | 76 ++++++++++++++++++- .../core/client/s3/S3FileClientConfig.java | 12 +++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index 94ba6a3ebb..e7b8b9789a 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -47,7 +47,9 @@ public class S3FileClient extends AbstractFileClient { config.setDomain(buildDomain()); } // 初始化 S3 客户端 - Region region = Region.of("us-east-1"); // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错 + // 优先级:配置的 region > 从 endpoint 解析的 region > 默认值 us-east-1 + String regionStr = resolveRegion(); + Region region = Region.of(regionStr); AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret())); URI endpoint = URI.create(buildEndpoint()); @@ -159,4 +161,76 @@ public class S3FileClient extends AbstractFileClient { return StrUtil.format("https://{}", config.getEndpoint()); } + /** + * 解析 AWS 区域 + * 优先级:配置的 region > 从 endpoint 解析的 region > 默认值 us-east-1 + * + * @return 区域字符串 + */ + private String resolveRegion() { + // 1. 如果配置了 region,直接使用 + if (StrUtil.isNotEmpty(config.getRegion())) { + return config.getRegion(); + } + + // 2. 尝试从 endpoint 中解析 region + String endpoint = config.getEndpoint(); + if (StrUtil.isEmpty(endpoint)) { + return "us-east-1"; + } + + // 移除协议头(http:// 或 https://) + String host = endpoint; + if (HttpUtil.isHttp(endpoint) || HttpUtil.isHttps(endpoint)) { + try { + host = URI.create(endpoint).getHost(); + } catch (Exception e) { + // 解析失败,使用默认值 + return "us-east-1"; + } + } + + if (StrUtil.isEmpty(host)) { + return "us-east-1"; + } + + // 3. AWS S3 格式:s3.us-west-2.amazonaws.com 或 s3.amazonaws.com + if (host.contains("amazonaws.com")) { + // 匹配 s3.{region}.amazonaws.com 格式 + if (host.startsWith("s3.") && host.contains(".amazonaws.com")) { + String regionPart = host.substring(3, host.indexOf(".amazonaws.com")); + if (StrUtil.isNotEmpty(regionPart) && !regionPart.equals("accelerate")) { + return regionPart; + } + } + // s3.amazonaws.com 或 s3-accelerate.amazonaws.com 使用默认值 + return "us-east-1"; + } + + // 4. 阿里云 OSS 格式:oss-cn-beijing.aliyuncs.com + if (host.contains(S3FileClientConfig.ENDPOINT_ALIYUN)) { + // 匹配 oss-{region}.aliyuncs.com 格式 + if (host.startsWith("oss-") && host.contains("." + S3FileClientConfig.ENDPOINT_ALIYUN)) { + String regionPart = host.substring(4, host.indexOf("." + S3FileClientConfig.ENDPOINT_ALIYUN)); + if (StrUtil.isNotEmpty(regionPart)) { + return regionPart; + } + } + } + + // 5. 腾讯云 COS 格式:cos.ap-shanghai.myqcloud.com + if (host.contains(S3FileClientConfig.ENDPOINT_TENCENT)) { + // 匹配 cos.{region}.myqcloud.com 格式 + if (host.startsWith("cos.") && host.contains("." + S3FileClientConfig.ENDPOINT_TENCENT)) { + String regionPart = host.substring(4, host.indexOf("." + S3FileClientConfig.ENDPOINT_TENCENT)); + if (StrUtil.isNotEmpty(regionPart)) { + return regionPart; + } + } + } + + // 6. 其他情况(MinIO、七牛云等)使用默认值 + return "us-east-1"; + } + } diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java index 216197964a..a0760c40f2 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java @@ -82,6 +82,18 @@ public class S3FileClientConfig implements FileClientConfig { @NotNull(message = "是否公开访问不能为空") private Boolean enablePublicAccess; + /** + * AWS 区域 + * 1. AWS S3:https://docs.aws.amazon.com/general/latest/gr/s3.html 例如说,us-east-1、us-west-2 + * 2. MinIO:可以填任意值,通常使用 us-east-1 + * 3. 阿里云:不需要填写,会自动识别 + * 4. 腾讯云:不需要填写,会自动识别 + * 5. 七牛云:不需要填写,会自动识别 + * 6. 华为云:不需要填写,会自动识别 + * 7. 火山云:不需要填写,会自动识别 + */ + private String region; + @SuppressWarnings("RedundantIfStatement") @AssertTrue(message = "domain 不能为空") @JsonIgnore From 4174debdecf114b35e42f3ce83ee0bdffe30be8e Mon Sep 17 00:00:00 2001 From: yunlongn Date: Thu, 27 Nov 2025 18:03:28 +0800 Subject: [PATCH 07/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90SocialClient?= =?UTF-8?q?=E3=80=91=20=E6=94=AF=E4=BB=98=E5=AE=9D=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E7=99=BB=E5=BD=95=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 2 +- sql/kingbase/ruoyi-vue-pro.sql | 2 +- sql/opengauss/ruoyi-vue-pro.sql | 2 +- sql/oracle/ruoyi-vue-pro.sql | 2 +- sql/postgresql/ruoyi-vue-pro.sql | 2 +- sql/sqlserver/ruoyi-vue-pro.sql | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index d013ad4f3d..e16c85ea79 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -1240,7 +1240,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); -INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; SET IDENTITY_INSERT system_dict_data OFF; -- @formatter:on diff --git a/sql/kingbase/ruoyi-vue-pro.sql b/sql/kingbase/ruoyi-vue-pro.sql index 2504ef48d1..63ea981d0a 100644 --- a/sql/kingbase/ruoyi-vue-pro.sql +++ b/sql/kingbase/ruoyi-vue-pro.sql @@ -1354,7 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); -INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', 40, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', 40, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on diff --git a/sql/opengauss/ruoyi-vue-pro.sql b/sql/opengauss/ruoyi-vue-pro.sql index 2b63492249..6a83ec1821 100644 --- a/sql/opengauss/ruoyi-vue-pro.sql +++ b/sql/opengauss/ruoyi-vue-pro.sql @@ -1354,7 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); -INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on diff --git a/sql/oracle/ruoyi-vue-pro.sql b/sql/oracle/ruoyi-vue-pro.sql index 82702c34f9..01e1de0b9d 100644 --- a/sql/oracle/ruoyi-vue-pro.sql +++ b/sql/oracle/ruoyi-vue-pro.sql @@ -1306,7 +1306,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', to_date('2025-03-23 12:15:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-03-23 12:15:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', to_date('2025-04-23 21:47:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-05-02 12:01:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', to_date('2025-05-10 08:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-05-10 08:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); -INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:07:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:07:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); COMMIT; -- @formatter:on diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index 7c657008a2..d41080d654 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -1354,7 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); -INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql index bd86a597d7..a217dac837 100644 --- a/sql/sqlserver/ruoyi-vue-pro.sql +++ b/sql/sqlserver/ruoyi-vue-pro.sql @@ -3299,7 +3299,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t GO INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, N'支付宝余额', N'6', N'brokerage_withdraw_type', 0, N'', N'', N'API 打款', N'1', N'2025-05-10 08:24:49', N'1', N'2025-05-10 08:24:49', N'0') GO -INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 40, N'支付宝小程序', N'40', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:38', N'1', N'2023-11-04 13:07:16', N'0') +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, N'支付宝小程序', N'40', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:38', N'1', N'2023-11-04 13:07:16', N'0') GO SET IDENTITY_INSERT system_dict_data OFF GO From aee514cf33bf22be56489f62c3b0ccaad669b662 Mon Sep 17 00:00:00 2001 From: zz Date: Fri, 28 Nov 2025 11:41:43 +0800 Subject: [PATCH 08/88] =?UTF-8?q?fix(bpm):=20=E6=9B=B4=E6=94=B9=20moveActi?= =?UTF-8?q?vityIdsToSingleActivityId=20=E4=BC=A0=E5=85=A5=E7=9A=84?= =?UTF-8?q?=E7=AC=AC=E4=B8=80=E4=B8=AA=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/service/task/BpmTaskServiceImpl.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index acd437b570..e562fef918 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -922,16 +922,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { List returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null); List returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId); - List runExecutionIds = new ArrayList<>(); +// List runExecutionIds = new ArrayList<>(); // 2. 给当前要被退回的 task 数组,设置退回意见 taskList.forEach(task -> { // 需要排除掉,不需要设置退回意见的任务 if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { return; } - if (task.getExecutionId() != null) { - runExecutionIds.add(task.getExecutionId()); - } +// if (task.getExecutionId() != null) { +// runExecutionIds.add(task.getExecutionId()); +// } // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 @@ -953,9 +953,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 相关 issue: https://github.com/flowable/flowable-engine/issues/3944 // ② flowable 7.2.0 版本后,继续使用 moveActivityIdsToSingleActivityId 方法。原因:flowable 7.2.0 版本修复了该问题。 // 相关 issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/1018 + // ③ moveExecutionsToSingleActivityId 基于运行时执行实例层面的精确控制,它的操作对象(第一个参数)是 executionId,需要收集到 runExecutionIds + // moveActivityIdsToSingleActivityId 基于 BPMN 模型层面的节点迁移,它的操作对象(第一个参数)是 taskKey runtimeService.createChangeActivityStateBuilder() .processInstanceId(currentTask.getProcessInstanceId()) - .moveActivityIdsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey()) +// .moveExecutionsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey()) + .moveActivityIdsToSingleActivityId(returnTaskKeyList, reqVO.getTargetTaskDefinitionKey()) // 设置需要预测的任务 ids 的流程变量,用于辅助预测 .processVariable(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskDefinitionKeys) // 设置流程变量(local)节点退回标记, 用于退回到节点,不执行 BpmUserTaskAssignStartUserHandlerTypeEnum 策略,导致自动通过 From 86de4684133b1da6e09e1307357418949f5c015c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Nov 2025 09:56:32 +0800 Subject: [PATCH 09/88] =?UTF-8?q?=E5=90=8C=E6=AD=A5=EF=BC=9Ahttps://gitee.?= =?UTF-8?q?com/zhijiantianya/ruoyi-vue-pro/pulls/1464/files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 5 ++++- sql/kingbase/ruoyi-vue-pro.sql | 5 ++++- sql/mysql/ruoyi-vue-pro.sql | 4 +++- sql/opengauss/ruoyi-vue-pro.sql | 5 ++++- sql/oracle/ruoyi-vue-pro.sql | 5 ++++- sql/postgresql/ruoyi-vue-pro.sql | 5 ++++- sql/sqlserver/ruoyi-vue-pro.sql | 12 +++++++++++- .../admin/socail/vo/client/SocialClientRespVO.java | 5 ++++- .../socail/vo/client/SocialClientSaveReqVO.java | 11 +++++++++++ .../system/dal/dataobject/social/SocialClientDO.java | 8 ++++++++ .../module/system/enums/social/SocialTypeEnum.java | 6 ++++++ .../service/social/SocialClientServiceImpl.java | 8 ++++++-- 12 files changed, 69 insertions(+), 10 deletions(-) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index f97d09de47..e16c85ea79 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -1240,6 +1240,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; SET IDENTITY_INSERT system_dict_data OFF; -- @formatter:on @@ -4179,7 +4180,8 @@ CREATE TABLE system_social_client social_type smallint NOT NULL, user_type smallint NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) DEFAULT NULL NULL, agent_id varchar(255) DEFAULT NULL NULL, status smallint NOT NULL, creator varchar(64) DEFAULT '' NULL, @@ -4195,6 +4197,7 @@ COMMENT ON COLUMN system_social_client.name IS '应用名'; COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; diff --git a/sql/kingbase/ruoyi-vue-pro.sql b/sql/kingbase/ruoyi-vue-pro.sql index c1f8e76666..63ea981d0a 100644 --- a/sql/kingbase/ruoyi-vue-pro.sql +++ b/sql/kingbase/ruoyi-vue-pro.sql @@ -1354,6 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', 40, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on @@ -4461,7 +4462,8 @@ CREATE TABLE system_social_client social_type int2 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) NULL DEFAULT NULL, agent_id varchar(255) NULL DEFAULT NULL, status int2 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4481,6 +4483,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 74a8c2cc82..526f2c17ad 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -1092,6 +1092,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3032, 50, 'Vben5.0 Element Plus Schema 模版', '50', 'infra_codegen_front_type', 0, '', '', '', '1', '2025-09-04 23:26:38', '1', '2025-09-04 23:26:38', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3033, 51, 'Vben5.0 Element Plus 标准模版', '51', 'infra_codegen_front_type', 0, '', '', '', '1', '2025-09-04 23:26:49', '1', '2025-09-04 23:26:49', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', b'0'); COMMIT; -- ---------------------------- @@ -3669,7 +3670,8 @@ CREATE TABLE `system_social_client` ( `social_type` tinyint NOT NULL COMMENT '社交平台的类型', `user_type` tinyint NOT NULL COMMENT '用户类型', `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端编号', - `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥', + `client_secret` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端密钥', + `public_key` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT 'publicKey公钥', `agent_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '代理编号', `status` tinyint NOT NULL COMMENT '状态', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', diff --git a/sql/opengauss/ruoyi-vue-pro.sql b/sql/opengauss/ruoyi-vue-pro.sql index c0408f34c5..6a83ec1821 100644 --- a/sql/opengauss/ruoyi-vue-pro.sql +++ b/sql/opengauss/ruoyi-vue-pro.sql @@ -1354,6 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on @@ -4461,7 +4462,8 @@ CREATE TABLE system_social_client social_type int2 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) NULL DEFAULT NULL, agent_id varchar(255) NULL DEFAULT NULL, status int2 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4481,6 +4483,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/oracle/ruoyi-vue-pro.sql b/sql/oracle/ruoyi-vue-pro.sql index 0af291458b..01e1de0b9d 100644 --- a/sql/oracle/ruoyi-vue-pro.sql +++ b/sql/oracle/ruoyi-vue-pro.sql @@ -1306,6 +1306,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', to_date('2025-03-23 12:15:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-03-23 12:15:46', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', to_date('2025-04-23 21:47:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-05-02 12:01:15', 'SYYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', to_date('2025-05-10 08:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-05-10 08:24:49', 'SYYYY-MM-DD HH24:MI:SS'), '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:07:16', 'SYYYY-MM-DD HH24:MI:SS'), '0'); COMMIT; -- @formatter:on @@ -4355,7 +4356,8 @@ CREATE TABLE system_social_client social_type smallint NOT NULL, user_type smallint NOT NULL, client_id varchar2(255) NULL, - client_secret varchar2(255) NULL, + client_secret varchar2(2048) NULL, + public_key varchar2(2048) DEFAULT NULL NULL, agent_id varchar2(255) DEFAULT NULL NULL, status smallint NOT NULL, creator varchar2(64) DEFAULT '' NULL, @@ -4375,6 +4377,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index 85eafefc4e..d41080d654 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -1354,6 +1354,7 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on @@ -4461,7 +4462,8 @@ CREATE TABLE system_social_client social_type int2 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(255) NOT NULL, + client_secret varchar(2048) NOT NULL, + public_key varchar(2048) NULL DEFAULT NULL, agent_id varchar(255) NULL DEFAULT NULL, status int2 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4481,6 +4483,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql index fc4c81bba4..a217dac837 100644 --- a/sql/sqlserver/ruoyi-vue-pro.sql +++ b/sql/sqlserver/ruoyi-vue-pro.sql @@ -3299,6 +3299,8 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t GO INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, N'支付宝余额', N'6', N'brokerage_withdraw_type', 0, N'', N'', N'API 打款', N'1', N'2025-05-10 08:24:49', N'1', N'2025-05-10 08:24:49', N'0') GO +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, N'支付宝小程序', N'40', N'system_social_type', 0, N'', N'', N'', N'1', N'2023-11-04 13:05:38', N'1', N'2023-11-04 13:07:16', N'0') +GO SET IDENTITY_INSERT system_dict_data OFF GO COMMIT @@ -10433,7 +10435,8 @@ CREATE TABLE system_social_client social_type tinyint NOT NULL, user_type tinyint NOT NULL, client_id nvarchar(255) NOT NULL, - client_secret nvarchar(255) NOT NULL, + client_secret nvarchar(2048) NOT NULL, + public_key nvarchar(2048) DEFAULT NULL NULL, agent_id nvarchar(255) DEFAULT NULL NULL, status tinyint NOT NULL, creator nvarchar(64) DEFAULT '' NULL, @@ -10487,6 +10490,13 @@ EXEC sp_addextendedproperty 'COLUMN', N'client_secret' GO +EXEC sp_addextendedproperty + 'MS_Description', N'publicKey公钥', + 'SCHEMA', N'dbo', + 'TABLE', N'system_social_client', + 'COLUMN', N'public_key' +GO + EXEC sp_addextendedproperty 'MS_Description', N'代理编号', 'SCHEMA', N'dbo', diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java index 900f363d1a..fee6061233 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientRespVO.java @@ -27,9 +27,12 @@ public class SocialClientRespVO { @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") private String clientSecret; - @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") + @Schema(description = "授权方的网页应用编号", example = "2000045") private String agentId; + @Schema(description = "publicKey 公钥", example = "2000045") + private String publicKey; + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java index 9549b826c5..6091b3bf84 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java @@ -45,6 +45,9 @@ public class SocialClientSaveReqVO { @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") private String agentId; + @Schema(description = "publicKey 公钥", example = "2000045") + private String publicKey; + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "状态不能为空") @InEnum(CommonStatusEnum.class) @@ -58,4 +61,12 @@ public class SocialClientSaveReqVO { || !StrUtil.isEmpty(agentId); } + @AssertTrue(message = "publicKey 不能为空") + @JsonIgnore + public boolean isPublicKeyValid() { + // 如果是支付宝,必须填写 publicKey 属性 + return !Objects.equals(socialType, SocialTypeEnum.ALIPAY.getType()) + || !StrUtil.isEmpty(publicKey); + } + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java index 5449106105..bc420ced63 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java @@ -73,4 +73,12 @@ public class SocialClientDO extends TenantBaseDO { */ private String agentId; + /** + * publicKey 公钥 + * + * 目前只有部分“社交类型”在使用: + * 1. 支付宝:支付宝公钥 + */ + private String publicKey; + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java index e6c4dc32b5..f84ce535de 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java @@ -53,6 +53,12 @@ public enum SocialTypeEnum implements ArrayValuable { * @see 接入文档 */ WECHAT_MINI_PROGRAM(34, "WECHAT_MINI_PROGRAM"), + /** + * 支付宝小程序 + * + * @see 接入文档 + */ + ALIPAY_MINI_PROGRAM(40, "ALIPAY"), ; public static final Integer[] ARRAYS = Arrays.stream(values()).map(SocialTypeEnum::getType).toArray(Integer[]::new); diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java index 97c65205d8..fc81be23b1 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java @@ -11,7 +11,6 @@ import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.ObjUtil; @@ -52,6 +51,7 @@ import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthAlipayRequest; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.utils.AuthStateUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -169,7 +169,7 @@ public class SocialClientServiceImpl implements SocialClientService { public AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state) { // 构建请求 AuthRequest authRequest = buildAuthRequest(socialType, userType); - AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); + AuthCallback authCallback = AuthCallback.builder().code(code).auth_code(code).state(state).build(); // 执行请求 AuthResponse authResponse = authRequest.login(authCallback); log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType, @@ -206,6 +206,10 @@ public class SocialClientServiceImpl implements SocialClientService { newAuthConfig.setAgentId(client.getAgentId()); } // 2.3 设置会 request 里,进行后续使用 + if (SocialTypeEnum.ALIPAY_MINI_PROGRAM.getType().equals(socialType)) { + // 特殊:如果是支付宝的小程序,多了 publicKey 属性,可见 AuthConfig 里的 alipayPublicKey 字段说明 + return new AuthAlipayRequest(newAuthConfig, client.getPublicKey()); + } ReflectUtil.setFieldValue(request, "config", newAuthConfig); } return request; From f7042897ff715f85dbed7bd7a7a1e40a0133d181 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Nov 2025 09:58:32 +0800 Subject: [PATCH 10/88] =?UTF-8?q?=E5=90=8C=E6=AD=A5=EF=BC=9Ahttps://gitee.?= =?UTF-8?q?com/zhijiantianya/ruoyi-vue-pro/pulls/1464/files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/socail/vo/client/SocialClientSaveReqVO.java | 2 +- yudao-server/src/main/resources/application-dev.yaml | 6 ++++++ yudao-server/src/main/resources/application-local.yaml | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java index 6091b3bf84..deeb1ebb93 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java @@ -65,7 +65,7 @@ public class SocialClientSaveReqVO { @JsonIgnore public boolean isPublicKeyValid() { // 如果是支付宝,必须填写 publicKey 属性 - return !Objects.equals(socialType, SocialTypeEnum.ALIPAY.getType()) + return !Objects.equals(socialType, SocialTypeEnum.ALIPAY_MINI_PROGRAM.getType()) || !StrUtil.isEmpty(publicKey); } diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 970002f84a..ac7efe3df8 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -198,6 +198,12 @@ justauth: client-id: ${wx.mp.app-id} client-secret: ${wx.mp.secret} ignore-check-redirect-uri: true + ALIPAY: # 支付宝小程序 + client-id: xx + client-secret: xx + alipay-public-key: xx + ignore-check-redirect-uri: true + ignore-check-state: true cache: type: REDIS prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 83be0582b9..168c4fc82e 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -262,6 +262,12 @@ justauth: client-id: ${wx.mp.app-id} client-secret: ${wx.mp.secret} ignore-check-redirect-uri: true + ALIPAY: # 支付宝小程序 + client-id: xx + client-secret: xx + alipay-public-key: xx + ignore-check-redirect-uri: true + ignore-check-state: true cache: type: REDIS prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: From 5d49baa69cb0a1bd0e48572d6f35b1f58f236a9f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Nov 2025 10:00:22 +0800 Subject: [PATCH 11/88] =?UTF-8?q?=E5=90=8C=E6=AD=A5=20https://gitee.com/zh?= =?UTF-8?q?ijiantianya/ruoyi-vue-pro/pulls/1464/files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/socail/vo/client/SocialClientSaveReqVO.java | 3 --- .../system/dal/dataobject/social/SocialClientDO.java | 8 -------- 2 files changed, 11 deletions(-) diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java index 8a8f2345cd..c8ec8cd0fa 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/client/SocialClientSaveReqVO.java @@ -41,9 +41,6 @@ public class SocialClientSaveReqVO { @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter") @NotNull(message = "客户端密钥不能为空") private String clientSecret; - - @Schema(description = "publicKey公钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") - private String publicKey; @Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045") private String agentId; diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java index b81d7d04d4..bc420ced63 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/social/SocialClientDO.java @@ -64,14 +64,6 @@ public class SocialClientDO extends TenantBaseDO { * 客户端 Secret */ private String clientSecret; - - /** - * publicKey公钥 - * - * 目前只有部分“社交类型”在使用: - * 1. 支付宝:支付宝公钥 - */ - private String publicKey; /** * 代理编号 From 35b6f9d31c9052af7e1bc783eddaf35bb50a9f53 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Nov 2025 12:10:55 +0800 Subject: [PATCH 12/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90infra=E3=80=91s3=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20region=20=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../file/core/client/s3/S3FileClient.java | 15 ++++++--------- .../file/core/client/s3/S3FileClientConfig.java | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index e7b8b9789a..d2213f5328 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -173,13 +173,13 @@ public class S3FileClient extends AbstractFileClient { return config.getRegion(); } - // 2. 尝试从 endpoint 中解析 region + // 2.1 尝试从 endpoint 中解析 region String endpoint = config.getEndpoint(); if (StrUtil.isEmpty(endpoint)) { return "us-east-1"; } - // 移除协议头(http:// 或 https://) + // 2.2 移除协议头(http:// 或 https://) String host = endpoint; if (HttpUtil.isHttp(endpoint) || HttpUtil.isHttps(endpoint)) { try { @@ -189,12 +189,11 @@ public class S3FileClient extends AbstractFileClient { return "us-east-1"; } } - if (StrUtil.isEmpty(host)) { return "us-east-1"; } - // 3. AWS S3 格式:s3.us-west-2.amazonaws.com 或 s3.amazonaws.com + // 3.1 AWS S3 格式:s3.us-west-2.amazonaws.com 或 s3.amazonaws.com if (host.contains("amazonaws.com")) { // 匹配 s3.{region}.amazonaws.com 格式 if (host.startsWith("s3.") && host.contains(".amazonaws.com")) { @@ -206,8 +205,7 @@ public class S3FileClient extends AbstractFileClient { // s3.amazonaws.com 或 s3-accelerate.amazonaws.com 使用默认值 return "us-east-1"; } - - // 4. 阿里云 OSS 格式:oss-cn-beijing.aliyuncs.com + // 3.2 阿里云 OSS 格式:oss-cn-beijing.aliyuncs.com if (host.contains(S3FileClientConfig.ENDPOINT_ALIYUN)) { // 匹配 oss-{region}.aliyuncs.com 格式 if (host.startsWith("oss-") && host.contains("." + S3FileClientConfig.ENDPOINT_ALIYUN)) { @@ -217,8 +215,7 @@ public class S3FileClient extends AbstractFileClient { } } } - - // 5. 腾讯云 COS 格式:cos.ap-shanghai.myqcloud.com + // 3.3 腾讯云 COS 格式:cos.ap-shanghai.myqcloud.com if (host.contains(S3FileClientConfig.ENDPOINT_TENCENT)) { // 匹配 cos.{region}.myqcloud.com 格式 if (host.startsWith("cos.") && host.contains("." + S3FileClientConfig.ENDPOINT_TENCENT)) { @@ -229,7 +226,7 @@ public class S3FileClient extends AbstractFileClient { } } - // 6. 其他情况(MinIO、七牛云等)使用默认值 + // 3.4 其他情况(MinIO、七牛云等)使用默认值 return "us-east-1"; } diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java index a0760c40f2..3300a3ef6e 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java @@ -83,7 +83,7 @@ public class S3FileClientConfig implements FileClientConfig { private Boolean enablePublicAccess; /** - * AWS 区域 + * 区域 * 1. AWS S3:https://docs.aws.amazon.com/general/latest/gr/s3.html 例如说,us-east-1、us-west-2 * 2. MinIO:可以填任意值,通常使用 us-east-1 * 3. 阿里云:不需要填写,会自动识别 From a2ff100c14930ac77fb69b46875eda9d05f5e527 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Nov 2025 16:21:10 +0800 Subject: [PATCH 13/88] =?UTF-8?q?fix=EF=BC=9Apgsql=20=E7=9A=84=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=EF=BC=8C=E8=87=AA=E5=A2=9E=20id=20=E6=9C=89=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=8C=E5=AF=B9=E5=BA=94=20https://gitee.com/zhijia?= =?UTF-8?q?ntianya/yudao-cloud/issues/ID97FH?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/postgresql/ruoyi-vue-pro.sql | 260 +++++++++++++++---------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index d41080d654..5fe221ae4b 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -27,6 +27,10 @@ COMMENT ON TABLE dual IS '数据库连接的表'; INSERT INTO dual VALUES (1); -- @formatter:on +DROP SEQUENCE IF EXISTS infra_api_access_log_seq; +CREATE SEQUENCE infra_api_access_log_seq + START 1; + -- ---------------------------- -- Table structure for infra_api_access_log -- ---------------------------- @@ -92,8 +96,8 @@ COMMENT ON COLUMN infra_api_access_log.deleted IS '是否删除'; COMMENT ON COLUMN infra_api_access_log.tenant_id IS '租户编号'; COMMENT ON TABLE infra_api_access_log IS 'API 访问日志表'; -DROP SEQUENCE IF EXISTS infra_api_access_log_seq; -CREATE SEQUENCE infra_api_access_log_seq +DROP SEQUENCE IF EXISTS infra_api_error_log_seq; +CREATE SEQUENCE infra_api_error_log_seq START 1; -- ---------------------------- @@ -165,8 +169,8 @@ COMMENT ON COLUMN infra_api_error_log.deleted IS '是否删除'; COMMENT ON COLUMN infra_api_error_log.tenant_id IS '租户编号'; COMMENT ON TABLE infra_api_error_log IS '系统异常日志'; -DROP SEQUENCE IF EXISTS infra_api_error_log_seq; -CREATE SEQUENCE infra_api_error_log_seq +DROP SEQUENCE IF EXISTS infra_codegen_column_seq; +CREATE SEQUENCE infra_codegen_column_seq START 1; -- ---------------------------- @@ -228,8 +232,8 @@ COMMENT ON COLUMN infra_codegen_column.update_time IS '更新时间'; COMMENT ON COLUMN infra_codegen_column.deleted IS '是否删除'; COMMENT ON TABLE infra_codegen_column IS '代码生成表字段定义'; -DROP SEQUENCE IF EXISTS infra_codegen_column_seq; -CREATE SEQUENCE infra_codegen_column_seq +DROP SEQUENCE IF EXISTS infra_codegen_table_seq; +CREATE SEQUENCE infra_codegen_table_seq START 1; -- ---------------------------- @@ -293,8 +297,9 @@ COMMENT ON COLUMN infra_codegen_table.update_time IS '更新时间'; COMMENT ON COLUMN infra_codegen_table.deleted IS '是否删除'; COMMENT ON TABLE infra_codegen_table IS '代码生成表定义'; -DROP SEQUENCE IF EXISTS infra_codegen_table_seq; -CREATE SEQUENCE infra_codegen_table_seq + +DROP SEQUENCE IF EXISTS infra_config_seq; +CREATE SEQUENCE infra_config_seq START 1; -- ---------------------------- @@ -352,9 +357,9 @@ INSERT INTO infra_config (id, category, type, name, config_key, value, visible, COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS infra_config_seq; -CREATE SEQUENCE infra_config_seq - START 14; +DROP SEQUENCE IF EXISTS infra_data_source_config_seq; +CREATE SEQUENCE infra_data_source_config_seq + START 1; -- ---------------------------- -- Table structure for infra_data_source_config @@ -389,8 +394,8 @@ COMMENT ON COLUMN infra_data_source_config.update_time IS '更新时间'; COMMENT ON COLUMN infra_data_source_config.deleted IS '是否删除'; COMMENT ON TABLE infra_data_source_config IS '数据源配置表'; -DROP SEQUENCE IF EXISTS infra_data_source_config_seq; -CREATE SEQUENCE infra_data_source_config_seq +DROP SEQUENCE IF EXISTS infra_file_seq; +CREATE SEQUENCE infra_file_seq START 1; -- ---------------------------- @@ -430,9 +435,9 @@ COMMENT ON COLUMN infra_file.update_time IS '更新时间'; COMMENT ON COLUMN infra_file.deleted IS '是否删除'; COMMENT ON TABLE infra_file IS '文件表'; -DROP SEQUENCE IF EXISTS infra_file_seq; -CREATE SEQUENCE infra_file_seq - START 1; +DROP SEQUENCE IF EXISTS infra_file_config_seq; +CREATE SEQUENCE infra_file_config_seq + START 31; -- ---------------------------- -- Table structure for infra_file_config @@ -486,9 +491,9 @@ INSERT INTO infra_file_config (id, name, storage, remark, master, config, creato COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS infra_file_config_seq; -CREATE SEQUENCE infra_file_config_seq - START 31; +DROP SEQUENCE IF EXISTS infra_file_content_seq; +CREATE SEQUENCE infra_file_content_seq + START 1; -- ---------------------------- -- Table structure for infra_file_content @@ -521,8 +526,8 @@ COMMENT ON COLUMN infra_file_content.update_time IS '更新时间'; COMMENT ON COLUMN infra_file_content.deleted IS '是否删除'; COMMENT ON TABLE infra_file_content IS '文件表'; -DROP SEQUENCE IF EXISTS infra_file_content_seq; -CREATE SEQUENCE infra_file_content_seq +DROP SEQUENCE IF EXISTS infra_job_seq; +CREATE SEQUENCE infra_job_seq START 1; -- ---------------------------- @@ -587,9 +592,9 @@ INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expre COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS infra_job_seq; -CREATE SEQUENCE infra_job_seq - START 36; +DROP SEQUENCE IF EXISTS infra_job_log_seq; +CREATE SEQUENCE infra_job_log_seq + START 1; -- ---------------------------- -- Table structure for infra_job_log @@ -634,8 +639,8 @@ COMMENT ON COLUMN infra_job_log.update_time IS '更新时间'; COMMENT ON COLUMN infra_job_log.deleted IS '是否删除'; COMMENT ON TABLE infra_job_log IS '定时任务日志表'; -DROP SEQUENCE IF EXISTS infra_job_log_seq; -CREATE SEQUENCE infra_job_log_seq +DROP SEQUENCE IF EXISTS system_dept_seq; +CREATE SEQUENCE system_dept_seq START 1; -- ---------------------------- @@ -701,9 +706,9 @@ INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_dept_seq; -CREATE SEQUENCE system_dept_seq - START 114; +DROP SEQUENCE IF EXISTS system_dict_data_seq; +CREATE SEQUENCE system_dict_data_seq + START 1; -- ---------------------------- -- Table structure for system_dict_data @@ -1354,13 +1359,12 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', '0'); INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0'); -INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '支付宝小程序', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0'); COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_dict_data_seq; -CREATE SEQUENCE system_dict_data_seq - START 3003; +DROP SEQUENCE IF EXISTS system_dict_type_seq; +CREATE SEQUENCE system_dict_type_seq + START 1; -- ---------------------------- -- Table structure for system_dict_type @@ -1512,9 +1516,9 @@ INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_ti COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_dict_type_seq; -CREATE SEQUENCE system_dict_type_seq - START 1014; +DROP SEQUENCE IF EXISTS system_login_log_seq; +CREATE SEQUENCE system_login_log_seq + START 1; -- ---------------------------- -- Table structure for system_login_log @@ -1559,8 +1563,8 @@ COMMENT ON COLUMN system_login_log.deleted IS '是否删除'; COMMENT ON COLUMN system_login_log.tenant_id IS '租户编号'; COMMENT ON TABLE system_login_log IS '系统访问记录'; -DROP SEQUENCE IF EXISTS system_login_log_seq; -CREATE SEQUENCE system_login_log_seq +DROP SEQUENCE IF EXISTS system_mail_account_seq; +CREATE SEQUENCE system_mail_account_seq START 1; -- ---------------------------- @@ -1614,9 +1618,9 @@ INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_e COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_mail_account_seq; -CREATE SEQUENCE system_mail_account_seq - START 5; +DROP SEQUENCE IF EXISTS system_mail_log_seq; +CREATE SEQUENCE system_mail_log_seq + START 1; -- ---------------------------- -- Table structure for system_mail_log @@ -1673,8 +1677,8 @@ COMMENT ON COLUMN system_mail_log.update_time IS '更新时间'; COMMENT ON COLUMN system_mail_log.deleted IS '是否删除'; COMMENT ON TABLE system_mail_log IS '邮件日志表'; -DROP SEQUENCE IF EXISTS system_mail_log_seq; -CREATE SEQUENCE system_mail_log_seq +DROP SEQUENCE IF EXISTS system_mail_template_seq; +CREATE SEQUENCE system_mail_template_seq START 1; -- ---------------------------- @@ -1731,9 +1735,9 @@ INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, c COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_mail_template_seq; -CREATE SEQUENCE system_mail_template_seq - START 16; +DROP SEQUENCE IF EXISTS system_menu_seq; +CREATE SEQUENCE system_menu_seq + START 1; -- ---------------------------- -- Table structure for system_menu @@ -2705,9 +2709,9 @@ INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_menu_seq; -CREATE SEQUENCE system_menu_seq - START 5013; +DROP SEQUENCE IF EXISTS system_notice_seq; +CREATE SEQUENCE system_notice_seq + START 1; -- ---------------------------- -- Table structure for system_notice @@ -2755,9 +2759,9 @@ INSERT INTO system_notice (id, title, content, type, status, creator, create_tim COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_notice_seq; -CREATE SEQUENCE system_notice_seq - START 5; +DROP SEQUENCE IF EXISTS system_notify_message_seq; +CREATE SEQUENCE system_notify_message_seq + START 1; -- ---------------------------- -- Table structure for system_notify_message @@ -2823,9 +2827,9 @@ INSERT INTO system_notify_message (id, user_id, user_type, template_id, template COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_notify_message_seq; -CREATE SEQUENCE system_notify_message_seq - START 11; +DROP SEQUENCE IF EXISTS system_notify_template_seq; +CREATE SEQUENCE system_notify_template_seq + START 1; -- ---------------------------- -- Table structure for system_notify_template @@ -2868,8 +2872,8 @@ COMMENT ON COLUMN system_notify_template.update_time IS '更新时间'; COMMENT ON COLUMN system_notify_template.deleted IS '是否删除'; COMMENT ON TABLE system_notify_template IS '站内信模板表'; -DROP SEQUENCE IF EXISTS system_notify_template_seq; -CREATE SEQUENCE system_notify_template_seq +DROP SEQUENCE IF EXISTS system_oauth2_access_token_seq; +CREATE SEQUENCE system_oauth2_access_token_seq START 1; -- ---------------------------- @@ -2918,8 +2922,8 @@ COMMENT ON COLUMN system_oauth2_access_token.deleted IS '是否删除'; COMMENT ON COLUMN system_oauth2_access_token.tenant_id IS '租户编号'; COMMENT ON TABLE system_oauth2_access_token IS 'OAuth2 访问令牌'; -DROP SEQUENCE IF EXISTS system_oauth2_access_token_seq; -CREATE SEQUENCE system_oauth2_access_token_seq +DROP SEQUENCE IF EXISTS system_oauth2_approve_seq; +CREATE SEQUENCE system_oauth2_approve_seq START 1; -- ---------------------------- @@ -2961,8 +2965,8 @@ COMMENT ON COLUMN system_oauth2_approve.deleted IS '是否删除'; COMMENT ON COLUMN system_oauth2_approve.tenant_id IS '租户编号'; COMMENT ON TABLE system_oauth2_approve IS 'OAuth2 批准表'; -DROP SEQUENCE IF EXISTS system_oauth2_approve_seq; -CREATE SEQUENCE system_oauth2_approve_seq +DROP SEQUENCE IF EXISTS system_oauth2_client_seq; +CREATE SEQUENCE system_oauth2_client_seq START 1; -- ---------------------------- @@ -3032,9 +3036,9 @@ INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_oauth2_client_seq; -CREATE SEQUENCE system_oauth2_client_seq - START 43; +DROP SEQUENCE IF EXISTS system_oauth2_code_seq; +CREATE SEQUENCE system_oauth2_code_seq + START 1; -- ---------------------------- -- Table structure for system_oauth2_code @@ -3079,8 +3083,8 @@ COMMENT ON COLUMN system_oauth2_code.deleted IS '是否删除'; COMMENT ON COLUMN system_oauth2_code.tenant_id IS '租户编号'; COMMENT ON TABLE system_oauth2_code IS 'OAuth2 授权码表'; -DROP SEQUENCE IF EXISTS system_oauth2_code_seq; -CREATE SEQUENCE system_oauth2_code_seq +DROP SEQUENCE IF EXISTS system_oauth2_refresh_token_seq; +CREATE SEQUENCE system_oauth2_refresh_token_seq START 1; -- ---------------------------- @@ -3122,8 +3126,8 @@ COMMENT ON COLUMN system_oauth2_refresh_token.deleted IS '是否删除'; COMMENT ON COLUMN system_oauth2_refresh_token.tenant_id IS '租户编号'; COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 刷新令牌'; -DROP SEQUENCE IF EXISTS system_oauth2_refresh_token_seq; -CREATE SEQUENCE system_oauth2_refresh_token_seq +DROP SEQUENCE IF EXISTS system_operate_log_seq; +CREATE SEQUENCE system_operate_log_seq START 1; -- ---------------------------- @@ -3179,8 +3183,8 @@ COMMENT ON COLUMN system_operate_log.deleted IS '是否删除'; COMMENT ON COLUMN system_operate_log.tenant_id IS '租户编号'; COMMENT ON TABLE system_operate_log IS '操作日志记录 V2 版本'; -DROP SEQUENCE IF EXISTS system_operate_log_seq; -CREATE SEQUENCE system_operate_log_seq +DROP SEQUENCE IF EXISTS system_post_seq; +CREATE SEQUENCE system_post_seq START 1; -- ---------------------------- @@ -3232,9 +3236,9 @@ INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_t COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_post_seq; -CREATE SEQUENCE system_post_seq - START 6; +DROP SEQUENCE IF EXISTS system_role_seq; +CREATE SEQUENCE system_role_seq + START 1; -- ---------------------------- -- Table structure for system_role @@ -3295,9 +3299,9 @@ INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_role_seq; -CREATE SEQUENCE system_role_seq - START 159; +DROP SEQUENCE IF EXISTS system_role_menu_seq; +CREATE SEQUENCE system_role_menu_seq + START 1; -- ---------------------------- -- Table structure for system_role_menu @@ -4201,9 +4205,9 @@ INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, update COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_role_menu_seq; -CREATE SEQUENCE system_role_menu_seq - START 6139; +DROP SEQUENCE IF EXISTS system_sms_channel_seq; +CREATE SEQUENCE system_sms_channel_seq + START 1; -- ---------------------------- -- Table structure for system_sms_channel @@ -4255,9 +4259,9 @@ INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, ap COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_sms_channel_seq; -CREATE SEQUENCE system_sms_channel_seq - START 8; +DROP SEQUENCE IF EXISTS system_sms_code_seq; +CREATE SEQUENCE system_sms_code_seq + START 1; -- ---------------------------- -- Table structure for system_sms_code @@ -4304,8 +4308,8 @@ COMMENT ON COLUMN system_sms_code.deleted IS '是否删除'; COMMENT ON COLUMN system_sms_code.tenant_id IS '租户编号'; COMMENT ON TABLE system_sms_code IS '手机验证码'; -DROP SEQUENCE IF EXISTS system_sms_code_seq; -CREATE SEQUENCE system_sms_code_seq +DROP SEQUENCE IF EXISTS system_sms_log_seq; +CREATE SEQUENCE system_sms_log_seq START 1; -- ---------------------------- @@ -4375,8 +4379,8 @@ COMMENT ON COLUMN system_sms_log.update_time IS '更新时间'; COMMENT ON COLUMN system_sms_log.deleted IS '是否删除'; COMMENT ON TABLE system_sms_log IS '短信日志'; -DROP SEQUENCE IF EXISTS system_sms_log_seq; -CREATE SEQUENCE system_sms_log_seq +DROP SEQUENCE IF EXISTS system_sms_template_seq; +CREATE SEQUENCE system_sms_template_seq START 1; -- ---------------------------- @@ -4447,9 +4451,9 @@ INSERT INTO system_sms_template (id, type, status, code, name, content, params, COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_sms_template_seq; -CREATE SEQUENCE system_sms_template_seq - START 20; +DROP SEQUENCE IF EXISTS system_social_client_seq; +CREATE SEQUENCE system_social_client_seq + START 1; -- ---------------------------- -- Table structure for system_social_client @@ -4462,8 +4466,8 @@ CREATE TABLE system_social_client social_type int2 NOT NULL, user_type int2 NOT NULL, client_id varchar(255) NOT NULL, - client_secret varchar(2048) NOT NULL, - public_key varchar(2048) NULL DEFAULT NULL, + client_secret varchar(255) NOT NULL, + public_key varchar(255) NULL DEFAULT NULL, agent_id varchar(255) NULL DEFAULT NULL, status int2 NOT NULL, creator varchar(64) NULL DEFAULT '', @@ -4483,7 +4487,7 @@ COMMENT ON COLUMN system_social_client.social_type IS '社交平台的类型'; COMMENT ON COLUMN system_social_client.user_type IS '用户类型'; COMMENT ON COLUMN system_social_client.client_id IS '客户端编号'; COMMENT ON COLUMN system_social_client.client_secret IS '客户端密钥'; -COMMENT ON COLUMN system_social_client.public_key IS 'publicKey公钥'; +COMMENT ON COLUMN system_social_client.public_key IS 'publicKey 公钥'; COMMENT ON COLUMN system_social_client.agent_id IS '代理编号'; COMMENT ON COLUMN system_social_client.status IS '状态'; COMMENT ON COLUMN system_social_client.creator IS '创建者'; @@ -4507,9 +4511,9 @@ INSERT INTO system_social_client (id, name, social_type, user_type, client_id, c COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_social_client_seq; -CREATE SEQUENCE system_social_client_seq - START 45; +DROP SEQUENCE IF EXISTS system_social_user_seq; +CREATE SEQUENCE system_social_user_seq + START 1; -- ---------------------------- -- Table structure for system_social_user @@ -4556,8 +4560,8 @@ COMMENT ON COLUMN system_social_user.deleted IS '是否删除'; COMMENT ON COLUMN system_social_user.tenant_id IS '租户编号'; COMMENT ON TABLE system_social_user IS '社交用户表'; -DROP SEQUENCE IF EXISTS system_social_user_seq; -CREATE SEQUENCE system_social_user_seq +DROP SEQUENCE IF EXISTS system_social_user_bind_seq; +CREATE SEQUENCE system_social_user_bind_seq START 1; -- ---------------------------- @@ -4595,8 +4599,8 @@ COMMENT ON COLUMN system_social_user_bind.deleted IS '是否删除'; COMMENT ON COLUMN system_social_user_bind.tenant_id IS '租户编号'; COMMENT ON TABLE system_social_user_bind IS '社交绑定表'; -DROP SEQUENCE IF EXISTS system_social_user_bind_seq; -CREATE SEQUENCE system_social_user_bind_seq +DROP SEQUENCE IF EXISTS system_tenant_seq; +CREATE SEQUENCE system_tenant_seq START 1; -- ---------------------------- @@ -4653,9 +4657,9 @@ INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobi COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_tenant_seq; -CREATE SEQUENCE system_tenant_seq - START 123; +DROP SEQUENCE IF EXISTS system_tenant_package_seq; +CREATE SEQUENCE system_tenant_package_seq + START 1; -- ---------------------------- -- Table structure for system_tenant_package @@ -4700,9 +4704,9 @@ INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_tenant_package_seq; -CREATE SEQUENCE system_tenant_package_seq - START 113; +DROP SEQUENCE IF EXISTS system_user_post_seq; +CREATE SEQUENCE system_user_post_seq + START 1; -- ---------------------------- -- Table structure for system_user_post @@ -4752,9 +4756,9 @@ INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, update COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_user_post_seq; -CREATE SEQUENCE system_user_post_seq - START 126; +DROP SEQUENCE IF EXISTS system_user_role_seq; +CREATE SEQUENCE system_user_role_seq + START 1; -- ---------------------------- -- Table structure for system_user_role @@ -4812,9 +4816,9 @@ INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, update COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_user_role_seq; -CREATE SEQUENCE system_user_role_seq - START 49; +DROP SEQUENCE IF EXISTS system_users_seq; +CREATE SEQUENCE system_users_seq + START 1; -- ---------------------------- -- Table structure for system_users @@ -4895,9 +4899,9 @@ INSERT INTO system_users (id, username, password, nickname, remark, dept_id, pos COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS system_users_seq; -CREATE SEQUENCE system_users_seq - START 142; +DROP SEQUENCE IF EXISTS yudao_demo01_contact_seq; +CREATE SEQUENCE yudao_demo01_contact_seq + START 1; -- ---------------------------- -- Table structure for yudao_demo01_contact @@ -4945,9 +4949,9 @@ INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS yudao_demo01_contact_seq; -CREATE SEQUENCE yudao_demo01_contact_seq - START 2; +DROP SEQUENCE IF EXISTS yudao_demo02_category_seq; +CREATE SEQUENCE yudao_demo02_category_seq + START 1; -- ---------------------------- -- Table structure for yudao_demo02_category @@ -4994,9 +4998,9 @@ INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, up COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS yudao_demo02_category_seq; -CREATE SEQUENCE yudao_demo02_category_seq - START 7; +DROP SEQUENCE IF EXISTS yudao_demo03_course_seq; +CREATE SEQUENCE yudao_demo03_course_seq + START 1; -- ---------------------------- -- Table structure for yudao_demo03_course @@ -5056,9 +5060,9 @@ INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_ti COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS yudao_demo03_course_seq; -CREATE SEQUENCE yudao_demo03_course_seq - START 21; +DROP SEQUENCE IF EXISTS yudao_demo03_grade_seq; +CREATE SEQUENCE yudao_demo03_grade_seq + START 1; -- ---------------------------- -- Table structure for yudao_demo03_grade @@ -5104,9 +5108,9 @@ INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_t COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS yudao_demo03_grade_seq; -CREATE SEQUENCE yudao_demo03_grade_seq - START 10; +DROP SEQUENCE IF EXISTS yudao_demo03_student_seq; +CREATE SEQUENCE yudao_demo03_student_seq + START 1; -- ---------------------------- -- Table structure for yudao_demo03_student @@ -5154,7 +5158,3 @@ INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, COMMIT; -- @formatter:on -DROP SEQUENCE IF EXISTS yudao_demo03_student_seq; -CREATE SEQUENCE yudao_demo03_student_seq - START 10; - From cdc4255da1539cd5d9016973f7b531d77cf8f774 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 29 Nov 2025 18:56:42 +0800 Subject: [PATCH 14/88] =?UTF-8?q?fix=EF=BC=9A=E3=80=90bpm=E3=80=91?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=20moveActivityIdsToSingleActivityId=20?= =?UTF-8?q?=E4=BC=A0=E5=85=A5=E7=9A=84=E7=AC=AC=E4=B8=80=E4=B8=AA=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E5=AF=B9=E5=BA=94=20https://gitee.com/zhijia?= =?UTF-8?q?ntianya/ruoyi-vue-pro/pulls/1466/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/service/task/BpmTaskServiceImpl.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index e562fef918..8bb9486594 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -922,16 +922,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { List returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null); List returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId); -// List runExecutionIds = new ArrayList<>(); // 2. 给当前要被退回的 task 数组,设置退回意见 taskList.forEach(task -> { // 需要排除掉,不需要设置退回意见的任务 if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { return; } -// if (task.getExecutionId() != null) { -// runExecutionIds.add(task.getExecutionId()); -// } // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 @@ -953,11 +949,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 相关 issue: https://github.com/flowable/flowable-engine/issues/3944 // ② flowable 7.2.0 版本后,继续使用 moveActivityIdsToSingleActivityId 方法。原因:flowable 7.2.0 版本修复了该问题。 // 相关 issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/1018 - // ③ moveExecutionsToSingleActivityId 基于运行时执行实例层面的精确控制,它的操作对象(第一个参数)是 executionId,需要收集到 runExecutionIds - // moveActivityIdsToSingleActivityId 基于 BPMN 模型层面的节点迁移,它的操作对象(第一个参数)是 taskKey runtimeService.createChangeActivityStateBuilder() .processInstanceId(currentTask.getProcessInstanceId()) -// .moveExecutionsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey()) .moveActivityIdsToSingleActivityId(returnTaskKeyList, reqVO.getTargetTaskDefinitionKey()) // 设置需要预测的任务 ids 的流程变量,用于辅助预测 .processVariable(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskDefinitionKeys) @@ -1470,7 +1463,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } - // 自动去重,通过自动审批的方式 TODO @芋艿 驳回的情况得考虑一下;@lesan:驳回后,又自动审批么? + // 自动去重,通过自动审批的方式 BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.getProcessDefinitionInfo(task.getProcessDefinitionId()); if (processDefinitionInfo == null) { log.error("[processTaskAssigned][taskId({}) 没有找到流程定义({})]", task.getId(), task.getProcessDefinitionId()); From 6bada543d3e1272a649ba6715e8f460f84204281 Mon Sep 17 00:00:00 2001 From: "MS-QKBGNHPINNKD\\Administrator" Date: Mon, 1 Dec 2025 16:37:53 +0800 Subject: [PATCH 15/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ai=E3=80=91?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=99=BA=E8=83=BD=E6=96=87=E6=A1=A3=E5=88=87?= =?UTF-8?q?=E7=89=87=E7=AD=96=E7=95=A5=EF=BC=8C=E6=94=AF=E6=8C=81=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=AF=86=E5=88=AB=20Markdown=20QA=20=E5=92=8C?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E5=8C=96=E5=88=87=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增 AiDocumentSplitStrategyEnum 枚举,支持 5 种切片策略:自动识别、Token 切分、段落切分、Markdown QA 切分、语义切分 2. 实现 MarkdownQaSplitter:专门处理 Markdown QA 格式文档,识别二级标题作为问题,保持问答对完整性 3. 实现 SemanticTextSplitter:语义化切片器,优先在段落和句子边界处切分,避免截断语义 4. 优化 AiKnowledgeSegmentServiceImpl:增加自动检测文档类型功能,根据文档特征选择最佳切片策略 5. 启用 AI 模块(pom.xml) 6. 修复 AiKnowledgeSegmentPageReqVO:documentId 类型从 Integer 改为 Long 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- pom.xml | 2 +- .../segment/AiKnowledgeSegmentPageReqVO.java | 2 +- .../ai/enums/AiDocumentSplitStrategyEnum.java | 65 ++++ .../AiKnowledgeSegmentServiceImpl.java | 128 ++++++- .../splitter/MarkdownQaSplitter.java | 349 ++++++++++++++++++ .../splitter/SemanticTextSplitter.java | 293 +++++++++++++++ 6 files changed, 826 insertions(+), 13 deletions(-) create mode 100644 yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java create mode 100644 yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java create mode 100644 yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java diff --git a/pom.xml b/pom.xml index 1de1b27e92..c60954fbe5 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ - + yudao-module-ai diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentPageReqVO.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentPageReqVO.java index f53d5be076..dd3b90300b 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentPageReqVO.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentPageReqVO.java @@ -11,7 +11,7 @@ import lombok.Data; public class AiKnowledgeSegmentPageReqVO extends PageParam { @Schema(description = "文档编号", example = "1") - private Integer documentId; + private Long documentId; @Schema(description = "分段内容关键字", example = "Java 开发") private String content; diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java new file mode 100644 index 0000000000..2c9f657579 --- /dev/null +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.ai.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * AI 知识库文档切片策略枚举 + * + * @author runzhen + */ +@AllArgsConstructor +@Getter +public enum AiDocumentSplitStrategyEnum { + + /** + * 自动识别文档类型并选择最佳切片策略 + */ + AUTO("auto", "自动识别"), + + /** + * 基于 Token 数量机械切分(默认策略) + */ + TOKEN("token", "Token 切分"), + + /** + * 按段落切分(以双换行符为分隔) + */ + PARAGRAPH("paragraph", "段落切分"), + + /** + * Markdown QA 格式专用切片器 + * 识别二级标题作为问题,保持问答对完整性 + * 长答案智能切分但保留问题作为上下文 + */ + MARKDOWN_QA("markdown_qa", "Markdown QA 切分"), + + /** + * 语义化切分,保留句子完整性 + * 在段落和句子边界处切分,避免截断 + */ + SEMANTIC("semantic", "语义切分"); + + /** + * 策略代码 + */ + private final String code; + + /** + * 策略名称 + */ + private final String name; + + /** + * 根据代码获取枚举 + */ + public static AiDocumentSplitStrategyEnum fromCode(String code) { + for (AiDocumentSplitStrategyEnum strategy : values()) { + if (strategy.getCode().equals(code)) { + return strategy; + } + } + return AUTO; // 默认返回自动识别 + } + +} diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java index 43c7e9cefe..51a1ce94d5 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; + import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -15,8 +16,11 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO; import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO; import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeSegmentMapper; +import cn.iocoder.yudao.module.ai.enums.AiDocumentSplitStrategyEnum; import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchReqBO; import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO; +import cn.iocoder.yudao.module.ai.service.knowledge.splitter.MarkdownQaSplitter; +import cn.iocoder.yudao.module.ai.service.knowledge.splitter.SemanticTextSplitter; import cn.iocoder.yudao.module.ai.service.model.AiModelService; import com.alibaba.cloud.ai.dashscope.rerank.DashScopeRerankOptions; import com.alibaba.cloud.ai.model.RerankModel; @@ -39,8 +43,7 @@ import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_SEGMENT_CONTENT_TOO_LONG; -import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_SEGMENT_NOT_EXISTS; +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.*; import static org.springframework.ai.vectorstore.SearchRequest.SIMILARITY_THRESHOLD_ACCEPT_ALL; /** @@ -95,16 +98,20 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService AiKnowledgeDO knowledgeDO = knowledgeService.validateKnowledgeExists(documentDO.getKnowledgeId()); VectorStore vectorStore = getVectorStoreById(knowledgeDO); - // 2. 文档切片 - List documentSegments = splitContentByToken(content, documentDO.getSegmentMaxTokens()); + // 2. 文档切片(使用自动检测策略) + List documentSegments = splitContentByStrategy(content, documentDO.getSegmentMaxTokens(), + AiDocumentSplitStrategyEnum.AUTO, documentDO.getUrl()); // 3.1 存储切片 List segmentDOs = convertList(documentSegments, segment -> { if (StrUtil.isEmpty(segment.getText())) { return null; } - return new AiKnowledgeSegmentDO().setKnowledgeId(documentDO.getKnowledgeId()).setDocumentId(documentId) - .setContent(segment.getText()).setContentLength(segment.getText().length()) + return new AiKnowledgeSegmentDO() + .setKnowledgeId(documentDO.getKnowledgeId()) + .setDocumentId(documentId) + .setContent(segment.getText()) + .setContentLength(segment.getText().length()) .setVectorId(AiKnowledgeSegmentDO.VECTOR_ID_EMPTY) .setTokens(tokenCountEstimator.estimate(segment.getText())) .setStatus(CommonStatusEnum.ENABLE.getStatus()); @@ -295,10 +302,13 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService // 1. 读取 URL 内容 String content = knowledgeDocumentService.readUrl(url); - // 2. 文档切片 - List documentSegments = splitContentByToken(content, segmentMaxTokens); + // 2. 自动检测文档类型并选择策略 + AiDocumentSplitStrategyEnum strategy = detectDocumentStrategy(content, url); - // 3. 转换为段落对象 + // 3. 文档切片 + List documentSegments = splitContentByStrategy(content, segmentMaxTokens, strategy, url); + + // 4. 转换为段落对象 return convertList(documentSegments, segment -> { if (StrUtil.isEmpty(segment.getText())) { return null; @@ -333,11 +343,107 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService return getVectorStoreById(knowledge); } - private static List splitContentByToken(String content, Integer segmentMaxTokens) { - TextSplitter textSplitter = buildTokenTextSplitter(segmentMaxTokens); + /** + * 根据策略切分内容 + * + * @param content 文档内容 + * @param segmentMaxTokens 分段的最大 Token 数 + * @param strategy 切片策略 + * @param url 文档 URL(用于自动检测文件类型) + * @return 切片后的文档列表 + */ + private List splitContentByStrategy(String content, Integer segmentMaxTokens, + AiDocumentSplitStrategyEnum strategy, String url) { + // 自动检测策略 + if (strategy == AiDocumentSplitStrategyEnum.AUTO) { + strategy = detectDocumentStrategy(content, url); + log.info("[splitContentByStrategy][自动检测到文档策略: {}]", strategy.getName()); + } + + TextSplitter textSplitter; + switch (strategy) { + case MARKDOWN_QA: + textSplitter = new MarkdownQaSplitter(segmentMaxTokens); + break; + case SEMANTIC: + textSplitter = new SemanticTextSplitter(segmentMaxTokens); + break; + case PARAGRAPH: + textSplitter = new SemanticTextSplitter(segmentMaxTokens, 0); // 段落切分,无重叠 + break; + case TOKEN: + default: + textSplitter = buildTokenTextSplitter(segmentMaxTokens); + break; + } + return textSplitter.apply(Collections.singletonList(new Document(content))); } + /** + * 自动检测文档类型并选择切片策略 + * + * @param content 文档内容 + * @param url 文档 URL + * @return 推荐的切片策略 + */ + private AiDocumentSplitStrategyEnum detectDocumentStrategy(String content, String url) { + if (StrUtil.isEmpty(content)) { + return AiDocumentSplitStrategyEnum.TOKEN; + } + + // 1. 检测 Markdown QA 格式 + if (isMarkdownQaFormat(content, url)) { + return AiDocumentSplitStrategyEnum.MARKDOWN_QA; + } + + // 2. 检测普通 Markdown 文档 + if (isMarkdownDocument(url)) { + return AiDocumentSplitStrategyEnum.SEMANTIC; + } + + // 3. 默认使用语义切分(比 Token 切分更智能) + return AiDocumentSplitStrategyEnum.SEMANTIC; + } + + /** + * 检测是否为 Markdown QA 格式 + * 特征:包含多个二级标题(## )且标题后紧跟答案内容 + */ + private boolean isMarkdownQaFormat(String content, String url) { + // 文件扩展名判断 + if (StrUtil.isNotEmpty(url) && !url.toLowerCase().endsWith(".md")) { + return false; + } + + // 统计二级标题数量 + long h2Count = content.lines() + .filter(line -> line.trim().startsWith("## ")) + .count(); + + // 至少包含 2 个二级标题才认为是 QA 格式 + if (h2Count < 2) { + return false; + } + + // 检查标题占比(QA 文档标题行数相对较多) + long totalLines = content.lines().count(); + double h2Ratio = (double) h2Count / totalLines; + + // 如果二级标题占比超过 10%,认为是 QA 格式 + return h2Ratio > 0.1; + } + + /** + * 检测是否为 Markdown 文档 + */ + private boolean isMarkdownDocument(String url) { + return StrUtil.isNotEmpty(url) && url.toLowerCase().endsWith(".md"); + } + + /** + * 构建基于 Token 的文本切片器(原有逻辑保留) + */ private static TextSplitter buildTokenTextSplitter(Integer segmentMaxTokens) { return TokenTextSplitter.builder() .withChunkSize(segmentMaxTokens) diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java new file mode 100644 index 0000000000..2957f4140e --- /dev/null +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java @@ -0,0 +1,349 @@ +package cn.iocoder.yudao.module.ai.service.knowledge.splitter; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.transformer.splitter.TextSplitter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Markdown QA 格式专用切片器 + * + *

功能特点: + *

    + *
  • 识别二级标题(## )作为问题标记
  • + *
  • 短 QA 对保持完整(不超过 Token 限制)
  • + *
  • 长答案智能切分,每个片段保留完整问题作为上下文
  • + *
  • 支持自定义 Token 估算器
  • + *
+ * + * @author runzhen + */ +@Slf4j +public class MarkdownQaSplitter extends TextSplitter { + + /** + * 二级标题正则:匹配 "## " 开头的行 + */ + private static final Pattern H2_PATTERN = Pattern.compile("^##\\s+(.+)$", Pattern.MULTILINE); + + /** + * 段落分隔符:双换行 + */ + private static final String PARAGRAPH_SEPARATOR = "\n\n"; + + /** + * 句子分隔符 + */ + private static final Pattern SENTENCE_PATTERN = Pattern.compile("[。!?.!?]\\s*"); + + /** + * 分段的最大 Token 数 + */ + private final int chunkSize; + + /** + * Token 估算器(简单实现:中文按字符数,英文按单词数的 1.3 倍) + */ + private final TokenEstimator tokenEstimator; + + public MarkdownQaSplitter(int chunkSize) { + this.chunkSize = chunkSize; + this.tokenEstimator = new SimpleTokenEstimator(); + } + + @Override + protected List splitText(String text) { + if (StrUtil.isEmpty(text)) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + + // 解析 QA 对 + List qaPairs = parseQaPairs(text); + + if (qaPairs.isEmpty()) { + // 如果没有识别到 QA 格式,按段落切分 + return fallbackSplit(text); + } + + // 处理每个 QA 对 + for (QaPair qaPair : qaPairs) { + result.addAll(splitQaPair(qaPair)); + } + + return result; + } + + /** + * 解析 Markdown QA 对 + */ + private List parseQaPairs(String content) { + List qaPairs = new ArrayList<>(); + Matcher matcher = H2_PATTERN.matcher(content); + + List headingPositions = new ArrayList<>(); + List questions = new ArrayList<>(); + + // 找到所有二级标题位置 + while (matcher.find()) { + headingPositions.add(matcher.start()); + questions.add(matcher.group(1).trim()); + } + + if (headingPositions.isEmpty()) { + return qaPairs; + } + + // 提取每个 QA 对 + for (int i = 0; i < headingPositions.size(); i++) { + int start = headingPositions.get(i); + int end = (i + 1 < headingPositions.size()) + ? headingPositions.get(i + 1) + : content.length(); + + String qaText = content.substring(start, end).trim(); + String question = questions.get(i); + + // 提取答案部分(去掉问题标题) + String answer = qaText.substring(qaText.indexOf('\n') + 1).trim(); + + qaPairs.add(new QaPair(question, answer, qaText)); + } + + return qaPairs; + } + + /** + * 切分单个 QA 对 + */ + private List splitQaPair(QaPair qaPair) { + List chunks = new ArrayList<>(); + + String fullQa = qaPair.fullText; + int qaTokens = tokenEstimator.estimate(fullQa); + + // 如果整个 QA 对不超过限制,保持完整 + if (qaTokens <= chunkSize) { + chunks.add(fullQa); + return chunks; + } + + // 长答案需要切分 + log.debug("QA 对超过 Token 限制 ({} > {}),开始智能切分: {}", + qaTokens, chunkSize, qaPair.question); + + List answerChunks = splitLongAnswer(qaPair.answer, qaPair.question); + + for (String answerChunk : answerChunks) { + // 每个片段都包含完整问题 + String chunkText = "## " + qaPair.question + "\n" + answerChunk; + chunks.add(chunkText); + } + + return chunks; + } + + /** + * 切分长答案 + */ + private List splitLongAnswer(String answer, String question) { + List chunks = new ArrayList<>(); + + // 预留问题的 Token 空间 + String questionHeader = "## " + question + "\n"; + int questionTokens = tokenEstimator.estimate(questionHeader); + int availableTokens = chunkSize - questionTokens - 10; // 预留 10 个 Token 的缓冲 + + // 先按段落切分 + String[] paragraphs = answer.split(PARAGRAPH_SEPARATOR); + + StringBuilder currentChunk = new StringBuilder(); + int currentTokens = 0; + + for (String paragraph : paragraphs) { + if (StrUtil.isEmpty(paragraph)) { + continue; + } + + int paragraphTokens = tokenEstimator.estimate(paragraph); + + // 如果单个段落就超过限制,需要按句子切分 + if (paragraphTokens > availableTokens) { + // 先保存当前块 + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + + // 按句子切分长段落 + chunks.addAll(splitLongParagraph(paragraph, availableTokens)); + continue; + } + + // 如果加上这个段落会超过限制 + if (currentTokens + paragraphTokens > availableTokens && currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + + if (currentChunk.length() > 0) { + currentChunk.append("\n\n"); + } + currentChunk.append(paragraph); + currentTokens += paragraphTokens; + } + + // 添加最后一块 + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + } + + return chunks.isEmpty() ? Collections.singletonList(answer) : chunks; + } + + /** + * 切分长段落(按句子) + */ + private List splitLongParagraph(String paragraph, int availableTokens) { + List chunks = new ArrayList<>(); + String[] sentences = SENTENCE_PATTERN.split(paragraph); + + StringBuilder currentChunk = new StringBuilder(); + int currentTokens = 0; + + for (String sentence : sentences) { + if (StrUtil.isEmpty(sentence)) { + continue; + } + + int sentenceTokens = tokenEstimator.estimate(sentence); + + // 如果单个句子就超过限制,强制切分 + if (sentenceTokens > availableTokens) { + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + chunks.add(sentence.trim()); + continue; + } + + if (currentTokens + sentenceTokens > availableTokens && currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + + currentChunk.append(sentence); + currentTokens += sentenceTokens; + } + + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + } + + return chunks.isEmpty() ? Collections.singletonList(paragraph) : chunks; + } + + /** + * 降级切分策略(当未识别到 QA 格式时) + */ + private List fallbackSplit(String content) { + List chunks = new ArrayList<>(); + String[] paragraphs = content.split(PARAGRAPH_SEPARATOR); + + StringBuilder currentChunk = new StringBuilder(); + int currentTokens = 0; + + for (String paragraph : paragraphs) { + if (StrUtil.isEmpty(paragraph)) { + continue; + } + + int paragraphTokens = tokenEstimator.estimate(paragraph); + + if (currentTokens + paragraphTokens > chunkSize && currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + + if (currentChunk.length() > 0) { + currentChunk.append("\n\n"); + } + currentChunk.append(paragraph); + currentTokens += paragraphTokens; + } + + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + } + + return chunks.isEmpty() ? Collections.singletonList(content) : chunks; + } + + /** + * QA 对数据结构 + */ + private static class QaPair { + String question; + String answer; + String fullText; + + QaPair(String question, String answer, String fullText) { + this.question = question; + this.answer = answer; + this.fullText = fullText; + } + } + + /** + * Token 估算器接口 + */ + public interface TokenEstimator { + int estimate(String text); + } + + /** + * 简单的 Token 估算器实现 + * 中文:1 字符 ≈ 1 Token + * 英文:1 单词 ≈ 1.3 Token + */ + private static class SimpleTokenEstimator implements TokenEstimator { + @Override + public int estimate(String text) { + if (StrUtil.isEmpty(text)) { + return 0; + } + + int chineseChars = 0; + int englishWords = 0; + + // 简单统计中英文 + for (char c : text.toCharArray()) { + if (c >= 0x4E00 && c <= 0x9FA5) { + chineseChars++; + } + } + + // 英文单词估算 + String[] words = text.split("\\s+"); + for (String word : words) { + if (word.matches(".*[a-zA-Z].*")) { + englishWords++; + } + } + + return chineseChars + (int) (englishWords * 1.3); + } + } +} diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java new file mode 100644 index 0000000000..64160a41a0 --- /dev/null +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java @@ -0,0 +1,293 @@ +package cn.iocoder.yudao.module.ai.service.knowledge.splitter; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.transformer.splitter.TextSplitter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +/** + * 语义化文本切片器 + * + *

功能特点: + *

    + *
  • 优先在段落边界(双换行)处切分
  • + *
  • 其次在句子边界(句号、问号、感叹号)处切分
  • + *
  • 避免在句子中间截断,保持语义完整性
  • + *
  • 支持中英文标点符号识别
  • + *
+ * + * @author runzhen + */ +@Slf4j +public class SemanticTextSplitter extends TextSplitter { + + /** + * 分段的最大 Token 数 + */ + private final int chunkSize; + + /** + * 段落重叠大小(用于保持上下文连贯性) + */ + private final int chunkOverlap; + + /** + * 段落分隔符(按优先级排序) + */ + private static final List PARAGRAPH_SEPARATORS = Arrays.asList( + "\n\n\n", // 三个换行 + "\n\n", // 双换行 + "\n" // 单换行 + ); + + /** + * 句子结束标记(中英文标点) + */ + private static final Pattern SENTENCE_END_PATTERN = Pattern.compile( + "[。!?.!?]+[\\s\"'))】\\]]*" + ); + + /** + * Token 估算器 + */ + private final MarkdownQaSplitter.TokenEstimator tokenEstimator; + + public SemanticTextSplitter(int chunkSize, int chunkOverlap) { + this.chunkSize = chunkSize; + this.chunkOverlap = Math.min(chunkOverlap, chunkSize / 2); // 重叠不超过一半 + this.tokenEstimator = new SimpleTokenEstimator(); + } + + public SemanticTextSplitter(int chunkSize) { + this(chunkSize, 50); // 默认重叠 50 个 Token + } + + @Override + protected List splitText(String text) { + if (StrUtil.isEmpty(text)) { + return Collections.emptyList(); + } + + return splitTextRecursive(text); + } + + /** + * 切分文本(递归策略) + */ + private List splitTextRecursive(String text) { + List chunks = new ArrayList<>(); + + // 如果文本不超过限制,直接返回 + int textTokens = tokenEstimator.estimate(text); + if (textTokens <= chunkSize) { + chunks.add(text.trim()); + return chunks; + } + + // 尝试按不同分隔符切分 + List splits = null; + String usedSeparator = null; + + for (String separator : PARAGRAPH_SEPARATORS) { + if (text.contains(separator)) { + splits = Arrays.asList(text.split(Pattern.quote(separator))); + usedSeparator = separator; + break; + } + } + + // 如果没有找到段落分隔符,按句子切分 + if (splits == null || splits.size() == 1) { + splits = splitBySentences(text); + usedSeparator = ""; // 句子切分不需要分隔符 + } + + // 合并小片段 + chunks = mergeSplits(splits, usedSeparator); + + return chunks; + } + + /** + * 按句子切分 + */ + private List splitBySentences(String text) { + List sentences = new ArrayList<>(); + int lastEnd = 0; + + java.util.regex.Matcher matcher = SENTENCE_END_PATTERN.matcher(text); + while (matcher.find()) { + String sentence = text.substring(lastEnd, matcher.end()).trim(); + if (StrUtil.isNotEmpty(sentence)) { + sentences.add(sentence); + } + lastEnd = matcher.end(); + } + + // 添加剩余部分 + if (lastEnd < text.length()) { + String remaining = text.substring(lastEnd).trim(); + if (StrUtil.isNotEmpty(remaining)) { + sentences.add(remaining); + } + } + + return sentences.isEmpty() ? Collections.singletonList(text) : sentences; + } + + /** + * 合并切分后的小片段 + */ + private List mergeSplits(List splits, String separator) { + List chunks = new ArrayList<>(); + List currentChunks = new ArrayList<>(); + int currentLength = 0; + + for (String split : splits) { + if (StrUtil.isEmpty(split)) { + continue; + } + + int splitTokens = tokenEstimator.estimate(split); + + // 如果单个片段就超过限制,进一步递归切分 + if (splitTokens > chunkSize) { + // 先保存当前累积的块 + if (!currentChunks.isEmpty()) { + String chunkText = String.join(separator, currentChunks); + chunks.add(chunkText.trim()); + currentChunks.clear(); + currentLength = 0; + } + + // 递归切分大片段 + if (!separator.isEmpty()) { + // 如果是段落分隔符,尝试按句子切分 + chunks.addAll(splitTextRecursive(split)); + } else { + // 如果已经是句子级别,强制按字符切分 + chunks.addAll(forceSplitLongText(split)); + } + continue; + } + + // 计算加上分隔符的 Token 数 + int separatorTokens = StrUtil.isEmpty(separator) ? 0 : tokenEstimator.estimate(separator); + + // 如果加上这个片段会超过限制 + if (!currentChunks.isEmpty() && currentLength + splitTokens + separatorTokens > chunkSize) { + // 保存当前块 + String chunkText = String.join(separator, currentChunks); + chunks.add(chunkText.trim()); + + // 处理重叠:保留最后几个片段 + currentChunks = getOverlappingChunks(currentChunks, separator); + currentLength = estimateTokens(currentChunks, separator); + } + + currentChunks.add(split); + currentLength += splitTokens + separatorTokens; + } + + // 添加最后一块 + if (!currentChunks.isEmpty()) { + String chunkText = String.join(separator, currentChunks); + chunks.add(chunkText.trim()); + } + + return chunks; + } + + /** + * 获取重叠的片段(用于保持上下文) + */ + private List getOverlappingChunks(List chunks, String separator) { + if (chunkOverlap == 0 || chunks.isEmpty()) { + return new ArrayList<>(); + } + + List overlapping = new ArrayList<>(); + int tokens = 0; + + // 从后往前取片段,直到达到重叠大小 + for (int i = chunks.size() - 1; i >= 0; i--) { + String chunk = chunks.get(i); + int chunkTokens = tokenEstimator.estimate(chunk); + + if (tokens + chunkTokens > chunkOverlap) { + break; + } + + overlapping.add(0, chunk); + tokens += chunkTokens + (StrUtil.isEmpty(separator) ? 0 : tokenEstimator.estimate(separator)); + } + + return overlapping; + } + + /** + * 估算片段列表的总 Token 数 + */ + private int estimateTokens(List chunks, String separator) { + int total = 0; + for (int i = 0; i < chunks.size(); i++) { + total += tokenEstimator.estimate(chunks.get(i)); + if (i < chunks.size() - 1 && StrUtil.isNotEmpty(separator)) { + total += tokenEstimator.estimate(separator); + } + } + return total; + } + + /** + * 强制切分长文本(当语义切分失败时) + */ + private List forceSplitLongText(String text) { + List chunks = new ArrayList<>(); + int charsPerChunk = (int) (chunkSize * 0.8); // 保守估计 + + for (int i = 0; i < text.length(); i += charsPerChunk) { + int end = Math.min(i + charsPerChunk, text.length()); + String chunk = text.substring(i, end); + chunks.add(chunk.trim()); + } + + log.warn("文本过长,已强制按字符切分,可能影响语义完整性"); + return chunks; + } + + /** + * 简单的 Token 估算器实现 + */ + private static class SimpleTokenEstimator implements MarkdownQaSplitter.TokenEstimator { + @Override + public int estimate(String text) { + if (StrUtil.isEmpty(text)) { + return 0; + } + + int chineseChars = 0; + int englishWords = 0; + + for (char c : text.toCharArray()) { + if (c >= 0x4E00 && c <= 0x9FA5) { + chineseChars++; + } + } + + String[] words = text.split("\\s+"); + for (String word : words) { + if (word.matches(".*[a-zA-Z].*")) { + englishWords++; + } + } + + return chineseChars + (int) (englishWords * 1.3); + } + } +} From 8aaead39bca6759dea3911a7abc83701cd12e906 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Tue, 2 Dec 2025 17:42:28 +0800 Subject: [PATCH 16/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90infra=E3=80=91s3=20?= =?UTF-8?q?=E7=94=9F=E6=88=90=20presignGetUrl=20=E6=97=B6=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E5=AF=B9=20path=20=E8=BF=9B=E8=A1=8C=E8=A7=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=8C=E8=A7=A3=E5=86=B3=E6=96=87=E4=BB=B6=E5=90=8D?= =?UTF-8?q?=E6=98=AF=E4=B8=AD=E6=96=87=E6=97=B6=E8=AE=BF=E9=97=AE=E4=B8=8D?= =?UTF-8?q?=E5=88=B0=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/common/util/http/HttpUtils.java | 11 +++++++++++ .../framework/file/core/client/s3/S3FileClient.java | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java index 85a644f1f1..10744d76bc 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java @@ -13,6 +13,7 @@ import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; +import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -35,6 +36,16 @@ public class HttpUtils { return URLEncoder.encode(value, StandardCharsets.UTF_8); } + /** + * 解码 URL 参数 + * + * @param value 参数 + * @return 解码后的参数 + */ + public static String decodeUtf8(String value) { + return URLDecoder.decode(value, StandardCharsets.UTF_8); + } + @SuppressWarnings("unchecked") public static String replaceUrlQuery(String url, String key, String value) { UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset()); diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index d2213f5328..74a9361f99 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -116,7 +116,7 @@ public class S3FileClient extends AbstractFileClient { public String presignGetUrl(String url, Integer expirationSeconds) { // 1. 将 url 转换为 path String path = StrUtil.removePrefix(url, config.getDomain() + "/"); - path = HttpUtils.removeUrlQuery(path); + path = HttpUtils.decodeUtf8(HttpUtils.removeUrlQuery(path)); // 2.1 情况一:公开访问:无需签名 // 考虑到老版本的兼容,所以必须是 config.getEnablePublicAccess() 为 false 时,才进行签名 From 0df951079be8e3dcf1d7186f41a7a95a1c33ab4a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 6 Dec 2025 09:28:00 +0800 Subject: [PATCH 17/88] =?UTF-8?q?fix=EF=BC=9A=E3=80=90=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E3=80=91TimestampLocalDateTimeSerializer=20=E7=9A=84=20fieldNa?= =?UTF-8?q?me=20=E4=B8=BA=E7=A9=BA=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=20https://github.com/YunaiV/ruoyi-vue-pro/is?= =?UTF-8?q?sues/1032?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimestampLocalDateTimeSerializer.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java index bed47e93bb..baefa50015 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java @@ -23,16 +23,18 @@ public class TimestampLocalDateTimeSerializer extends JsonSerializer clazz = gen.getOutputContext().getCurrentValue().getClass(); - Field field = ReflectUtil.getField(clazz, fieldName); // 情况一:有 JsonFormat 自定义注解,则使用它。https://github.com/YunaiV/ruoyi-vue-pro/pull/1019 - JsonFormat[] jsonFormats = field.getAnnotationsByType(JsonFormat.class); - if (jsonFormats.length > 0) { - String pattern = jsonFormats[0].pattern(); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); - gen.writeString(formatter.format(value)); - return; + String fieldName = gen.getOutputContext().getCurrentName(); + if (fieldName != null) { + Class clazz = gen.getOutputContext().getCurrentValue().getClass(); + Field field = ReflectUtil.getField(clazz, fieldName); + JsonFormat[] jsonFormats = field.getAnnotationsByType(JsonFormat.class); + if (jsonFormats.length > 0) { + String pattern = jsonFormats[0].pattern(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + gen.writeString(formatter.format(value)); + return; + } } // 情况二:默认将 LocalDateTime 对象,转换为 Long 时间戳 From d12abb4e5a9ed55cca9164ac7bb8dc80d633d6ac Mon Sep 17 00:00:00 2001 From: Leslie Date: Sat, 6 Dec 2025 22:56:19 +0800 Subject: [PATCH 18/88] =?UTF-8?q?fixed:=20=E5=BC=BA=E5=88=B6=E6=8C=87?= =?UTF-8?q?=E5=AE=9Aquartz=E7=89=88=E6=9C=AC=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E4=BD=BF=E7=94=A8Postgres=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E4=B8=8Equartz2.5.2=E7=89=88=E6=9C=AC=E4=BA=A7?= =?UTF-8?q?=E7=94=9F=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 1de1b27e92..e00876b545 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,13 @@ pom import + + + + org.quartz-scheduler + quartz + 2.5.0 + From 08aba06eff1505e09253fe586e3d998240ce8080 Mon Sep 17 00:00:00 2001 From: Leslie Date: Sat, 6 Dec 2025 23:00:11 +0800 Subject: [PATCH 19/88] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/web/config/YudaoWebAutoConfiguration.java | 1 - 1 file changed, 1 deletion(-) diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java index 38748930cc..c0d1344392 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -103,7 +103,6 @@ public class YudaoWebAutoConfiguration { /** * 创建 CorsFilter Bean,解决跨域问题 */ - @Order(value = WebFilterOrderEnum.CORS_FILTER) @Bean @Order(value = WebFilterOrderEnum.CORS_FILTER) // 特殊:修复因执行顺序影响到跨域配置不生效问题 public FilterRegistrationBean corsFilterBean() { From ea283f117fad68bb5e76a4624c79dea9a5781a12 Mon Sep 17 00:00:00 2001 From: Leslie Date: Sat, 6 Dec 2025 23:00:38 +0800 Subject: [PATCH 20/88] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E4=B8=8D=E5=BF=85?= =?UTF-8?q?=E8=A6=81=E7=9A=84=E4=BB=A3=E7=A0=81=E7=89=87=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pay/core/client/impl/weixin/AbstractWxPayClient.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java index 71ffa320ca..3b54862a7d 100644 --- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -72,11 +72,6 @@ public abstract class AbstractWxPayClient extends AbstractPayClient Date: Sat, 6 Dec 2025 23:08:17 +0800 Subject: [PATCH 21/88] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0quartz=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E8=87=B32.5.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e00876b545..52bf76cc72 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ org.quartz-scheduler quartz - 2.5.0 + 2.5.2 From 0531651efcbf14824cedb360dd6b23a7822198d4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Dec 2025 10:21:00 +0800 Subject: [PATCH 22/88] =?UTF-8?q?fix=EF=BC=9A=E6=9C=80=E5=A4=A7=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E4=BB=8E=20100->=20200=EF=BC=8C=E6=9B=B4=E5=A5=BD?= =?UTF-8?q?=E7=9A=84=E9=80=82=E5=BA=94=20vben=EF=BC=8C=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=20issue=EF=BC=9Ahttps://github.com/yudaocode/yudao-ui-admin-vb?= =?UTF-8?q?en/issues/176?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/iocoder/yudao/framework/common/pojo/PageParam.java | 2 +- .../controller/admin/kefu/vo/message/KeFuMessageListReqVO.java | 2 +- .../controller/app/kefu/vo/message/AppKeFuMessagePageReqVO.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java index 268d117f95..65356e31d7 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java @@ -30,7 +30,7 @@ public class PageParam implements Serializable { @Schema(description = "每页条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @NotNull(message = "每页条数不能为空") @Min(value = 1, message = "每页条数最小值为 1") - @Max(value = 100, message = "每页条数最大值为 100") + @Max(value = 200, message = "每页条数最大值为 200") private Integer pageSize = PAGE_SIZE; } diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/kefu/vo/message/KeFuMessageListReqVO.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/kefu/vo/message/KeFuMessageListReqVO.java index 25b8f499ce..a7d76f8542 100644 --- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/kefu/vo/message/KeFuMessageListReqVO.java +++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/kefu/vo/message/KeFuMessageListReqVO.java @@ -28,7 +28,7 @@ public class KeFuMessageListReqVO { @Schema(description = "每次查询条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @NotNull(message = "每次查询条数不能为空") @Min(value = 1, message = "每次查询条数最小值为 1") - @Max(value = 100, message = "每次查询最大值为 100") + @Max(value = 200, message = "每次查询最大值为 200") private Integer limit = LIMIT; } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/kefu/vo/message/AppKeFuMessagePageReqVO.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/kefu/vo/message/AppKeFuMessagePageReqVO.java index 78b105aeac..6eae3f9738 100644 --- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/kefu/vo/message/AppKeFuMessagePageReqVO.java +++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/kefu/vo/message/AppKeFuMessagePageReqVO.java @@ -27,7 +27,7 @@ public class AppKeFuMessagePageReqVO { @Schema(description = "每次查询条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @NotNull(message = "每次查询条数不能为空") @Min(value = 1, message = "每次查询条数最小值为 1") - @Max(value = 100, message = "每次查询最大值为 100") + @Max(value = 200, message = "每次查询最大值为 200") private Integer limit = LIMIT; } \ No newline at end of file From ff129c2ed26e73495bcd3cd55dcd289455104565 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Dec 2025 10:38:20 +0800 Subject: [PATCH 23/88] =?UTF-8?q?fix=EF=BC=9Aquartz=20=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=A4=B1=E6=95=88=E9=97=AE=E9=A2=98=EF=BC=88?= =?UTF-8?q?=E4=BB=85=20postgresql=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 52bf76cc72..5f859b0fd1 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,7 @@ + org.quartz-scheduler quartz From 289d847effb27677effa4c8ea57921fcca0c2ce1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Dec 2025 10:40:21 +0800 Subject: [PATCH 24/88] =?UTF-8?q?=E3=80=90=E5=90=8C=E6=AD=A5=E3=80=91jdk21?= =?UTF-8?q?=20=E5=92=8C=20jdk8=20=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 -------- .../yudao/framework/common/util/http/HttpUtils.java | 3 ++- .../framework/quartz/core/handler/JobHandlerInvoker.java | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index c373c41c1c..6995c0fc2c 100644 --- a/pom.xml +++ b/pom.xml @@ -57,14 +57,6 @@ pom import - - - - - org.quartz-scheduler - quartz - 2.5.2 - diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java index 47fa2b7242..c7a7bb32f8 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java @@ -44,8 +44,9 @@ public class HttpUtils { * @param value 参数 * @return 解码后的参数 */ + @SneakyThrows public static String decodeUtf8(String value) { - return URLDecoder.decode(value, StandardCharsets.UTF_8); + return URLDecoder.decode(value, StandardCharsets.UTF_8.name()); } @SuppressWarnings("unchecked") diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java index 736126fec6..f518170fda 100644 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java @@ -15,7 +15,6 @@ import org.springframework.scheduling.quartz.QuartzJobBean; import javax.annotation.Resource; import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; From 32304b74df073666e566b4bbe5adbba279f91462 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Dec 2025 18:13:55 +0800 Subject: [PATCH 25/88] =?UTF-8?q?fix=EF=BC=9A=E6=9C=80=E5=A4=A7=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E4=BB=8E=20100->=20200=EF=BC=8C=E6=9B=B4=E5=A5=BD?= =?UTF-8?q?=E7=9A=84=E9=80=82=E5=BA=94=20vben=EF=BC=8C=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=20issue=EF=BC=9Ahttps://github.com/yudaocode/yudao-ui-admin-vb?= =?UTF-8?q?en/issues/176?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/iocoder/yudao/framework/common/pojo/PageParam.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java index 65356e31d7..114f15e770 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java @@ -27,7 +27,7 @@ public class PageParam implements Serializable { @Min(value = 1, message = "页码最小值为 1") private Integer pageNo = PAGE_NO; - @Schema(description = "每页条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @Schema(description = "每页条数,最大值为 200", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @NotNull(message = "每页条数不能为空") @Min(value = 1, message = "每页条数最小值为 1") @Max(value = 200, message = "每页条数最大值为 200") From e45e2ae29f9f9df55281c1fd541d7f54a670e0a8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Dec 2025 18:19:33 +0800 Subject: [PATCH 26/88] =?UTF-8?q?fix=EF=BC=9A=E3=80=90system=E3=80=91"syst?= =?UTF-8?q?em=5Fsocial=5Fclient"=20=E7=9A=84=E5=8D=95=E6=B5=8B=E7=BC=BA?= =?UTF-8?q?=E5=B0=91=20public=5Fkey=20=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-system/src/test/resources/sql/create_tables.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/yudao-module-system/src/test/resources/sql/create_tables.sql b/yudao-module-system/src/test/resources/sql/create_tables.sql index 124b307612..9970065ae0 100644 --- a/yudao-module-system/src/test/resources/sql/create_tables.sql +++ b/yudao-module-system/src/test/resources/sql/create_tables.sql @@ -339,6 +339,7 @@ CREATE TABLE IF NOT EXISTS "system_social_client" ( "user_type" int NOT NULL, "client_id" varchar(255) NOT NULL, "client_secret" varchar(255) NOT NULL, + "public_key" varchar(2048) NOT NULL, "agent_id" varchar(255) NOT NULL, "status" int NOT NULL, "creator" varchar(64) DEFAULT '', From 8b616c315367b01cd4410012cb4dd73a7e9bfd7e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Dec 2025 18:39:05 +0800 Subject: [PATCH 27/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90system/infra?= =?UTF-8?q?=E3=80=91=E8=AE=BF=E9=97=AE=E6=97=A5=E5=BF=97=E3=80=81=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=97=A5=E5=BF=97=E3=80=81=E9=94=99=E8=AF=AF=E6=97=A5?= =?UTF-8?q?=E5=BF=97=EF=BC=8C=E5=A2=9E=E5=8A=A0=20get=20=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E6=BB=A1=E8=B6=B3=20admin=20uniapp=20=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E8=AF=89=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/logger/ApiAccessLogController.java | 11 +++++++++++ .../admin/logger/ApiErrorLogController.java | 9 +++++++++ .../infra/service/logger/ApiAccessLogService.java | 8 ++++++++ .../infra/service/logger/ApiAccessLogServiceImpl.java | 5 +++++ .../infra/service/logger/ApiErrorLogService.java | 8 ++++++++ .../infra/service/logger/ApiErrorLogServiceImpl.java | 5 +++++ .../controller/admin/logger/OperateLogController.java | 11 +++++++++++ .../system/service/logger/OperateLogService.java | 8 ++++++++ .../system/service/logger/OperateLogServiceImpl.java | 5 +++++ 9 files changed, 70 insertions(+) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java index 513b3ef21b..bbbf1d4e55 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.Api import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO; import cn.iocoder.yudao.module.infra.service.logger.ApiAccessLogService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; @@ -19,6 +20,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; @@ -36,6 +38,15 @@ public class ApiAccessLogController { @Resource private ApiAccessLogService apiAccessLogService; + @GetMapping("/get") + @Operation(summary = "获得 API 访问日志") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:api-access-log:query')") + public CommonResult getApiAccessLog(@RequestParam("id") Long id) { + ApiAccessLogDO apiAccessLog = apiAccessLogService.getApiAccessLog(id); + return success(BeanUtils.toBean(apiAccessLog, ApiAccessLogRespVO.class)); + } + @GetMapping("/page") @Operation(summary = "获得API 访问日志分页") @PreAuthorize("@ss.hasPermission('infra:api-access-log:query')") diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java index 525bb9eda8..154984d05d 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java @@ -50,6 +50,15 @@ public class ApiErrorLogController { return success(true); } + @GetMapping("/get") + @Operation(summary = "获得 API 错误日志") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('infra:api-error-log:query')") + public CommonResult getApiErrorLog(@RequestParam("id") Long id) { + ApiErrorLogDO apiErrorLog = apiErrorLogService.getApiErrorLog(id); + return success(BeanUtils.toBean(apiErrorLog, ApiErrorLogRespVO.class)); + } + @GetMapping("/page") @Operation(summary = "获得 API 错误日志分页") @PreAuthorize("@ss.hasPermission('infra:api-error-log:query')") diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogService.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogService.java index 65faa3f333..cc4cda5c52 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogService.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogService.java @@ -19,6 +19,14 @@ public interface ApiAccessLogService { */ void createApiAccessLog(ApiAccessLogCreateReqDTO createReqDTO); + /** + * 获得 API 访问日志 + * + * @param id 编号 + * @return API 访问日志 + */ + ApiAccessLogDO getApiAccessLog(Long id); + /** * 获得 API 访问日志分页 * diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java index d47f192126..89746d5f8f 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java @@ -45,6 +45,11 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService { } } + @Override + public ApiAccessLogDO getApiAccessLog(Long id) { + return apiAccessLogMapper.selectById(id); + } + @Override public PageResult getApiAccessLogPage(ApiAccessLogPageReqVO pageReqVO) { return apiAccessLogMapper.selectPage(pageReqVO); diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogService.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogService.java index b05ccf3d89..5c45797e35 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogService.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogService.java @@ -19,6 +19,14 @@ public interface ApiErrorLogService { */ void createApiErrorLog(ApiErrorLogCreateReqDTO createReqDTO); + /** + * 获得 API 错误日志 + * + * @param id 编号 + * @return API 错误日志 + */ + ApiErrorLogDO getApiErrorLog(Long id); + /** * 获得 API 错误日志分页 * diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java index 536b265f93..7392c67ffc 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java @@ -58,6 +58,11 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService { return apiErrorLogMapper.selectPage(pageReqVO); } + @Override + public ApiErrorLogDO getApiErrorLog(Long id) { + return apiErrorLogMapper.selectById(id); + } + @Override public void updateApiErrorLogProcess(Long id, Integer processStatus, Long processUserId) { ApiErrorLogDO errorLog = apiErrorLogMapper.selectById(id); diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java index 257477071a..be9dedc68c 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; import cn.iocoder.yudao.module.system.service.logger.OperateLogService; import com.fhs.core.trans.anno.TransMethodResult; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; @@ -21,6 +22,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; @@ -38,6 +40,15 @@ public class OperateLogController { @Resource private OperateLogService operateLogService; + @GetMapping("/get") + @Operation(summary = "查看操作日志") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:operate-log:query')") + public CommonResult getOperateLog(@RequestParam("id") Long id) { + OperateLogDO operateLog = operateLogService.getOperateLog(id); + return success(BeanUtils.toBean(operateLog, OperateLogRespVO.class)); + } + @GetMapping("/page") @Operation(summary = "查看操作日志分页列表") @PreAuthorize("@ss.hasPermission('system:operate-log:query')") diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java index c647e822d8..bc99a4d3cb 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java @@ -20,6 +20,14 @@ public interface OperateLogService { */ void createOperateLog(OperateLogCreateReqDTO createReqDTO); + /** + * 获得操作日志 + * + * @param id 编号 + * @return 操作日志 + */ + OperateLogDO getOperateLog(Long id); + /** * 获得操作日志分页列表 * diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java index 167be55ae6..45d69552a8 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java @@ -31,6 +31,11 @@ public class OperateLogServiceImpl implements OperateLogService { operateLogMapper.insert(log); } + @Override + public OperateLogDO getOperateLog(Long id) { + return operateLogMapper.selectById(id); + } + @Override public PageResult getOperateLogPage(OperateLogPageReqVO pageReqVO) { return operateLogMapper.selectPage(pageReqVO); From 91f37e756aabd52ae24fb7b2cadf425045748774 Mon Sep 17 00:00:00 2001 From: dafang <1073816412@qq.com> Date: Mon, 8 Dec 2025 15:58:29 +0800 Subject: [PATCH 28/88] =?UTF-8?q?fix(product):=20=E4=BF=AE=E5=A4=8D@Select?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2JSON=E5=AD=97=E6=AE=B5=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @Select注解不会应用autoResultMap,需手动指定@Results和typeHandler: - ProductSpuMapper: sliderPicUrls字段添加JacksonTypeHandler - ProductSkuMapper: properties字段添加JacksonTypeHandler --- .../product/dal/mysql/sku/ProductSkuMapper.java | 12 +++++++++--- .../product/dal/mysql/spu/ProductSpuMapper.java | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java index da920a5b82..21f58f75e4 100755 --- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java +++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java @@ -5,9 +5,8 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import org.apache.ibatis.annotations.*; import java.util.Collection; import java.util.List; @@ -15,7 +14,14 @@ import java.util.List; @Mapper public interface ProductSkuMapper extends BaseMapperX { + /** + * 查询商品 SKU(包含已删除) + * 注意:使用 @Results 手动指定 typeHandler,否则 @Select 不会应用 autoResultMap,properties 字段无法解析 JSON + */ @Select("SELECT * FROM product_sku WHERE id = #{id}") + @Results({ + @Result(column = "properties", property = "properties", typeHandler = JacksonTypeHandler.class), + }) ProductSkuDO selectByIdIncludeDeleted(@Param("id") Long id); default List selectListBySpuId(Long spuId) { diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java index fc00ae78d4..ee9d3339bf 100755 --- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java +++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java @@ -10,9 +10,8 @@ import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.enums.ProductConstants; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import org.apache.ibatis.annotations.*; import java.util.Objects; import java.util.Set; @@ -20,7 +19,14 @@ import java.util.Set; @Mapper public interface ProductSpuMapper extends BaseMapperX { + /** + * 查询商品 SPU(包含已删除) + * 注意:使用 @Results 手动指定 typeHandler,否则 @Select 不会应用 autoResultMap,sliderPicUrls 字段无法解析 JSON + */ @Select("SELECT * FROM product_spu WHERE id = #{id}") + @Results({ + @Result(column = "slider_pic_urls", property = "sliderPicUrls", typeHandler = JacksonTypeHandler.class), + }) ProductSpuDO selectByIdIncludeDeleted(@Param("id") Long id); /** From 0a7fa72b3a202f61989450a05968735deb190b68 Mon Sep 17 00:00:00 2001 From: dafang <1073816412@qq.com> Date: Mon, 8 Dec 2025 16:04:43 +0800 Subject: [PATCH 29/88] =?UTF-8?q?fix(product):=20=E4=BF=AE=E5=A4=8D@Select?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2JSON=E5=AD=97=E6=AE=B5=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/product/dal/mysql/spu/ProductSpuMapper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java index ee9d3339bf..24ebd6864e 100755 --- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java +++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java @@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; @@ -21,11 +22,12 @@ public interface ProductSpuMapper extends BaseMapperX { /** * 查询商品 SPU(包含已删除) - * 注意:使用 @Results 手动指定 typeHandler,否则 @Select 不会应用 autoResultMap,sliderPicUrls 字段无法解析 JSON + * 注意:使用 @Results 手动指定 typeHandler,否则 @Select 不会应用 autoResultMap,sliderPicUrls,deliveryTypes 字段无法解析 JSON */ @Select("SELECT * FROM product_spu WHERE id = #{id}") @Results({ @Result(column = "slider_pic_urls", property = "sliderPicUrls", typeHandler = JacksonTypeHandler.class), + @Result(column = "delivery_types", property = "deliveryTypes", typeHandler = IntegerListTypeHandler.class), }) ProductSpuDO selectByIdIncludeDeleted(@Param("id") Long id); From 07c9202c6116e6df874c6f9f01562c4b55d4dbdf Mon Sep 17 00:00:00 2001 From: fuwenjun <3806569631@qq.com> Date: Tue, 9 Dec 2025 17:10:06 +0800 Subject: [PATCH 30/88] =?UTF-8?q?fix:=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E8=BF=87=E6=9C=9F=E6=97=B6=E9=97=B4=E7=9A=84=E7=BC=93?= =?UTF-8?q?=E5=AD=98key=EF=BC=8C=E4=B8=8D=E8=83=BD=E5=BF=BD=E7=95=A5?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenant/core/redis/TenantRedisCacheManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java index aeea4b589c..fd033e6de2 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.framework.tenant.core.redis; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import lombok.extern.slf4j.Slf4j; @@ -21,6 +22,8 @@ import java.util.Set; @Slf4j public class TenantRedisCacheManager extends TimeoutRedisCacheManager { + private static final String SPLIT = "#"; + private final Set ignoreCaches; public TenantRedisCacheManager(RedisCacheWriter cacheWriter, @@ -32,10 +35,11 @@ public class TenantRedisCacheManager extends TimeoutRedisCacheManager { @Override public Cache getCache(String name) { + String[] names = StrUtil.splitToArray(name, SPLIT); // 如果开启多租户,则 name 拼接租户后缀 if (!TenantContextHolder.isIgnore() - && TenantContextHolder.getTenantId() != null - && !CollUtil.contains(ignoreCaches, name)) { + && TenantContextHolder.getTenantId() != null + && !CollUtil.contains(ignoreCaches, names[0])) { name = name + ":" + TenantContextHolder.getTenantId(); } From 8b10df084122006266f4dc884dc515031aa19905 Mon Sep 17 00:00:00 2001 From: CaiHao Date: Fri, 12 Dec 2025 13:36:03 +0800 Subject: [PATCH 31/88] =?UTF-8?q?fix(infra):=20=E4=BF=AE=E6=AD=A3=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=97=A5=E5=BF=97=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=AD=97=E5=85=B8=E6=A0=BC=E5=BC=8F=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将定时任务日志状态字段的字典格式引用从 JOB_STATUS 更改为 JOB_LOG_STATUS - 确保定时任务日志状态导出excel时映射到正确的名称 --- .../module/infra/controller/admin/job/vo/log/JobLogRespVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java index 3574e98d59..1d33cdf278 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java @@ -49,7 +49,7 @@ public class JobLogRespVO { @Schema(description = "任务状态,参见 JobLogStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty(value = "任务状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.JOB_STATUS) + @DictFormat(DictTypeConstants.JOB_LOG_STATUS) private Integer status; @Schema(description = "结果数据", example = "执行成功") From 04e59b0561ece910bffb905c02d030091b2af506 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 09:30:58 +0800 Subject: [PATCH 32/88] =?UTF-8?q?fix(infra):=20=E4=BF=AE=E6=AD=A3=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=97=A5=E5=BF=97=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=AD=97=E5=85=B8=E6=A0=BC=E5=BC=8F=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/infra/controller/admin/job/vo/log/JobLogRespVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java index 3574e98d59..1d33cdf278 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogRespVO.java @@ -49,7 +49,7 @@ public class JobLogRespVO { @Schema(description = "任务状态,参见 JobLogStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty(value = "任务状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.JOB_STATUS) + @DictFormat(DictTypeConstants.JOB_LOG_STATUS) private Integer status; @Schema(description = "结果数据", example = "执行成功") From be27ba3aa638f7d0cacf8466eba86f93a33244dc Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 09:39:30 +0800 Subject: [PATCH 33/88] =?UTF-8?q?fix(infra):=20=E6=96=87=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=97=B6=EF=BC=8C=E6=94=BE=E5=AE=BD=20directory=20?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=EF=BC=8C=E5=8F=AF=E6=94=AF=E6=8C=81=E7=B1=BB?= =?UTF-8?q?=E4=BC=BC=20XXX/YYY=20=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/file/vo/file/FileUploadReqVO.java | 9 ++++++++- .../infra/controller/app/file/vo/AppFileUploadReqVO.java | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java index 44e8b65d76..06dff7c087 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java @@ -22,7 +22,14 @@ public class FileUploadReqVO { @AssertTrue(message = "文件目录不正确") @JsonIgnore public boolean isDirectoryValid() { - return !StrUtil.containsAny(directory, "..", "/", "\\"); + return isDirectoryValid(directory); + } + + public static boolean isDirectoryValid(String directory) { + // 1. 不能包含 .. 防止目录穿越 + // 2. 不能以 / 或 \ 开头,防止上传到根目录 + return !StrUtil.contains(directory, "..") + && !StrUtil.startWithAny(directory, "/", "\\"); } } diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java index d10a21cc49..9423906ba6 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.app.file.vo; -import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileUploadReqVO; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.AssertTrue; @@ -22,7 +22,7 @@ public class AppFileUploadReqVO { @AssertTrue(message = "文件目录不正确") @JsonIgnore public boolean isDirectoryValid() { - return !StrUtil.containsAny(directory, "..", "/", "\\"); + return FileUploadReqVO.isDirectoryValid(directory); } } From e1f64eaad2415a54a9c008838b8b6cdca936880f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 09:43:48 +0800 Subject: [PATCH 34/88] =?UTF-8?q?fix:=E3=80=90=E6=A1=86=E6=9E=B6=E3=80=91?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E8=BF=87=E6=9C=9F?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=9A=84=E7=BC=93=E5=AD=98=20key=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E8=83=BD=E5=BF=BD=E7=95=A5=E7=A7=9F=E6=88=B7=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=8C=E5=AF=B9=E5=BA=94=20https://gitee.com/zhijia?= =?UTF-8?q?ntianya/ruoyi-vue-pro/pulls/1474?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenant/core/redis/TenantRedisCacheManager.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java index aeea4b589c..86577388b5 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisCacheManager.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.framework.tenant.core.redis; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import lombok.extern.slf4j.Slf4j; @@ -21,6 +22,8 @@ import java.util.Set; @Slf4j public class TenantRedisCacheManager extends TimeoutRedisCacheManager { + private static final String SPLIT = "#"; + private final Set ignoreCaches; public TenantRedisCacheManager(RedisCacheWriter cacheWriter, @@ -32,10 +35,11 @@ public class TenantRedisCacheManager extends TimeoutRedisCacheManager { @Override public Cache getCache(String name) { + String[] names = StrUtil.splitToArray(name, SPLIT); // 如果开启多租户,则 name 拼接租户后缀 if (!TenantContextHolder.isIgnore() - && TenantContextHolder.getTenantId() != null - && !CollUtil.contains(ignoreCaches, name)) { + && TenantContextHolder.getTenantId() != null + && !CollUtil.contains(ignoreCaches, names[0])) { name = name + ":" + TenantContextHolder.getTenantId(); } @@ -43,4 +47,4 @@ public class TenantRedisCacheManager extends TimeoutRedisCacheManager { return super.getCache(name); } -} +} \ No newline at end of file From 4576801e7543fcb86ab50fc260dd1488e067f173 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 09:48:09 +0800 Subject: [PATCH 35/88] =?UTF-8?q?1476=20fix:=20=E4=BF=AE=E5=A4=8Dsystem?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=B2=97=E4=BD=8D=E6=89=B9=E9=87=8F=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/controller/admin/dept/PostController.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java index 0f1b957f18..b8d24721bb 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java @@ -64,6 +64,14 @@ public class PostController { return success(true); } + @DeleteMapping("delete-list") + @Operation(summary = "批量删除岗位") + @PreAuthorize("@ss.hasPermission('system:post:delete')") + public CommonResult deletePostList(@RequestParam("ids") List ids) { + postService.deletePostList(ids); + return success(true); + } + @GetMapping(value = "/get") @Operation(summary = "获得岗位信息") @Parameter(name = "id", description = "岗位编号", required = true, example = "1024") From ed136ff02224f9763c373d7c62b12e7a9cdeef98 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 10:08:32 +0800 Subject: [PATCH 36/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ai=E3=80=91?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=99=BA=E8=83=BD=E6=96=87=E6=A1=A3=E5=88=87?= =?UTF-8?q?=E7=89=87=E7=AD=96=E7=95=A5=EF=BC=8C=E6=94=AF=E6=8C=81=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=AF=86=E5=88=AB=20Markdown=20QA=20=E5=92=8C?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E5=8C=96=E5=88=87=E5=88=86=E3=80=8C=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BC=98=E5=8C=96=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../ai/enums/AiDocumentSplitStrategyEnum.java | 12 - .../AiKnowledgeSegmentServiceImpl.java | 30 +-- .../splitter/MarkdownQaSplitter.java | 235 +++++++++--------- .../splitter/SemanticTextSplitter.java | 54 ++-- 5 files changed, 157 insertions(+), 176 deletions(-) diff --git a/pom.xml b/pom.xml index ba6add4137..5f859b0fd1 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ - yudao-module-ai + diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java index 2c9f657579..f0a9cd21d6 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/AiDocumentSplitStrategyEnum.java @@ -50,16 +50,4 @@ public enum AiDocumentSplitStrategyEnum { */ private final String name; - /** - * 根据代码获取枚举 - */ - public static AiDocumentSplitStrategyEnum fromCode(String code) { - for (AiDocumentSplitStrategyEnum strategy : values()) { - if (strategy.getCode().equals(code)) { - return strategy; - } - } - return AUTO; // 默认返回自动识别 - } - } diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java index 51a1ce94d5..9d64fcce9f 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java @@ -107,11 +107,8 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService if (StrUtil.isEmpty(segment.getText())) { return null; } - return new AiKnowledgeSegmentDO() - .setKnowledgeId(documentDO.getKnowledgeId()) - .setDocumentId(documentId) - .setContent(segment.getText()) - .setContentLength(segment.getText().length()) + return new AiKnowledgeSegmentDO().setKnowledgeId(documentDO.getKnowledgeId()).setDocumentId(documentId) + .setContent(segment.getText()).setContentLength(segment.getText().length()) .setVectorId(AiKnowledgeSegmentDO.VECTOR_ID_EMPTY) .setTokens(tokenCountEstimator.estimate(segment.getText())) .setStatus(CommonStatusEnum.ENABLE.getStatus()); @@ -302,13 +299,12 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService // 1. 读取 URL 内容 String content = knowledgeDocumentService.readUrl(url); - // 2. 自动检测文档类型并选择策略 + // 2.1 自动检测文档类型并选择策略 AiDocumentSplitStrategyEnum strategy = detectDocumentStrategy(content, url); - - // 3. 文档切片 + // 2.2 文档切片 List documentSegments = splitContentByStrategy(content, segmentMaxTokens, strategy, url); - // 4. 转换为段落对象 + // 3. 转换为段落对象 return convertList(documentSegments, segment -> { if (StrUtil.isEmpty(segment.getText())) { return null; @@ -352,6 +348,7 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService * @param url 文档 URL(用于自动检测文件类型) * @return 切片后的文档列表 */ + @SuppressWarnings("EnhancedSwitchMigration") private List splitContentByStrategy(String content, Integer segmentMaxTokens, AiDocumentSplitStrategyEnum strategy, String url) { // 自动检测策略 @@ -359,7 +356,7 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService strategy = detectDocumentStrategy(content, url); log.info("[splitContentByStrategy][自动检测到文档策略: {}]", strategy.getName()); } - + // 根据策略切分 TextSplitter textSplitter; switch (strategy) { case MARKDOWN_QA: @@ -376,7 +373,7 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService textSplitter = buildTokenTextSplitter(segmentMaxTokens); break; } - + // 执行切分 return textSplitter.apply(Collections.singletonList(new Document(content))); } @@ -391,17 +388,14 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService if (StrUtil.isEmpty(content)) { return AiDocumentSplitStrategyEnum.TOKEN; } - // 1. 检测 Markdown QA 格式 if (isMarkdownQaFormat(content, url)) { return AiDocumentSplitStrategyEnum.MARKDOWN_QA; } - // 2. 检测普通 Markdown 文档 if (isMarkdownDocument(url)) { return AiDocumentSplitStrategyEnum.SEMANTIC; } - // 3. 默认使用语义切分(比 Token 切分更智能) return AiDocumentSplitStrategyEnum.SEMANTIC; } @@ -421,16 +415,14 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService .filter(line -> line.trim().startsWith("## ")) .count(); - // 至少包含 2 个二级标题才认为是 QA 格式 + // 要求一:至少包含 2 个二级标题才认为是 QA 格式 if (h2Count < 2) { return false; } - // 检查标题占比(QA 文档标题行数相对较多) + // 要求二:检查标题占比(QA 文档标题行数相对较多),如果二级标题占比超过 10%,认为是 QA 格式 long totalLines = content.lines().count(); double h2Ratio = (double) h2Count / totalLines; - - // 如果二级标题占比超过 10%,认为是 QA 格式 return h2Ratio > 0.1; } @@ -438,7 +430,7 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService * 检测是否为 Markdown 文档 */ private boolean isMarkdownDocument(String url) { - return StrUtil.isNotEmpty(url) && url.toLowerCase().endsWith(".md"); + return StrUtil.endWithAnyIgnoreCase(url, ".md", ".markdown"); } /** diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java index 2957f4140e..1fbf4f2429 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/MarkdownQaSplitter.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.ai.service.knowledge.splitter; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.transformer.splitter.TextSplitter; @@ -24,6 +26,7 @@ import java.util.regex.Pattern; * @author runzhen */ @Slf4j +@SuppressWarnings("SizeReplaceableByIsEmpty") public class MarkdownQaSplitter extends TextSplitter { /** @@ -62,41 +65,38 @@ public class MarkdownQaSplitter extends TextSplitter { return Collections.emptyList(); } - List result = new ArrayList<>(); - // 解析 QA 对 List qaPairs = parseQaPairs(text); - - if (qaPairs.isEmpty()) { + if (CollUtil.isEmpty(qaPairs)) { // 如果没有识别到 QA 格式,按段落切分 return fallbackSplit(text); } // 处理每个 QA 对 + List result = new ArrayList<>(); for (QaPair qaPair : qaPairs) { result.addAll(splitQaPair(qaPair)); } - return result; } /** * 解析 Markdown QA 对 + * + * @param content 文本内容 + * @return QA 对列表 */ private List parseQaPairs(String content) { + // 找到所有二级标题位置 List qaPairs = new ArrayList<>(); - Matcher matcher = H2_PATTERN.matcher(content); - List headingPositions = new ArrayList<>(); List questions = new ArrayList<>(); - - // 找到所有二级标题位置 + Matcher matcher = H2_PATTERN.matcher(content); while (matcher.find()) { headingPositions.add(matcher.start()); questions.add(matcher.group(1).trim()); } - - if (headingPositions.isEmpty()) { + if (CollUtil.isEmpty(headingPositions)) { return qaPairs; } @@ -106,55 +106,51 @@ public class MarkdownQaSplitter extends TextSplitter { int end = (i + 1 < headingPositions.size()) ? headingPositions.get(i + 1) : content.length(); - String qaText = content.substring(start, end).trim(); String question = questions.get(i); - // 提取答案部分(去掉问题标题) String answer = qaText.substring(qaText.indexOf('\n') + 1).trim(); - qaPairs.add(new QaPair(question, answer, qaText)); } - return qaPairs; } /** * 切分单个 QA 对 + * + * @param qaPair QA 对 + * @return 切分后的文本片段列表 */ private List splitQaPair(QaPair qaPair) { + // 如果整个 QA 对不超过限制,保持完整 List chunks = new ArrayList<>(); - String fullQa = qaPair.fullText; int qaTokens = tokenEstimator.estimate(fullQa); - - // 如果整个 QA 对不超过限制,保持完整 if (qaTokens <= chunkSize) { chunks.add(fullQa); return chunks; } // 长答案需要切分 - log.debug("QA 对超过 Token 限制 ({} > {}),开始智能切分: {}", - qaTokens, chunkSize, qaPair.question); - + log.debug("QA 对超过 Token 限制 ({} > {}),开始智能切分: {}", qaTokens, chunkSize, qaPair.question); List answerChunks = splitLongAnswer(qaPair.answer, qaPair.question); - for (String answerChunk : answerChunks) { // 每个片段都包含完整问题 String chunkText = "## " + qaPair.question + "\n" + answerChunk; chunks.add(chunkText); } - return chunks; } /** * 切分长答案 + * + * @param answer 答案文本 + * @param question 问题文本 + * @return 切分后的答案片段列表 */ private List splitLongAnswer(String answer, String question) { List chunks = new ArrayList<>(); - // 预留问题的 Token 空间 String questionHeader = "## " + question + "\n"; int questionTokens = tokenEstimator.estimate(questionHeader); @@ -162,17 +158,13 @@ public class MarkdownQaSplitter extends TextSplitter { // 先按段落切分 String[] paragraphs = answer.split(PARAGRAPH_SEPARATOR); - StringBuilder currentChunk = new StringBuilder(); int currentTokens = 0; - for (String paragraph : paragraphs) { if (StrUtil.isEmpty(paragraph)) { continue; } - int paragraphTokens = tokenEstimator.estimate(paragraph); - // 如果单个段落就超过限制,需要按句子切分 if (paragraphTokens > availableTokens) { // 先保存当前块 @@ -181,19 +173,105 @@ public class MarkdownQaSplitter extends TextSplitter { currentChunk = new StringBuilder(); currentTokens = 0; } - // 按句子切分长段落 chunks.addAll(splitLongParagraph(paragraph, availableTokens)); continue; } - // 如果加上这个段落会超过限制 if (currentTokens + paragraphTokens > availableTokens && currentChunk.length() > 0) { chunks.add(currentChunk.toString().trim()); currentChunk = new StringBuilder(); currentTokens = 0; } + if (currentChunk.length() > 0) { + currentChunk.append("\n\n"); + } + // 添加段落 + currentChunk.append(paragraph); + currentTokens += paragraphTokens; + } + // 添加最后一块 + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + } + return CollUtil.isEmpty(chunks) ? Collections.singletonList(answer) : chunks; + } + + /** + * 切分长段落(按句子) + * + * @param paragraph 段落文本 + * @param availableTokens 可用的 Token 数 + * @return 切分后的文本片段列表 + */ + private List splitLongParagraph(String paragraph, int availableTokens) { + // 按句子切分 + List chunks = new ArrayList<>(); + String[] sentences = SENTENCE_PATTERN.split(paragraph); + + // 按句子累积切分 + StringBuilder currentChunk = new StringBuilder(); + int currentTokens = 0; + for (String sentence : sentences) { + if (StrUtil.isEmpty(sentence)) { + continue; + } + int sentenceTokens = tokenEstimator.estimate(sentence); + // 如果单个句子就超过限制,强制切分 + if (sentenceTokens > availableTokens) { + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + chunks.add(sentence.trim()); + continue; + } + // 如果加上这个句子会超过限制 + if (currentTokens + sentenceTokens > availableTokens && currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + // 添加句子 + currentChunk.append(sentence); + currentTokens += sentenceTokens; + } + + // 添加最后一块 + if (currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + } + return chunks.isEmpty() ? Collections.singletonList(paragraph) : chunks; + } + + /** + * 降级切分策略(当未识别到 QA 格式时) + * + * @param content 文本内容 + * @return 切分后的文本片段列表 + */ + private List fallbackSplit(String content) { + // 按段落切分 + List chunks = new ArrayList<>(); + String[] paragraphs = content.split(PARAGRAPH_SEPARATOR); + + // 按段落累积切分 + StringBuilder currentChunk = new StringBuilder(); + int currentTokens = 0; + for (String paragraph : paragraphs) { + if (StrUtil.isEmpty(paragraph)) { + continue; + } + int paragraphTokens = tokenEstimator.estimate(paragraph); + // 如果加上这个段落会超过限制 + if (currentTokens + paragraphTokens > chunkSize && currentChunk.length() > 0) { + chunks.add(currentChunk.toString().trim()); + currentChunk = new StringBuilder(); + currentTokens = 0; + } + // 添加段落 if (currentChunk.length() > 0) { currentChunk.append("\n\n"); } @@ -205,112 +283,28 @@ public class MarkdownQaSplitter extends TextSplitter { if (currentChunk.length() > 0) { chunks.add(currentChunk.toString().trim()); } - - return chunks.isEmpty() ? Collections.singletonList(answer) : chunks; - } - - /** - * 切分长段落(按句子) - */ - private List splitLongParagraph(String paragraph, int availableTokens) { - List chunks = new ArrayList<>(); - String[] sentences = SENTENCE_PATTERN.split(paragraph); - - StringBuilder currentChunk = new StringBuilder(); - int currentTokens = 0; - - for (String sentence : sentences) { - if (StrUtil.isEmpty(sentence)) { - continue; - } - - int sentenceTokens = tokenEstimator.estimate(sentence); - - // 如果单个句子就超过限制,强制切分 - if (sentenceTokens > availableTokens) { - if (currentChunk.length() > 0) { - chunks.add(currentChunk.toString().trim()); - currentChunk = new StringBuilder(); - currentTokens = 0; - } - chunks.add(sentence.trim()); - continue; - } - - if (currentTokens + sentenceTokens > availableTokens && currentChunk.length() > 0) { - chunks.add(currentChunk.toString().trim()); - currentChunk = new StringBuilder(); - currentTokens = 0; - } - - currentChunk.append(sentence); - currentTokens += sentenceTokens; - } - - if (currentChunk.length() > 0) { - chunks.add(currentChunk.toString().trim()); - } - - return chunks.isEmpty() ? Collections.singletonList(paragraph) : chunks; - } - - /** - * 降级切分策略(当未识别到 QA 格式时) - */ - private List fallbackSplit(String content) { - List chunks = new ArrayList<>(); - String[] paragraphs = content.split(PARAGRAPH_SEPARATOR); - - StringBuilder currentChunk = new StringBuilder(); - int currentTokens = 0; - - for (String paragraph : paragraphs) { - if (StrUtil.isEmpty(paragraph)) { - continue; - } - - int paragraphTokens = tokenEstimator.estimate(paragraph); - - if (currentTokens + paragraphTokens > chunkSize && currentChunk.length() > 0) { - chunks.add(currentChunk.toString().trim()); - currentChunk = new StringBuilder(); - currentTokens = 0; - } - - if (currentChunk.length() > 0) { - currentChunk.append("\n\n"); - } - currentChunk.append(paragraph); - currentTokens += paragraphTokens; - } - - if (currentChunk.length() > 0) { - chunks.add(currentChunk.toString().trim()); - } - return chunks.isEmpty() ? Collections.singletonList(content) : chunks; } /** * QA 对数据结构 */ + @AllArgsConstructor private static class QaPair { + String question; String answer; String fullText; - QaPair(String question, String answer, String fullText) { - this.question = question; - this.answer = answer; - this.fullText = fullText; - } } /** * Token 估算器接口 */ public interface TokenEstimator { + int estimate(String text); + } /** @@ -319,6 +313,7 @@ public class MarkdownQaSplitter extends TextSplitter { * 英文:1 单词 ≈ 1.3 Token */ private static class SimpleTokenEstimator implements TokenEstimator { + @Override public int estimate(String text) { if (StrUtil.isEmpty(text)) { @@ -327,14 +322,12 @@ public class MarkdownQaSplitter extends TextSplitter { int chineseChars = 0; int englishWords = 0; - // 简单统计中英文 for (char c : text.toCharArray()) { if (c >= 0x4E00 && c <= 0x9FA5) { chineseChars++; } } - // 英文单词估算 String[] words = text.split("\\s+"); for (String word : words) { @@ -342,8 +335,8 @@ public class MarkdownQaSplitter extends TextSplitter { englishWords++; } } - return chineseChars + (int) (englishWords * 1.3); } } + } diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java index 64160a41a0..4c7112e9ad 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/splitter/SemanticTextSplitter.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -72,12 +73,14 @@ public class SemanticTextSplitter extends TextSplitter { if (StrUtil.isEmpty(text)) { return Collections.emptyList(); } - return splitTextRecursive(text); } /** * 切分文本(递归策略) + * + * @param text 待切分文本 + * @return 切分后的文本块列表 */ private List splitTextRecursive(String text) { List chunks = new ArrayList<>(); @@ -92,7 +95,6 @@ public class SemanticTextSplitter extends TextSplitter { // 尝试按不同分隔符切分 List splits = null; String usedSeparator = null; - for (String separator : PARAGRAPH_SEPARATORS) { if (text.contains(separator)) { splits = Arrays.asList(text.split(Pattern.quote(separator))); @@ -109,18 +111,20 @@ public class SemanticTextSplitter extends TextSplitter { // 合并小片段 chunks = mergeSplits(splits, usedSeparator); - return chunks; } /** * 按句子切分 + * + * @param text 待切分文本 + * @return 句子列表 */ private List splitBySentences(String text) { + // 使用正则表达式匹配句子结束位置 List sentences = new ArrayList<>(); int lastEnd = 0; - - java.util.regex.Matcher matcher = SENTENCE_END_PATTERN.matcher(text); + Matcher matcher = SENTENCE_END_PATTERN.matcher(text); while (matcher.find()) { String sentence = text.substring(lastEnd, matcher.end()).trim(); if (StrUtil.isNotEmpty(sentence)) { @@ -136,12 +140,15 @@ public class SemanticTextSplitter extends TextSplitter { sentences.add(remaining); } } - return sentences.isEmpty() ? Collections.singletonList(text) : sentences; } /** * 合并切分后的小片段 + * + * @param splits 切分后的片段列表 + * @param separator 片段间的分隔符 + * @return 合并后的文本块列表 */ private List mergeSplits(List splits, String separator) { List chunks = new ArrayList<>(); @@ -152,9 +159,7 @@ public class SemanticTextSplitter extends TextSplitter { if (StrUtil.isEmpty(split)) { continue; } - int splitTokens = tokenEstimator.estimate(split); - // 如果单个片段就超过限制,进一步递归切分 if (splitTokens > chunkSize) { // 先保存当前累积的块 @@ -164,7 +169,6 @@ public class SemanticTextSplitter extends TextSplitter { currentChunks.clear(); currentLength = 0; } - // 递归切分大片段 if (!separator.isEmpty()) { // 如果是段落分隔符,尝试按句子切分 @@ -175,10 +179,8 @@ public class SemanticTextSplitter extends TextSplitter { } continue; } - // 计算加上分隔符的 Token 数 int separatorTokens = StrUtil.isEmpty(separator) ? 0 : tokenEstimator.estimate(separator); - // 如果加上这个片段会超过限制 if (!currentChunks.isEmpty() && currentLength + splitTokens + separatorTokens > chunkSize) { // 保存当前块 @@ -189,7 +191,7 @@ public class SemanticTextSplitter extends TextSplitter { currentChunks = getOverlappingChunks(currentChunks, separator); currentLength = estimateTokens(currentChunks, separator); } - + // 添加当前片段 currentChunks.add(split); currentLength += splitTokens + separatorTokens; } @@ -199,39 +201,43 @@ public class SemanticTextSplitter extends TextSplitter { String chunkText = String.join(separator, currentChunks); chunks.add(chunkText.trim()); } - return chunks; } /** * 获取重叠的片段(用于保持上下文) + * + * @param chunks 当前片段列表 + * @param separator 片段间的分隔符 + * @return 重叠的片段列表 */ private List getOverlappingChunks(List chunks, String separator) { if (chunkOverlap == 0 || chunks.isEmpty()) { return new ArrayList<>(); } + // 从后往前取片段,直到达到重叠大小 List overlapping = new ArrayList<>(); int tokens = 0; - - // 从后往前取片段,直到达到重叠大小 for (int i = chunks.size() - 1; i >= 0; i--) { String chunk = chunks.get(i); int chunkTokens = tokenEstimator.estimate(chunk); - if (tokens + chunkTokens > chunkOverlap) { break; } - + // 添加到重叠列表前端 overlapping.add(0, chunk); tokens += chunkTokens + (StrUtil.isEmpty(separator) ? 0 : tokenEstimator.estimate(separator)); } - return overlapping; } /** * 估算片段列表的总 Token 数 + * + * @param chunks 片段列表 + * @param separator 片段间的分隔符 + * @return 总 Token 数 */ private int estimateTokens(List chunks, String separator) { int total = 0; @@ -246,17 +252,18 @@ public class SemanticTextSplitter extends TextSplitter { /** * 强制切分长文本(当语义切分失败时) + * + * @param text 待切分文本 + * @return 切分后的文本块列表 */ private List forceSplitLongText(String text) { List chunks = new ArrayList<>(); int charsPerChunk = (int) (chunkSize * 0.8); // 保守估计 - for (int i = 0; i < text.length(); i += charsPerChunk) { int end = Math.min(i + charsPerChunk, text.length()); String chunk = text.substring(i, end); chunks.add(chunk.trim()); } - log.warn("文本过长,已强制按字符切分,可能影响语义完整性"); return chunks; } @@ -265,6 +272,7 @@ public class SemanticTextSplitter extends TextSplitter { * 简单的 Token 估算器实现 */ private static class SimpleTokenEstimator implements MarkdownQaSplitter.TokenEstimator { + @Override public int estimate(String text) { if (StrUtil.isEmpty(text)) { @@ -273,21 +281,21 @@ public class SemanticTextSplitter extends TextSplitter { int chineseChars = 0; int englishWords = 0; - + // 简单统计中英文 for (char c : text.toCharArray()) { if (c >= 0x4E00 && c <= 0x9FA5) { chineseChars++; } } - + // 英文单词估算 String[] words = text.split("\\s+"); for (String word : words) { if (word.matches(".*[a-zA-Z].*")) { englishWords++; } } - return chineseChars + (int) (englishWords * 1.3); } } + } From 7347c1c9d6addcf1ddd2abd97e1e4b721e79c835 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 10:18:31 +0800 Subject: [PATCH 37/88] =?UTF-8?q?fix=EF=BC=9A=E3=80=90pay=E3=80=91pay=5Fwa?= =?UTF-8?q?llet=20=E8=A1=A8=EF=BC=8C=E9=83=A8=E5=88=86=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E4=B8=A4=E6=9D=A1=E9=92=B1=E5=8C=85=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E9=97=AE=E9=A2=98=EF=BC=8C=E5=AF=B9=E5=BA=94=20https:?= =?UTF-8?q?//gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1475?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/wallet/PayWalletServiceImpl.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java index 0005acef63..58036eebc9 100644 --- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java +++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java @@ -58,13 +58,22 @@ public class PayWalletServiceImpl implements PayWalletService { private PayRefundService refundService; @Override + @SneakyThrows public PayWalletDO getOrCreateWallet(Long userId, Integer userType) { PayWalletDO wallet = walletMapper.selectByUserIdAndType(userId, userType); if (wallet == null) { - wallet = new PayWalletDO().setUserId(userId).setUserType(userType) - .setBalance(0).setTotalExpense(0).setTotalRecharge(0); - wallet.setCreateTime(LocalDateTime.now()); - walletMapper.insert(wallet); + // 使用双重检查锁,保证钱包创建并发问题 + // https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1475/files + wallet = lockRedisDAO.lock(userId, UPDATE_TIMEOUT_MILLIS, () -> { + PayWalletDO newWallet = walletMapper.selectByUserIdAndType(userId, userType); + if (newWallet == null) { + newWallet = new PayWalletDO().setUserId(userId).setUserType(userType) + .setBalance(0).setTotalExpense(0).setTotalRecharge(0); + newWallet.setCreateTime(LocalDateTime.now()); + walletMapper.insert(newWallet); + } + return newWallet; + }); } return wallet; } From a86b5830c2ad47b9fe72d955bca409e337f5e891 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 11:20:25 +0800 Subject: [PATCH 38/88] =?UTF-8?q?fix=EF=BC=9A=E3=80=90ai=E3=80=91=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=20elasticsearch=20=E4=BE=9D=E8=B5=96=EF=BC=8C?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=20spring=20boot=20admin=20=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-ai/pom.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/yudao-module-ai/pom.xml b/yudao-module-ai/pom.xml index 65017da345..d295f72ff6 100644 --- a/yudao-module-ai/pom.xml +++ b/yudao-module-ai/pom.xml @@ -20,7 +20,8 @@ 1.1.0 - 1.1.0.0-M5 + + 1.1.0.0-RC1 1.2.6 @@ -226,6 +227,11 @@ com.agentsflex agents-flex-store-elasticsearch + + + com.agentsflex + agents-flex-search-engine-es + org.codehaus.groovy From bfff8f5ec43656a3487a6c04a911115ea6a71f88 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 11:28:36 +0800 Subject: [PATCH 39/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90infra=E3=80=91?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=E7=9A=84=20swagger=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=9A=84=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/infra/controller/admin/file/FileController.java | 3 +++ .../module/infra/controller/app/file/AppFileController.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java index a12ba3934e..5b6f52ea9b 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.infra.service.file.FileService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.annotation.security.PermitAll; @@ -44,6 +45,8 @@ public class FileController { @PostMapping("/upload") @Operation(summary = "上传文件", description = "模式一:后端上传文件") + @Parameter(name = "file", description = "文件附件", required = true, + schema = @Schema(type = "string", format = "binary")) public CommonResult uploadFile(@Valid FileUploadReqVO uploadReqVO) throws Exception { MultipartFile file = uploadReqVO.getFile(); byte[] content = IoUtil.readBytes(file.getInputStream()); diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java index a4c1d202e8..c3e14a803e 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.infra.service.file.FileService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.annotation.security.PermitAll; @@ -32,6 +33,8 @@ public class AppFileController { @PostMapping("/upload") @Operation(summary = "上传文件") + @Parameter(name = "file", description = "文件附件", required = true, + schema = @Schema(type = "string", format = "binary")) @PermitAll public CommonResult uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception { MultipartFile file = uploadReqVO.getFile(); From 32e9c17f1272b9bdd06e7252814b63bed4ecb10d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 11:40:26 +0800 Subject: [PATCH 40/88] =?UTF-8?q?fix=EF=BC=9A=E3=80=90pay=E3=80=91?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E9=92=B1=E5=8C=85=E9=80=80=E6=AC=BE=E6=97=B6?= =?UTF-8?q?=EF=BC=8CmerchantRefundId=20=E4=BC=A0=E9=80=92=E4=B8=8D?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/wallet/PayWalletRechargeController.java | 2 +- .../pay/service/wallet/PayWalletRechargeService.java | 4 ++-- .../pay/service/wallet/PayWalletRechargeServiceImpl.java | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java index c5e84aa700..2626323843 100644 --- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java +++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java @@ -51,7 +51,7 @@ public class PayWalletRechargeController { public CommonResult updateWalletRechargeRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) { walletRechargeService.updateWalletRechargeRefunded( Long.valueOf(notifyReqDTO.getMerchantOrderId()), - Long.valueOf(notifyReqDTO.getMerchantRefundId()), + notifyReqDTO.getMerchantRefundId(), notifyReqDTO.getPayRefundId()); return success(true); } diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java index f2ab50ed68..d837b9acd6 100644 --- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java +++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java @@ -56,9 +56,9 @@ public interface PayWalletRechargeService { * 更新钱包充值记录为已退款 * * @param id 钱包充值记录编号 - * @param refundId 钱包充值退款编号(实际和 id 相同) + * @param refundId 钱包充值退款编号(格式:{id}-refund) * @param payRefundId 退款单id */ - void updateWalletRechargeRefunded(Long id, Long refundId, Long payRefundId); + void updateWalletRechargeRefunded(Long id, String refundId, Long payRefundId); } diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java index 95539b28d5..a49936d9f0 100644 --- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java +++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java @@ -220,9 +220,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { @Override @Transactional(rollbackFor = Exception.class) - public void updateWalletRechargeRefunded(Long id, Long refundId, Long payRefundId) { + public void updateWalletRechargeRefunded(Long id, String refundId, Long payRefundId) { // 1.1 获取钱包充值记录 - // 说明:因为 id 和 refundId 是相同的,所以直接使用 id 查询即可! PayWalletRechargeDO walletRecharge = walletRechargeMapper.selectById(id); if (walletRecharge == null) { log.error("[updateWalletRechargerPaid][钱包充值记录不存在,钱包充值记录 id({})]", id); @@ -274,8 +273,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { walletRecharge.getId(), payRefundId, toJsonString(walletRecharge), toJsonString(payRefund)); throw exception(WALLET_RECHARGE_REFUND_FAIL_REFUND_PRICE_NOT_MATCH); } - // 2.3 校验退款订单商户订单是否匹配 - if (notEqual(payRefund.getMerchantRefundId(), walletRecharge.getId().toString())) { + // 2.3 校验退款订单商户退款单是否匹配 + if (notEqual(payRefund.getMerchantRefundId(), walletRecharge.getId() + "-refund")) { log.error("[validateWalletRechargeCanRefunded][钱包({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]", walletRecharge.getId(), payRefundId, toJsonString(payRefund)); throw exception(WALLET_RECHARGE_REFUND_FAIL_REFUND_ORDER_ID_ERROR); From 7041baf17847535309670fda4f6f36c2829263d1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 13 Dec 2025 11:43:32 +0800 Subject: [PATCH 41/88] =?UTF-8?q?fix=EF=BC=9A=E3=80=90mall=E3=80=91?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=97=A5=E5=BF=97=E3=80=81=E5=94=AE=E5=90=8E?= =?UTF-8?q?=E6=97=A5=E5=BF=97=EF=BC=8C=E5=A2=9E=E5=8A=A0=20USER=5FID=20?= =?UTF-8?q?=E7=9A=84=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/framework/aftersale/core/aop/AfterSaleLogAspect.java | 3 +++ .../trade/framework/order/core/aop/TradeOrderLogAspect.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java index c56f33afbe..ba443e8a17 100644 --- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java +++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java @@ -113,6 +113,9 @@ public class AfterSaleLogAspect { * @return 用户类型 */ private static Long getUserId() { + if (USER_ID.get() != null) { + return USER_ID.get(); + } return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM); } diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java index 840e9b05b9..5a8d26e944 100644 --- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java +++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java @@ -109,6 +109,9 @@ public class TradeOrderLogAspect { * @return 用户类型 */ private static Long getUserId() { + if (USER_ID.get() != null) { + return USER_ID.get(); + } return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM); } From 33fb112dfecc23df103e8039f57097a451238519 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 16 Dec 2025 21:09:48 +0800 Subject: [PATCH 42/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90infra=E3=80=91?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=20admin=20uniapp=20=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E7=9A=84=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/codegen/CodegenFrontTypeEnum.java | 2 + .../service/codegen/inner/CodegenEngine.java | 19 ++ .../codegen/vue3_admin_uniapp/api/api.ts.vm | 55 ++++ .../components/search-form.vue.vm | 257 ++++++++++++++++++ .../views/detail/index.vue.vm | 143 ++++++++++ .../vue3_admin_uniapp/views/form/index.vue.vm | 225 +++++++++++++++ .../vue3_admin_uniapp/views/index.vue.vm | 220 +++++++++++++++ 7 files changed, 921 insertions(+) create mode 100644 yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm create mode 100644 yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm create mode 100644 yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm create mode 100644 yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm create mode 100644 yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java index 7f55507e42..b3c8116cd6 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java @@ -23,6 +23,8 @@ public enum CodegenFrontTypeEnum { VUE3_VBEN5_EP_SCHEMA(50), // Vue3 VBEN5 + EP + schema 模版 VUE3_VBEN5_EP_GENERAL(51), // Vue3 VBEN5 + EP 标准模版 + + VUE3_ADMIN_UNIAPP_WOT(60), // Vue3 Admin + Uniapp + WOT 标准模版 ; /** diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java index cf8e030945..5de27ce23f 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java @@ -137,6 +137,16 @@ public class CodegenEngine { vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue")) .put(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType(), vue3TemplatePath("api/api.ts"), vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) + .put(CodegenFrontTypeEnum.VUE3_ADMIN_UNIAPP_WOT.getType(), vue3AdminUniappTemplatePath("api/api.ts"), + vue3UniappFilePath("api/${table.moduleName}/${table.businessName}/index.ts")) + .put(CodegenFrontTypeEnum.VUE3_ADMIN_UNIAPP_WOT.getType(), vue3AdminUniappTemplatePath("views/index.vue"), + vue3UniappFilePath("pages-${table.moduleName}/${table.businessName}/index.vue")) + .put(CodegenFrontTypeEnum.VUE3_ADMIN_UNIAPP_WOT.getType(), vue3AdminUniappTemplatePath("components/search-form.vue"), + vue3UniappFilePath("pages-${table.moduleName}/${table.businessName}/components/search-form.vue")) + .put(CodegenFrontTypeEnum.VUE3_ADMIN_UNIAPP_WOT.getType(), vue3AdminUniappTemplatePath("views/form/index.vue"), + vue3UniappFilePath("pages-${table.moduleName}/${table.businessName}/form/index.vue")) + .put(CodegenFrontTypeEnum.VUE3_ADMIN_UNIAPP_WOT.getType(), vue3AdminUniappTemplatePath("views/detail/index.vue"), + vue3UniappFilePath("pages-${table.moduleName}/${table.businessName}/detail/index.vue")) // VUE3_VBEN2_ANTD_SCHEMA .put(CodegenFrontTypeEnum.VUE3_VBEN2_ANTD_SCHEMA.getType(), vue3VbenTemplatePath("views/data.ts"), vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts")) @@ -617,6 +627,15 @@ public class CodegenEngine { "src/" + path; } + private static String vue3AdminUniappTemplatePath(String path) { + return "codegen/vue3_admin_uniapp/" + path + ".vm"; + } + + private static String vue3UniappFilePath(String path) { + return "yudao-ui-${sceneEnum.basePackage}-uniapp/" + // 顶级目录 + "src/" + path; + } + private static String vue3VbenFilePath(String path) { return "yudao-ui-${sceneEnum.basePackage}-vben/" + // 顶级目录 "src/" + path; diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm new file mode 100644 index 0000000000..4754bfacdd --- /dev/null +++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm @@ -0,0 +1,55 @@ +import type { PageParam, PageResult } from '@/http/types' +import { http } from '@/http/http' + +// TODO @AI:不使用 baseUrl,而是参考之前的,直接写在每个方法里。 +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") +const baseUrl = '${baseURL}' + +#set ($primaryJavaType = $primaryColumn.javaType.toLowerCase()) +#if(${primaryJavaType} == "long" || ${primaryJavaType} == "integer" || ${primaryJavaType} == "short" || ${primaryJavaType} == "double" || ${primaryJavaType} == "bigdecimal" || ${primaryJavaType} == "byte") +#set ($primaryTsType = "number") +#else +#set ($primaryTsType = "string") +#end + +/** ${table.classComment}信息 */ +export interface ${simpleClassName} { +#foreach ($column in $columns) + #if ($column.primaryKey || $column.createOperation || $column.updateOperation || $column.listOperationResult) + #set ($javaType = $column.javaType.toLowerCase()) + #set ($optional = $column.nullable || $column.primaryKey) + #if(${javaType} == "long" || ${javaType} == "integer" || ${javaType} == "short" || ${javaType} == "double" || ${javaType} == "bigdecimal" || ${javaType} == "byte") + ${column.javaField}#if($optional)?#end: number + #elseif(${javaType} == "boolean") + ${column.javaField}#if($optional)?#end: boolean + #else + ${column.javaField}#if($optional)?#end: string + #end + #end +#end +} + +/** 获取${table.classComment}分页列表 */ +export function get${simpleClassName}Page(params: PageParam) { + return http.get>(baseUrl + '/page', params) +} + +/** 获取${table.classComment}详情 */ +export function get${simpleClassName}(id: ${primaryTsType}) { + return http.get<${simpleClassName}>(baseUrl + '/get?id=' + id) +} + +/** 创建${table.classComment} */ +export function create${simpleClassName}(data: ${simpleClassName}) { + return http.post(baseUrl + '/create', data) +} + +/** 更新${table.classComment} */ +export function update${simpleClassName}(data: ${simpleClassName}) { + return http.put(baseUrl + '/update', data) +} + +/** 删除${table.classComment} */ +export function delete${simpleClassName}(id: ${primaryTsType}) { + return http.delete(baseUrl + '/delete?id=' + id) +} diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm new file mode 100644 index 0000000000..fad564b15c --- /dev/null +++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm @@ -0,0 +1,257 @@ + + + diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm new file mode 100644 index 0000000000..fdc340d686 --- /dev/null +++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm @@ -0,0 +1,143 @@ + + + + + diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm new file mode 100644 index 0000000000..ffee229db7 --- /dev/null +++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm @@ -0,0 +1,225 @@ + + + + + diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm new file mode 100644 index 0000000000..7cebd5ac83 --- /dev/null +++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm @@ -0,0 +1,220 @@ + + + + + From 94a1c4636f204c400fabcfffbdbffbbd4eab8f63 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 16 Dec 2025 23:33:01 +0800 Subject: [PATCH 43/88] =?UTF-8?q?feat=EF=BC=9A=E3=80=90infra=E3=80=91?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=20admin=20uniapp=20=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E7=9A=84=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=88api.ts=E3=80=81detail=E3=80=81form=20=E7=9A=84?= =?UTF-8?q?=E6=A8=A1=E7=89=88=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/codegen/inner/CodegenEngine.java | 4 +- .../codegen/vue3_admin_uniapp/api/api.ts.vm | 19 ++-- .../views/detail/index.vue.vm | 32 ++++--- .../vue3_admin_uniapp/views/form/index.vue.vm | 94 ++++++++++++------- 4 files changed, 92 insertions(+), 57 deletions(-) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java index 5de27ce23f..072e3925b8 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java @@ -397,8 +397,8 @@ public class CodegenEngine { * @return 格式化后的代码 */ private String prettyCode(String content, String vmPath) { - // Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错(需要排除 vben5) - if (!StrUtil.contains(vmPath, "vben5")) { + // Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错(需要排除 vben5、vue3_admin_uniapp) + if (!StrUtil.containsAny(vmPath, "vben5", "vue3_admin_uniapp")) { content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }"); } // Vue 界面:去除多的 dateFormatter,只有一个的情况下,说明没使用到 diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm index 4754bfacdd..a77561a540 100644 --- a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm +++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm @@ -1,10 +1,6 @@ import type { PageParam, PageResult } from '@/http/types' import { http } from '@/http/http' -// TODO @AI:不使用 baseUrl,而是参考之前的,直接写在每个方法里。 -#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") -const baseUrl = '${baseURL}' - #set ($primaryJavaType = $primaryColumn.javaType.toLowerCase()) #if(${primaryJavaType} == "long" || ${primaryJavaType} == "integer" || ${primaryJavaType} == "short" || ${primaryJavaType} == "double" || ${primaryJavaType} == "bigdecimal" || ${primaryJavaType} == "byte") #set ($primaryTsType = "number") @@ -17,9 +13,12 @@ export interface ${simpleClassName} { #foreach ($column in $columns) #if ($column.primaryKey || $column.createOperation || $column.updateOperation || $column.listOperationResult) #set ($javaType = $column.javaType.toLowerCase()) - #set ($optional = $column.nullable || $column.primaryKey) + #set ($javaFieldLower = $column.javaField.toLowerCase()) + #set ($optional = $column.nullable || $column.primaryKey || $javaFieldLower == "createtime" || $javaFieldLower == "updatetime") #if(${javaType} == "long" || ${javaType} == "integer" || ${javaType} == "short" || ${javaType} == "double" || ${javaType} == "bigdecimal" || ${javaType} == "byte") ${column.javaField}#if($optional)?#end: number + #elseif(${javaType} == "date" || ${javaType} == "localdate" || ${javaType} == "localdatetime") + ${column.javaField}#if($optional)?#end: Date #elseif(${javaType} == "boolean") ${column.javaField}#if($optional)?#end: boolean #else @@ -31,25 +30,25 @@ export interface ${simpleClassName} { /** 获取${table.classComment}分页列表 */ export function get${simpleClassName}Page(params: PageParam) { - return http.get>(baseUrl + '/page', params) + return http.get>('/${table.moduleName}/${simpleClassName_strikeCase}/page', params) } /** 获取${table.classComment}详情 */ export function get${simpleClassName}(id: ${primaryTsType}) { - return http.get<${simpleClassName}>(baseUrl + '/get?id=' + id) + return http.get<${simpleClassName}>('/${table.moduleName}/${simpleClassName_strikeCase}/get?id=' + id) } /** 创建${table.classComment} */ export function create${simpleClassName}(data: ${simpleClassName}) { - return http.post(baseUrl + '/create', data) + return http.post('/${table.moduleName}/${simpleClassName_strikeCase}/create', data) } /** 更新${table.classComment} */ export function update${simpleClassName}(data: ${simpleClassName}) { - return http.put(baseUrl + '/update', data) + return http.put('/${table.moduleName}/${simpleClassName_strikeCase}/update', data) } /** 删除${table.classComment} */ export function delete${simpleClassName}(id: ${primaryTsType}) { - return http.delete(baseUrl + '/delete?id=' + id) + return http.delete('/${table.moduleName}/${simpleClassName_strikeCase}/delete?id=' + id) } diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm index fdc340d686..b336c1dcc0 100644 --- a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm +++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm @@ -1,11 +1,13 @@