瀏覽代碼

Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-redis

 Conflicts:
	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java
	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java
YunaiV 1 年之前
父節點
當前提交
95edd1d451
共有 100 個文件被更改,包括 1203 次插入478 次删除
  1. 15 24
      Docker-HOWTO.md
  2. 1 1
      README.md
  3. 6 17
      docker-compose.yml
  4. 1 1
      pom.xml
  5. 19 5
      yudao-dependencies/pom.xml
  6. 0 2
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
  7. 0 11
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/GlobalErrorCodeConstants.java
  8. 0 5
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java
  9. 1 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
  10. 22 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
  11. 5 2
      yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java
  12. 0 2
      yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml
  13. 0 4
      yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml
  14. 1 2
      yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
  15. 4 29
      yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
  16. 2 3
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
  17. 1 0
      yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbAndRedisUnitTest.java
  18. 1 0
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
  19. 2 1
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java
  20. 1 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
  21. 9 38
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
  22. 0 105
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmActivityDO.java
  23. 10 10
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
  24. 0 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
  25. 4 0
      yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java
  26. 1 1
      yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java
  27. 4 4
      yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java
  28. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java
  29. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnBaseVO.java
  30. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableBaseVO.java
  31. 3 3
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java
  32. 2 2
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExportReqVO.java
  33. 3 3
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java
  34. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java
  35. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigCreateReqVO.java
  36. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java
  37. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigRespVO.java
  38. 3 3
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java
  39. 3 3
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobPageReqVO.java
  40. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogBaseVO.java
  41. 3 3
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogExportReqVO.java
  42. 2 2
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogPageReqVO.java
  43. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogBaseVO.java
  44. 3 3
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogExportReqVO.java
  45. 2 2
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java
  46. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogExportReqVO.java
  47. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExportReqVO.java
  48. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java
  49. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImpl.java
  50. 1 2
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
  51. 2 4
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
  52. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
  53. 0 13
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentBaseVO.java
  54. 1 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentPageReqVO.java
  55. 12 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentRespVO.java
  56. 10 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
  57. 0 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuCreateReqVO.java
  58. 0 6
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java
  59. 1 6
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuExportReqVO.java
  60. 0 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
  61. 0 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
  62. 0 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java
  63. 0 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateReqVO.java
  64. 0 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateStatusReqVO.java
  65. 11 23
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java
  66. 0 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentRespVO.java
  67. 38 15
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java
  68. 14 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
  69. 3 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java
  70. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java
  71. 8 14
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
  72. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
  73. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
  74. 4 5
      yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java
  75. 49 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java
  76. 78 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordReqDTO.java
  77. 10 3
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  78. 39 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java
  79. 42 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java
  80. 114 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
  81. 49 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java
  82. 22 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java
  83. 65 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExcelVO.java
  84. 61 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExportReqVO.java
  85. 65 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java
  86. 56 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java
  87. 27 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java
  88. 27 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java
  89. 14 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductCreateReqVO.java
  90. 44 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExcelVO.java
  91. 43 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExportReqVO.java
  92. 47 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductPageReqVO.java
  93. 22 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductRespVO.java
  94. 14 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductUpdateReqVO.java
  95. 13 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java
  96. 0 5
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java
  97. 1 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
  98. 26 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
  99. 19 3
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigBaseVO.java
  100. 0 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigPageReqVO.java

+ 15 - 24
Docker-HOWTO.md

@@ -1,23 +1,24 @@
 # Docker Build & Up
 
 目标: 快速部署体验系统,帮助了解系统之间的依赖关系。
+依赖:docker compose v2,删除`name: yudao-system`,降低`version`版本为`3.3`以下,支持`docker-compose`。
 
 ## 功能文件列表
 
 ```text
 .
-├── Docker-HOWTO.md
-├── docker-compose.yml
-├── docker.env
+├── Docker-HOWTO.md                 
+├── docker-compose.yml              
+├── docker.env                      <-- 提供docker-compose环境变量配置
 ├── yudao-server
-│   ├── Dockerfile
-│   └── nginx.conf
+│   └── Dockerfile
 └── yudao-ui-admin
     ├── .dockerignore
-    └── Dockerfile
+    ├── Dockerfile
+    └── nginx.conf                  <-- 提供基础配置,gzip压缩、api转发
 ```
 
-## Maven build (Optional)
+## 构建 jar 包
 
 ```shell
 # 创建maven缓存volume
@@ -30,29 +31,19 @@ docker run -it --rm --name yudao-maven \
     maven mvn clean install package '-Dmaven.test.skip=true'
 ```
 
-## Docker Compose Build
-
-```shell
-docker compose --env-file docker.env build
-```
-
-## Docker Compose Up
+## 构建启动服务
 
 ```shell
 docker compose --env-file docker.env up -d
 ```
 
-第一次执行,由于数据库未初始化,因此yudao-server容器会运行失败。执行如下命令初始化数据库:
+首次运行会自动构建容器。可以通过`docker compose build [service]`来手动构建所有或某个docker镜像
 
-```shell
-docker compose exec -T mysql \
-    sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" --default-character-set=utf8mb4 ruoyi-vue-pro' \
-    < ./sql/mysql/ruoyi-vue-pro.sql
-```
+`--env-file docker.env`为可选参数,只是展示了通过`.env`文件配置容器启动的环境变量,`docker-compose.yml`本身已经提供足够的默认参数来正常运行系统。
 
-## Server:Port
+## 服务器的宿主机端口映射
 
-- admin: http://localhost:8080
-- API: http://localhost:48080
-- mysql: root/123456, port: 3308
+- admin ui: http://localhost:8080
+- api server: http://localhost:48080
+- mysql: root/123456, port: 3306
 - redis: port: 6379

+ 1 - 1
README.md

@@ -102,7 +102,7 @@
 
 系统内置多种多种业务功能,可以用于快速你的业务系统:
 
-![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png)
+![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png?imageView2/2/format/webp)
 
 * 系统功能
 * 基础设施

+ 6 - 17
docker-compose.yml

@@ -1,4 +1,4 @@
-version: "3.8"
+version: "3.4"
 
 name: yudao-system
 
@@ -9,25 +9,22 @@ services:
     restart: unless-stopped
     tty: true
     ports:
-      - 13306:3306
+      - "3306:3306"
     environment:
       MYSQL_DATABASE: ${MYSQL_DATABASE:-ruoyi-vue-pro}
       MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456}
     volumes:
       - mysql:/var/lib/mysql/
-    networks:
-      - yudao-network
+      - ./sql/mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro
 
   redis:
     container_name: yudao-redis
     image: redis:6-alpine
     restart: unless-stopped
     ports:
-      - 16379:6379
+      - "6379:6379"
     volumes:
       - redis:/data
-    networks:
-      - yudao-network
 
   server:
     container_name: yudao-server
@@ -36,7 +33,7 @@ services:
     image: yudao-server
     restart: unless-stopped
     ports:
-      - 48080:48080
+      - "48080:48080"
     environment:
       # https://github.com/polovyivan/docker-pass-configs-to-container
       SPRING_PROFILES_ACTIVE: local
@@ -54,8 +51,6 @@ services:
         --spring.datasource.dynamic.datasource.slave.username=${SLAVE_DATASOURCE_USERNAME:-root}
         --spring.datasource.dynamic.datasource.slave.password=${SLAVE_DATASOURCE_PASSWORD:-123456}
         --spring.redis.host=${REDIS_HOST:-yudao-redis}
-    networks:
-      - yudao-network
     depends_on:
       - mysql
       - redis
@@ -78,16 +73,10 @@ services:
     image: yudao-admin
     restart: unless-stopped
     ports:
-      - 8080:80
-    networks:
-      - yudao-network
+      - "8080:80"
     depends_on:
       - server
 
-networks:
-  yudao-network:
-    driver: bridge
-
 volumes:
   mysql:
     driver: local

+ 1 - 1
pom.xml

@@ -30,7 +30,7 @@
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
 
     <properties>
-        <revision>1.7.3-snapshot</revision>
+        <revision>1.8.0-snapshot</revision>
         <!-- Maven 相关 -->
         <java.version>1.8</java.version>
         <maven.compiler.source>${java.version}</maven.compiler.source>

+ 19 - 5
yudao-dependencies/pom.xml

@@ -14,7 +14,7 @@
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
 
     <properties>
-        <revision>1.7.3-snapshot</revision>
+        <revision>1.8.0-snapshot</revision>
         <!-- 统一依赖管理 -->
         <spring.boot.version>2.7.13</spring.boot.version>
         <!-- Web 相关 -->
@@ -71,7 +71,7 @@
         <justauth.version>1.0.1</justauth.version>
         <jimureport.version>1.5.8</jimureport.version>
         <xercesImpl.version>2.12.2</xercesImpl.version>
-        <wx-java-mp.version>4.5.0</wx-java-mp.version>
+        <weixin-java.version>4.5.0</weixin-java.version>
     </properties>
 
     <dependencyManagement>
@@ -216,10 +216,9 @@
                 <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
                 <version>${dynamic-datasource.version}</version>
             </dependency>
-
             <dependency>
                 <groupId>com.github.yulichang</groupId>
-                <artifactId>mybatis-plus-join-boot-starter</artifactId>
+                <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
                 <version>${mybatis-plus-join-boot-starter.version}</version>
             </dependency>
 
