Commit dad0cc4cb1d00840b5df2c80b549e3ac1bafaac2
Merge branch 'develop' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17
Showing
30 changed files
with
270 additions
and
138 deletions
yudao-dependencies/pom.xml
| @@ -71,7 +71,7 @@ | @@ -71,7 +71,7 @@ | ||
| 71 | <!-- 三方云服务相关 --> | 71 | <!-- 三方云服务相关 --> |
| 72 | <commons-io.version>2.17.0</commons-io.version> | 72 | <commons-io.version>2.17.0</commons-io.version> |
| 73 | <commons-compress.version>1.27.1</commons-compress.version> | 73 | <commons-compress.version>1.27.1</commons-compress.version> |
| 74 | - <aws-java-sdk-s3.version>1.12.777</aws-java-sdk-s3.version> | 74 | + <awssdk.version>2.30.14</awssdk.version> |
| 75 | <justauth.version>2.0.5</justauth.version> | 75 | <justauth.version>2.0.5</justauth.version> |
| 76 | <jimureport.version>1.8.1</jimureport.version> | 76 | <jimureport.version>1.8.1</jimureport.version> |
| 77 | <weixin-java.version>4.7.2.B</weixin-java.version> | 77 | <weixin-java.version>4.7.2.B</weixin-java.version> |
| @@ -553,9 +553,9 @@ | @@ -553,9 +553,9 @@ | ||
| 553 | 553 | ||
| 554 | <!-- 三方云服务相关 --> | 554 | <!-- 三方云服务相关 --> |
| 555 | <dependency> | 555 | <dependency> |
| 556 | - <groupId>com.amazonaws</groupId> | ||
| 557 | - <artifactId>aws-java-sdk-s3</artifactId> | ||
| 558 | - <version>${aws-java-sdk-s3.version}</version> | 556 | + <groupId>software.amazon.awssdk</groupId> |
| 557 | + <artifactId>s3</artifactId> | ||
| 558 | + <version>${awssdk.version}</version> | ||
| 559 | </dependency> | 559 | </dependency> |
| 560 | 560 | ||
| 561 | <dependency> | 561 | <dependency> |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
| @@ -11,6 +11,7 @@ import java.util.function.*; | @@ -11,6 +11,7 @@ import java.util.function.*; | ||
| 11 | import java.util.stream.Collectors; | 11 | import java.util.stream.Collectors; |
| 12 | import java.util.stream.Stream; | 12 | import java.util.stream.Stream; |
| 13 | 13 | ||
| 14 | +import static cn.hutool.core.convert.Convert.toCollection; | ||
| 14 | import static java.util.Arrays.asList; | 15 | import static java.util.Arrays.asList; |
| 15 | 16 | ||
| 16 | /** | 17 | /** |
| @@ -335,4 +336,17 @@ public class CollectionUtils { | @@ -335,4 +336,17 @@ public class CollectionUtils { | ||
| 335 | return list.stream().filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList()); | 336 | return list.stream().filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList()); |
| 336 | } | 337 | } |
| 337 | 338 | ||
| 339 | + /** | ||
| 340 | + * 转换为 LinkedHashSet | ||
| 341 | + * | ||
| 342 | + * @param <T> 元素类型 | ||
| 343 | + * @param elementType 集合中元素类型 | ||
| 344 | + * @param value 被转换的值 | ||
| 345 | + * @return {@link LinkedHashSet} | ||
| 346 | + */ | ||
| 347 | + @SuppressWarnings("unchecked") | ||
| 348 | + public static <T> LinkedHashSet<T> toLinkedHashSet(Class<T> elementType, Object value) { | ||
| 349 | + return (LinkedHashSet<T>) toCollection(LinkedHashSet.class, elementType, value); | ||
| 350 | + } | ||
| 351 | + | ||
| 338 | } | 352 | } |
| 339 | \ No newline at end of file | 353 | \ No newline at end of file |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/form/BpmTaskCandidateFormUserStrategy.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.form; | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.form; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.convert.Convert; | ||
| 4 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 5 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; | 5 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; |
| 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy; | 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy; |
| 7 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; | 7 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; |
| @@ -33,7 +33,7 @@ public class BpmTaskCandidateFormUserStrategy implements BpmTaskCandidateStrateg | @@ -33,7 +33,7 @@ public class BpmTaskCandidateFormUserStrategy implements BpmTaskCandidateStrateg | ||
| 33 | @Override | 33 | @Override |
| 34 | public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) { | 34 | public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) { |
| 35 | Object result = execution.getVariable(param); | 35 | Object result = execution.getVariable(param); |
| 36 | - return Convert.toSet(Long.class, result); | 36 | + return CollectionUtils.toLinkedHashSet(Long.class, result); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | @Override | 39 | @Override |
| @@ -41,7 +41,7 @@ public class BpmTaskCandidateFormUserStrategy implements BpmTaskCandidateStrateg | @@ -41,7 +41,7 @@ public class BpmTaskCandidateFormUserStrategy implements BpmTaskCandidateStrateg | ||
| 41 | String param, Long startUserId, String processDefinitionId, | 41 | String param, Long startUserId, String processDefinitionId, |
| 42 | Map<String, Object> processVariables) { | 42 | Map<String, Object> processVariables) { |
| 43 | Object result = processVariables == null ? null : processVariables.get(param); | 43 | Object result = processVariables == null ? null : processVariables.get(param); |
| 44 | - return Convert.toSet(Long.class, result); | 44 | + return CollectionUtils.toLinkedHashSet(Long.class, result); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | } | 47 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/other/BpmTaskCandidateExpressionStrategy.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other; | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.convert.Convert; | 3 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 4 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; | 4 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; |
| 5 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; | 5 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; |
| 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; | 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; |
| @@ -37,7 +37,7 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat | @@ -37,7 +37,7 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat | ||
| 37 | @Override | 37 | @Override |
| 38 | public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) { | 38 | public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) { |
| 39 | Object result = FlowableUtils.getExpressionValue(execution, param); | 39 | Object result = FlowableUtils.getExpressionValue(execution, param); |
| 40 | - return Convert.toSet(Long.class, result); | 40 | + return CollectionUtils.toLinkedHashSet(Long.class, result); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | @Override | 43 | @Override |
| @@ -46,7 +46,7 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat | @@ -46,7 +46,7 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat | ||
| 46 | Map<String, Object> variables = processVariables == null ? new HashMap<>() : processVariables; | 46 | Map<String, Object> variables = processVariables == null ? new HashMap<>() : processVariables; |
| 47 | try { | 47 | try { |
| 48 | Object result = FlowableUtils.getExpressionValue(variables, param); | 48 | Object result = FlowableUtils.getExpressionValue(variables, param); |
| 49 | - return Convert.toSet(Long.class, result); | 49 | + return CollectionUtils.toLinkedHashSet(Long.class, result); |
| 50 | } catch (FlowableException ex) { | 50 | } catch (FlowableException ex) { |
| 51 | // 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常, | 51 | // 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常, |
| 52 | log.warn("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex); | 52 | log.warn("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex); |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| @@ -6,7 +6,6 @@ import cn.hutool.core.lang.Assert; | @@ -6,7 +6,6 @@ import cn.hutool.core.lang.Assert; | ||
| 6 | import cn.hutool.core.util.*; | 6 | import cn.hutool.core.util.*; |
| 7 | import cn.hutool.extra.spring.SpringUtil; | 7 | import cn.hutool.extra.spring.SpringUtil; |
| 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 10 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; | 9 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 11 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 10 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 12 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | 11 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| @@ -882,6 +881,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -882,6 +881,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 882 | return; | 881 | return; |
| 883 | } | 882 | } |
| 884 | runExecutionIds.add(task.getExecutionId()); | 883 | runExecutionIds.add(task.getExecutionId()); |
| 884 | + | ||
| 885 | // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 | 885 | // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 |
| 886 | if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 | 886 | if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 |
| 887 | // 2.1.1 添加评论 | 887 | // 2.1.1 添加评论 |
yudao-module-infra/yudao-module-infra-biz/pom.xml
| @@ -115,9 +115,10 @@ | @@ -115,9 +115,10 @@ | ||
| 115 | <groupId>com.jcraft</groupId> | 115 | <groupId>com.jcraft</groupId> |
| 116 | <artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 --> | 116 | <artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 --> |
| 117 | </dependency> | 117 | </dependency> |
| 118 | + <!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 --> | ||
| 118 | <dependency> | 119 | <dependency> |
| 119 | - <groupId>com.amazonaws</groupId> | ||
| 120 | - <artifactId>aws-java-sdk-s3</artifactId><!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 --> | 120 | + <groupId>software.amazon.awssdk</groupId> |
| 121 | + <artifactId>s3</artifactId> | ||
| 121 | </dependency> | 122 | </dependency> |
| 122 | 123 | ||
| 123 | <dependency> | 124 | <dependency> |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java
| @@ -13,10 +13,13 @@ import lombok.Getter; | @@ -13,10 +13,13 @@ import lombok.Getter; | ||
| 13 | public enum CodegenFrontTypeEnum { | 13 | public enum CodegenFrontTypeEnum { |
| 14 | 14 | ||
| 15 | VUE2_ELEMENT_UI(10), // Vue2 Element UI 标准模版 | 15 | VUE2_ELEMENT_UI(10), // Vue2 Element UI 标准模版 |
| 16 | + | ||
| 16 | VUE3_ELEMENT_PLUS(20), // Vue3 Element Plus 标准模版 | 17 | VUE3_ELEMENT_PLUS(20), // Vue3 Element Plus 标准模版 |
| 18 | + | ||
| 17 | VUE3_VBEN2_ANTD_SCHEMA(30), // Vue3 VBEN2 + ANTD + Schema 模版 | 19 | VUE3_VBEN2_ANTD_SCHEMA(30), // Vue3 VBEN2 + ANTD + Schema 模版 |
| 20 | + | ||
| 18 | VUE3_VBEN5_ANTD_SCHEMA(40), // Vue3 VBEN5 + ANTD + schema 模版 | 21 | VUE3_VBEN5_ANTD_SCHEMA(40), // Vue3 VBEN5 + ANTD + schema 模版 |
| 19 | - VUE3_VBEN5_ANTD(50), // Vue3 VBEN5 + ANTD 模版 | 22 | + VUE3_VBEN5_ANTD_GENERAL(41), // Vue3 VBEN5 + ANTD 标准模版 |
| 20 | ; | 23 | ; |
| 21 | 24 | ||
| 22 | /** | 25 | /** |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java
| @@ -4,29 +4,31 @@ import cn.hutool.core.io.IoUtil; | @@ -4,29 +4,31 @@ import cn.hutool.core.io.IoUtil; | ||
| 4 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | import cn.hutool.http.HttpUtil; | 5 | import cn.hutool.http.HttpUtil; |
| 6 | import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; | 6 | import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; |
| 7 | -import com.amazonaws.HttpMethod; | ||
| 8 | -import com.amazonaws.auth.AWSStaticCredentialsProvider; | ||
| 9 | -import com.amazonaws.auth.BasicAWSCredentials; | ||
| 10 | -import com.amazonaws.client.builder.AwsClientBuilder; | ||
| 11 | -import com.amazonaws.services.s3.AmazonS3Client; | ||
| 12 | -import com.amazonaws.services.s3.AmazonS3ClientBuilder; | ||
| 13 | -import com.amazonaws.services.s3.model.ObjectMetadata; | ||
| 14 | -import com.amazonaws.services.s3.model.S3Object; | 7 | +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; |
| 8 | +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; | ||
| 9 | +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; | ||
| 10 | +import software.amazon.awssdk.core.sync.RequestBody; | ||
| 11 | +import software.amazon.awssdk.regions.Region; | ||
| 12 | +import software.amazon.awssdk.services.s3.S3Client; | ||
| 13 | +import software.amazon.awssdk.services.s3.S3Configuration; | ||
| 14 | +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; | ||
| 15 | +import software.amazon.awssdk.services.s3.model.GetObjectRequest; | ||
| 16 | +import software.amazon.awssdk.services.s3.model.PutObjectRequest; | ||
| 17 | +import software.amazon.awssdk.services.s3.presigner.S3Presigner; | ||
| 18 | +import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest; | ||
| 15 | 19 | ||
| 16 | -import java.io.ByteArrayInputStream; | ||
| 17 | -import java.util.Date; | ||
| 18 | -import java.util.concurrent.TimeUnit; | 20 | +import java.net.URI; |
| 21 | +import java.time.Duration; | ||
| 19 | 22 | ||
| 20 | /** | 23 | /** |
| 21 | * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 | 24 | * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 |
| 22 | - * <p> | ||
| 23 | - * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库 | ||
| 24 | * | 25 | * |
| 25 | * @author 芋道源码 | 26 | * @author 芋道源码 |
| 26 | */ | 27 | */ |
| 27 | public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | 28 | public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { |
| 28 | 29 | ||
| 29 | - private AmazonS3Client client; | 30 | + private S3Client client; |
| 31 | + private S3Presigner presigner; | ||
| 30 | 32 | ||
| 31 | public S3FileClient(Long id, S3FileClientConfig config) { | 33 | public S3FileClient(Long id, S3FileClientConfig config) { |
| 32 | super(id, config); | 34 | super(id, config); |
| @@ -38,31 +40,80 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | @@ -38,31 +40,80 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | ||
| 38 | if (StrUtil.isEmpty(config.getDomain())) { | 40 | if (StrUtil.isEmpty(config.getDomain())) { |
| 39 | config.setDomain(buildDomain()); | 41 | config.setDomain(buildDomain()); |
| 40 | } | 42 | } |
| 41 | - // 初始化客户端 | ||
| 42 | - client = (AmazonS3Client)AmazonS3ClientBuilder.standard() | ||
| 43 | - .withCredentials(buildCredentials()) | ||
| 44 | - .withEndpointConfiguration(buildEndpointConfiguration()) | 43 | + // 初始化 S3 客户端 |
| 44 | + Region region = Region.of("us-east-1"); // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错 | ||
| 45 | + AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( | ||
| 46 | + AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret())); | ||
| 47 | + URI endpoint = URI.create(buildEndpoint()); | ||
| 48 | + S3Configuration serviceConfiguration = S3Configuration.builder() // Path-style 访问 | ||
| 49 | + .pathStyleAccessEnabled(Boolean.TRUE.equals(config.getEnablePathStyleAccess())) | ||
| 50 | + .chunkedEncodingEnabled(false) // 禁用分块编码,参见 https://t.zsxq.com/kBy57 | ||
| 51 | + .build(); | ||
| 52 | + client = S3Client.builder() | ||
| 53 | + .credentialsProvider(credentialsProvider) | ||
| 54 | + .region(region) | ||
| 55 | + .endpointOverride(endpoint) | ||
| 56 | + .serviceConfiguration(serviceConfiguration) | ||
| 57 | + .build(); | ||
| 58 | + presigner = S3Presigner.builder() | ||
| 59 | + .credentialsProvider(credentialsProvider) | ||
| 60 | + .region(region) | ||
| 61 | + .endpointOverride(endpoint) | ||
| 62 | + .serviceConfiguration(serviceConfiguration) | ||
| 45 | .build(); | 63 | .build(); |
| 46 | } | 64 | } |
| 47 | 65 | ||
| 48 | - /** | ||
| 49 | - * 基于 config 秘钥,构建 S3 客户端的认证信息 | ||
| 50 | - * | ||
| 51 | - * @return S3 客户端的认证信息 | ||
| 52 | - */ | ||
| 53 | - private AWSStaticCredentialsProvider buildCredentials() { | ||
| 54 | - return new AWSStaticCredentialsProvider( | ||
| 55 | - new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret())); | 66 | + @Override |
| 67 | + public String upload(byte[] content, String path, String type) { | ||
| 68 | + // 构造 PutObjectRequest | ||
| 69 | + PutObjectRequest putRequest = PutObjectRequest.builder() | ||
| 70 | + .bucket(config.getBucket()) | ||
| 71 | + .key(path) | ||
| 72 | + .contentType(type) | ||
| 73 | + .contentLength((long) content.length) | ||
| 74 | + .build(); | ||
| 75 | + // 上传文件 | ||
| 76 | + client.putObject(putRequest, RequestBody.fromBytes(content)); | ||
| 77 | + // 拼接返回路径 | ||
| 78 | + return config.getDomain() + "/" + path; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @Override | ||
| 82 | + public void delete(String path) { | ||
| 83 | + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder() | ||
| 84 | + .bucket(config.getBucket()) | ||
| 85 | + .key(path) | ||
| 86 | + .build(); | ||
| 87 | + client.deleteObject(deleteRequest); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Override | ||
| 91 | + public byte[] getContent(String path) { | ||
| 92 | + GetObjectRequest getRequest = GetObjectRequest.builder() | ||
| 93 | + .bucket(config.getBucket()) | ||
| 94 | + .key(path) | ||
| 95 | + .build(); | ||
| 96 | + return IoUtil.readBytes(client.getObject(getRequest)); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + @Override | ||
| 100 | + public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) { | ||
| 101 | + Duration expiration = Duration.ofHours(24); | ||
| 102 | + return new FilePresignedUrlRespDTO(getPresignedUrl(path, expiration), config.getDomain() + "/" + path); | ||
| 56 | } | 103 | } |
| 57 | 104 | ||
| 58 | /** | 105 | /** |
| 59 | - * 构建 S3 客户端的 Endpoint 配置,包括 region、endpoint | 106 | + * 生成动态的预签名上传 URL |
| 60 | * | 107 | * |
| 61 | - * @return S3 客户端的 EndpointConfiguration 配置 | 108 | + * @param path 相对路径 |
| 109 | + * @param expiration 过期时间 | ||
| 110 | + * @return 生成的上传 URL | ||
| 62 | */ | 111 | */ |
| 63 | - private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() { | ||
| 64 | - return new AwsClientBuilder.EndpointConfiguration(config.getEndpoint(), | ||
| 65 | - null); // 无需设置 region | 112 | + private String getPresignedUrl(String path, Duration expiration) { |
| 113 | + return presigner.presignPutObject(PutObjectPresignRequest.builder() | ||
| 114 | + .signatureDuration(expiration) | ||
| 115 | + .putObjectRequest(b -> b.bucket(config.getBucket()).key(path)) | ||
| 116 | + .build()).url().toString(); | ||
| 66 | } | 117 | } |
| 67 | 118 | ||
| 68 | /** | 119 | /** |
| @@ -79,40 +130,17 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | @@ -79,40 +130,17 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { | ||
| 79 | return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint()); | 130 | return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint()); |
| 80 | } | 131 | } |
| 81 | 132 | ||
| 82 | - @Override | ||
| 83 | - public String upload(byte[] content, String path, String type) throws Exception { | ||
| 84 | - // 元数据,主要用于设置文件类型 | ||
| 85 | - ObjectMetadata objectMetadata = new ObjectMetadata(); | ||
| 86 | - objectMetadata.setContentType(type); | ||
| 87 | - objectMetadata.setContentLength(content.length); // 如果不设置,会有 “ No content length specified for stream data” 警告日志 | ||
| 88 | - // 执行上传 | ||
| 89 | - client.putObject(config.getBucket(), | ||
| 90 | - path, // 相对路径 | ||
| 91 | - new ByteArrayInputStream(content), // 文件内容 | ||
| 92 | - objectMetadata); | ||
| 93 | - | ||
| 94 | - // 拼接返回路径 | ||
| 95 | - return config.getDomain() + "/" + path; | ||
| 96 | - } | ||
| 97 | - | ||
| 98 | - @Override | ||
| 99 | - public void delete(String path) throws Exception { | ||
| 100 | - client.deleteObject(config.getBucket(), path); | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - @Override | ||
| 104 | - public byte[] getContent(String path) throws Exception { | ||
| 105 | - S3Object tempS3Object = client.getObject(config.getBucket(), path); | ||
| 106 | - return IoUtil.readBytes(tempS3Object.getObjectContent()); | ||
| 107 | - } | ||
| 108 | - | ||
| 109 | - @Override | ||
| 110 | - public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception { | ||
| 111 | - // 设定过期时间为 10 分钟。取值范围:1 秒 ~ 7 天 | ||
| 112 | - Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10)); | ||
| 113 | - // 生成上传 URL | ||
| 114 | - String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path, expiration , HttpMethod.PUT)); | ||
| 115 | - return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path); | 133 | + /** |
| 134 | + * 节点地址补全协议头 | ||
| 135 | + * | ||
| 136 | + * @return 节点地址 | ||
| 137 | + */ | ||
| 138 | + private String buildEndpoint() { | ||
| 139 | + // 如果已经是 http 或者 https,则不进行拼接 | ||
| 140 | + if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) { | ||
| 141 | + return config.getEndpoint(); | ||
| 142 | + } | ||
| 143 | + return StrUtil.format("https://{}", config.getEndpoint()); | ||
| 116 | } | 144 | } |
| 117 | 145 | ||
| 118 | } | 146 | } |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java
| @@ -67,6 +67,12 @@ public class S3FileClientConfig implements FileClientConfig { | @@ -67,6 +67,12 @@ public class S3FileClientConfig implements FileClientConfig { | ||
| 67 | @NotNull(message = "accessSecret 不能为空") | 67 | @NotNull(message = "accessSecret 不能为空") |
| 68 | private String accessSecret; | 68 | private String accessSecret; |
| 69 | 69 | ||
| 70 | + /** | ||
| 71 | + * 是否启用 PathStyle 访问 | ||
| 72 | + */ | ||
| 73 | + @NotNull(message = "enablePathStyleAccess 不能为空") | ||
| 74 | + private Boolean enablePathStyleAccess; | ||
| 75 | + | ||
| 70 | @SuppressWarnings("RedundantIfStatement") | 76 | @SuppressWarnings("RedundantIfStatement") |
| 71 | @AssertTrue(message = "domain 不能为空") | 77 | @AssertTrue(message = "domain 不能为空") |
| 72 | @JsonIgnore | 78 | @JsonIgnore |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
| @@ -164,23 +164,23 @@ public class CodegenEngine { | @@ -164,23 +164,23 @@ public class CodegenEngine { | ||
| 164 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑 | 164 | .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑 |
| 165 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) | 165 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) |
| 166 | // VUE3_VBEN5_ANTD | 166 | // VUE3_VBEN5_ANTD |
| 167 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/data.ts"), | 167 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/data.ts"), |
| 168 | vue3FilePath("views/${table.moduleName}/${table.businessName}/data.ts")) | 168 | vue3FilePath("views/${table.moduleName}/${table.businessName}/data.ts")) |
| 169 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/index.vue"), | 169 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/index.vue"), |
| 170 | vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) | 170 | vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue")) |
| 171 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/form.vue"), | 171 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/form.vue"), |
| 172 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) | 172 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue")) |
| 173 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("api/api.ts"), | 173 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("api/api.ts"), |
| 174 | vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) | 174 | vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts")) |
| 175 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 | 175 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑 |
| 176 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue")) | 176 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue")) |
| 177 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_inner.vue"), // 特殊:主子表专属逻辑 | 177 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_inner.vue"), // 特殊:主子表专属逻辑 |
| 178 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue")) | 178 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue")) |
| 179 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_erp.vue"), // 特殊:主子表专属逻辑 | 179 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/form_sub_erp.vue"), // 特殊:主子表专属逻辑 |
| 180 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue")) | 180 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue")) |
| 181 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/list_sub_inner.vue"), // 特殊:主子表专属逻辑 | 181 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/list_sub_inner.vue"), // 特殊:主子表专属逻辑 |
| 182 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) | 182 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) |
| 183 | - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑 | 183 | + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑 |
| 184 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) | 184 | vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) |
| 185 | .build(); | 185 | .build(); |
| 186 | 186 |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
| @@ -5,6 +5,9 @@ import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | @@ -5,6 +5,9 @@ import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | ||
| 5 | 5 | ||
| 6 | import java.util.Collection; | 6 | import java.util.Collection; |
| 7 | import java.util.List; | 7 | import java.util.List; |
| 8 | +import java.util.Map; | ||
| 9 | + | ||
| 10 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 8 | 11 | ||
| 9 | /** | 12 | /** |
| 10 | * 商品 SKU API 接口 | 13 | * 商品 SKU API 接口 |
| @@ -31,6 +34,16 @@ public interface ProductSkuApi { | @@ -31,6 +34,16 @@ public interface ProductSkuApi { | ||
| 31 | List<ProductSkuRespDTO> getSkuList(Collection<Long> ids); | 34 | List<ProductSkuRespDTO> getSkuList(Collection<Long> ids); |
| 32 | 35 | ||
| 33 | /** | 36 | /** |
| 37 | + * 批量查询 SKU MAP | ||
| 38 | + * | ||
| 39 | + * @param ids SKU 编号列表 | ||
| 40 | + * @return SKU MAP | ||
| 41 | + */ | ||
| 42 | + default Map<Long, ProductSkuRespDTO> getSkuMap(Collection<Long> ids) { | ||
| 43 | + return convertMap(getSkuList(ids), ProductSkuRespDTO::getId); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 34 | * 批量查询 SKU 数组 | 47 | * 批量查询 SKU 数组 |
| 35 | * | 48 | * |
| 36 | * @param spuIds SPU 编号列表 | 49 | * @param spuIds SPU 编号列表 |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java
| @@ -30,7 +30,7 @@ public interface ProductSpuApi { | @@ -30,7 +30,7 @@ public interface ProductSpuApi { | ||
| 30 | * @param ids SPU 编号列表 | 30 | * @param ids SPU 编号列表 |
| 31 | * @return SPU MAP | 31 | * @return SPU MAP |
| 32 | */ | 32 | */ |
| 33 | - default Map<Long, ProductSpuRespDTO> getSpusMap(Collection<Long> ids) { | 33 | + default Map<Long, ProductSpuRespDTO> getSpuMap(Collection<Long> ids) { |
| 34 | return convertMap(getSpuList(ids), ProductSpuRespDTO::getId); | 34 | return convertMap(getSpuList(ids), ProductSpuRespDTO::getId); |
| 35 | } | 35 | } |
| 36 | 36 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/point/PointActivityController.java
| @@ -124,7 +124,7 @@ public class PointActivityController { | @@ -124,7 +124,7 @@ public class PointActivityController { | ||
| 124 | List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds( | 124 | List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds( |
| 125 | convertSet(activityList, PointActivityDO::getId)); | 125 | convertSet(activityList, PointActivityDO::getId)); |
| 126 | Map<Long, List<PointProductDO>> productsMap = convertMultiMap(products, PointProductDO::getActivityId); | 126 | Map<Long, List<PointProductDO>> productsMap = convertMultiMap(products, PointProductDO::getActivityId); |
| 127 | - Map<Long, ProductSpuRespDTO> spuMap = productSpuApi.getSpusMap( | 127 | + Map<Long, ProductSpuRespDTO> spuMap = productSpuApi.getSpuMap( |
| 128 | convertSet(activityList, PointActivityDO::getSpuId)); | 128 | convertSet(activityList, PointActivityDO::getSpuId)); |
| 129 | List<PointActivityRespVO> result = BeanUtils.toBean(activityList, PointActivityRespVO.class); | 129 | List<PointActivityRespVO> result = BeanUtils.toBean(activityList, PointActivityRespVO.class); |
| 130 | result.forEach(activity -> { | 130 | result.forEach(activity -> { |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java
| @@ -104,7 +104,7 @@ public class AppPointActivityController { | @@ -104,7 +104,7 @@ public class AppPointActivityController { | ||
| 104 | List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds( | 104 | List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds( |
| 105 | convertSet(activityList, PointActivityDO::getId)); | 105 | convertSet(activityList, PointActivityDO::getId)); |
| 106 | Map<Long, List<PointProductDO>> productsMap = convertMultiMap(products, PointProductDO::getActivityId); | 106 | Map<Long, List<PointProductDO>> productsMap = convertMultiMap(products, PointProductDO::getActivityId); |
| 107 | - Map<Long, ProductSpuRespDTO> spuMap = productSpuApi.getSpusMap( | 107 | + Map<Long, ProductSpuRespDTO> spuMap = productSpuApi.getSpuMap( |
| 108 | convertSet(activityList, PointActivityDO::getSpuId)); | 108 | convertSet(activityList, PointActivityDO::getSpuId)); |
| 109 | List<AppPointActivityRespVO> result = BeanUtils.toBean(activityList, AppPointActivityRespVO.class); | 109 | List<AppPointActivityRespVO> result = BeanUtils.toBean(activityList, AppPointActivityRespVO.class); |
| 110 | result.forEach(activity -> { | 110 | result.forEach(activity -> { |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
| @@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityType | @@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityType | ||
| 22 | import jakarta.annotation.Resource; | 22 | import jakarta.annotation.Resource; |
| 23 | import lombok.extern.slf4j.Slf4j; | 23 | import lombok.extern.slf4j.Slf4j; |
| 24 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
| 25 | +import org.springframework.transaction.annotation.Propagation; | ||
| 25 | import org.springframework.transaction.annotation.Transactional; | 26 | import org.springframework.transaction.annotation.Transactional; |
| 26 | import org.springframework.validation.annotation.Validated; | 27 | import org.springframework.validation.annotation.Validated; |
| 27 | 28 | ||
| @@ -180,7 +181,7 @@ public class CouponServiceImpl implements CouponService { | @@ -180,7 +181,7 @@ public class CouponServiceImpl implements CouponService { | ||
| 180 | * @param couponId 模版编号 | 181 | * @param couponId 模版编号 |
| 181 | * @param userId 用户编号 | 182 | * @param userId 用户编号 |
| 182 | */ | 183 | */ |
| 183 | - @Transactional(rollbackFor = Exception.class) | 184 | + @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) // 每次调用开启一个新的事务,避免在一个大的事务里面 |
| 184 | public void invalidateCoupon(Long couponId, Long userId) { | 185 | public void invalidateCoupon(Long couponId, Long userId) { |
| 185 | if (couponId == null || couponId <= 0) { | 186 | if (couponId == null || couponId <= 0) { |
| 186 | return; | 187 | return; |
| @@ -270,13 +271,17 @@ public class CouponServiceImpl implements CouponService { | @@ -270,13 +271,17 @@ public class CouponServiceImpl implements CouponService { | ||
| 270 | if (CollUtil.isEmpty(userIds)) { | 271 | if (CollUtil.isEmpty(userIds)) { |
| 271 | throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); | 272 | throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); |
| 272 | } | 273 | } |
| 273 | - | ||
| 274 | // 校验模板 | 274 | // 校验模板 |
| 275 | if (couponTemplate == null) { | 275 | if (couponTemplate == null) { |
| 276 | throw exception(COUPON_TEMPLATE_NOT_EXISTS); | 276 | throw exception(COUPON_TEMPLATE_NOT_EXISTS); |
| 277 | } | 277 | } |
| 278 | - // 校验剩余数量 | ||
| 279 | - if (ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制 | 278 | + // 校验领取方式 |
| 279 | + if (ObjUtil.notEqual(couponTemplate.getTakeType(), takeType.getType())) { | ||
| 280 | + throw exception(COUPON_TEMPLATE_CANNOT_TAKE); | ||
| 281 | + } | ||
| 282 | + // 校验发放数量不能过小(仅在 CouponTakeTypeEnum.USER 用户领取时) | ||
| 283 | + if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType()) | ||
| 284 | + && ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制 | ||
| 280 | && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { | 285 | && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { |
| 281 | throw exception(COUPON_TEMPLATE_NOT_ENOUGH); | 286 | throw exception(COUPON_TEMPLATE_NOT_ENOUGH); |
| 282 | } | 287 | } |
| @@ -286,10 +291,6 @@ public class CouponServiceImpl implements CouponService { | @@ -286,10 +291,6 @@ public class CouponServiceImpl implements CouponService { | ||
| 286 | throw exception(COUPON_TEMPLATE_EXPIRED); | 291 | throw exception(COUPON_TEMPLATE_EXPIRED); |
| 287 | } | 292 | } |
| 288 | } | 293 | } |
| 289 | - // 校验领取方式 | ||
| 290 | - if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getType())) { | ||
| 291 | - throw exception(COUPON_TEMPLATE_CANNOT_TAKE); | ||
| 292 | - } | ||
| 293 | } | 294 | } |
| 294 | 295 | ||
| 295 | /** | 296 | /** |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java
| 1 | package cn.iocoder.yudao.module.trade.controller.app.aftersale; | 1 | package cn.iocoder.yudao.module.trade.controller.app.aftersale; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; | 6 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; |
| 7 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; | 7 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; |
| 8 | +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSalePageReqVO; | ||
| 8 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO; | 9 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO; |
| 9 | -import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert; | 10 | +import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; |
| 10 | import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService; | 11 | import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService; |
| 11 | import io.swagger.v3.oas.annotations.Operation; | 12 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | import io.swagger.v3.oas.annotations.Parameter; | 13 | import io.swagger.v3.oas.annotations.Parameter; |
| @@ -31,16 +32,17 @@ public class AppAfterSaleController { | @@ -31,16 +32,17 @@ public class AppAfterSaleController { | ||
| 31 | 32 | ||
| 32 | @GetMapping(value = "/page") | 33 | @GetMapping(value = "/page") |
| 33 | @Operation(summary = "获得售后分页") | 34 | @Operation(summary = "获得售后分页") |
| 34 | - public CommonResult<PageResult<AppAfterSaleRespVO>> getAfterSalePage(PageParam pageParam) { | ||
| 35 | - return success(AfterSaleConvert.INSTANCE.convertPage02( | ||
| 36 | - afterSaleService.getAfterSalePage(getLoginUserId(), pageParam))); | 35 | + public CommonResult<PageResult<AppAfterSaleRespVO>> getAfterSalePage(AppAfterSalePageReqVO pageReqVO) { |
| 36 | + PageResult<AfterSaleDO> pageResult = afterSaleService.getAfterSalePage(getLoginUserId(), pageReqVO); | ||
| 37 | + return success(BeanUtils.toBean(pageResult, AppAfterSaleRespVO.class)); | ||
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | @GetMapping(value = "/get") | 40 | @GetMapping(value = "/get") |
| 40 | @Operation(summary = "获得售后订单") | 41 | @Operation(summary = "获得售后订单") |
| 41 | @Parameter(name = "id", description = "售后编号", required = true, example = "1") | 42 | @Parameter(name = "id", description = "售后编号", required = true, example = "1") |
| 42 | public CommonResult<AppAfterSaleRespVO> getAfterSale(@RequestParam("id") Long id) { | 43 | public CommonResult<AppAfterSaleRespVO> getAfterSale(@RequestParam("id") Long id) { |
| 43 | - return success(AfterSaleConvert.INSTANCE.convert(afterSaleService.getAfterSale(getLoginUserId(), id))); | 44 | + AfterSaleDO afterSale = afterSaleService.getAfterSale(getLoginUserId(), id); |
| 45 | + return success(BeanUtils.toBean(afterSale, AppAfterSaleRespVO.class)); | ||
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | @PostMapping(value = "/create") | 48 | @PostMapping(value = "/create") |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSalePageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import lombok.Data; | ||
| 6 | +import lombok.EqualsAndHashCode; | ||
| 7 | +import lombok.ToString; | ||
| 8 | + | ||
| 9 | +import java.util.Set; | ||
| 10 | + | ||
| 11 | +@Schema(description = "用户 App - 交易售后分页 Request VO") | ||
| 12 | +@Data | ||
| 13 | +@EqualsAndHashCode(callSuper = true) | ||
| 14 | +@ToString(callSuper = true) | ||
| 15 | +public class AppAfterSalePageReqVO extends PageParam { | ||
| 16 | + | ||
| 17 | + @Schema(description = "售后状态", example = "10, 20") | ||
| 18 | + private Set<Integer> statuses; | ||
| 19 | + | ||
| 20 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java
| @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.base.spu; | @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.base.spu; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Data; | 4 | import lombok.Data; |
| 5 | 5 | ||
| 6 | -import java.util.List; | ||
| 7 | - | ||
| 8 | /** | 6 | /** |
| 9 | * 商品 SPU 基础 Response VO | 7 | * 商品 SPU 基础 Response VO |
| 10 | * | 8 | * |
| @@ -25,4 +23,10 @@ public class AppProductSpuBaseRespVO { | @@ -25,4 +23,10 @@ public class AppProductSpuBaseRespVO { | ||
| 25 | @Schema(description = "商品分类编号", example = "1") | 23 | @Schema(description = "商品分类编号", example = "1") |
| 26 | private Long categoryId; | 24 | private Long categoryId; |
| 27 | 25 | ||
| 26 | + @Schema(description = "商品库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") | ||
| 27 | + private Integer stock; | ||
| 28 | + | ||
| 29 | + @Schema(description = "商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 30 | + private Integer status; | ||
| 31 | + | ||
| 28 | } | 32 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/vo/pickup/AppDeliveryPickUpStoreRespVO.java
| 1 | package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.pickup; | 1 | package cn.iocoder.yudao.module.trade.controller.app.delivery.vo.pickup; |
| 2 | 2 | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | +import jakarta.validation.constraints.NotNull; | ||
| 4 | import lombok.Data; | 6 | import lombok.Data; |
| 5 | 7 | ||
| 8 | +import java.time.LocalTime; | ||
| 9 | + | ||
| 6 | @Schema(description = "用户 App - 自提门店 Response VO") | 10 | @Schema(description = "用户 App - 自提门店 Response VO") |
| 7 | @Data | 11 | @Data |
| 8 | public class AppDeliveryPickUpStoreRespVO { | 12 | public class AppDeliveryPickUpStoreRespVO { |
| @@ -28,6 +32,16 @@ public class AppDeliveryPickUpStoreRespVO { | @@ -28,6 +32,16 @@ public class AppDeliveryPickUpStoreRespVO { | ||
| 28 | @Schema(description = "门店详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "复旦大学路 188 号") | 32 | @Schema(description = "门店详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "复旦大学路 188 号") |
| 29 | private String detailAddress; | 33 | private String detailAddress; |
| 30 | 34 | ||
| 35 | + @Schema(description = "营业开始时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 36 | + @NotNull(message = "营业开始时间不能为空") | ||
| 37 | + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||
| 38 | + private LocalTime openingTime; | ||
| 39 | + | ||
| 40 | + @Schema(description = "营业结束时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 41 | + @NotNull(message = "营业结束时间不能为空") | ||
| 42 | + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm") | ||
| 43 | + private LocalTime closingTime; | ||
| 44 | + | ||
| 31 | @Schema(description = "纬度", requiredMode = Schema.RequiredMode.REQUIRED, example = "5.88") | 45 | @Schema(description = "纬度", requiredMode = Schema.RequiredMode.REQUIRED, example = "5.88") |
| 32 | private Double latitude; | 46 | private Double latitude; |
| 33 | 47 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleConvert.java
| @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUse | @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUse | ||
| 11 | import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; | 11 | import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; |
| 12 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO; | 12 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO; |
| 13 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; | 13 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; |
| 14 | -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleRespVO; | ||
| 15 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; | 14 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; |
| 16 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; | 15 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO; |
| 17 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | 16 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| @@ -63,10 +62,6 @@ public interface AfterSaleConvert { | @@ -63,10 +62,6 @@ public interface AfterSaleConvert { | ||
| 63 | 62 | ||
| 64 | ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); | 63 | ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); |
| 65 | 64 | ||
| 66 | - AppAfterSaleRespVO convert(AfterSaleDO bean); | ||
| 67 | - | ||
| 68 | - PageResult<AppAfterSaleRespVO> convertPage02(PageResult<AfterSaleDO> page); | ||
| 69 | - | ||
| 70 | default AfterSaleDetailRespVO convert(AfterSaleDO afterSale, TradeOrderDO order, TradeOrderItemDO orderItem, | 65 | default AfterSaleDetailRespVO convert(AfterSaleDO afterSale, TradeOrderDO order, TradeOrderItemDO orderItem, |
| 71 | MemberUserRespDTO user, List<AfterSaleLogDO> logs) { | 66 | MemberUserRespDTO user, List<AfterSaleLogDO> logs) { |
| 72 | AfterSaleDetailRespVO respVO = convert02(afterSale); | 67 | AfterSaleDetailRespVO respVO = convert02(afterSale); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java
| 1 | package cn.iocoder.yudao.module.trade.convert.cart; | 1 | package cn.iocoder.yudao.module.trade.convert.cart; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 3 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 4 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 4 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | 5 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 5 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | 6 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; |
| @@ -33,21 +34,18 @@ public interface TradeCartConvert { | @@ -33,21 +34,18 @@ public interface TradeCartConvert { | ||
| 33 | cartVO.setId(cart.getId()).setCount(cart.getCount()).setSelected(cart.getSelected()); | 34 | cartVO.setId(cart.getId()).setCount(cart.getCount()).setSelected(cart.getSelected()); |
| 34 | ProductSpuRespDTO spu = spuMap.get(cart.getSpuId()); | 35 | ProductSpuRespDTO spu = spuMap.get(cart.getSpuId()); |
| 35 | ProductSkuRespDTO sku = skuMap.get(cart.getSkuId()); | 36 | ProductSkuRespDTO sku = skuMap.get(cart.getSkuId()); |
| 36 | - cartVO.setSpu(convert(spu)).setSku(convert(sku)); | 37 | + cartVO.setSpu(BeanUtils.toBean(spu, AppProductSpuBaseRespVO.class)) |
| 38 | + .setSku(BeanUtils.toBean(sku, AppProductSkuBaseRespVO.class)); | ||
| 37 | // 如果 SPU 不存在,或者下架,或者库存不足,说明是无效的 | 39 | // 如果 SPU 不存在,或者下架,或者库存不足,说明是无效的 |
| 38 | if (spu == null | 40 | if (spu == null |
| 39 | || !ProductSpuStatusEnum.isEnable(spu.getStatus()) | 41 | || !ProductSpuStatusEnum.isEnable(spu.getStatus()) |
| 40 | || spu.getStock() <= 0) { | 42 | || spu.getStock() <= 0) { |
| 41 | - cartVO.setSelected(false); // 强制设置成不可选中 | ||
| 42 | invalidList.add(cartVO); | 43 | invalidList.add(cartVO); |
| 43 | } else { | 44 | } else { |
| 44 | - // 虽然 SKU 可能也会不存在,但是可以通过购物车重新选择 | ||
| 45 | validList.add(cartVO); | 45 | validList.add(cartVO); |
| 46 | } | 46 | } |
| 47 | }); | 47 | }); |
| 48 | return new AppCartListRespVO().setValidList(validList).setInvalidList(invalidList); | 48 | return new AppCartListRespVO().setValidList(validList).setInvalidList(invalidList); |
| 49 | } | 49 | } |
| 50 | - AppProductSpuBaseRespVO convert(ProductSpuRespDTO spu); | ||
| 51 | - AppProductSkuBaseRespVO convert(ProductSkuRespDTO sku); | ||
| 52 | 50 | ||
| 53 | } | 51 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleMapper.java
| 1 | package cn.iocoder.yudao.module.trade.dal.mysql.aftersale; | 1 | package cn.iocoder.yudao.module.trade.dal.mysql.aftersale; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 7 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; | 6 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; |
| 7 | +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSalePageReqVO; | ||
| 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; |
| 9 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | 9 | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| 10 | import org.apache.ibatis.annotations.Mapper; | 10 | import org.apache.ibatis.annotations.Mapper; |
| @@ -27,9 +27,10 @@ public interface AfterSaleMapper extends BaseMapperX<AfterSaleDO> { | @@ -27,9 +27,10 @@ public interface AfterSaleMapper extends BaseMapperX<AfterSaleDO> { | ||
| 27 | .orderByDesc(AfterSaleDO::getId)); | 27 | .orderByDesc(AfterSaleDO::getId)); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | - default PageResult<AfterSaleDO> selectPage(Long userId, PageParam pageParam) { | ||
| 31 | - return selectPage(pageParam, new LambdaQueryWrapperX<AfterSaleDO>() | ||
| 32 | - .eqIfPresent(AfterSaleDO::getUserId, userId) | 30 | + default PageResult<AfterSaleDO> selectPage(Long userId, AppAfterSalePageReqVO pageReqVO) { |
| 31 | + return selectPage(pageReqVO, new LambdaQueryWrapperX<AfterSaleDO>() | ||
| 32 | + .eq(AfterSaleDO::getUserId, userId) | ||
| 33 | + .inIfPresent(AfterSaleDO::getStatus, pageReqVO.getStatuses()) | ||
| 33 | .orderByDesc(AfterSaleDO::getId)); | 34 | .orderByDesc(AfterSaleDO::getId)); |
| 34 | } | 35 | } |
| 35 | 36 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleService.java
| 1 | package cn.iocoder.yudao.module.trade.service.aftersale; | 1 | package cn.iocoder.yudao.module.trade.service.aftersale; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO; | 4 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO; |
| 6 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; | 5 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO; |
| 7 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO; | 6 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO; |
| 8 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; | 7 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; |
| 9 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; | 8 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; |
| 9 | +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSalePageReqVO; | ||
| 10 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; | 10 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; |
| 11 | 11 | ||
| 12 | /** | 12 | /** |
| @@ -28,10 +28,10 @@ public interface AfterSaleService { | @@ -28,10 +28,10 @@ public interface AfterSaleService { | ||
| 28 | * 【会员】获得售后订单分页 | 28 | * 【会员】获得售后订单分页 |
| 29 | * | 29 | * |
| 30 | * @param userId 用户编号 | 30 | * @param userId 用户编号 |
| 31 | - * @param pageParam 分页参数 | 31 | + * @param pageReqVO 分页参数 |
| 32 | * @return 售后订单分页 | 32 | * @return 售后订单分页 |
| 33 | */ | 33 | */ |
| 34 | - PageResult<AfterSaleDO> getAfterSalePage(Long userId, PageParam pageParam); | 34 | + PageResult<AfterSaleDO> getAfterSalePage(Long userId, AppAfterSalePageReqVO pageReqVO); |
| 35 | 35 | ||
| 36 | /** | 36 | /** |
| 37 | * 【会员】获得售后单 | 37 | * 【会员】获得售后单 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java
| @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.aftersale; | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.aftersale; | ||
| 3 | import cn.hutool.core.map.MapUtil; | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 9 | import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; | 8 | import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; |
| @@ -16,6 +15,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePage | @@ -16,6 +15,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePage | ||
| 16 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO; | 15 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO; |
| 17 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; | 16 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; |
| 18 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; | 17 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO; |
| 18 | +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSalePageReqVO; | ||
| 19 | import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert; | 19 | import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert; |
| 20 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; | 20 | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO; |
| 21 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; | 21 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; |
| @@ -36,6 +36,7 @@ import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties | @@ -36,6 +36,7 @@ import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties | ||
| 36 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; | 36 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; |
| 37 | import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; | 37 | import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; |
| 38 | import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; | 38 | import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; |
| 39 | +import jakarta.annotation.Resource; | ||
| 39 | import lombok.extern.slf4j.Slf4j; | 40 | import lombok.extern.slf4j.Slf4j; |
| 40 | import org.springframework.context.annotation.Lazy; | 41 | import org.springframework.context.annotation.Lazy; |
| 41 | import org.springframework.stereotype.Service; | 42 | import org.springframework.stereotype.Service; |
| @@ -44,7 +45,6 @@ import org.springframework.transaction.support.TransactionSynchronization; | @@ -44,7 +45,6 @@ import org.springframework.transaction.support.TransactionSynchronization; | ||
| 44 | import org.springframework.transaction.support.TransactionSynchronizationManager; | 45 | import org.springframework.transaction.support.TransactionSynchronizationManager; |
| 45 | import org.springframework.validation.annotation.Validated; | 46 | import org.springframework.validation.annotation.Validated; |
| 46 | 47 | ||
| 47 | -import jakarta.annotation.Resource; | ||
| 48 | import java.time.LocalDateTime; | 48 | import java.time.LocalDateTime; |
| 49 | 49 | ||
| 50 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 50 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| @@ -87,8 +87,8 @@ public class AfterSaleServiceImpl implements AfterSaleService { | @@ -87,8 +87,8 @@ public class AfterSaleServiceImpl implements AfterSaleService { | ||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | @Override | 89 | @Override |
| 90 | - public PageResult<AfterSaleDO> getAfterSalePage(Long userId, PageParam pageParam) { | ||
| 91 | - return tradeAfterSaleMapper.selectPage(userId, pageParam); | 90 | + public PageResult<AfterSaleDO> getAfterSalePage(Long userId, AppAfterSalePageReqVO pageReqVO) { |
| 91 | + return tradeAfterSaleMapper.selectPage(userId, pageReqVO); | ||
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | @Override | 94 | @Override |
| @@ -386,7 +386,7 @@ public class AfterSaleServiceImpl implements AfterSaleService { | @@ -386,7 +386,7 @@ public class AfterSaleServiceImpl implements AfterSaleService { | ||
| 386 | public void afterCommit() { | 386 | public void afterCommit() { |
| 387 | // 创建退款单 | 387 | // 创建退款单 |
| 388 | PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties) | 388 | PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties) |
| 389 | - .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));; | 389 | + .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName())); |
| 390 | Long payRefundId = payRefundApi.createRefund(createReqDTO); | 390 | Long payRefundId = payRefundApi.createRefund(createReqDTO); |
| 391 | // 更新售后单的退款单号 | 391 | // 更新售后单的退款单号 |
| 392 | tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); | 392 | tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
| @@ -545,6 +545,14 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -545,6 +545,14 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 545 | if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) { | 545 | if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) { |
| 546 | throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); | 546 | throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); |
| 547 | } | 547 | } |
| 548 | + // 1.3 校验是否支持延迟(不允许取消) | ||
| 549 | + if (TradeOrderStatusEnum.isUnpaid(order.getStatus())) { | ||
| 550 | + PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId()); | ||
| 551 | + if (payOrder != null && PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { | ||
| 552 | + log.warn("[cancelOrderByMember][order({}) 支付单已支付(支付回调延迟),不支持取消]", order.getId()); | ||
| 553 | + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); | ||
| 554 | + } | ||
| 555 | + } | ||
| 548 | 556 | ||
| 549 | // 2. 取消订单 | 557 | // 2. 取消订单 |
| 550 | cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL); | 558 | cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL); |
| @@ -581,6 +589,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -581,6 +589,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 581 | @Transactional(rollbackFor = Exception.class) | 589 | @Transactional(rollbackFor = Exception.class) |
| 582 | @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL) | 590 | @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL) |
| 583 | public void cancelOrderBySystem(TradeOrderDO order) { | 591 | public void cancelOrderBySystem(TradeOrderDO order) { |
| 592 | + // 校验是否支持延迟(不允许取消) | ||
| 593 | + if (TradeOrderStatusEnum.isUnpaid(order.getStatus())) { | ||
| 594 | + PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId()); | ||
| 595 | + if (payOrder != null && PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { | ||
| 596 | + log.warn("[cancelOrderBySystem][order({}) 支付单已支付(支付回调延迟),不支持取消]", order.getId()); | ||
| 597 | + return; | ||
| 598 | + } | ||
| 599 | + } | ||
| 600 | + | ||
| 584 | cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT); | 601 | cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT); |
| 585 | } | 602 | } |
| 586 | 603 | ||
| @@ -895,12 +912,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -895,12 +912,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 895 | if (order == null) { | 912 | if (order == null) { |
| 896 | throw exception(ORDER_NOT_FOUND); | 913 | throw exception(ORDER_NOT_FOUND); |
| 897 | } | 914 | } |
| 898 | - | ||
| 899 | // 1.3 校验订单是否支付 | 915 | // 1.3 校验订单是否支付 |
| 900 | if (!order.getPayStatus()) { | 916 | if (!order.getPayStatus()) { |
| 901 | throw exception(ORDER_CANCEL_PAID_FAIL, "已支付"); | 917 | throw exception(ORDER_CANCEL_PAID_FAIL, "已支付"); |
| 902 | } | 918 | } |
| 903 | - // 1.3 校验订单是否未退款 | 919 | + // 1.4 校验订单是否未退款 |
| 904 | if (ObjUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { | 920 | if (ObjUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { |
| 905 | throw exception(ORDER_CANCEL_PAID_FAIL, "未退款"); | 921 | throw exception(ORDER_CANCEL_PAID_FAIL, "未退款"); |
| 906 | } | 922 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java
| @@ -20,6 +20,7 @@ import org.springframework.stereotype.Component; | @@ -20,6 +20,7 @@ import org.springframework.stereotype.Component; | ||
| 20 | 20 | ||
| 21 | import jakarta.annotation.Resource; | 21 | import jakarta.annotation.Resource; |
| 22 | import java.util.List; | 22 | import java.util.List; |
| 23 | +import java.util.Map; | ||
| 23 | 24 | ||
| 24 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 25 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 25 | 26 | ||
| @@ -101,13 +102,17 @@ public class TradeBrokerageOrderHandler implements TradeOrderHandler { | @@ -101,13 +102,17 @@ public class TradeBrokerageOrderHandler implements TradeOrderHandler { | ||
| 101 | protected void addBrokerage(Long userId, List<TradeOrderItemDO> orderItems) { | 102 | protected void addBrokerage(Long userId, List<TradeOrderItemDO> orderItems) { |
| 102 | MemberUserRespDTO user = memberUserApi.getUser(userId); | 103 | MemberUserRespDTO user = memberUserApi.getUser(userId); |
| 103 | Assert.notNull(user); | 104 | Assert.notNull(user); |
| 104 | - ProductSpuRespDTO spu = productSpuApi.getSpu(orderItems.get(0).getSpuId()); | ||
| 105 | - Assert.notNull(spu); | ||
| 106 | - ProductSkuRespDTO sku = productSkuApi.getSku(orderItems.get(0).getSkuId()); | 105 | + Map<Long, ProductSpuRespDTO> spusMap = productSpuApi.getSpuMap(convertList(orderItems, TradeOrderItemDO::getSpuId)); |
| 106 | + Map<Long, ProductSkuRespDTO> skusMap = productSkuApi.getSkuMap(convertList(orderItems, TradeOrderItemDO::getSkuId)); | ||
| 107 | 107 | ||
| 108 | // 每一个订单项,都会去生成分销记录 | 108 | // 每一个订单项,都会去生成分销记录 |
| 109 | - List<BrokerageAddReqBO> addList = convertList(orderItems, | ||
| 110 | - item -> TradeOrderConvert.INSTANCE.convert(user, item, spu, sku)); | 109 | + List<BrokerageAddReqBO> addList = convertList(orderItems, item -> { |
| 110 | + ProductSpuRespDTO spu = spusMap.get(item.getSpuId()); | ||
| 111 | + Assert.notNull(spu); | ||
| 112 | + ProductSkuRespDTO sku = skusMap.get(item.getSkuId()); | ||
| 113 | + Assert.notNull(sku); | ||
| 114 | + return TradeOrderConvert.INSTANCE.convert(user, item, spu, sku); | ||
| 115 | + }); | ||
| 111 | brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, addList); | 116 | brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, addList); |
| 112 | } | 117 | } |
| 113 | 118 |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
| @@ -45,6 +45,7 @@ public interface ErrorCodeConstants { | @@ -45,6 +45,7 @@ public interface ErrorCodeConstants { | ||
| 45 | ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "创建用户失败,原因:超过租户最大租户配额({})!"); | 45 | ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "创建用户失败,原因:超过租户最大租户配额({})!"); |
| 46 | ErrorCode USER_IMPORT_INIT_PASSWORD = new ErrorCode(1_002_003_009, "初始密码不能为空"); | 46 | ErrorCode USER_IMPORT_INIT_PASSWORD = new ErrorCode(1_002_003_009, "初始密码不能为空"); |
| 47 | ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1_002_003_010, "该手机号尚未注册"); | 47 | ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1_002_003_010, "该手机号尚未注册"); |
| 48 | + ErrorCode USER_REGISTER_DISABLED = new ErrorCode(1_002_003_011, "注册功能已关闭"); | ||
| 48 | 49 | ||
| 49 | // ========== 部门模块 1-002-004-000 ========== | 50 | // ========== 部门模块 1-002-004-000 ========== |
| 50 | ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门"); | 51 | ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门"); |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
| @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 9 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 9 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 10 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; | 10 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 11 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 11 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 12 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | ||
| 12 | import cn.iocoder.yudao.framework.tenant.config.TenantProperties; | 13 | import cn.iocoder.yudao.framework.tenant.config.TenantProperties; |
| 13 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | 14 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 14 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | 15 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| @@ -96,6 +97,7 @@ public class TenantServiceImpl implements TenantService { | @@ -96,6 +97,7 @@ public class TenantServiceImpl implements TenantService { | ||
| 96 | 97 | ||
| 97 | @Override | 98 | @Override |
| 98 | @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 | 99 | @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 |
| 100 | + @DataPermission(enable = false) // 参见 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1154 说明 | ||
| 99 | public Long createTenant(TenantSaveReqVO createReqVO) { | 101 | public Long createTenant(TenantSaveReqVO createReqVO) { |
| 100 | // 校验租户名称是否重复 | 102 | // 校验租户名称是否重复 |
| 101 | validTenantNameDuplicate(createReqVO.getName(), null); | 103 | validTenantNameDuplicate(createReqVO.getName(), null); |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.user; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.user; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.collection.CollectionUtil; | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | import cn.hutool.core.io.IoUtil; | 5 | import cn.hutool.core.io.IoUtil; |
| 6 | +import cn.hutool.core.util.ObjUtil; | ||
| 6 | import cn.hutool.core.util.StrUtil; | 7 | import cn.hutool.core.util.StrUtil; |
| 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 8 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 8 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 9 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| @@ -61,6 +62,8 @@ public class AdminUserServiceImpl implements AdminUserService { | @@ -61,6 +62,8 @@ public class AdminUserServiceImpl implements AdminUserService { | ||
| 61 | 62 | ||
| 62 | static final String USER_INIT_PASSWORD_KEY = "system.user.init-password"; | 63 | static final String USER_INIT_PASSWORD_KEY = "system.user.init-password"; |
| 63 | 64 | ||
| 65 | + static final String USER_REGISTER_ENABLED_KEY = "system.user.register-enabled"; | ||
| 66 | + | ||
| 64 | @Resource | 67 | @Resource |
| 65 | private AdminUserMapper userMapper; | 68 | private AdminUserMapper userMapper; |
| 66 | 69 | ||
| @@ -117,14 +120,18 @@ public class AdminUserServiceImpl implements AdminUserService { | @@ -117,14 +120,18 @@ public class AdminUserServiceImpl implements AdminUserService { | ||
| 117 | 120 | ||
| 118 | @Override | 121 | @Override |
| 119 | public Long registerUser(AuthRegisterReqVO registerReqVO) { | 122 | public Long registerUser(AuthRegisterReqVO registerReqVO) { |
| 120 | - // 1.1 校验账户配合 | 123 | + // 1.1 校验是否开启注册 |
| 124 | + if (ObjUtil.notEqual(configApi.getConfigValueByKey(USER_REGISTER_ENABLED_KEY), "true")) { | ||
| 125 | + throw exception(USER_REGISTER_DISABLED); | ||
| 126 | + } | ||
| 127 | + // 1.2 校验账户配合 | ||
| 121 | tenantService.handleTenantInfo(tenant -> { | 128 | tenantService.handleTenantInfo(tenant -> { |
| 122 | long count = userMapper.selectCount(); | 129 | long count = userMapper.selectCount(); |
| 123 | if (count >= tenant.getAccountCount()) { | 130 | if (count >= tenant.getAccountCount()) { |
| 124 | throw exception(USER_COUNT_MAX, tenant.getAccountCount()); | 131 | throw exception(USER_COUNT_MAX, tenant.getAccountCount()); |
| 125 | } | 132 | } |
| 126 | }); | 133 | }); |
| 127 | - // 1.2 校验正确性 | 134 | + // 1.3 校验正确性 |
| 128 | validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null); | 135 | validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null); |
| 129 | 136 | ||
| 130 | // 2. 插入用户 | 137 | // 2. 插入用户 |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java
| @@ -212,6 +212,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { | @@ -212,6 +212,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { | ||
| 212 | UserProfileUpdateReqVO reqVO = randomPojo(UserProfileUpdateReqVO.class, o -> { | 212 | UserProfileUpdateReqVO reqVO = randomPojo(UserProfileUpdateReqVO.class, o -> { |
| 213 | o.setMobile(randomString()); | 213 | o.setMobile(randomString()); |
| 214 | o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); | 214 | o.setSex(RandomUtil.randomEle(SexEnum.values()).getSex()); |
| 215 | + o.setAvatar(randomURL()); | ||
| 215 | }); | 216 | }); |
| 216 | 217 | ||
| 217 | // 调用 | 218 | // 调用 |