From 69da706f555df8329c63584f3134f520d0d04a8c Mon Sep 17 00:00:00 2001 From: preschooler Date: Mon, 29 Dec 2025 00:32:34 +0800 Subject: [PATCH 01/22] =?UTF-8?q?=F0=9F=90=9E=20fix:=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E7=94=A8=E6=88=B7=E7=9A=84=20username=20?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E6=97=B6=E4=BC=9A=E5=BC=82=E5=B8=B8=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/user/AdminUserServiceImpl.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 59052ea8db..b3dab061b9 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -36,6 +36,7 @@ import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import jakarta.validation.ConstraintViolationException; +import java.util.concurrent.atomic.AtomicInteger; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.security.crypto.password.PasswordEncoder; @@ -284,11 +285,16 @@ public class AdminUserServiceImpl implements AdminUserService { @Override public PageResult getUserPage(UserPageReqVO reqVO) { // 如果有角色编号,查询角色对应的用户编号 - Set userIds = reqVO.getRoleId() != null ? - permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())) : null; - if (userIds != null && userIds.isEmpty()) { - return PageResult.empty(); + Set userIds; + if (reqVO.getRoleId() != null) { + userIds = permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())); + if (CollUtil.isEmpty(userIds)) { + return PageResult.empty(); + } + } else { + userIds = null; } + // 分页查询 return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()), userIds); } @@ -484,12 +490,16 @@ public class AdminUserServiceImpl implements AdminUserService { // 2. 遍历,逐个创建 or 更新 UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()) .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build(); + AtomicInteger index = new AtomicInteger(1); importUsers.forEach(importUser -> { + int currentIndex = index.getAndIncrement(); // 2.1.1 校验字段是否符合要求 try { ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(initPassword)); - } catch (ConstraintViolationException ex){ - respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage()); + } catch (ConstraintViolationException ex) { + String key = importUser.getUsername(); + if (StrUtil.isBlank(key)) key = "第" + currentIndex + "行"; + respVO.getFailureUsernames().put(key, ex.getMessage()); return; } // 2.1.2 校验,判断是否有不符合的原因 From b84db7c16845331debed6b153da7230692d939d5 Mon Sep 17 00:00:00 2001 From: preschooler Date: Mon, 29 Dec 2025 00:29:38 +0800 Subject: [PATCH 02/22] =?UTF-8?q?=F0=9F=8E=88=20perf:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=85=BC=E5=AE=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datapermission/core/rule/dept/DeptDataPermissionRule.java | 2 +- .../yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java | 2 +- .../yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java | 2 +- .../ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java | 3 +-- .../infra/controller/admin/file/vo/file/FileCreateReqVO.java | 2 +- .../infra/controller/admin/file/vo/file/FileRespVO.java | 2 +- .../yudao/module/infra/dal/dataobject/file/FileDO.java | 2 +- .../module/infra/service/db/DatabaseTableServiceImpl.java | 4 ++-- .../yudao/module/infra/service/file/FileServiceImpl.java | 2 +- 9 files changed, 10 insertions(+), 11 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java index 56b6ea4504..8cfad28697 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java @@ -136,7 +136,7 @@ public class DeptDataPermissionRule implements DataPermissionRule { JsonUtils.toJsonString(loginUser), tableName, tableAlias, JsonUtils.toJsonString(deptDataPermission)); // throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 构建的条件为空", // loginUser.getId(), tableName, tableAlias.getName())); - return EXPRESSION_NULL; + return new EqualsTo(null, null); // WHERE null = null,可以保证返回的数据为空 } if (deptExpression == null) { return userExpression; diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java index 722cc6ecf0..6885fedf6f 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java @@ -27,7 +27,7 @@ import java.util.List; * @since 2024/4/14 17:35 */ @TableName(value = "ai_chat_message", autoResultMap = true) -@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@KeySequence("ai_chat_message_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java index f2c683a503..a29f8f116a 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java @@ -14,7 +14,7 @@ import lombok.*; * @author 芋道源码 */ @TableName("ai_api_key") -@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@KeySequence("ai_api_key_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java index 1b9ca867f5..2b7daacda8 100644 --- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java +++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java @@ -51,8 +51,7 @@ public interface AiKnowledgeSegmentMapper extends BaseMapperX wrapper = new MPJLambdaWrapperX() .selectAs(AiKnowledgeSegmentDO::getDocumentId, AiKnowledgeSegmentProcessRespVO::getDocumentId) .selectCount(AiKnowledgeSegmentDO::getId, "count") - .select("COUNT(CASE WHEN vector_id > '" + AiKnowledgeSegmentDO.VECTOR_ID_EMPTY - + "' THEN 1 ELSE NULL END) AS embeddingCount") + .select("COUNT(CASE WHEN vector_id IS NOT NULL AND vector_id <> '" + AiKnowledgeSegmentDO.VECTOR_ID_EMPTY + "' THEN 1 ELSE NULL END) AS embeddingCount") .in(AiKnowledgeSegmentDO::getDocumentId, documentIds) .groupBy(AiKnowledgeSegmentDO::getDocumentId); return selectJoinList(AiKnowledgeSegmentProcessRespVO.class, wrapper); diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java index 5daa3972e9..72bcfd1ded 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java @@ -28,6 +28,6 @@ public class FileCreateReqVO { private String type; @Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED) - private Integer size; + private Long size; } diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java index a0357da15c..17df49afb1 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java @@ -28,7 +28,7 @@ public class FileRespVO { private String type; @Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED) - private Integer size; + private Long size; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java index 5cb666ef56..7219788930 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java @@ -52,6 +52,6 @@ public class FileDO extends BaseDO { /** * 文件大小 */ - private Integer size; + private Long size; } diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java index 289cae1e3e..d278579ba7 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java @@ -59,9 +59,9 @@ public class DatabaseTableServiceImpl implements DatabaseTableService { strategyConfig.addInclude(name); } else { // 移除工作流和定时任务前缀的表名 - strategyConfig.addExclude("ACT_[\\S\\s]+|QRTZ_[\\S\\s]+|FLW_[\\S\\s]+"); + strategyConfig.addExclude("ACT_[\\S\\s]+|QRTZ_[\\S\\s]+|FLW_[\\S\\s]+|act_[\\S\\s]+|qrtz_[\\S\\s]+|flw_[\\S\\s]+"); // 移除 ORACLE 相关的系统表 - strategyConfig.addExclude("IMPDP_[\\S\\s]+|ALL_[\\S\\s]+|HS_[\\S\\\\s]+"); + strategyConfig.addExclude("IMPDP_[\\S\\s]+|ALL_[\\S\\s]+|HS_[\\S\\s]+|impdp_[\\S\\s]+|all_[\\S\\s]+|hs_[\\S\\s]+"); strategyConfig.addExclude("[\\S\\s]+\\$[\\S\\s]+|[\\S\\s]+\\$"); // 表里不能有 $,一般有都是系统的表 } diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index 703df8c5f0..168db02c6b 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -88,7 +88,7 @@ public class FileServiceImpl implements FileService { // 3. 保存到数据库 fileMapper.insert(new FileDO().setConfigId(client.getId()) .setName(name).setPath(path).setUrl(url) - .setType(type).setSize(content.length)); + .setType(type).setSize((long) content.length)); return url; } From fc9fe221d7bbd1b1d4a1aac0e0b955c675d56bb1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 29 Dec 2025 06:31:21 +0800 Subject: [PATCH 03/22] =?UTF-8?q?1487=20fix:=20=E4=BF=AE=E5=A4=8D=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E7=94=A8=E6=88=B7=E7=9A=84=20username=20=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=E6=97=B6=E4=BC=9A=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/system/service/user/AdminUserServiceImpl.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index b3dab061b9..84e3bb6497 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -36,7 +36,6 @@ import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import jakarta.validation.ConstraintViolationException; -import java.util.concurrent.atomic.AtomicInteger; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.security.crypto.password.PasswordEncoder; @@ -45,6 +44,7 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @@ -285,14 +285,12 @@ public class AdminUserServiceImpl implements AdminUserService { @Override public PageResult getUserPage(UserPageReqVO reqVO) { // 如果有角色编号,查询角色对应的用户编号 - Set userIds; + Set userIds = null; if (reqVO.getRoleId() != null) { userIds = permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())); if (CollUtil.isEmpty(userIds)) { return PageResult.empty(); } - } else { - userIds = null; } // 分页查询 @@ -497,8 +495,7 @@ public class AdminUserServiceImpl implements AdminUserService { try { ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(initPassword)); } catch (ConstraintViolationException ex) { - String key = importUser.getUsername(); - if (StrUtil.isBlank(key)) key = "第" + currentIndex + "行"; + String key = StrUtil.blankToDefault(importUser.getUsername(), "第 " + currentIndex + " 行"); respVO.getFailureUsernames().put(key, ex.getMessage()); return; } From f8d9c4170c23cbd14e229afbd0906b68e09d69df Mon Sep 17 00:00:00 2001 From: preschooler Date: Mon, 29 Dec 2025 11:31:06 +0800 Subject: [PATCH 04/22] =?UTF-8?q?=F0=9F=8E=88=20perf:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20swagger-annotation=20=E7=89=88=E6=9C=AC=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-ai/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/yudao-module-ai/pom.xml b/yudao-module-ai/pom.xml index 51e6825966..dc78d42049 100644 --- a/yudao-module-ai/pom.xml +++ b/yudao-module-ai/pom.xml @@ -204,6 +204,12 @@ org.springframework.ai spring-ai-starter-mcp-server-webmvc ${spring-ai.version} + + + io.swagger.core.v3 + swagger-annotations-jakarta + + From 586a7f6a4a7d2c83c1960f001df97c1f1f2cf355 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 29 Dec 2025 23:24:07 +0800 Subject: [PATCH 05/22] =?UTF-8?q?feat=EF=BC=9A=E3=80=90infra=E3=80=91?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=EF=BC=9A=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20admin=20uniapp=20=E6=A8=A1=E7=89=88=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20const=20formRef=20=3D=20ref()=20?= =?UTF-8?q?=E7=9A=84=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codegen/vue3_admin_uniapp/views/form/index.vue.vm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 60c844381e..f1631447a0 100644 --- 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 @@ -107,6 +107,7 @@ - From 7835363c88fc60a19b596b5906a3d5c7eaa98ac5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 2 Jan 2026 18:36:42 +0800 Subject: [PATCH 08/22] =?UTF-8?q?fix=EF=BC=9A=E3=80=90infra=E3=80=91?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=EF=BC=9A=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E6=A8=A1=E7=89=88=EF=BC=8Cid=3D=20=E7=9A=84?= =?UTF-8?q?=E6=8B=BC=E6=8E=A5=E4=B8=8D=E5=AF=B9=EF=BC=88linter=20=E6=8A=A5?= =?UTF-8?q?=E9=94=99=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/codegen/vue3_admin_uniapp/api/api.ts.vm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 2ae596e273..6c5d7068fa 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 @@ -7,7 +7,6 @@ import { http } from '@/http/http' #else #set ($primaryTsType = "string") #end - /** ${table.classComment}信息 */ export interface ${simpleClassName} { #foreach ($column in $columns) @@ -28,7 +27,6 @@ export interface ${simpleClassName} { #end } -// TODO @AI:`/system/operate-log/get?id=${id}` 类似这种 /** 获取${table.classComment}分页列表 */ export function get${simpleClassName}Page(params: PageParam) { return http.get>('/${table.moduleName}/${simpleClassName_strikeCase}/page', params) @@ -36,7 +34,7 @@ export function get${simpleClassName}Page(params: PageParam) { /** 获取${table.classComment}详情 */ export function get${simpleClassName}(id: ${primaryTsType}) { - return http.get<${simpleClassName}>('/${table.moduleName}/${simpleClassName_strikeCase}/get?id=' + id) + return http.get<${simpleClassName}>(`/${table.moduleName}/${simpleClassName_strikeCase}/get?id=${id}`) } /** 创建${table.classComment} */ @@ -49,8 +47,7 @@ export function update${simpleClassName}(data: ${simpleClassName}) { return http.put('/${table.moduleName}/${simpleClassName_strikeCase}/update', data) } -// TODO @AI:`/system/operate-log/get?id=${id}` 类似这种 /** 删除${table.classComment} */ export function delete${simpleClassName}(id: ${primaryTsType}) { - return http.delete('/${table.moduleName}/${simpleClassName_strikeCase}/delete?id=' + id) + return http.delete(`/${table.moduleName}/${simpleClassName_strikeCase}/delete?id=${id}`) } From d1f85163da14b8158cd9b7593ad69d6438485f5b Mon Sep 17 00:00:00 2001 From: lijian <616766585@qq.com> Date: Sun, 4 Jan 2026 16:59:22 +0800 Subject: [PATCH 09/22] =?UTF-8?q?fix(mall):=20=E4=BF=AE=E5=A4=8D=E5=95=86?= =?UTF-8?q?=E5=93=81SPU=E5=BA=93=E5=AD=98=E8=AE=A1=E7=AE=97=E6=BA=A2?= =?UTF-8?q?=E5=87=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/product/service/spu/ProductSpuServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 6e6ed2bded..b7b90578bf 100755 --- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -109,7 +109,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { // sku 单价最低的商品的成本价格 spu.setCostPrice(getMinValue(skus, ProductSkuSaveReqVO::getCostPrice)); // skus 库存总数 - spu.setStock(getSumValue(skus, ProductSkuSaveReqVO::getStock, Integer::sum)); + spu.setStock(getSumValue(skus, ProductSkuSaveReqVO::getStock, Math::addExact)); // 若是 spu 已有状态则不处理 if (spu.getStatus() == null) { spu.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); // 默认状态为上架 From 605b4016101b614dcbef6740e5c7d5ad957e4b0e Mon Sep 17 00:00:00 2001 From: lijian <616766585@qq.com> Date: Mon, 5 Jan 2026 10:19:35 +0800 Subject: [PATCH 10/22] =?UTF-8?q?fix(mall):=20=E4=BF=AE=E5=A4=8D=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=95=86=E5=93=81=E6=97=B6=EF=BC=8C=E6=9C=AA=E8=AE=BE?= =?UTF-8?q?=E7=BD=AEsku=E9=94=80=E9=87=8F=EF=BC=8C=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E5=8F=AA=E8=83=BD=E7=BB=9F=E8=AE=A1spu=E9=94=80=E9=87=8F?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E8=83=BD=E7=BB=9F=E8=AE=A1sku=E9=94=80?= =?UTF-8?q?=E9=87=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/product/service/sku/ProductSkuServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java index bad799556d..6267aea676 100755 --- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java @@ -144,7 +144,7 @@ public class ProductSkuServiceImpl implements ProductSkuService { @Override public void createSkuList(Long spuId, List skuCreateReqList) { - List skus = BeanUtils.toBean(skuCreateReqList, ProductSkuDO.class, sku -> sku.setSpuId(spuId)); + List skus = BeanUtils.toBean(skuCreateReqList, ProductSkuDO.class, sku -> sku.setSpuId(spuId).setSalesCount(0)); productSkuMapper.insertBatch(skus); } From 6816821e13c1e9428f71d58ac1b45df808942a34 Mon Sep 17 00:00:00 2001 From: sisw Date: Tue, 6 Jan 2026 17:35:05 +0800 Subject: [PATCH 11/22] =?UTF-8?q?refactor(bpm):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=B9=B6=E8=A1=8C=E5=92=8C=E4=B8=B2=E8=A1=8C=E5=A4=9A=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E8=A1=8C=E4=B8=BA=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除多余的集合变量设置逻辑,简化任务处理人获取流程 - 添加对集合表达式、集合变量和元素变量的解析器覆写屏蔽 - 修复串行多实例中使用 getVariableLocal 替代 getVariable 避免变量清理问题 - 统一代码注释和实现逻辑,提高代码可读性 --- .../BpmParallelMultiInstanceBehavior.java | 27 +++++++++++++------ .../BpmSequentialMultiInstanceBehavior.java | 9 +------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java index 20fcf54753..b35f18e563 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -14,6 +14,7 @@ import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.common.engine.api.delegate.Expression; import java.util.List; import java.util.Set; @@ -56,14 +57,7 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav protected int resolveNrOfInstances(DelegateExecution execution) { // 情况一:UserTask 节点 if (execution.getCurrentFlowElement() instanceof UserTask) { - // 第一步,设置 collectionVariable 和 CollectionVariable - // 从 execution.getVariable() 读取所有任务处理人的 key - super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 - super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); - // 从 execution.getVariable() 读取当前所有任务处理的人的 key - super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); - - // 第二步,获取任务的所有处理人 + // 获取任务的所有处理人 @SuppressWarnings("unchecked") Set assigneeUserIds = (Set) execution.getVariable(super.collectionVariable, Set.class); if (assigneeUserIds == null) { @@ -94,4 +88,21 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav return super.resolveNrOfInstances(execution); } + // ========== 屏蔽解析器覆写 ========== + + @Override + public void setCollectionExpression(Expression collectionExpression) { + // 保持自定义变量名,忽略解析器写入的 collection 表达式 + } + + @Override + public void setCollectionVariable(String collectionVariable) { + // 保持自定义变量名,忽略解析器写入的 collection 变量名 + } + + @Override + public void setCollectionElementVariable(String collectionElementVariable) { + // 保持自定义变量名,忽略解析器写入的单元素变量名 + } + } diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java index ebf67a46bb..75582a0541 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java @@ -47,14 +47,7 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB protected int resolveNrOfInstances(DelegateExecution execution) { // 情况一:UserTask 节点 if (execution.getCurrentFlowElement() instanceof UserTask) { - // 第一步,设置 collectionVariable 和 CollectionVariable - // 从 execution.getVariable() 读取所有任务处理人的 key - super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 - super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); - // 从 execution.getVariable() 读取当前所有任务处理的人的 key - super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); - - // 第二步,获取任务的所有处理人 + // 获取任务的所有处理人 // 不使用 execution.getVariable 原因:目前依次审批任务回退后 collectionVariable 变量没有清理, 如果重新进入该任务不会重新分配审批人 @SuppressWarnings("unchecked") Set assigneeUserIds = (Set) execution.getVariableLocal(super.collectionVariable, Set.class); From fdfca8588f0a329f17bb3500274d5d07ed35c62f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 12:14:58 +0800 Subject: [PATCH 12/22] =?UTF-8?q?fix=EF=BC=9A=E3=80=90mall=E3=80=91?= =?UTF-8?q?=E5=88=86=E9=94=80=E7=94=A8=E6=88=B7=E5=88=9B=E5=BB=BA=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E7=BC=BA=E5=B0=91=E5=AF=B9=20bindUserId=20=E7=9A=84?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/brokerage/vo/user/BrokerageUserCreateReqVO.java | 1 + 1 file changed, 1 insertion(+) diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java index f93149afb8..7865725a72 100644 --- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java +++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java @@ -13,6 +13,7 @@ public class BrokerageUserCreateReqVO { private Long userId; @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587") + @NotNull(message = "推广员编号不能为空") private Long bindUserId; } From 5bb29a3fa07209dd1d466ae21dc84e900686488e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 14:57:04 +0800 Subject: [PATCH 13/22] =?UTF-8?q?feat=EF=BC=9A=E3=80=90erp=E3=80=91?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9=20pgsql=20=E7=9A=84=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E6=80=A7=EF=BC=8C=E5=AF=B9=E5=BA=94=20https://t.zsxq.?= =?UTF-8?q?com/rM8Y1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java | 4 ++-- .../erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java | 4 ++-- .../erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java | 4 ++-- .../erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java | 4 ++-- .../yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java | 4 ++-- .../module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java | 4 ++-- .../yudao/module/erp/dal/mysql/stock/ErpStockMapper.java | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java index 7787e8d709..7a5bb6e63c 100644 --- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java +++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java @@ -31,14 +31,14 @@ public interface ErpFinancePaymentItemMapper extends BaseMapperX> result = selectMaps(new QueryWrapper() - .select("SUM(payment_price) AS paymentPriceSum") + .select("SUM(payment_price) AS payment_price_sum") .eq("biz_id", bizId) .eq("biz_type", bizType)); // 获得数量 if (CollUtil.isEmpty(result)) { return BigDecimal.ZERO; } - return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "paymentPriceSum", 0D)); + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "payment_price_sum", 0D)); } } \ No newline at end of file diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java index cb6082b0e4..40ac887582 100644 --- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java +++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java @@ -31,14 +31,14 @@ public interface ErpFinanceReceiptItemMapper extends BaseMapperX> result = selectMaps(new QueryWrapper() - .select("SUM(receipt_price) AS receiptPriceSum") + .select("SUM(receipt_price) AS receipt_price_sum") .eq("biz_id", bizId) .eq("biz_type", bizType)); // 获得数量 if (CollUtil.isEmpty(result)) { return BigDecimal.ZERO; } - return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "receiptPriceSum", 0D)); + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "receipt_price_sum", 0D)); } } \ No newline at end of file diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java index 9140f9548f..5a14317806 100644 --- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java +++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java @@ -46,11 +46,11 @@ public interface ErpPurchaseInItemMapper extends BaseMapperX> result = selectMaps(new QueryWrapper() - .select("order_item_id, SUM(count) AS sumCount") + .select("order_item_id, SUM(count) AS sum_count") .groupBy("order_item_id") .in("in_id", inIds)); // 获得数量 - return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sum_count")); } } \ No newline at end of file diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java index 2a8011900c..30527d2321 100644 --- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java +++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java @@ -46,11 +46,11 @@ public interface ErpPurchaseReturnItemMapper extends BaseMapperX> result = selectMaps(new QueryWrapper() - .select("order_item_id, SUM(count) AS sumCount") + .select("order_item_id, SUM(count) AS sum_count") .groupBy("order_item_id") .in("return_id", returnIds)); // 获得数量 - return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sum_count")); } } \ No newline at end of file diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java index 9cd5dede0d..7872bb2b9d 100644 --- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java +++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java @@ -46,11 +46,11 @@ public interface ErpSaleOutItemMapper extends BaseMapperX { } // SQL sum 查询 List> result = selectMaps(new QueryWrapper() - .select("order_item_id, SUM(count) AS sumCount") + .select("order_item_id, SUM(count) AS sum_count") .groupBy("order_item_id") .in("out_id", outIds)); // 获得数量 - return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sum_count")); } } \ No newline at end of file diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java index fdc5729643..609ee2445e 100644 --- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java +++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java @@ -46,11 +46,11 @@ public interface ErpSaleReturnItemMapper extends BaseMapperX> result = selectMaps(new QueryWrapper() - .select("order_item_id, SUM(count) AS sumCount") + .select("order_item_id, SUM(count) AS sum_count") .groupBy("order_item_id") .in("return_id", returnIds)); // 获得数量 - return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sumCount")); + return convertMap(result, obj -> (Long) obj.get("order_item_id"), obj -> (BigDecimal) obj.get("sum_count")); } } \ No newline at end of file diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java index 0ebc985979..63ff1ca5f4 100644 --- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java +++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java @@ -52,13 +52,13 @@ public interface ErpStockMapper extends BaseMapperX { default BigDecimal selectSumByProductId(Long productId) { // SQL sum 查询 List> result = selectMaps(new QueryWrapper() - .select("SUM(count) AS sumCount") + .select("SUM(count) AS sum_count") .eq("product_id", productId)); // 获得数量 if (CollUtil.isEmpty(result)) { return BigDecimal.ZERO; } - return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "sumCount", 0D)); + return BigDecimal.valueOf(MapUtil.getDouble(result.get(0), "sum_count", 0D)); } } \ No newline at end of file From 65205144269ef5310460e9dcb77b30e0547a7ceb Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 15:16:31 +0800 Subject: [PATCH 14/22] =?UTF-8?q?fix=EF=BC=9A=E3=80=90system=E3=80=91?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20node=20=E7=9A=84=20parentId=20=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=E4=B8=8B=E7=9A=84=E5=85=BC=E5=AE=B9=E6=80=A7=EF=BC=8C?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=20https://t.zsxq.com/ktTUO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/trade/convert/order/TradeOrderConvert.java | 3 +-- .../trade/service/brokerage/BrokerageRecordServiceImpl.java | 2 +- .../iocoder/yudao/module/system/convert/auth/AuthConvert.java | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index c90d9ed81a..0e2380a463 100644 --- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -265,8 +265,7 @@ public interface TradeOrderConvert { ProductSpuRespDTO spu, ProductSkuRespDTO sku) { BrokerageAddReqBO bo = new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId()) .setBasePrice(item.getPayPrice()) - .setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName())) - .setFirstFixedPrice(0).setSecondFixedPrice(0); + .setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName())); if (BooleanUtil.isTrue(spu.getSubCommissionType())) { // 特殊:单独设置的佣金需要乘以购买数量。关联 https://gitee.com/yudaocode/yudao-mall-uniapp/issues/ICY7SJ bo.setFirstFixedPrice(sku.getFirstBrokeragePrice() * item.getCount()) diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java index 93f99c94fb..ed314c3ac0 100644 --- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java @@ -142,7 +142,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { */ int calculatePrice(Integer basePrice, Integer percent, Integer fixedPrice) { // 1. 优先使用固定佣金 - if (fixedPrice != null && fixedPrice > 0) { + if (fixedPrice != null && fixedPrice >= 0) { return ObjectUtil.defaultIfNull(fixedPrice, 0); } // 2. 根据比例计算佣金 diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java index 72c8cb187f..925013c5e0 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.system.convert.auth; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; @@ -61,7 +62,7 @@ public interface AuthConvert { Map treeNodeMap = new LinkedHashMap<>(); menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); // 处理父子关系 - treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> { + treeNodeMap.values().stream().filter(node -> ObjUtil.notEqual(node.getParentId(), ID_ROOT)).forEach(childNode -> { // 获得父节点 AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId()); if (parentNode == null) { From cfcf0dc1075994df2d824a1f28b5985a19ad910b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 15:21:14 +0800 Subject: [PATCH 15/22] =?UTF-8?q?fix=EF=BC=9A=E3=80=90framework=E3=80=91?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E7=9A=84=E5=8D=95=E6=B5=8B?= =?UTF-8?q?=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 --- .../datapermission/core/rule/dept/DeptDataPermissionRule.java | 3 --- .../core/rule/dept/DeptDataPermissionRuleTest.java | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java index 8cfad28697..2e209e6ad7 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; -import net.sf.jsqlparser.expression.NullValue; import net.sf.jsqlparser.expression.operators.conditional.OrExpression; import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; @@ -60,8 +59,6 @@ public class DeptDataPermissionRule implements DataPermissionRule { private static final String DEPT_COLUMN_NAME = "dept_id"; private static final String USER_COLUMN_NAME = "user_id"; - static final Expression EXPRESSION_NULL = new NullValue(); - private final PermissionCommonApi permissionApi; /** diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java index 7faae00877..3c3db4e1f9 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java @@ -19,7 +19,6 @@ import org.mockito.MockedStatic; import java.util.Map; -import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule.EXPRESSION_NULL; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static org.junit.jupiter.api.Assertions.*; @@ -150,7 +149,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { // 调用 Expression expression = rule.getExpression(tableName, tableAlias); // 断言 - assertSame(EXPRESSION_NULL, expression); + assertEquals("null = null", expression.toString()); assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } } From 3db0c41bf3667749fad2655f32ed436c9b3c7bcc Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 15:27:58 +0800 Subject: [PATCH 16/22] =?UTF-8?q?feat=EF=BC=9A=E3=80=90mall=E3=80=91?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=A2=E5=8D=95=E6=97=A5=E5=BF=97=E5=88=87?= =?UTF-8?q?=E9=9D=A2=E4=B8=AD=E7=9A=84=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91=EF=BC=8C=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=20https://gitee.com/zhijiantianya/yudao-cloud/pulls/231/files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../order/core/aop/TradeOrderLogAspect.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 5a8d26e944..74f2d42d59 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 @@ -65,11 +65,17 @@ public class TradeOrderLogAspect { public void doAfterReturning(JoinPoint joinPoint, TradeOrderLog orderLog) { try { // 1.1 操作用户 - Integer userType = getUserType(); - Long userId = getUserId(); + Integer userType = USER_TYPE.get(); + if (ObjectUtil.isNull(userType)) { + userType = getUserType(); + } + Long userId = USER_ID.get(); + if (ObjectUtil.isNull(userId)) { + userId = getUserId(); + } // 1.2 订单信息 Long orderId = ORDER_ID.get(); - if (orderId == null) { // 如果未设置,只有注解,说明不需要记录日志 + if (ObjectUtil.isNull(orderId)) { // 如果未设置,只有注解,说明不需要记录日志 return; } Integer beforeStatus = BEFORE_STATUS.get(); @@ -136,4 +142,4 @@ public class TradeOrderLogAspect { EXTS.remove(); } -} +} \ No newline at end of file From f743ffd195df4d38c19eb3a97c1feea159c7cb05 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 15:43:52 +0800 Subject: [PATCH 17/22] =?UTF-8?q?feat=EF=BC=9A=E3=80=90system=E3=80=91?= =?UTF-8?q?=E5=8F=91=E9=80=81=E9=82=AE=E4=BB=B6=E6=97=B6=EF=BC=8C=E6=90=BA?= =?UTF-8?q?=E5=B8=A6=E9=99=84=E4=BB=B6=EF=BC=8C=E5=AF=B9=E5=BA=94=20https:?= =?UTF-8?q?//gitee.com/zhijiantianya/yudao-cloud/pulls/233?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/api/mail/MailSendApiImpl.java | 4 +-- .../mail/dto/MailSendSingleToUserReqDTO.java | 9 +++-- .../mq/message/mail/MailSendMessage.java | 10 ++++-- .../system/mq/producer/mail/MailProducer.java | 29 ++++++++-------- .../system/service/mail/MailSendService.java | 17 +++++++--- .../service/mail/MailSendServiceImpl.java | 8 +++-- .../service/mail/MailSendServiceImplTest.java | 33 ++++++++----------- 7 files changed, 60 insertions(+), 50 deletions(-) diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java index 59bb505891..ebb10800fd 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/MailSendApiImpl.java @@ -23,14 +23,14 @@ public class MailSendApiImpl implements MailSendApi { public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) { return mailSendService.sendSingleMailToAdmin(reqDTO.getUserId(), reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(), - reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + reqDTO.getTemplateCode(), reqDTO.getTemplateParams(), reqDTO.getAttachments()); } @Override public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) { return mailSendService.sendSingleMailToMember(reqDTO.getUserId(), reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(), - reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); + reqDTO.getTemplateCode(), reqDTO.getTemplateParams(), reqDTO.getAttachments()); } } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java index 2d67a78087..0b7b125f9a 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.system.api.mail.dto; -import lombok.Data; - import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotNull; +import lombok.Data; +import java.io.File; import java.util.List; import java.util.Map; @@ -47,4 +47,9 @@ public class MailSendSingleToUserReqDTO { */ private Map templateParams; + /** + * 附件 + */ + private File[] attachments; + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java index 03a4b7f198..dcf3588583 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java @@ -1,12 +1,11 @@ package cn.iocoder.yudao.module.system.mq.message.mail; -import lombok.Data; - import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import lombok.Data; +import java.io.File; import java.util.Collection; -import java.util.List; /** * 邮箱发送消息 @@ -55,4 +54,9 @@ public class MailSendMessage { @NotEmpty(message = "邮件内容不能为空") private String content; + /** + * 附件 + */ + private File[] attachments; + } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java index 07aabb00a8..4173734a7b 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java @@ -1,16 +1,13 @@ package cn.iocoder.yudao.module.system.mq.producer.mail; import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; -import jakarta.annotation.Resource; - +import java.io.File; import java.util.Collection; -import java.util.List; - -import static java.util.Collections.singletonList; /** * Mail 邮件相关消息的 Producer @@ -28,23 +25,25 @@ public class MailProducer { /** * 发送 {@link MailSendMessage} 消息 * - * @param sendLogId 发送日志编码 - * @param toMails 接收邮件地址 - * @param ccMails 抄送邮件地址 - * @param bccMails 密送邮件地址 - * @param accountId 邮件账号编号 - * @param nickname 邮件发件人 - * @param title 邮件标题 - * @param content 邮件内容 + * @param sendLogId 发送日志编码 + * @param toMails 接收邮件地址 + * @param ccMails 抄送邮件地址 + * @param bccMails 密送邮件地址 + * @param accountId 邮件账号编号 + * @param nickname 邮件发件人 + * @param title 邮件标题 + * @param content 邮件内容 + * @param attachments 附件 */ public void sendMailSendMessage(Long sendLogId, Collection toMails, Collection ccMails, Collection bccMails, - Long accountId, String nickname, String title, String content) { + Long accountId, String nickname, String title, String content, + File[] attachments) { MailSendMessage message = new MailSendMessage() .setLogId(sendLogId) .setToMails(toMails).setCcMails(ccMails).setBccMails(bccMails) .setAccountId(accountId).setNickname(nickname) - .setTitle(title).setContent(content); + .setTitle(title).setContent(content).setAttachments(attachments); applicationContext.publishEvent(message); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java index 1b600bc90c..c94de6d27e 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.mail; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; +import java.io.File; import java.util.Collection; import java.util.Map; @@ -23,13 +24,15 @@ public interface MailSendService { * @param bccMails 密送邮箱 * @param templateCode 邮件模版编码 * @param templateParams 邮件模版参数 + * @param attachments 附件 * @return 发送日志编号 */ default Long sendSingleMailToAdmin(Long userId, Collection toMails, Collection ccMails, Collection bccMails, - String templateCode, Map templateParams) { + String templateCode, Map templateParams, + File... attachments) { return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.ADMIN.getValue(), - templateCode, templateParams); + templateCode, templateParams, attachments); } /** @@ -41,13 +44,15 @@ public interface MailSendService { * @param bccMails 密送邮箱 * @param templateCode 邮件模版编码 * @param templateParams 邮件模版参数 + * @param attachments 附件 * @return 发送日志编号 */ default Long sendSingleMailToMember(Long userId, Collection toMails, Collection ccMails, Collection bccMails, - String templateCode, Map templateParams) { + String templateCode, Map templateParams, + File... attachments) { return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.MEMBER.getValue(), - templateCode, templateParams); + templateCode, templateParams, attachments); } /** @@ -60,11 +65,13 @@ public interface MailSendService { * @param userType 用户类型 * @param templateCode 邮件模版编码 * @param templateParams 邮件模版参数 + * @param attachments 附件 * @return 发送日志编号 */ Long sendSingleMail(Collection toMails, Collection ccMails, Collection bccMails, Long userId, Integer userType, - String templateCode, Map templateParams); + String templateCode, Map templateParams, + File... attachments); /** * 执行真正的邮件发送 diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java index 682696f932..310ae7e282 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java @@ -20,6 +20,7 @@ import org.dromara.hutool.extra.mail.MailUtil; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.io.File; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Map; @@ -56,7 +57,8 @@ public class MailSendServiceImpl implements MailSendService { @Override public Long sendSingleMail(Collection toMails, Collection ccMails, Collection bccMails, Long userId, Integer userType, - String templateCode, Map templateParams) { + String templateCode, Map templateParams, + File... attachments) { // 1.1 校验邮箱模版是否合法 MailTemplateDO template = validateMailTemplate(templateCode); // 1.2 校验邮箱账号是否合法 @@ -94,7 +96,7 @@ public class MailSendServiceImpl implements MailSendService { // 发送 MQ 消息,异步执行发送短信 if (isSend) { mailProducer.sendMailSendMessage(sendLogId, toMailSet, ccMailSet, bccMailSet, - account.getId(), template.getNickname(), title, content); + account.getId(), template.getNickname(), title, content, attachments); } return sendLogId; } @@ -123,7 +125,7 @@ public class MailSendServiceImpl implements MailSendService { // 2. 发送邮件 try { String messageId = MailUtil.send(mailAccount, message.getToMails(), message.getCcMails(), message.getBccMails(), - message.getTitle(), message.getContent(), true); + message.getTitle(), message.getContent(), true, message.getAttachments()); // 3. 更新结果(成功) mailLogService.updateMailSendResult(message.getLogId(), messageId, null); } catch (Exception e) { diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java index 459568360d..6da1b8414f 100644 --- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java +++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java @@ -13,13 +13,15 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; import cn.iocoder.yudao.module.system.service.member.MemberService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import org.assertj.core.util.Lists; -import org.dromara.hutool.extra.mail.*; +import org.dromara.hutool.extra.mail.MailAccount; +import org.dromara.hutool.extra.mail.MailUtil; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedStatic; +import java.io.File; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -106,7 +108,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { // 调用 Long resultMailLogId = mailSendService.sendSingleMail(toMails, ccMails, bccMails, userId, - UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, (File[]) null); // 断言 assertEquals(mailLogId, resultMailLogId); // 断言调用 @@ -114,7 +116,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { argThat(toMailSet -> toMailSet.contains(user.getEmail()) && toMailSet.contains("admin@test.com")), argThat(ccMailSet -> ccMailSet.contains("cc@test.com")), argThat(bccMailSet -> bccMailSet.contains("bcc@test.com")), - eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); + eq(account.getId()), eq(template.getNickname()), eq(title), eq(content), isNull()); } /** @@ -156,7 +158,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId); // 调用 - Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams); + Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams, (java.io.File[]) null); // 断言 assertEquals(mailLogId, resultMailLogId); // 断言调用 @@ -164,7 +166,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { argThat(toMailSet -> toMailSet.contains(mail)), argThat(Collection::isEmpty), argThat(Collection::isEmpty), - eq(account.getId()), eq(template.getNickname()), eq(title), eq(content)); + eq(account.getId()), eq(template.getNickname()), eq(title), eq(content), isNull()); } /** @@ -206,12 +208,12 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { eq(account), eq(template), eq(content), eq(templateParams), eq(false))).thenReturn(mailLogId); // 调用 - Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams); + Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams, (java.io.File[]) null); // 断言 assertEquals(mailLogId, resultMailLogId); // 断言调用 verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), any(), any(), any(), - anyLong(), anyString(), anyString(), anyString()); + anyLong(), anyString(), anyString(), anyString(), any()); } @Test @@ -261,7 +263,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { // 调用,并断言异常 assertServiceException(() -> mailSendService.sendSingleMail(toMails, null, null, userId, - UserTypeEnum.ADMIN.getValue(), templateCode, templateParams), + UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, (java.io.File[]) null), MAIL_SEND_MAIL_NOT_EXISTS); } @@ -288,7 +290,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); return true; }), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()), - eq(message.getTitle()), eq(message.getContent()), eq(true))) + eq(message.getTitle()), eq(message.getContent()), eq(true), eq(message.getAttachments()))) .thenReturn(messageId); // 调用 @@ -310,17 +312,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { // mock 方法(发送邮件) Exception e = new NullPointerException("啦啦啦"); - mailUtilMock.when(() -> MailUtil.send(argThat(mailAccount -> { - assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom()); - assertTrue(mailAccount.isAuth()); - assertEquals(account.getUsername(), mailAccount.getUser()); - assertArrayEquals(account.getPassword().toCharArray(), mailAccount.getPass()); - assertEquals(account.getHost(), mailAccount.getHost()); - assertEquals(account.getPort(), mailAccount.getPort()); - assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); - return true; - }), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()), - eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e); + mailUtilMock.when(() -> MailUtil.send(any(MailAccount.class), any(), any(), any(), + any(), any(), eq(true), any(java.io.File[].class))).thenThrow(e); // 调用 mailSendService.doSendMail(message); From 76477bbb1844bdf390a4c4d2dd4e8f3e77107f9d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 16:01:38 +0800 Subject: [PATCH 18/22] =?UTF-8?q?feat=EF=BC=9A=E3=80=90report=E3=80=91?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=AF=B9=E6=8A=A5=E8=A1=A8=E7=9A=84=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E9=9B=86=E6=88=90=EF=BC=8C=E5=AF=B9=E5=BA=94=20https:?= =?UTF-8?q?//t.zsxq.com/yzlkA=20=E5=8F=8D=E9=A6=88=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/JmReportTokenServiceImpl.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/yudao-module-report/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java b/yudao-module-report/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java index e5f63967d8..50673b57f5 100644 --- a/yudao-module-report/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java +++ b/yudao-module-report/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.report.framework.jmreport.core.service; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi; +import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO; import cn.iocoder.yudao.framework.common.biz.system.permission.PermissionCommonApi; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; @@ -10,9 +12,6 @@ import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi; -import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; @@ -158,4 +157,33 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI { return StrUtil.toStringOrNull(loginUser.getTenantId()); } + @Override + public String[] getPermissions(String token) { + // 设置租户上下文 + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser == null) { + return null; + } + TenantContextHolder.setTenantId(loginUser.getTenantId()); + + // 参见文档 https://help.jimureport.com/prodSafe/ 文档 + // 适配:如果是本系统的管理员,则返回积木报表(仪表盘/大屏设计器)的所有权限指令 + // 如果不处理,会碰到 https://t.zsxq.com/yzlkA 反馈的问题 + Long userId = SecurityFrameworkUtils.getLoginUserId(); + if (permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode())) { + return new String[]{ + "drag:datasource:testConnection", // 数据库连接测试 + "drag:datasource:saveOrUpate", // 数据源保存 + "drag:datasource:delete", // 数据源删除 + "drag:analysis:sql", // SQL解析 + "drag:design:getTotalData", // 展示Online表单数据 + "drag:dataset:save", // 数据集保存 + "drag:dataset:delete", // 数据集删除 + "onl:drag:clear:recovery", // 清空回收站 + "onl:drag:page:delete" // 数据删除 + }; + } + return null; + } + } From 258b4c3d60cb2ed0ff927e5df4e6ad5af75fbf7e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 16:35:02 +0800 Subject: [PATCH 19/22] =?UTF-8?q?fix=EF=BC=9A=E3=80=90system=E3=80=91?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=94=AF=E4=BB=98=E5=9B=9E=E8=B0=83=E4=B8=8E?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E4=BF=A1=E6=81=AF=E4=B8=8A=E4=BC=A0=E4=B9=8B?= =?UTF-8?q?=E9=97=B4=E7=9A=84=E6=97=B6=E9=97=B4=E5=B7=AE=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=20uploadWxaOrderShippingInfo=20=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../social/SocialClientServiceImpl.java | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) 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 fc81be23b1..0a8e30d714 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 @@ -102,6 +102,19 @@ public class SocialClientServiceImpl implements SocialClientService { @Value("${yudao.wxa-subscribe-message.miniprogram-state:formal}") public String miniprogramState; + /** + * 上传发货信息重试次数 + */ + private static final int UPLOAD_SHIPPING_INFO_MAX_RETRIES = 5; + /** + * 上传发货信息重试间隔 + */ + private static final Duration UPLOAD_SHIPPING_INFO_RETRY_INTERVAL = Duration.ofMillis(500L); + /** + * 微信错误码:支付单不存在 + */ + private static final int WX_ERR_CODE_PAY_ORDER_NOT_EXIST = 10060001; + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") @Autowired(required = false) // 由于 justauth.enable 配置项,可以关闭 AuthRequestFactory 的功能,所以这里只能不强制注入 private AuthRequestFactory authRequestFactory; @@ -368,16 +381,34 @@ public class SocialClientServiceImpl implements SocialClientService { .payer(PayerBean.builder().openid(reqDTO.getOpenid()).build()) .uploadTime(ZonedDateTime.now().format(UTC_MS_WITH_XXX_OFFSET_FORMATTER)) .build(); - try { - WxMaOrderShippingInfoBaseResponse response = service.getWxMaOrderShippingService().upload(request); - if (response.getErrCode() != 0) { + // 重试机制:解决支付回调与订单信息上传之间的时间差导致的 10060001 错误 + // 对应 ISSUE:https://gitee.com/zhijiantianya/yudao-cloud/pulls/230 + for (int attempt = 1; attempt <= UPLOAD_SHIPPING_INFO_MAX_RETRIES; attempt++) { + try { + WxMaOrderShippingInfoBaseResponse response = service.getWxMaOrderShippingService().upload(request); + // 成功,直接返回 + if (response.getErrCode() == 0) { + log.info("[uploadWxaOrderShippingInfo][上传微信小程序发货信息成功:request({}) response({})]", request, response); + return; + } + // 如果是 10060001 错误(支付单不存在)且还有重试次数,则等待后重试 + if (response.getErrCode() == WX_ERR_CODE_PAY_ORDER_NOT_EXIST && attempt < UPLOAD_SHIPPING_INFO_MAX_RETRIES) { + log.warn("[uploadWxaOrderShippingInfo][第 {} 次尝试失败,支付单不存在,{} 后重试:request({}) response({})]", + attempt, UPLOAD_SHIPPING_INFO_RETRY_INTERVAL, request, response); + Thread.sleep(UPLOAD_SHIPPING_INFO_RETRY_INTERVAL.toMillis()); + continue; + } + // 其他错误或重试次数用尽,抛出异常 log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败:request({}) response({})]", request, response); throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, response.getErrMsg()); + } catch (WxErrorException ex) { + log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败:request({})]", request, ex); + throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, ex.getError().getErrorMsg()); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + log.error("[uploadWxaOrderShippingInfo][重试等待被中断:request({})]", request, ex); + throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, "重试等待被中断"); } - log.info("[uploadWxaOrderShippingInfo][上传微信小程序发货信息成功:request({}) response({})]", request, response); - } catch (WxErrorException ex) { - log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败:request({})]", request, ex); - throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, ex.getError().getErrorMsg()); } } From 90f0ea13e0c1d6323012d6803930aa10b3a9e6d9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 16:54:04 +0800 Subject: [PATCH 20/22] =?UTF-8?q?fix=EF=BC=9A=E3=80=90system=E3=80=91?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20node=20=E7=9A=84=20parentId=20=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=E4=B8=8B=E7=9A=84=E5=85=BC=E5=AE=B9=E6=80=A7=EF=BC=8C?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=20https://t.zsxq.com/ktTUO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/system/convert/auth/AuthConvert.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java index 925013c5e0..b89627573e 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java @@ -40,8 +40,6 @@ public interface AuthConvert { .build(); } - AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu); - /** * 将菜单列表,构建成菜单树 * @@ -60,7 +58,8 @@ public interface AuthConvert { // 构建菜单树 // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 Map treeNodeMap = new LinkedHashMap<>(); - menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); + menuList.forEach(menu -> treeNodeMap.put(menu.getId(), + BeanUtils.toBean(menu, AuthPermissionInfoRespVO.MenuVO.class))); // 处理父子关系 treeNodeMap.values().stream().filter(node -> ObjUtil.notEqual(node.getParentId(), ID_ROOT)).forEach(childNode -> { // 获得父节点 From 9fa9183f2eb006136f793238642e2daae7dff1fe Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 17:21:07 +0800 Subject: [PATCH 21/22] =?UTF-8?q?feat=EF=BC=9A=E3=80=90system=E3=80=91?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20MailSendServiceImplTest=20=E7=9A=84?= =?UTF-8?q?=E5=8D=95=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/mail/MailSendServiceImplTest.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java index 6da1b8414f..9d67c844e1 100644 --- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java +++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java @@ -312,8 +312,17 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { // mock 方法(发送邮件) Exception e = new NullPointerException("啦啦啦"); - mailUtilMock.when(() -> MailUtil.send(any(MailAccount.class), any(), any(), any(), - any(), any(), eq(true), any(java.io.File[].class))).thenThrow(e); + mailUtilMock.when(() -> MailUtil.send(argThat(mailAccount -> { + assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom()); + assertTrue(mailAccount.isAuth()); + assertEquals(account.getUsername(), mailAccount.getUser()); + assertArrayEquals(account.getPassword().toCharArray(), mailAccount.getPass()); + assertEquals(account.getHost(), mailAccount.getHost()); + assertEquals(account.getPort(), mailAccount.getPort()); + assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); + return true; + }), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()), + eq(message.getTitle()), eq(message.getContent()), eq(true), same(message.getAttachments()))).thenThrow(e); // 调用 mailSendService.doSendMail(message); From 17ec78f68a5a1eae7a985d7a1c207cf6a517e912 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 18 Jan 2026 17:58:34 +0800 Subject: [PATCH 22/22] =?UTF-8?q?fix=EF=BC=9A=E3=80=90pay=E3=80=91?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=92=B1=E5=8C=85=E6=B5=81=E6=B0=B4=E7=94=9F?= =?UTF-8?q?=E6=88=90=E9=80=BB=E8=BE=91=EF=BC=8C=E5=8C=BA=E5=88=86=E5=85=85?= =?UTF-8?q?=E5=80=BC=E9=80=80=E6=AC=BE=E4=B8=8E=E6=B6=88=E8=B4=B9=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E6=83=85=E5=86=B5=EF=BC=8C=E5=AF=B9=E5=BA=94=20https:?= =?UTF-8?q?//t.zsxq.com/OJk9m?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/pay/service/wallet/PayWalletServiceImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 58036eebc9..445f06a40f 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 @@ -174,7 +174,11 @@ public class PayWalletServiceImpl implements PayWalletService { } // 3. 生成钱包流水 - Integer afterBalance = payWallet.getBalance() - price; + // 情况一:充值退款:balance 在冻结时已扣,updateWhenRechargeRefund 只扣 freeze_price,所以 afterBalance 不变。https://t.zsxq.com/OJk9m + // 情况二:消费支付:updateWhenConsumption 从 balance 扣,所以 afterBalance = balance - price + Integer afterBalance = bizType == PayWalletBizTypeEnum.RECHARGE_REFUND + ? payWallet.getBalance() + : payWallet.getBalance() - price; WalletTransactionCreateReqBO bo = new WalletTransactionCreateReqBO().setWalletId(payWallet.getId()) .setPrice(-price).setBalance(afterBalance).setBizId(String.valueOf(bizId)) .setBizType(bizType.getType()).setTitle(bizType.getDescription());