@@ -599,10 +598,25 @@
                 <version>${justauth.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>com.github.binarywang</groupId>
+                <artifactId>weixin-java-pay</artifactId>
+                <version>${weixin-java.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.github.binarywang</groupId>
+                <artifactId>weixin-java-mp</artifactId>
+                <version>${weixin-java.version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.github.binarywang</groupId>
                 <artifactId>wx-java-mp-spring-boot-starter</artifactId>
-                <version>${wx-java-mp.version}</version>
+                <version>${weixin-java.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.github.binarywang</groupId>
+                <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
+                <version>${weixin-java.version}</version>
             </dependency>
 
             <!-- 积木报表-->

+ 0 - 2
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java

@@ -27,8 +27,6 @@ public interface WebFilterOrderEnum {
 
     int TENANT_SECURITY_FILTER = -99; // 需要保证在 Spring Security 过滤器后面
 
-    int ACTIVITI_FILTER = -98; // 需要保证在 Spring Security 过滤后面
-
     int FLOWABLE_FILTER = -98; // 需要保证在 Spring Security 过滤后面
 
     int DEMO_FILTER = Integer.MAX_VALUE;

+ 0 - 11
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/GlobalErrorCodeConstants.java

@@ -37,15 +37,4 @@ public interface GlobalErrorCodeConstants {
 
     ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
 
-    /**
-     * 是否为服务端错误,参考 HTTP 5XX 错误码段
-     *
-     * @param code 错误码
-     * @return 是否
-     */
-   static boolean isServerErrorCode(Integer code) {
-       return code != null
-               && code >= INTERNAL_SERVER_ERROR.getCode() && code <= INTERNAL_SERVER_ERROR.getCode() + 99;
-   }
-
 }

+ 0 - 5
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.framework.common.pojo;
 
 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
-import cn.iocoder.yudao.framework.common.exception.ServerException;
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -92,10 +91,6 @@ public class CommonResult<T> implements Serializable {
         if (isSuccess()) {
             return;
         }
-        // 服务端异常
-        if (GlobalErrorCodeConstants.isServerErrorCode(code)) {
-            throw new ServerException(code, msg);
-        }
         // 业务异常
         throw new ServiceException(code, msg);
     }

+ 1 - 1
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java

@@ -164,7 +164,7 @@ public class CollectionUtils {
         return from.stream().filter(predicate).findFirst().orElse(null);
     }
 
-    public static <T, V extends Comparable<? super V>> V getMaxValue(List<T> from, Function<T, V> valueFunc) {
+    public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) {
         if (CollUtil.isEmpty(from)) {
             return null;
         }

+ 22 - 1
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java

@@ -4,6 +4,7 @@ import cn.hutool.core.date.LocalDateTimeUtil;
 
 import java.time.Duration;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
 
 /**
  * 时间工具类,用于 {@link java.time.LocalDateTime}
@@ -50,7 +51,7 @@ public class LocalDateTimeUtils {
      * 判断当前时间是否在该时间范围内
      *
      * @param startTime 开始时间
-     * @param endTime 结束时间
+     * @param endTime   结束时间
      * @return 是否
      */
     public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
@@ -60,4 +61,24 @@ public class LocalDateTimeUtils {
         return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
     }
 
+    /**
+     * 检查时间重叠 不包含日期
+     *
+     * @param startTime1 需要校验的开始时间
+     * @param endTime1   需要校验的结束时间
+     * @param startTime2 校验所需的开始时间
+     * @param endTime2   校验所需的结束时间
+     * @return 是否重叠
+     */
+    // TODO @puhui999:LocalDateTimeUtil.isOverlap() 是不是可以满足呀?
+    public static boolean checkTimeOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
+        // 判断时间是否重叠
+        // 开始时间在已配置时段的结束时间之前 且 结束时间在已配置时段的开始时间之后 []
+        return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
+                // 开始时间在已配置时段的开始时间之前 且 结束时间在已配置时段的开始时间之后 (] 或 ()
+                || startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
+                // 开始时间在已配置时段的结束时间之前 且 结束时间在已配值时段的结束时间之后 [) 或 ()
+                || startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
+    }
+
 }

+ 5 - 2
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java

@@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ReflectUtil;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
-import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
-import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
 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.module.system.api.permission.PermissionApi;
+import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
 import net.sf.jsqlparser.expression.Alias;
 import net.sf.jsqlparser.expression.Expression;
 import org.junit.jupiter.api.BeforeEach;
@@ -23,6 +23,7 @@ import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataP
 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.*;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.when;
@@ -73,6 +74,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
             LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
                     .setUserType(UserTypeEnum.ADMIN.getValue()));
             securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
+            // mock 方法(permissionApi 返回 null)
+            when(permissionApi.getDeptDataPermission(eq(loginUser.getId()))).thenReturn(null);
 
             // 调用
             NullPointerException exception = assertThrows(NullPointerException.class,

+ 0 - 2
yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml

@@ -63,9 +63,7 @@
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-pay</artifactId>
-            <version>4.5.0</version>
         </dependency>
-        <!-- TODO 芋艿:清理 -->
 
         <!-- Test 测试相关 -->
         <dependency>

+ 0 - 4
yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml

@@ -34,16 +34,12 @@
         <!-- 三方云服务相关 -->
         <dependency>
             <groupId>com.github.binarywang</groupId>
-<!--            <artifactId>weixin-java-mp</artifactId>-->
             <artifactId>wx-java-mp-spring-boot-starter</artifactId>
-            <version>4.5.0</version>
         </dependency>
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
-            <version>4.5.0</version>
         </dependency>
-        <!-- TODO 芋艿:清理 -->
     </dependencies>
 
 </project>

+ 1 - 2
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml

@@ -64,9 +64,8 @@
 
         <dependency>
             <groupId>com.github.yulichang</groupId>
-            <artifactId>mybatis-plus-join-boot-starter</artifactId>
+            <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
         </dependency>
-
     </dependencies>
 
 </project>

+ 4 - 29
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java

@@ -6,10 +6,10 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.extension.toolkit.Db;
-import com.github.yulichang.base.MPJBaseMapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Collection;
@@ -17,10 +17,8 @@ import java.util.List;
 
 /**
  * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
- * <p>
- * 为什么继承 MPJBaseMapper 接口?支持 MyBatis Plus 多表 Join 的能力。
  */
-public interface BaseMapperX<T> extends MPJBaseMapper<T> {
+public interface BaseMapperX<T> extends BaseMapper<T> {
 
     default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
         // MyBatis Plus 查询
@@ -46,18 +44,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
     }
 
-    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
-                        SFunction<T, ?> field3, Object value3) {
-        return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
-                .eq(field3, value3));
-    }
-
-    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
-                        SFunction<T, ?> field3, Object value3, SFunction<T, ?> field4, Object value4) {
-        return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
-                .eq(field3, value3).eq(field4, value4));
-    }
-
     default Long selectCount() {
         return selectCount(new QueryWrapper<T>());
     }
@@ -117,26 +103,15 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         update(update, new QueryWrapper<>());
     }
 
-    /**
-     * 根据ID 批量更新,适合大量数据更新
-     *
-     * @param entities 实体们
-     */
     default void updateBatch(Collection<T> entities) {
         Db.updateBatchById(entities);
     }
-
     default void updateBatch(Collection<T> entities, int size) {
         Db.updateBatchById(entities, size);
     }
 
-    /**
-     * 批量修改插入, 会根据实体的主键是否为空,更新还是修改。默认为 1000
-     *
-     * @param entities 实体们
-     */
-    default void saveOrUpdateBatch(Collection<T> entities){
-        Db.saveOrUpdateBatch(entities);
+    default void saveOrUpdateBatch(Collection<T> collection) {
+        Db.saveOrUpdateBatch(collection);
     }
 
 }

+ 2 - 3
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java

@@ -60,7 +60,7 @@ public class YudaoWebSecurityConfigurerAdapter {
     /**
      * 自定义的权限映射 Bean 们
      *
-     * @see #configure(HttpSecurity)
+     * @see #filterChain(HttpSecurity)
      */
     @Resource
     private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@@ -79,7 +79,7 @@ public class YudaoWebSecurityConfigurerAdapter {
 
     /**
      * 配置 URL 的安全配置
-     * <p>
+     *
      * anyRequest          |   匹配所有请求路径
      * access              |   SpringEl表达式结果为true时可以访问
      * anonymous           |   匿名可以访问
@@ -141,7 +141,6 @@ public class YudaoWebSecurityConfigurerAdapter {
 
         // 添加 Token Filter
         httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
-
         return httpSecurity.build();
     }
 

+ 1 - 0
yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbAndRedisUnitTest.java

@@ -40,6 +40,7 @@ public class BaseDbAndRedisUnitTest {
 
             // Redis 配置类
             RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
+//            RedisAutoConfiguration.class, // Spring Redis 自动配置类
             YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
             RedissonAutoConfiguration.class, // Redisson 自动高配置类
     })

+ 1 - 0
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java

@@ -21,6 +21,7 @@ public class YudaoJacksonAutoConfiguration {
     @Bean
     public BeanPostProcessor objectMapperBeanPostProcessor() {
         return new BeanPostProcessor() {
+
             @Override
             public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                 if (!(bean instanceof ObjectMapper)) {

+ 2 - 1
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java

@@ -52,7 +52,8 @@ public class YudaoSwaggerAutoConfiguration {
                 // 接口信息
                 .info(buildInfo(properties))
                 // 接口安全配置
-                .components(new Components().securitySchemes(securitySchemas));
+                .components(new Components().securitySchemes(securitySchemas))
+                .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
         securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key)));
         return openAPI;
     }

+ 1 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java

@@ -47,7 +47,7 @@ public class BpmTaskController {
     @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true)
     @PreAuthorize("@ss.hasPermission('bpm:task:query')")
     public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId(
-        @RequestParam("processInstanceId") String processInstanceId) {
+            @RequestParam("processInstanceId") String processInstanceId) {
         return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
     }
 

+ 9 - 38
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java

@@ -17,12 +17,9 @@ import org.flowable.task.api.Task;
 import org.flowable.task.api.history.HistoricTaskInstance;
 import org.mapstruct.*;
 import org.mapstruct.factory.Mappers;
-import org.springframework.beans.BeanUtils;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 /**
  * Bpm 任务 Convert
@@ -34,37 +31,9 @@ public interface BpmTaskConvert {
 
     BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class);
 
-    /**
-     * 复制对象
-     *
-     * @param source 源 要复制的对象
-     * @param target 目标 复制到此对象
-     * @param <T>
-     *
-     * @return
-     */
-    public static <T> T copy(Object source, Class<T> target) {
-        if (source == null || target == null) {
-            return null;
-        }
-        try {
-            T newInstance = target.getDeclaredConstructor().newInstance();
-            BeanUtils.copyProperties(source, newInstance);
-            return newInstance;
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    default <T, K> List<K> copyList(List<T> source, Class<K> target) {
-        if (null == source || source.isEmpty()) {
-            return Collections.emptyList();
-        }
-        return source.stream().map(e -> copy(e, target)).collect(Collectors.toList());
-    }
-
     default List<BpmTaskTodoPageItemRespVO> convertList1(List<Task> tasks,
-        Map<String, ProcessInstance> processInstanceMap, Map<Long, AdminUserRespDTO> userMap) {
+                                                         Map<String, ProcessInstance> processInstanceMap,
+                                                         Map<Long, AdminUserRespDTO> userMap) {
         return CollectionUtils.convertList(tasks, task -> {
             BpmTaskTodoPageItemRespVO respVO = convert1(task);
             ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId());
@@ -104,11 +73,13 @@ public interface BpmTaskConvert {
 
     BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean);
 
-    @Mappings({@Mapping(source = "processInstance.id", target = "id"),
-        @Mapping(source = "processInstance.name", target = "name"),
-        @Mapping(source = "processInstance.startUserId", target = "startUserId"),
-        @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
-        @Mapping(source = "startUser.nickname", target = "startUserNickname")})
+    @Mappings({
+            @Mapping(source = "processInstance.id", target = "id"),
+            @Mapping(source = "processInstance.name", target = "name"),
+            @Mapping(source = "processInstance.startUserId", target = "startUserId"),
+            @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
+            @Mapping(source = "startUser.nickname", target = "startUserNickname")
+    })
     BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
 
     default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks,

+ 0 - 105
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmActivityDO.java

@@ -1,105 +0,0 @@
-package cn.iocoder.yudao.module.bpm.dal.dataobject.task;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.*;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
-
-/**
- * 任务流程关联表
- *
- * @author kemengkai
- * @create 2022-05-09 10:33
- */
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class BpmActivityDO {
-
-    /**
-     * 任务流程关联id
-     */
-    private String id;
-
-    /**
-     * 审批结果
-     */
-    private Integer rev;
-
-    /**
-     * 任务流程部署id
-     */
-    private String procDefId;
-
-    /**
-     * 任务流程id
-     */
-    private String processInstanceId;
-
-    /**
-     * 任务执行id
-     */
-    private String executionId;
-
-    /**
-     * 任务key
-     */
-    private String activityId;
-
-    /**
-     * 任务id
-     */
-    private String taskId;
-
-    /**
-     * 调用流程id
-     */
-    private String callProcInstId;
-
-    /**
-     * 任务名称
-     */
-    private String activityName;
-
-    /**
-     * 任务类型
-     */
-    private String activityType;
-
-    /**
-     * 任务审批人id
-     */
-    private String assignee;
-
-    /**
-     * 任务开始时间
-     */
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
-    private LocalDateTime startTime;
-
-    /**
-     * 任务结束时间
-     */
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
-    private LocalDateTime endTime;
-
-    private Integer transactionOrder;
-
-    private LocalDateTime duration;
-
-    /**
-     * 删除结果
-     */
-    private String deleteReason;
-
-    /**
-     * 租户id
-     */
-    private String tenantId;
-}

+ 10 - 10
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java

@@ -15,8 +15,8 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
-import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
 import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
+import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.PostApi;
@@ -89,7 +89,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
 
     @Override
     public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
-        String taskDefinitionKey) {
+                                                                                String taskDefinitionKey) {
         return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
     }
 
@@ -128,14 +128,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
         validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
         // 校验是否已经配置
         BpmTaskAssignRuleDO existRule =
-            taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey());
+                taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey());
         if (existRule != null) {
             throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey());
         }
 
         // 存储
         BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)
-            .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建
+                .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建
         taskRuleMapper.insert(rule);
         return rule.getId();
     }
