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 7ec7a4a5c..921ad3833 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 @@ -57,8 +57,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; /** @@ -120,7 +118,7 @@ public class DeptDataPermissionRule implements DataPermissionRule { // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) - && Boolean.FALSE.equals(deptDataPermission.getSelf())) { + && Boolean.FALSE.equals(deptDataPermission.getSelf())) { return new EqualsTo(null, null); // WHERE null = null,可以保证返回的数据为空 } @@ -133,7 +131,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-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 1f4d1f152..5a80003a0 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 @@ -3,12 +3,12 @@ package cn.iocoder.yudao.framework.datapermission.core.rule.dept; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ReflectUtil; import cn.iocoder.yudao.framework.common.biz.system.permission.PermissionCommonApi; +import cn.iocoder.yudao.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.yudao.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import org.junit.jupiter.api.BeforeEach; @@ -20,7 +20,6 @@ import org.mockito.MockedStatic; import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -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.*; @@ -151,7 +150,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)); } } diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java index 722cc6ecf..6885fedf6 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java +++ b/yudao-module-ai/yudao-module-ai-server/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/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java index f2c683a50..a29f8f116 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiApiKeyDO.java +++ b/yudao-module-ai/yudao-module-ai-server/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/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java index 1b9ca867f..2b7daacda 100644 --- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java +++ b/yudao-module-ai/yudao-module-ai-server/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-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java index 20fcf5475..b35f18e56 100644 --- a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-server/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/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java index ebf67a46b..75582a054 100644 --- a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-server/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); diff --git a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 890a34bfe..5569f09a6 100644 --- a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -116,6 +116,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { .taskAssignee(String.valueOf(userId)) // 分配给自己 .active() .includeProcessVariables() + .taskTenantId(FlowableUtils.getTenantId()) .orderByTaskCreateTime().desc(); // 创建时间倒序 if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); diff --git a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java b/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java index 7787e8d70..7a5bb6e63 100644 --- a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinancePaymentItemMapper.java +++ b/yudao-module-erp/yudao-module-erp-server/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/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java b/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java index cb6082b0e..40ac88758 100644 --- a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/finance/ErpFinanceReceiptItemMapper.java +++ b/yudao-module-erp/yudao-module-erp-server/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/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java b/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java index 9140f9548..5a1431780 100644 --- a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseInItemMapper.java +++ b/yudao-module-erp/yudao-module-erp-server/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/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java b/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java index 2a8011900..30527d232 100644 --- a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseReturnItemMapper.java +++ b/yudao-module-erp/yudao-module-erp-server/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/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java b/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java index 9cd5dede0..7872bb2b9 100644 --- a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleOutItemMapper.java +++ b/yudao-module-erp/yudao-module-erp-server/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/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java b/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java index fdc572964..609ee2445 100644 --- a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/sale/ErpSaleReturnItemMapper.java +++ b/yudao-module-erp/yudao-module-erp-server/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/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java index 0ebc98597..63ff1ca5f 100644 --- a/yudao-module-erp/yudao-module-erp-server/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java +++ b/yudao-module-erp/yudao-module-erp-server/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 diff --git a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java b/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java index 5daa3972e..72bcfd1de 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileCreateReqVO.java +++ b/yudao-module-infra/yudao-module-infra-server/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/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java b/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java index a0357da15..17df49afb 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileRespVO.java +++ b/yudao-module-infra/yudao-module-infra-server/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/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java b/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java index 5cb666ef5..721978893 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java +++ b/yudao-module-infra/yudao-module-infra-server/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/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java b/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java index 289cae1e3..d278579ba 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-server/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/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index 703df8c5f..168db02c6 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-server/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; } diff --git a/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm b/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm index 194f17290..40087063c 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm +++ b/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm @@ -294,4 +294,3 @@ function handleReset() { emit('reset') } - diff --git a/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm b/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm index 60c844381..f1631447a 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm +++ b/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm @@ -107,6 +107,7 @@ + + + + + + diff --git a/yudao-module-mall/yudao-module-product-server/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-server/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java index bad799556..6267aea67 100755 --- a/yudao-module-mall/yudao-module-product-server/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-server/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); } diff --git a/yudao-module-mall/yudao-module-product-server/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-server/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 6e6ed2bde..b7b90578b 100755 --- a/yudao-module-mall/yudao-module-product-server/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-server/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()); // 默认状态为上架 diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java index f93149afb..7865725a7 100644 --- a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserCreateReqVO.java +++ b/yudao-module-mall/yudao-module-trade-server/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; } diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index c90d9ed81..0e2380a46 100644 --- a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-server/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-server/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java index 78ba227c4..74f2d42d5 100644 --- a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java +++ b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java @@ -142,4 +142,4 @@ public class TradeOrderLogAspect { EXTS.remove(); } -} +} \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java index fbce5cbd4..5d97d70f8 100644 --- a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-server/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-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java index 58036eebc..445f06a40 100644 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-server/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()); diff --git a/yudao-module-report/yudao-module-report-server/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java b/yudao-module-report/yudao-module-report-server/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java index afd1e87b2..41eb4eef7 100644 --- a/yudao-module-report/yudao-module-report-server/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java +++ b/yudao-module-report/yudao-module-report-server/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()).getCheckedData()) { + 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; + } + } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java index f5be00c73..0b7b125f9 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java @@ -36,6 +36,7 @@ public class MailSendSingleToUserReqDTO { */ private List<@Email String> bccMails; + /** * 邮件模板编号 */ @@ -45,8 +46,9 @@ public class MailSendSingleToUserReqDTO { * 邮件模板参数 */ private Map templateParams; + /** - * 附件内容 + * 附件 */ private File[] attachments; diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java index 72c8cb187..b89627573 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java +++ b/yudao-module-system/yudao-module-system-server/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; @@ -39,8 +40,6 @@ public interface AuthConvert { .build(); } - AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu); - /** * 将菜单列表,构建成菜单树 * @@ -59,9 +58,10 @@ 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 -> !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) { diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java index 4bd87fde5..dcf358858 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java +++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java @@ -53,8 +53,9 @@ public class MailSendMessage { */ @NotEmpty(message = "邮件内容不能为空") private String content; + /** - * 邮件附件 + * 附件 */ private File[] attachments; diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java index 7616f2c07..4173734a7 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java +++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java @@ -25,24 +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, File[] attachments) { + 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) - .setAttachments(attachments); + .setTitle(title).setContent(content).setAttachments(attachments); applicationContext.publishEvent(message); } diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java index 9863a4f43..c94de6d27 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java +++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java @@ -24,11 +24,13 @@ 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, File... attachments) { + String templateCode, Map templateParams, + File... attachments) { return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, attachments); } @@ -42,11 +44,13 @@ 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, File... attachments) { + String templateCode, Map templateParams, + File... attachments) { return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams, attachments); } @@ -61,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, File... attachments); + String templateCode, Map templateParams, + File... attachments); /** * 执行真正的邮件发送 diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java index 8a728eb81..310ae7e28 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java +++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java @@ -121,7 +121,7 @@ public class MailSendServiceImpl implements MailSendService { public void doSendMail(MailSendMessage message) { // 1. 创建发送账号 MailAccountDO account = validateMailAccount(message.getAccountId()); - MailAccount mailAccount = buildMailAccount(account, message.getNickname()); + MailAccount mailAccount = buildMailAccount(account, message.getNickname()); // 2. 发送邮件 try { String messageId = MailUtil.send(mailAccount, message.getToMails(), message.getCcMails(), message.getBccMails(), diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java index fc81be23b..0a8e30d71 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java +++ b/yudao-module-system/yudao-module-system-server/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()); } } diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index ac1d88be9..5d332c4b7 100644 --- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -44,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.*; @@ -284,11 +285,14 @@ 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 = null; + if (reqVO.getRoleId() != null) { + userIds = permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())); + if (CollUtil.isEmpty(userIds)) { + return PageResult.empty(); + } } + // 分页查询 return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()), userIds); } @@ -484,12 +488,15 @@ 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 = StrUtil.blankToDefault(importUser.getUsername(), "第 " + currentIndex + " 行"); + respVO.getFailureUsernames().put(key, ex.getMessage()); return; } // 2.1.2 校验,判断是否有不符合的原因 diff --git a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java index 34cbee4cf..9d67c844e 100644 --- a/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-server/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java @@ -263,7 +263,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { // 调用,并断言异常 assertServiceException(() -> mailSendService.sendSingleMail(toMails, null, null, userId, - UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, (java.io.File[]) null), + UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, (java.io.File[]) null), MAIL_SEND_MAIL_NOT_EXISTS); } @@ -280,17 +280,17 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest { // mock 方法(发送邮件) String messageId = randomString(); 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), eq(message.getAttachments()))) + 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), eq(message.getAttachments()))) .thenReturn(messageId); // 调用