@@ -169,14 +169,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
 
         // 遍历,匹配对应的规则
         Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap =
-            CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
+                CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
         for (BpmTaskAssignRuleRespVO modelRule : modelRules) {
             BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey());
             if (processInstanceRule == null) {
                 return false;
             }
             if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal(
-                modelRule.getOptions(), processInstanceRule.getOptions())) {
+                    modelRule.getOptions(), processInstanceRule.getOptions())) {
                 return false;
             }
         }
@@ -192,7 +192,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
         // 开始复制
         List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules);
         newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null)
-            .setUpdateTime(null));
+                .setUpdateTime(null));
         taskRuleMapper.insertBatch(newRules);
     }
 
@@ -215,7 +215,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
         if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) {
             roleApi.validRoleList(options);
         } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
-            BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
+                BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
             deptApi.validateDeptList(options);
         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) {
             postApi.validPostList(options);
@@ -225,7 +225,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
             userGroupService.validUserGroups(options);
         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) {
             dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT,
-                CollectionUtils.convertSet(options, String::valueOf));
+                    CollectionUtils.convertSet(options, String::valueOf));
         } else {
             throw new IllegalArgumentException(format("未知的规则类型({})", type));
         }
@@ -298,7 +298,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
     }
 
     private Set<Long> calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) {
-        List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions());
+        List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(rule.getOptions());
         return convertSet(users, AdminUserRespDTO::getId);
     }
 

文件差異過大導致無法顯示
+ 0 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java


+ 4 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java

@@ -40,6 +40,8 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
         // mock 方法(startUser)
         AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
         when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
+        // mock 方法(getStartUserDept)没有部门
+        when(deptApi.getDept(eq(10L))).thenReturn(null);
 
         // 调用
         Set<Long> result = script.calculateTaskCandidateUsers(execution);
@@ -56,7 +58,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
         when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
         DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
                 .setLeaderUserId(20L));
+        // mock 方法(getDept)
         when(deptApi.getDept(eq(10L))).thenReturn(startUserDept);
+        when(deptApi.getDept(eq(100L))).thenReturn(null);
 
         // 调用
         Set<Long> result = script.calculateTaskCandidateUsers(execution);

+ 1 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java

@@ -120,7 +120,7 @@ public class BpmTaskAssignRuleServiceImplTest extends BaseDbUnitTest {
         // mock 方法
         List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L),
                 id -> new AdminUserRespDTO().setId(id));
-        when(adminUserApi.getUsersByPostIds(eq(rule.getOptions()))).thenReturn(users);
+        when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users);
         mockGetUserMap(asSet(11L, 22L));
 
         // 调用

+ 4 - 4
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java

@@ -23,10 +23,10 @@ import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgn
 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS;
 
 /**
-* {@link BpmUserGroupServiceImpl} 的单元测试类
-*
-* @author 芋道源码
-*/
+ * {@link BpmUserGroupServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
 @Import(BpmUserGroupServiceImpl.class)
 public class BpmUserGroupServiceTest extends BaseDbUnitTest {
 

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenPreviewRespVO.java

@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
-@Schema(description = "管理后台 - 代码生成预览 Response VO,注意,每个文件都是一个该对象")
+@Schema(description = "管理后台 - 代码生成预览 Response VO注意,每个文件都是一个该对象")
 @Data
 public class CodegenPreviewRespVO {
 

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnBaseVO.java

@@ -70,7 +70,7 @@ public class CodegenColumnBaseVO {
     @NotNull(message = "是否为 List 查询操作的字段不能为空")
     private Boolean listOperation;
 
-    @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
+    @Schema(description = "List 查询操作的条件类型参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
     @NotNull(message = "List 查询操作的条件类型不能为空")
     private String listOperationCondition;
 

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableBaseVO.java

@@ -12,7 +12,7 @@ import javax.validation.constraints.NotNull;
 @Data
 public class CodegenTableBaseVO {
 
-    @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "生成场景参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "导入类型不能为空")
     private Integer scene;
 

+ 3 - 3
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java

@@ -17,13 +17,13 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @ToString(callSuper = true)
 public class CodegenTablePageReqVO extends PageParam {
 
-    @Schema(description = "表名称,模糊匹配", example = "yudao")
+    @Schema(description = "表名称模糊匹配", example = "yudao")
     private String tableName;
 
-    @Schema(description = "表描述,模糊匹配", example = "芋道")
+    @Schema(description = "表描述模糊匹配", example = "芋道")
     private String tableComment;
 
-    @Schema(description = "实体,模糊匹配", example = "Yudao")
+    @Schema(description = "实体模糊匹配", example = "Yudao")
     private String className;
 
     @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")

+ 2 - 2
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigExportReqVO.java

@@ -15,10 +15,10 @@ public class ConfigExportReqVO {
     @Schema(description = "参数名称", example = "模糊匹配")
     private String name;
 
-    @Schema(description = "参数键名,模糊匹配", example = "yunai.db.username")
+    @Schema(description = "参数键名模糊匹配", example = "yunai.db.username")
     private String key;
 
-    @Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", example = "1")
+    @Schema(description = "参数类型参见 SysConfigTypeEnum 枚举", example = "1")
     private Integer type;
 
     @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")

+ 3 - 3
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigPageReqVO.java

@@ -17,13 +17,13 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @ToString(callSuper = true)
 public class ConfigPageReqVO extends PageParam {
 
-    @Schema(description = "数据源名称,模糊匹配", example = "名称")
+    @Schema(description = "数据源名称模糊匹配", example = "名称")
     private String name;
 
-    @Schema(description = "参数键名,模糊匹配", example = "yunai.db.username")
+    @Schema(description = "参数键名模糊匹配", example = "yunai.db.username")
     private String key;
 
-    @Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", example = "1")
+    @Schema(description = "参数类型参见 SysConfigTypeEnum 枚举", example = "1")
     private Integer type;
 
     @Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/vo/ConfigRespVO.java

@@ -21,7 +21,7 @@ public class ConfigRespVO extends ConfigBaseVO {
     @Size(max = 100, message = "参数键名长度不能超过100个字符")
     private String key;
 
-    @Schema(description = "参数类型,参见 SysConfigTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "参数类型参见 SysConfigTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Integer type;
 
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigCreateReqVO.java

@@ -14,7 +14,7 @@ import java.util.Map;
 @ToString(callSuper = true)
 public class FileConfigCreateReqVO extends FileConfigBaseVO {
 
-    @Schema(description = "存储器,参见 FileStorageEnum 枚举类参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "存储器参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "存储器不能为空")
     private Integer storage;
 

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java

@@ -23,8 +23,8 @@ public class FileConfigPageReqVO extends PageParam {
     @Schema(description = "存储器", example = "1")
     private Integer storage;
 
+    @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    @Schema(description = "创建时间")
     private LocalDateTime[] createTime;
 
 }

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigRespVO.java

@@ -18,7 +18,7 @@ public class FileConfigRespVO extends FileConfigBaseVO {
     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Long id;
 
-    @Schema(description = "存储器,参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "存储器参见 FileStorageEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "存储器不能为空")
     private Integer storage;
 

+ 3 - 3
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java

@@ -17,14 +17,14 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @ToString(callSuper = true)
 public class FilePageReqVO extends PageParam {
 
-    @Schema(description = "文件路径,模糊匹配", example = "yudao")
+    @Schema(description = "文件路径模糊匹配", example = "yudao")
     private String path;
 
-    @Schema(description = "文件类型,模糊匹配", example = "application/octet-stream")
+    @Schema(description = "文件类型,模糊匹配", example = "jpg")
     private String type;
 
+    @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    @Schema(description = "创建时间")
     private LocalDateTime[] createTime;
 
 }

+ 3 - 3
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/job/JobPageReqVO.java

@@ -12,13 +12,13 @@ import lombok.ToString;
 @ToString(callSuper = true)
 public class JobPageReqVO extends PageParam {
 
-    @Schema(description = "任务名称,模糊匹配", example = "测试任务")
+    @Schema(description = "任务名称模糊匹配", example = "测试任务")
     private String name;
 
-    @Schema(description = "任务状态,参见 JobStatusEnum 枚举", example = "1")
+    @Schema(description = "任务状态参见 JobStatusEnum 枚举", example = "1")
     private Integer status;
 
-    @Schema(description = "处理器的名字,模糊匹配", example = "sysUserSessionTimeoutJob")
+    @Schema(description = "处理器的名字模糊匹配", example = "sysUserSessionTimeoutJob")
     private String handlerName;
 
 }

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogBaseVO.java

@@ -43,7 +43,7 @@ public class JobLogBaseVO {
     @Schema(description = "执行时长", example = "123")
     private Integer duration;
 
-    @Schema(description = "任务状态,参见 JobLogStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "任务状态参见 JobLogStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "任务状态不能为空")
     private Integer status;
 

+ 3 - 3
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogExportReqVO.java

@@ -8,14 +8,14 @@ import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
-@Schema(description = "管理后台 - 定时任务 Excel 导出 Request VO,参数和 JobLogPageReqVO 是一致的")
+@Schema(description = "管理后台 - 定时任务 Excel 导出 Request VO参数和 JobLogPageReqVO 是一致的")
 @Data
 public class JobLogExportReqVO {
 
     @Schema(description = "任务编号", example = "10")
     private Long jobId;
 
-    @Schema(description = "处理器的名字,模糊匹配")
+    @Schema(description = "处理器的名字模糊匹配")
     private String handlerName;
 
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@@ -26,7 +26,7 @@ public class JobLogExportReqVO {
     @Schema(description = "结束执行时间")
     private LocalDateTime endTime;
 
-    @Schema(description = "任务状态,参见 JobLogStatusEnum 枚举")
+    @Schema(description = "任务状态参见 JobLogStatusEnum 枚举")
     private Integer status;
 
 }

+ 2 - 2
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/vo/log/JobLogPageReqVO.java

@@ -20,7 +20,7 @@ public class JobLogPageReqVO extends PageParam {
     @Schema(description = "任务编号", example = "10")
     private Long jobId;
 
-    @Schema(description = "处理器的名字,模糊匹配")
+    @Schema(description = "处理器的名字模糊匹配")
     private String handlerName;
 
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@@ -31,7 +31,7 @@ public class JobLogPageReqVO extends PageParam {
     @Schema(description = "结束执行时间")
     private LocalDateTime endTime;
 
-    @Schema(description = "任务状态,参见 JobLogStatusEnum 枚举")
+    @Schema(description = "任务状态参见 JobLogStatusEnum 枚举")
     private Integer status;
 
 }

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogBaseVO.java

@@ -24,7 +24,7 @@ public class ApiAccessLogBaseVO {
     @NotNull(message = "用户编号不能为空")
     private Long userId;
 
-    @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @Schema(description = "用户类型参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
     @NotNull(message = "用户类型不能为空")
     private Integer userType;
 

+ 3 - 3
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogExportReqVO.java

@@ -8,7 +8,7 @@ import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
-@Schema(description = "管理后台 - API 访问日志 Excel 导出 Request VO,参数和 ApiAccessLogPageReqVO 是一致的")
+@Schema(description = "管理后台 - API 访问日志 Excel 导出 Request VO参数和 ApiAccessLogPageReqVO 是一致的")
 @Data
 public class ApiAccessLogExportReqVO {
 
@@ -21,11 +21,11 @@ public class ApiAccessLogExportReqVO {
     @Schema(description = "应用名", example = "dashboard")
     private String applicationName;
 
-    @Schema(description = "请求地址,模糊匹配", example = "/xxx/yyy")
+    @Schema(description = "请求地址模糊匹配", example = "/xxx/yyy")
     private String requestUrl;
 
+    @Schema(description = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    @Schema(description = "开始请求时间")
     private LocalDateTime[] beginTime;
 
     @Schema(description = "执行时长,大于等于,单位:毫秒", example = "100")

+ 2 - 2
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java

@@ -26,11 +26,11 @@ public class ApiAccessLogPageReqVO extends PageParam {
     @Schema(description = "应用名", example = "dashboard")
     private String applicationName;
 
-    @Schema(description = "请求地址,模糊匹配", example = "/xxx/yyy")
+    @Schema(description = "请求地址模糊匹配", example = "/xxx/yyy")
     private String requestUrl;
 
+    @Schema(description = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    @Schema(description = "开始请求时间")
     private LocalDateTime[] beginTime;
 
     @Schema(description = "执行时长,大于等于,单位:毫秒", example = "100")

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogExportReqVO.java

@@ -8,7 +8,7 @@ import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
-@Schema(description = "管理后台 - API 错误日志 Excel 导出 Request VO,参数和 ApiErrorLogPageReqVO 是一致的")
+@Schema(description = "管理后台 - API 错误日志 Excel 导出 Request VO参数和 ApiErrorLogPageReqVO 是一致的")
 @Data
 public class ApiErrorLogExportReqVO {
 

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExportReqVO.java

@@ -7,7 +7,7 @@ import org.springframework.format.annotation.DateTimeFormat;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
-@Schema(description = "管理后台 - 字典类型 Excel 导出 Request VO,参数和 TestDemoPageReqVO 是一致的")
+@Schema(description = "管理后台 - 字典类型 Excel 导出 Request VO参数和 TestDemoPageReqVO 是一致的")
 @Data
 public class TestDemoExportReqVO {
 

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DatabaseTableServiceImpl.java

@@ -57,7 +57,7 @@ public class DatabaseTableServiceImpl implements DatabaseTableService {
             strategyConfig.addExclude("ACT_[\\S\\s]+|QRTZ_[\\S\\s]+|FLW_[\\S\\s]+");
         }
 
-        GlobalConfig globalConfig = new GlobalConfig.Builder().dateType(DateType.TIME_PACK).build(); // 只使用 Date 类型,不使用 LocalDate
+        GlobalConfig globalConfig = new GlobalConfig.Builder().dateType(DateType.TIME_PACK).build(); // 只使用 LocalDateTime 类型,不使用 LocalDate
         ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfig, strategyConfig.build(),
                 null, globalConfig, null);
         // 按照名字排序

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImpl.java

@@ -79,7 +79,7 @@ public class TestDemoServiceImpl implements TestDemoService {
 
     @Override
     public PageResult<TestDemoDO> getTestDemoPage(TestDemoPageReqVO pageReqVO) {
-        testDemoMapper.selectList2();
+//        testDemoMapper.selectList2();
         return testDemoMapper.selectPage(pageReqVO);
     }
 

+ 1 - 2
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java

@@ -30,14 +30,13 @@ public interface ProductSkuApi {
      */
     List<ProductSkuRespDTO> getSkuList(Collection<Long> ids);
 
-    // TODO puhui999:入参用 Collection<Long> 更通用
     /**
      * 批量查询 SKU 数组
      *
      * @param spuIds SPU 编号列表
      * @return SKU 数组
      */
-    List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds);
+    List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
 
     /**
      * 更新 SKU 库存

+ 2 - 4
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java

@@ -45,10 +45,8 @@ public interface ErrorCodeConstants {
     ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足");
 
     // ========== 商品 评价 1008007000 ==========
-    ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1008007000, "商品 评价 不存在");
-    ErrorCode ORDER_SPU_COMMENT_EXISTS = new ErrorCode(1008007001, "订单 商品评价 已存在");
-    ErrorCode COMMENT_ERROR_OPT = new ErrorCode(1008007002, "商品评价非法操作");
-    ErrorCode COMMENT_ADDITIONAL_EXISTS  = new ErrorCode(1008007003, "商品追加评价已存在");
+    ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1008007000, "商品评价不存在");
+    ErrorCode COMMENT_ORDER_EXISTS = new ErrorCode(1008007001, "订单的商品评价已存在");
 
     // ========== 商品 收藏 1008008000 ==========
     ErrorCode FAVORITE_EXISTS = new ErrorCode(1008008000, "该商品已经被收藏");

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java

@@ -43,7 +43,7 @@ public class ProductSkuApiImpl implements ProductSkuApi {
     }
 
     @Override
-    public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) {
+    public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) {
         if (CollUtil.isEmpty(spuIds)) {
             return Collections.emptyList();
         }

+ 0 - 13
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentBaseVO.java

@@ -26,23 +26,10 @@ public class ProductCommentBaseVO {
     @NotNull(message = "评价人头像不能为空")
     private String userAvatar;
 
-    // TODO @puhui:spuId、spuName 是不是只有 ProductCommentRespVO 有呀。
-    @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖")
-    @NotNull(message = "商品 SPU 编号不能为空")
-    private Long spuId;
-
-    @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
-    @NotNull(message = "商品 SPU 名称不能为空")
-    private String spuName;
-
     @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "商品 SKU 编号不能为空")
     private Long skuId;
 
-    @Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
-    @NotNull(message = "评分星级不能为空")
-    private Integer scores;
-
     @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
     @NotNull(message = "描述星级不能为空")
     private Integer descriptionScores;

+ 1 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentPageReqVO.java

@@ -35,9 +35,8 @@ public class ProductCommentPageReqVO extends PageParam {
     @InEnum(ProductCommentScoresEnum.class)
     private Integer scores;
 
-    // TODO @puhui999:replyStatus 哈
     @Schema(description = "商家是否回复", example = "true")
-    private Boolean replied;
+    private Boolean replyStatus;
 
     @Schema(description = "创建时间")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

+ 12 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentRespVO.java

@@ -5,6 +5,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
+import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
 
 @Schema(description = "管理后台 - 商品评价 Response VO")
@@ -40,4 +41,15 @@ public class ProductCommentRespVO extends ProductCommentBaseVO {
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime createTime;
 
+    @Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+    private Integer scores;
+
+    @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖")
+    @NotNull(message = "商品 SPU 编号不能为空")
+    private Long spuId;
+
+    @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+    @NotNull(message = "商品 SPU 名称不能为空")
+    private String spuName;
+
 }

+ 10 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java

@@ -21,6 +21,7 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -29,11 +30,6 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 
-/**
- * 商品 SPU 相关接口
- *
- * @author HUIHUI
- */
 @Tag(name = "管理后台 - 商品 SPU")
 @RestController
 @RequestMapping("/product/spu")
@@ -100,6 +96,15 @@ public class ProductSpuController {
         return success(ProductSpuConvert.INSTANCE.convertList02(list));
     }
 
+    @GetMapping("/list")
+    @Operation(summary = "获得商品 SPU 详情列表")
+    @Parameter(name = "spuIds", description = "spu 编号列表", required = true, example = "[1,2,3]")
+    @PreAuthorize("@ss.hasPermission('product:spu:query')")
+    public CommonResult<List<ProductSpuDetailRespVO>> getSpuList(@RequestParam("spuIds") Collection<Long> spuIds) {
+        return success(ProductSpuConvert.INSTANCE.convertForSpuDetailRespListVO(
+                productSpuService.getSpuList(spuIds), productSkuService.getSkuListBySpuId(spuIds)));
+    }
+
     @GetMapping("/page")
     @Operation(summary = "获得商品 SPU 分页")
     @PreAuthorize("@ss.hasPermission('product:spu:query')")

+ 0 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuCreateReqVO.java

@@ -9,11 +9,6 @@ import lombok.ToString;
 import javax.validation.Valid;
 import java.util.List;
 
-/**
- * 商品 SPU 创建 Request VO
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 商品 SPU 创建 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 0 - 6
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java

@@ -8,12 +8,6 @@ import lombok.ToString;
 
 import java.util.List;
 
-/**
- * 商品 SPU 详细 Response VO
- * 包括关联的 SKU 等信息
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 商品 SPU 详细 Response VO")
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 1 - 6
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuExportReqVO.java

@@ -10,12 +10,7 @@ import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
-/**
- * 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的
- *
- * @author HUIHUI
- */
-@Schema(description = "管理后台 - 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的")
+@Schema(description = "管理后台 - 商品 SPU 导出 Request VO,参数和 ProductSpuPageReqVO 是一致的")
 @Data
 @NoArgsConstructor
 @AllArgsConstructor

+ 0 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java

@@ -11,11 +11,6 @@ import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
-/**
- * 商品 SPU 分页 Request VO
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 商品 SPU 分页 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 0 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java

@@ -7,11 +7,6 @@ import lombok.ToString;
 
 import java.time.LocalDateTime;
 
-/**
- * 商品 SPU Response VO
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 商品 SPU Response VO")
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 0 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java

@@ -4,11 +4,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.ToString;
 
-/**
- * 商品 SPU 精简 Response VO
- *  TODO 商品 SPU 精简 VO 暂时没有使用到,用到的时候再按需添加\修改属性
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 商品 SPU 精简 Response VO")
 @Data
 @ToString(callSuper = true)

+ 0 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateReqVO.java

@@ -12,11 +12,6 @@ import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import java.util.List;
 
-/**
- * 商品 SPU 更新 Request VO
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 商品 SPU 更新 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 0 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateStatusReqVO.java

@@ -7,11 +7,6 @@ import lombok.Data;
 
 import javax.validation.constraints.NotNull;
 
-/**
- * 商品 SPU Status 更新 Request VO
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 商品 SPU Status 更新 Request VO")
 @Data
 public class ProductSpuUpdateStatusReqVO{

+ 11 - 23
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java

@@ -1,18 +1,18 @@
 package cn.iocoder.yudao.module.product.controller.app.comment;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
-import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
 import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
+import com.google.common.collect.Maps;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.Parameters;
@@ -26,11 +26,9 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
@@ -53,34 +51,24 @@ public class AppProductCommentController {
             @Parameter(name = "spuId", description = "商品 SPU 编号", required = true, example = "1024"),
             @Parameter(name = "count", description = "数量", required = true, example = "10")
     })
-    public CommonResult<List<AppProductCommentRespVO>> getCommentList(@RequestParam("spuId") Long spuId,
-                                                                      @RequestParam(value = "count", defaultValue = "10") Integer count) {
+    public CommonResult<List<AppProductCommentRespVO>> getCommentList(
+            @RequestParam("spuId") Long spuId,
+            @RequestParam(value = "count", defaultValue = "10") Integer count) {
         return success(productCommentService.getCommentList(spuId, count));
     }
 
     @GetMapping("/page")
     @Operation(summary = "获得商品评价分页")
     public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
-        PageResult<AppProductCommentRespVO> page = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
-        // TODO @puhui CollUtils 有简化 convertmap 和 list 的方法
-        Set<Long> skuIds = page.getList().stream().map(AppProductCommentRespVO::getSkuId).collect(Collectors.toSet());
+        // TODO @puhui999:写到 convert 里,可以更简洁哈。
+        PageResult<ProductCommentDO> commentDOPage = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
+        Set<Long> skuIds = CollectionUtils.convertSet(commentDOPage.getList(), ProductCommentDO::getSkuId);
         List<ProductSkuDO> skuList = productSkuService.getSkuList(skuIds);
-        Map<Long, ProductSkuDO> skuDOMap = new HashMap<>(skuIds.size());
+        Map<Long, ProductSkuDO> skuDOMap = Maps.newLinkedHashMapWithExpectedSize(skuIds.size());
         if (CollUtil.isNotEmpty(skuList)) {
-            skuDOMap.putAll(skuList.stream().collect(Collectors.toMap(ProductSkuDO::getId, c -> c)));
+            skuDOMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId, c -> c));
         }
-        // TODO @puihui999:下面也可以放到 convert 里哈
-        page.getList().forEach(item -> {
-            // 判断用户是否选择匿名
-            if (ObjectUtil.equal(item.getAnonymous(), true)) {
-                item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
-            }
-            ProductSkuDO productSkuDO = skuDOMap.get(item.getSkuId());
-            if (productSkuDO != null) {
-                List<AppProductPropertyValueDetailRespVO> skuProperties = ProductCommentConvert.INSTANCE.convertList01(productSkuDO.getProperties());
-                item.setSkuProperties(skuProperties);
-            }
-        });
+        PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, skuDOMap);
         return success(page);
     }
 

+ 0 - 5
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentRespVO.java

@@ -10,11 +10,6 @@ import javax.validation.constraints.Size;
 import java.time.LocalDateTime;
 import java.util.List;
 
-/**
- * 用户 App - 商品评价详情 Response VO
- *
- * @author HUIHUI
- */
 @Schema(description = "用户 App - 商品评价详情 Response VO")
 @Data
 @ToString(callSuper = true)

+ 38 - 15
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java

@@ -1,6 +1,8 @@
 package cn.iocoder.yudao.module.product.convert.comment;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO;
@@ -19,6 +21,7 @@ import org.mapstruct.factory.Mappers;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 商品评价 Convert
@@ -32,19 +35,33 @@ public interface ProductCommentConvert {
 
     ProductCommentRespVO convert(ProductCommentDO bean);
 
-    // TODO @puhui999:这里貌似字段对上,就不用 mapping 了;可以测试下看看哈
-    @Mapping(target = "goodCount", source = "goodCount")
-    @Mapping(target = "mediocreCount", source = "mediocreCount")
-    @Mapping(target = "negativeCount", source = "negativeCount")
+    @Mapping(target = "scores", expression = "java(calculateOverallScore(goodCount, mediocreCount, negativeCount))")
     AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount);
-
+    @Named("calculateOverallScore")
+    default double calculateOverallScore(long goodCount, long mediocreCount, long negativeCount) {
+        return (goodCount * 5 + mediocreCount * 3 + negativeCount) / (double) (goodCount + mediocreCount + negativeCount);
+    }
+    
     List<ProductCommentRespVO> convertList(List<ProductCommentDO> list);
 
-    List<AppProductPropertyValueDetailRespVO> convertList01(List<ProductSkuDO.Property> properties);
-
     PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> page);
 
-    PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult);
+    PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult);
+
+    default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult,
+                                                              Map<Long, ProductSkuDO> skuMap) {
+        PageResult<AppProductCommentRespVO> page = convertPage01(pageResult);
+        page.getList().forEach(item -> {
+            // 判断用户是否选择匿名
+            if (ObjectUtil.equal(item.getAnonymous(), true)) {
+                item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
+            }
+            MapUtils.findAndThen(skuMap, item.getSkuId(),
+                    sku -> item.setSkuProperties(convertList01(sku.getProperties())));
+        });
+        return page;
+    }
+    List<AppProductPropertyValueDetailRespVO> convertList01(List<ProductSkuDO.Property> properties);
 
     /**
      * 计算综合评分
@@ -63,14 +80,19 @@ public interface ProductCommentConvert {
 
     ProductCommentDO convert(ProductCommentCreateReqDTO createReqDTO);
 
-    @Mapping(target = "scores", expression = "java(convertScores(createReqDTO.getDescriptionScores(), createReqDTO.getBenefitScores()))")
+    @Mapping(target = "scores",
+            expression = "java(convertScores(createReqDTO.getDescriptionScores(), createReqDTO.getBenefitScores()))")
     default ProductCommentDO convert(ProductCommentCreateReqDTO createReqDTO, ProductSpuDO spuDO, MemberUserRespDTO user) {
         ProductCommentDO commentDO = convert(createReqDTO);
-        commentDO.setUserId(user.getId());
-        commentDO.setUserNickname(user.getNickname());
-        commentDO.setUserAvatar(user.getAvatar());
-        commentDO.setSpuId(spuDO.getId());
-        commentDO.setSpuName(spuDO.getName());
+        if (user != null) {
+            commentDO.setUserId(user.getId());
+            commentDO.setUserNickname(user.getNickname());
+            commentDO.setUserAvatar(user.getAvatar());
+        }
+        if (spuDO != null) {
+            commentDO.setSpuId(spuDO.getId());
+            commentDO.setSpuName(spuDO.getName());
+        }
         return commentDO;
     }
 
@@ -78,7 +100,8 @@ public interface ProductCommentConvert {
     @Mapping(target = "orderId", constant = "0L")
     @Mapping(target = "orderItemId", constant = "0L")
     @Mapping(target = "anonymous", expression = "java(Boolean.FALSE)")
-    @Mapping(target = "scores", expression = "java(convertScores(createReq.getDescriptionScores(), createReq.getBenefitScores()))")
+    @Mapping(target = "scores",
+            expression = "java(convertScores(createReq.getDescriptionScores(), createReq.getBenefitScores()))")
     ProductCommentDO convert(ProductCommentCreateReqVO createReq);
 
     List<AppProductCommentRespVO> convertList02(List<ProductCommentDO> list);

+ 14 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java

@@ -18,8 +18,10 @@ import org.mapstruct.factory.Mappers;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 import static cn.hutool.core.util.ObjectUtil.defaultIfNull;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
 
 /**
  * 商品 SPU Convert
@@ -107,4 +109,16 @@ public interface ProductSpuConvert {
         return detailRespVO;
     }
 
+    default List<ProductSpuDetailRespVO> convertForSpuDetailRespListVO(List<ProductSpuDO> spus, List<ProductSkuDO> skus) {
+        List<ProductSpuDetailRespVO> vos = new ArrayList<>(spus.size());
+        Map<Long, List<ProductSkuDO>> skuMultiMap = convertMultiMap(skus, ProductSkuDO::getSpuId);
+        // TODO @puhui999:可以直接使用 CollUtils.convertList
+        spus.forEach(spu -> {
+            ProductSpuDetailRespVO detailRespVO = convert03(spu);
+            detailRespVO.setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId())));
+            vos.add(detailRespVO);
+        });
+        return vos;
+    }
+
 }

+ 3 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java

@@ -26,6 +26,7 @@ public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
     }
 
     static void appendTabQuery(LambdaQueryWrapperX<ProductCommentDO> queryWrapper, Integer type) {
+        // TODO @puhui999:是不是不用 apply 拉?直接用 mybatis 的方法就好啦
         // 构建好评查询语句:好评计算 总评 >= 4
         if (ObjectUtil.equal(type, AppCommentPageReqVO.GOOD_COMMENT)) {
             queryWrapper.apply("scores >= 4");
@@ -51,11 +52,11 @@ public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
         return selectPage(reqVO, queryWrapper);
     }
 
-    default ProductCommentDO selectByUserIdAndOrderItemIdAndSpuId(Long userId, Long orderItemId, Long spuId) {
+    default ProductCommentDO selectByUserIdAndOrderItemIdAndSpuId(Long userId, Long orderItemId, Long skuId) {
         return selectOne(new LambdaQueryWrapperX<ProductCommentDO>()
                 .eq(ProductCommentDO::getUserId, userId)
                 .eq(ProductCommentDO::getOrderItemId, orderItemId)
-                .eq(ProductCommentDO::getSpuId, spuId));
+                .eq(ProductCommentDO::getSpuId, skuId));
     }
 
     default Long selectCountBySpuId(Long spuId, Boolean visible, Integer type) {

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java

@@ -54,7 +54,7 @@ public interface ProductCommentService {
      * @param visible 是否可见
      * @return 商品评价分页
      */
-    PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
+    PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
 
     /**
      * 创建商品评论

+ 8 - 14
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java

@@ -81,7 +81,7 @@ public class ProductCommentServiceImpl implements ProductCommentService {
     @Transactional(rollbackFor = Exception.class)
     public void createComment(ProductCommentCreateReqVO createReqVO) {
         // 校验评论
-        validateComment(createReqVO.getSpuId(), createReqVO.getUserId(), createReqVO.getOrderItemId());
+        validateComment(createReqVO.getSkuId(), createReqVO.getUserId(), createReqVO.getOrderItemId());
 
         ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqVO);
         productCommentMapper.insert(commentDO);
@@ -108,11 +108,11 @@ public class ProductCommentServiceImpl implements ProductCommentService {
         return commentDO.getId();
     }
 
-    private void validateComment(Long spuId, Long userId, Long orderItemId) {
+    private void validateComment(Long skuId, Long userId, Long orderItemId) {
         // 判断当前订单的当前商品用户是否评价过
-        ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemIdAndSpuId(userId, orderItemId, spuId);
+        ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemIdAndSpuId(userId, orderItemId, skuId);
         if (null != exist) {
-            throw exception(ORDER_SPU_COMMENT_EXISTS);
+            throw exception(COMMENT_ORDER_EXISTS);
         }
     }
 
@@ -141,23 +141,17 @@ public class ProductCommentServiceImpl implements ProductCommentService {
                 productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT),
                 // 查询商品 id = spuId 的所有差评数量
                 productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT)
-        ).setScores(3.0); // TODO @puhui999:这里要实现下;;
+        );
     }
 
     @Override
     public List<AppProductCommentRespVO> getCommentList(Long spuId, Integer count) {
-        // 校验商品 spu 是否存在
-        // TODO @puhui 这里校验可以去掉哈。
-        ProductSpuDO spuDO = validateSpu(spuId);
-        return ProductCommentConvert.INSTANCE.convertList02(productCommentMapper.selectCommentList(spuDO.getId(), count).getList());
+        return ProductCommentConvert.INSTANCE.convertList02(productCommentMapper.selectCommentList(spuId, count).getList());
     }
 
-    // TODO @puhui 可以放到 controller 去 convert 哈
     @Override
-    public PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) {
-        // TODO @puhui 可以放到 controller 去 convert 哈
-        return ProductCommentConvert.INSTANCE.convertPage02(
-                productCommentMapper.selectPage(pageVO, visible));
+    public PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) {
+        return productCommentMapper.selectPage(pageVO, visible);
     }
 
     @Override

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java

@@ -90,7 +90,7 @@ public interface ProductSkuService {
      * @param spuIds spu 编码集合
      * @return 商品 sku 集合
      */
-    List<ProductSkuDO> getSkuListBySpuId(List<Long> spuIds);
+    List<ProductSkuDO> getSkuListBySpuId(Collection<Long> spuIds);
 
     /**
      * 通过 spuId 删除 sku 信息

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java

@@ -148,7 +148,7 @@ public class ProductSkuServiceImpl implements ProductSkuService {
     }
 
     @Override
-    public List<ProductSkuDO> getSkuListBySpuId(List<Long> spuIds) {
+    public List<ProductSkuDO> getSkuListBySpuId(Collection<Long> spuIds) {
         return productSkuMapper.selectListBySpuId(spuIds);
     }
 

+ 4 - 5
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java

@@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommen
 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO;
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
-import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
 import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
 import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper;
@@ -128,7 +127,7 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
         productCommentPageReqVO.setSpuId(spuId);
         productCommentPageReqVO.setSpuName("感冒药");
         productCommentPageReqVO.setScores(ProductCommentScoresEnum.FOUR.getScores());
-        productCommentPageReqVO.setReplied(Boolean.TRUE);
+        productCommentPageReqVO.setReplyStatus(Boolean.TRUE);
 
         PageResult<ProductCommentDO> commentPage = productCommentService.getCommentPage(productCommentPageReqVO);
         PageResult<ProductCommentRespVO> result = ProductCommentConvert.INSTANCE.convertPage(productCommentMapper.selectPage(productCommentPageReqVO));
@@ -138,15 +137,15 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
         assertEquals(8, all.getTotal());
 
         // 测试获取所有商品分页评论数据
-        PageResult<AppProductCommentRespVO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE);
+        PageResult<ProductCommentDO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE);
         assertEquals(7, result1.getTotal());
 
         // 测试获取所有商品分页中评数据
-        PageResult<AppProductCommentRespVO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
+        PageResult<ProductCommentDO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
         assertEquals(2, result2.getTotal());
 
         // 测试获取指定 spuId 商品分页中评数据
-        PageResult<AppProductCommentRespVO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
+        PageResult<ProductCommentDO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
         assertEquals(2, result3.getTotal());
 
         // 测试分页 tab count

+ 49 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApi.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.promotion.api.combination;
+
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
+
+import javax.validation.Valid;
+
+// TODO @puhui999:CombinationRecordApi 分成活动、记录哈
+// TODO @芋艿:后面也再撸撸这几个接口
+/**
+ * 拼团活动 API 接口
+ *
+ * @author HUIHUI
+ */
+public interface CombinationApi {
+
+    /**
+     * 创建开团记录
+     *
+     * @param reqDTO 请求 DTO
+     */
+    void createRecord(@Valid CombinationRecordReqDTO reqDTO);
+
+    /**
+     * 获取开团记录状态
+     *
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     */
+    boolean validateRecordStatusIsSuccess(Long userId, Long orderId);
+
+    /**
+     * 更新开团记录状态
+     *
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     * @param status  状态值
+     */
+    void updateRecordStatus(Long userId, Long orderId, Integer status);
+
+    /**
+     * 更新开团记录状态和开始时间
+     *
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     * @param status  状态值
+     */
+    void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status);
+
+}

+ 78 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordReqDTO.java

@@ -0,0 +1,78 @@
+package cn.iocoder.yudao.module.promotion.api.combination.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+// TODO @puhui999:CombinationRecordCreateReqDTO,这样更容易知道是创建噢
+/**
+ * 拼团记录 Request DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class CombinationRecordReqDTO {
+
+    /**
+     * 拼团活动编号
+     */
+    @NotNull(message = "拼团活动编号不能为空")
+    private Long activityId;
+    /**
+     * spu 编号
+     */
+    @NotNull(message = "spu 编号不能为空")
+    private Long spuId;
+    /**
+     * sku 编号
+     */
+    @NotNull(message = "sku 编号不能为空")
+    private Long skuId;
+    /**
+     * 用户编号
+     */
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+    /**
+     * 订单编号
+     */
+    @NotNull(message = "订单编号不能为空")
+    private Long orderId;
+    /**
+     * 团长编号
+     */
+    @NotNull(message = "团长编号不能为空")
+    private Long headId;
+    /**
+     * 商品名字
+     */
+    @NotEmpty(message = "商品名字不能为空")
+    private String spuName;
+    /**
+     * 商品图片
+     */
+    @NotEmpty(message = "商品图片不能为空")
+    private String picUrl;
+    /**
+     * 拼团商品单价
+     */
+    @NotNull(message = "拼团商品单价不能为空")
+    private Integer combinationPrice;
+    /**
+     * 用户昵称
+     */
+    @NotEmpty(message = "用户昵称不能为空")
+    private String nickname;
+    /**
+     * 用户头像
+     */
+    @NotEmpty(message = "用户头像不能为空")
+    private String avatar;
+    /**
+     * 开团状态:正在开团 拼团成功 拼团失败 TODO 等待支付
+     */
+    @NotNull(message = "开团状态不能为空")
+    private Integer status;
+
+}

+ 10 - 3
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 
 /**
  * Promotion 错误码枚举类
- *
+ * <p>
  * promotion 系统,使用 1-013-000-000 段
  */
 public interface ErrorCodeConstants {
@@ -42,8 +42,7 @@ public interface ErrorCodeConstants {
     ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013006004, "满减送活动已关闭,不能重复关闭");
     ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1013006005, "满减送活动已结束,不能关闭");
 
-    // ========== Price 相关 1013007000 ============
-    ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1013007000, "支付价格计算异常,原因:价格小于等于 0");
+    // ========== TODO 空着 1013007000 ============
 
     // ========== 秒杀活动 1013008000 ==========
     ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在");
@@ -58,5 +57,13 @@ public interface ErrorCodeConstants {
     ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
     ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等");
     ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
+    ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
+
+    // ========== 拼团活动 1013010000 ==========
+    ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
+    ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010001, "存在商品参加了其它拼团活动");
+    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
+    ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
+    ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
 
 }

+ 39 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/combination/CombinationRecordStatusEnum.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.promotion.enums.combination;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 拼团状态枚举
+ *
+ * @author HUIHUI
+ */
+@AllArgsConstructor
+@Getter
+public enum CombinationRecordStatusEnum implements IntArrayValuable {
+
+    WAITING(0, "未付款"),
+    IN_PROGRESS(1, "进行中"),
+    SUCCESS(2, "拼团成功"),
+    FAILED(3, "拼团失败");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CombinationRecordStatusEnum::getStatus).toArray();
+
+    /**
+     * 状态值
+     */
+    private final Integer status;
+    /**
+     * 状态名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 42 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.promotion.api.combination;
+
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
+import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ * 拼团活动 API 实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+public class CombinationApiImpl implements CombinationApi {
+
+    @Resource
+    private CombinationActivityService activityService;
+
+    @Override
+    public void createRecord(CombinationRecordReqDTO reqDTO) {
+        activityService.createRecord(reqDTO);
+    }
+
+    @Override
+    public boolean validateRecordStatusIsSuccess(Long userId, Long orderId) {
+        return activityService.validateRecordStatusIsSuccess(userId, orderId);
+    }
+
+    @Override
+    public void updateRecordStatus(Long userId, Long orderId, Integer status) {
+        activityService.updateRecordStatusByUserIdAndOrderId(userId, orderId, status);
+    }
+
+    @Override
+    public void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status) {
+        activityService.updateRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
+    }
+
+
+}

+ 114 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java

@@ -0,0 +1,114 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.*;
+import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
+import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static cn.hutool.core.collection.CollectionUtil.newArrayList;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
+
+@Tag(name = "管理后台 - 拼团活动")
+@RestController
+@RequestMapping("/promotion/combination-activity")
+@Validated
+public class CombinationActivityController {
+
+    @Resource
+    private CombinationActivityService combinationActivityService;
+    @Resource
+    private ProductSpuApi spuApi;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建拼团活动")
+    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:create')")
+    public CommonResult<Long> createCombinationActivity(@Valid @RequestBody CombinationActivityCreateReqVO createReqVO) {
+        return success(combinationActivityService.createCombinationActivity(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新拼团活动")
+    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:update')")
+    public CommonResult<Boolean> updateCombinationActivity(@Valid @RequestBody CombinationActivityUpdateReqVO updateReqVO) {
+        combinationActivityService.updateCombinationActivity(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除拼团活动")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:delete')")
+    public CommonResult<Boolean> deleteCombinationActivity(@RequestParam("id") Long id) {
+        combinationActivityService.deleteCombinationActivity(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得拼团活动")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
+    public CommonResult<CombinationActivityRespVO> getCombinationActivity(@RequestParam("id") Long id) {
+        CombinationActivityDO activity = combinationActivityService.getCombinationActivity(id);
+        List<CombinationProductDO> products = combinationActivityService.getProductsByActivityIds(newArrayList(id));
+        return success(CombinationActivityConvert.INSTANCE.convert(activity, products));
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "获得拼团活动列表")
+    @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
+    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
+    public CommonResult<List<CombinationActivityRespVO>> getCombinationActivityList(@RequestParam("ids") Collection<Long> ids) {
+        List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(ids);
+        return success(CombinationActivityConvert.INSTANCE.convertList(list));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得拼团活动分页")
+    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
+    public CommonResult<PageResult<CombinationActivityRespVO>> getCombinationActivityPage(
+            @Valid CombinationActivityPageReqVO pageVO) {
+        PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO);
+        // TODO @puhui999:可以不一定 aIds,直接批量查询结果出来;下面也是类似;
+        Set<Long> aIds = CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getId);
+        List<CombinationProductDO> products = combinationActivityService.getProductsByActivityIds(aIds);
+        Set<Long> spuIds = CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getSpuId);
+        List<ProductSpuRespDTO> spus = spuApi.getSpuList(spuIds);
+        return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出拼团活动 Excel")
+    @PreAuthorize("@ss.hasPermission('promotion:combination-activity:export')")
+    @OperateLog(type = EXPORT)
+    public void exportCombinationActivityExcel(@Valid CombinationActivityExportReqVO exportReqVO,
+                                               HttpServletResponse response) throws IOException {
+        List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(exportReqVO);
+        // 导出 Excel
+        List<CombinationActivityExcelVO> datas = CombinationActivityConvert.INSTANCE.convertList02(list);
+        ExcelUtils.write(response, "拼团活动.xls", "数据", CombinationActivityExcelVO.class, datas);
+    }
+
+}

+ 49 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+ * 拼团活动 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class CombinationActivityBaseVO {
+
+    @Schema(description = "拼团名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "越拼越省钱")
+    @NotNull(message = "拼团名称不能为空")
+    private String name;
+
+    @Schema(description = "商品 SPU 编号,关联 ProductSpuDO 的 id", example = "[1,2,3]")
+    @NotNull(message = "拼团商品不能为空")
+    private Long spuId;
+
+    @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218")
+    @NotNull(message = "总限购数量不能为空")
+    private Integer totalLimitCount;
+
+    @Schema(description = "单次限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "28265")
+    @NotNull(message = "单次限购数量不能为空")
+    private Integer singleLimitCount;
+
+    // TODO @puhui999:是不是弄成 2 个字段会好点哈。开始、结束
+    @Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
+    @NotNull(message = "活动时间不能为空")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityTime;
+
+    @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
+    @NotNull(message = "开团人数不能为空")
+    private Integer userSize;
+
+    @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "限制时长不能为空")
+    private Integer limitDuration;
+
+}

+ 22 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.Valid;
+import java.util.List;
+
+@Schema(description = "管理后台 - 拼团活动创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationActivityCreateReqVO extends CombinationActivityBaseVO {
+
+    @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Valid
+    private List<CombinationProductCreateReqVO> products;
+
+}

+ 65 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExcelVO.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+// TODO @puhui999:如无必要,导出都可以删除哈
+/**
+ * 拼团活动 Excel VO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class CombinationActivityExcelVO {
+
+    @ExcelProperty("活动编号")
+    private Long id;
+
+    @ExcelProperty("拼团名称")
+    private String name;
+
+    @ExcelProperty("商品 SPU 编号关联 ProductSpuDO 的 id")
+    private Long spuId;
+
+    @ExcelProperty("总限购数量")
+    private Integer totalLimitCount;
+
+    @ExcelProperty("单次限购数量")
+    private Integer singleLimitCount;
+
+    @ExcelProperty("开始时间")
+    private LocalDateTime startTime;
+
+    @ExcelProperty("结束时间")
+    private LocalDateTime endTime;
+
+    @ExcelProperty("开团人数")
+    private Integer userSize;
+
+    @ExcelProperty("开团组数")
+    private Integer totalNum;
+
+    @ExcelProperty("成团组数")
+    private Integer successNum;
+
+    @ExcelProperty("参与人数")
+    private Integer orderUserCount;
+
+    @ExcelProperty("虚拟成团")
+    private Integer virtualGroup;
+
+    @ExcelProperty(value = "活动状态:0开启 1关闭", converter = DictConvert.class)
+    @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
+    private Integer status;
+
+    @ExcelProperty("限制时长(小时)")
+    private Integer limitDuration;
+
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 61 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExportReqVO.java

@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+// TODO @puhui999:如无必要,导出都可以删除哈
+@Schema(description = "管理后台 - 拼团活动 Excel 导出 Request VO,参数和 CombinationActivityPageReqVO 是一致的")
+@Data
+public class CombinationActivityExportReqVO {
+
+    @Schema(description = "拼团名称", example = "赵六")
+    private String name;
+
+    @Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "14016")
+    private Long spuId;
+
+    @Schema(description = "总限购数量", example = "16218")
+    private Integer totalLimitCount;
+
+    @Schema(description = "单次限购数量", example = "28265")
+    private Integer singleLimitCount;
+
+    @Schema(description = "开始时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] startTime;
+
+    @Schema(description = "结束时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] endTime;
+
+    @Schema(description = "开团人数")
+    private Integer userSize;
+
+    @Schema(description = "开团组数")
+    private Integer totalNum;
+
+    @Schema(description = "成团组数")
+    private Integer successNum;
+
+    @Schema(description = "参与人数", example = "25222")
+    private Integer orderUserCount;
+
+    @Schema(description = "虚拟成团")
+    private Integer virtualGroup;
+
+    @Schema(description = "活动状态:0开启 1关闭", example = "0")
+    private Integer status;
+
+    @Schema(description = "限制时长(小时)")
+    private Integer limitDuration;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 65 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 拼团活动分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationActivityPageReqVO extends PageParam {
+
+    @Schema(description = "拼团名称", example = "赵六")
+    private String name;
+
+    @Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "14016")
+    private Long spuId;
+
+    @Schema(description = "总限购数量", example = "16218")
+    private Integer totalLimitCount;
+
+    @Schema(description = "单次限购数量", example = "28265")
+    private Integer singleLimitCount;
+
+    @Schema(description = "开始时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] startTime;
+
+    @Schema(description = "结束时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] endTime;
+
+    @Schema(description = "开团人数")
+    private Integer userSize;
+
+    @Schema(description = "开团组数")
+    private Integer totalNum;
+
+    @Schema(description = "成团组数")
+    private Integer successNum;
+
+    @Schema(description = "参与人数", example = "25222")
+    private Integer orderUserCount;
+
+    @Schema(description = "虚拟成团")
+    private Integer virtualGroup;
+
+    @Schema(description = "活动状态:0开启 1关闭", example = "0")
+    private Integer status;
+
+    @Schema(description = "限制时长(小时)")
+    private Integer limitDuration;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 56 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 拼团活动 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationActivityRespVO extends CombinationActivityBaseVO {
+
+    @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
+    private String spuName;
+
+    @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
+    private String picUrl;
+
+    @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
+    private Long id;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+    @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "开团人数不能为空")
+    private Integer userSize;
+
+    @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "开团组数不能为空")
+    private Integer totalNum;
+
+    @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "成团组数不能为空")
+    private Integer successNum;
+
+    @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "虚拟成团不能为空")
+    private Integer virtualGroup;
+
+    @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    @NotNull(message = "活动状态不能为空")
+    private Integer status;
+
+    @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Valid
+    private List<CombinationProductRespVO> products;
+
+}

+ 27 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Schema(description = "管理后台 - 拼团活动更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationActivityUpdateReqVO extends CombinationActivityBaseVO {
+
+    @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
+    @NotNull(message = "活动编号不能为空")
+    private Long id;
+
+    @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Valid
+    private List<CombinationProductUpdateReqVO> products;
+
+}

+ 27 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 拼团商品 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class CombinationProductBaseVO {
+
+    @Schema(description = "商品 spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
+    @NotNull(message = "商品 spuId 不能为空")
+    private Long spuId;
+
+    @Schema(description = "商品 skuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
+    @NotNull(message = "商品 skuId 不能为空")
+    private Long skuId;
+
+    @Schema(description = "拼团价格,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "27682")
+    @NotNull(message = "拼团价格,单位分不能为空")
+    private Integer activePrice;
+
+}

+ 14 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductCreateReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 拼团商品创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationProductCreateReqVO extends CombinationProductBaseVO {
+
+}

+ 44 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExcelVO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+// TODO @puhui999:可以考虑删除 excel 导出哈
+/**
+ * 拼团商品 Excel VO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class CombinationProductExcelVO {
+
+    @ExcelProperty("编号")
+    private Long id;
+
+    @ExcelProperty("拼团活动编号")
+    private Long activityId;
+
+    @ExcelProperty("商品 SPU 编号")
+    private Long spuId;
+
+    @ExcelProperty("商品 SKU 编号")
+    private Long skuId;
+
+    @ExcelProperty("拼团商品状态")
+    private Integer activityStatus;
+
+    @ExcelProperty("活动开始时间点")
+    private LocalDateTime activityStartTime;
+
+    @ExcelProperty("活动结束时间点")
+    private LocalDateTime activityEndTime;
+
+    @ExcelProperty("拼团价格,单位分")
+    private Integer activePrice;
+
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 43 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExportReqVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+// TODO @puhui999:可以考虑删除 excel 导出哈
+@Schema(description = "管理后台 - 拼团商品 Excel 导出 Request VO,参数和 CombinationProductPageReqVO 是一致的")
+@Data
+public class CombinationProductExportReqVO {
+
+    @Schema(description = "拼团活动编号", example = "6829")
+    private Long activityId;
+
+    @Schema(description = "商品 SPU 编号", example = "18731")
+    private Long spuId;
+
+    @Schema(description = "商品 SKU 编号", example = "31675")
+    private Long skuId;
+
+    @Schema(description = "拼团商品状态", example = "2")
+    private Integer activityStatus;
+
+    @Schema(description = "活动开始时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityStartTime;
+
+    @Schema(description = "活动结束时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityEndTime;
+
+    @Schema(description = "拼团价格,单位分", example = "27682")
+    private Integer activePrice;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 47 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductPageReqVO.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 拼团商品分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationProductPageReqVO extends PageParam {
+
+    @Schema(description = "拼团活动编号", example = "6829")
+    private Long activityId;
+
+    @Schema(description = "商品 SPU 编号", example = "18731")
+    private Long spuId;
+
+    @Schema(description = "商品 SKU 编号", example = "31675")
+    private Long skuId;
+
+    @Schema(description = "拼团商品状态", example = "2")
+    private Integer activityStatus;
+
+    @Schema(description = "活动开始时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityStartTime;
+
+    @Schema(description = "活动结束时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityEndTime;
+
+    @Schema(description = "拼团价格,单位分", example = "27682")
+    private Integer activePrice;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 22 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductRespVO.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 拼团商品 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationProductRespVO extends CombinationProductBaseVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28322")
+    private Long id;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+}

+ 14 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductUpdateReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 拼团商品更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationProductUpdateReqVO extends CombinationProductBaseVO {
+
+}

+ 13 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java

@@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.promotion.controller.admin.seckill;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*;
 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
@@ -18,6 +21,7 @@ import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
@@ -29,6 +33,8 @@ public class SeckillActivityController {
 
     @Resource
     private SeckillActivityService seckillActivityService;
+    @Resource
+    private ProductSpuApi spuApi;
 
     @PostMapping("/create")
     @Operation(summary = "创建秒杀活动")
@@ -69,11 +75,8 @@ public class SeckillActivityController {
     @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
     public CommonResult<SeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
         SeckillActivityDO seckillActivity = seckillActivityService.getSeckillActivity(id);
-        if (seckillActivity == null) {
-            return success(null);
-        }
-        List<SeckillProductDO> seckillProducts =  seckillActivityService.getSeckillProductListByActivityId(id);
-        return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity,seckillProducts));
+        List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(id);
+        return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity, seckillProducts));
     }
 
     @GetMapping("/list")
@@ -90,7 +93,11 @@ public class SeckillActivityController {
     @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
     public CommonResult<PageResult<SeckillActivityRespVO>> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) {
         PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(pageVO);
-        return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult));
+        Set<Long> aIds = CollectionUtils.convertSet(pageResult.getList(), SeckillActivityDO::getId);
+        List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(aIds);
+        Set<Long> spuIds = CollectionUtils.convertSet(pageResult.getList(), SeckillActivityDO::getSpuId);
+        List<ProductSpuRespDTO> spuList = spuApi.getSpuList(spuIds);
+        return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, seckillProducts, spuList));
     }
 
 }

+ 0 - 5
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java

@@ -19,11 +19,6 @@ import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
-/**
- * 管理后台 - 秒杀时段相关接口
- *
- * @author HUIHUI
- */
 @Tag(name = "管理后台 - 秒杀时段")
 @RestController
 @RequestMapping("/promotion/seckill-config")

+ 1 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java

@@ -20,10 +20,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @Data
 public class SeckillActivityBaseVO {
 
-    // TODO @puhui999:对应单 spuId 哈
     @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
     @NotNull(message = "秒杀活动商品不能为空")
-    private List<Long> spuIds;
+    private Long spuId;
 
     @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
     @NotNull(message = "秒杀活动名称不能为空")
@@ -56,8 +55,4 @@ public class SeckillActivityBaseVO {
     @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683")
     private Integer singleLimitCount;
 
-    // TODO @puhui999:这个应该是计算出来的字段,只返回,create 和 update 不用哈
-    @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
-    private Integer totalStock;
-
 }

+ 26 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java

@@ -6,26 +6,46 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
+import java.time.LocalDateTime;
 import java.util.List;
 
-/**
- * 管理后台 - 秒杀活动 Response VO
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 秒杀活动 Response VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
 public class SeckillActivityRespVO extends SeckillActivityBaseVO {
 
+    @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
+    private String spuName;
+
+    @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
+    private String picUrl;
+
     @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Long id;
 
     @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
-    private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除
+    private List<SeckillProductRespVO> products;
 
     @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
     private Integer status;
 
+    @Schema(description = "订单实付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22354")
+    private Integer totalPrice;
+
+    @Schema(description = "秒杀库存", example = "10")
+    private Integer stock;
+
+    @Schema(description = "秒杀总库存", example = "20")
+    private Integer totalStock;
+
+    @Schema(description = "新增订单数", example = "20")
+    private Integer orderCount;
+
+    @Schema(description = "付款人数", example = "20")
+    private Integer userCount;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
 }

+ 19 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigBaseVO.java

@@ -1,9 +1,13 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import javax.validation.constraints.AssertTrue;
 import javax.validation.constraints.NotNull;
+import java.time.LocalTime;
+import java.util.List;
 
 /**
  * 秒杀时段 Base VO,提供给添加、修改、详细的子 VO 使用
@@ -26,12 +30,24 @@ public class SeckillConfigBaseVO {
     @NotNull(message = "结束时间点不能为空")
     private String endTime;
 
-    @Schema(description = "秒杀图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
-    @NotNull(message = "秒杀图不能为空")
-    private String picUrl;
+    @Schema(description = "秒杀轮播图", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]")
+    @NotNull(message = "秒杀轮播图不能为空")
+    private List<String> sliderPicUrls;
 
     @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
     @NotNull(message = "状态不能为空")
     private Integer status;
 
+    @AssertTrue(message = "秒杀时段开始时间和结束时间不能相等")
+    @JsonIgnore
+    public boolean isValidStartTimeValid() {
+        return !LocalTime.parse(startTime).equals(LocalTime.parse(endTime));
+    }
+
+    @AssertTrue(message = "秒杀时段开始时间不能在结束时间之后")
+    @JsonIgnore
+    public boolean isValidEndTimeValid() {
+        return !LocalTime.parse(startTime).isAfter(LocalTime.parse(endTime));
+    }
+
 }

+ 0 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigPageReqVO.java

@@ -6,12 +6,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
-// TODO @puhui:VO 上不写注释,已经有注解啦。
-/**
- * 管理后台 - 秒杀时段分页 Request VO
- *
- * @author HUIHUI
- */
 @Schema(description = "管理后台 - 秒杀时段分页 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)

部分文件因文件數量過多而無法顯示